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 static constexpr QMatrix4x4 m(1.0f, 0.0f, 0.0f, 0.0f,
791 0.0f, 1.0f, 0.0f, 0.0f,
792 0.0f, 0.0f, 0.5f, 0.5f,
793 0.0f, 0.0f, 0.0f, 1.0f);
797bool QRhiD3D12::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags)
const
801 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ASTC_12x12)
807bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature)
const
810 case QRhi::MultisampleTexture:
812 case QRhi::MultisampleRenderBuffer:
814 case QRhi::DebugMarkers:
815#ifdef QRHI_D3D12_HAS_OLD_PIX
820 case QRhi::Timestamps:
822 case QRhi::Instancing:
824 case QRhi::CustomInstanceStepRate:
826 case QRhi::PrimitiveRestart:
828 case QRhi::NonDynamicUniformBuffers:
830 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
832 case QRhi::NPOTTextureRepeat:
834 case QRhi::RedOrAlpha8IsRed:
836 case QRhi::ElementIndexUint:
840 case QRhi::WideLines:
842 case QRhi::VertexShaderPointSize:
844 case QRhi::BaseVertex:
846 case QRhi::BaseInstance:
848 case QRhi::TriangleFanTopology:
850 case QRhi::ReadBackNonUniformBuffer:
852 case QRhi::ReadBackNonBaseMipLevel:
854 case QRhi::TexelFetch:
856 case QRhi::RenderToNonBaseMipLevel:
858 case QRhi::IntAttributes:
860 case QRhi::ScreenSpaceDerivatives:
862 case QRhi::ReadBackAnyTextureFormat:
864 case QRhi::PipelineCacheDataLoadSave:
866 case QRhi::ImageDataStride:
868 case QRhi::RenderBufferImport:
870 case QRhi::ThreeDimensionalTextures:
872 case QRhi::RenderTo3DTextureSlice:
874 case QRhi::TextureArrays:
876 case QRhi::Tessellation:
878 case QRhi::GeometryShader:
880 case QRhi::TextureArrayRange:
882 case QRhi::NonFillPolygonMode:
884 case QRhi::OneDimensionalTextures:
886 case QRhi::OneDimensionalTextureMipmaps:
888 case QRhi::HalfAttributes:
890 case QRhi::RenderToOneDimensionalTexture:
892 case QRhi::ThreeDimensionalTextureMipmaps:
894 case QRhi::MultiView:
895 return caps.multiView;
896 case QRhi::TextureViewFormat:
897 return caps.textureViewFormat;
898 case QRhi::ResolveDepthStencil:
902 case QRhi::VariableRateShading:
904 case QRhi::VariableRateShadingMap:
905 case QRhi::VariableRateShadingMapWithTexture:
907 case QRhi::PerRenderTargetBlending:
908 case QRhi::SampleVariables:
910 case QRhi::InstanceIndexIncludesBaseInstance:
912 case QRhi::DepthClamp:
914 case QRhi::DrawIndirect:
915 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
916 case QRhi::DrawIndirectMulti:
917 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
918 case QRhi::ShaderDrawParameters:
924int QRhiD3D12::resourceLimit(QRhi::ResourceLimit limit)
const
927 case QRhi::TextureSizeMin:
929 case QRhi::TextureSizeMax:
931 case QRhi::MaxColorAttachments:
933 case QRhi::FramesInFlight:
934 return QD3D12_FRAMES_IN_FLIGHT;
935 case QRhi::MaxAsyncReadbackFrames:
936 return QD3D12_FRAMES_IN_FLIGHT;
937 case QRhi::MaxThreadGroupsPerDimension:
939 case QRhi::MaxThreadsPerThreadGroup:
941 case QRhi::MaxThreadGroupX:
943 case QRhi::MaxThreadGroupY:
945 case QRhi::MaxThreadGroupZ:
947 case QRhi::TextureArraySizeMax:
949 case QRhi::MaxUniformBufferRange:
951 case QRhi::MaxVertexInputs:
953 case QRhi::MaxVertexOutputs:
955 case QRhi::ShadingRateImageTileSize:
956 return shadingRateImageTileSize;
961const QRhiNativeHandles *QRhiD3D12::nativeHandles()
963 return &nativeHandlesStruct;
966QRhiDriverInfo QRhiD3D12::driverInfo()
const
968 return driverInfoStruct;
971QRhiStats QRhiD3D12::statistics()
974 result.totalPipelineCreationTime = totalPipelineCreationTime();
976 D3D12MA::Budget budgets[2];
977 vma.getBudget(&budgets[0], &budgets[1]);
978 for (
int i = 0; i < 2; ++i) {
979 const D3D12MA::Statistics &stats(budgets[i].Stats);
980 result.blockCount += stats.BlockCount;
981 result.allocCount += stats.AllocationCount;
982 result.usedBytes += stats.AllocationBytes;
983 result.unusedBytes += stats.BlockBytes - stats.AllocationBytes;
984 result.totalUsageBytes += budgets[i].UsageBytes;
990bool QRhiD3D12::makeThreadLocalNativeContextCurrent()
996void QRhiD3D12::setQueueSubmitParams(QRhiNativeHandles *)
1001void QRhiD3D12::releaseCachedResources()
1003 shaderBytecodeCache.data.clear();
1006bool QRhiD3D12::isDeviceLost()
const
1011QByteArray QRhiD3D12::pipelineCacheData()
1016void QRhiD3D12::setPipelineCacheData(
const QByteArray &data)
1021QRhiRenderBuffer *QRhiD3D12::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
1022 int sampleCount, QRhiRenderBuffer::Flags flags,
1023 QRhiTexture::Format backingFormatHint)
1025 return new QD3D12RenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
1028QRhiTexture *QRhiD3D12::createTexture(QRhiTexture::Format format,
1029 const QSize &pixelSize,
int depth,
int arraySize,
1030 int sampleCount, QRhiTexture::Flags flags)
1032 return new QD3D12Texture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
1035QRhiSampler *QRhiD3D12::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
1036 QRhiSampler::Filter mipmapMode,
1037 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
1039 return new QD3D12Sampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
1042QRhiTextureRenderTarget *QRhiD3D12::createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
1043 QRhiTextureRenderTarget::Flags flags)
1045 return new QD3D12TextureRenderTarget(
this, desc, flags);
1048QRhiShadingRateMap *QRhiD3D12::createShadingRateMap()
1050 return new QD3D12ShadingRateMap(
this);
1053QRhiGraphicsPipeline *QRhiD3D12::createGraphicsPipeline()
1055 return new QD3D12GraphicsPipeline(
this);
1058QRhiComputePipeline *QRhiD3D12::createComputePipeline()
1060 return new QD3D12ComputePipeline(
this);
1063QRhiShaderResourceBindings *QRhiD3D12::createShaderResourceBindings()
1065 return new QD3D12ShaderResourceBindings(
this);
1068void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
1070 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1071 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1072 QD3D12GraphicsPipeline *psD = QRHI_RES(QD3D12GraphicsPipeline, ps);
1073 const bool pipelineChanged = cbD->currentGraphicsPipeline != psD || cbD->currentPipelineGeneration != psD->generation;
1075 if (pipelineChanged) {
1076 cbD->currentGraphicsPipeline = psD;
1077 cbD->currentComputePipeline =
nullptr;
1078 cbD->currentPipelineGeneration = psD->generation;
1080 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
1081 Q_ASSERT(pipeline->type == QD3D12Pipeline::Graphics);
1082 cbD->cmdList->SetPipelineState(pipeline->pso);
1083 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
1084 cbD->cmdList->SetGraphicsRootSignature(rs->rootSig);
1087 cbD->cmdList->IASetPrimitiveTopology(psD->topology);
1089 if (psD->viewInstanceMask)
1090 cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
1092 if (cbD->hasCustomScissorSet && !psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor))
1093 setDefaultScissor(cbD);
1097void QD3D12CommandBuffer::visitUniformBuffer(QD3D12Stage s,
1098 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
1101 int dynamicOffsetCount,
1102 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1104 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1105 quint32 offset = d.offset;
1106 if (d.hasDynamicOffset) {
1107 for (
int i = 0; i < dynamicOffsetCount; ++i) {
1108 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1109 if (dynOfs.first == binding) {
1110 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1111 offset += dynOfs.second;
1115 QRHI_RES_RHI(QRhiD3D12);
1116 visitorData.cbufs[s].append({ bufD->handles[rhiD->currentFrameSlot], offset });
1119void QD3D12CommandBuffer::visitTexture(QD3D12Stage s,
1120 const QRhiShaderResourceBinding::TextureAndSampler &d,
1123 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1124 visitorData.srvs[s].append(texD->srv);
1127void QD3D12CommandBuffer::visitSampler(QD3D12Stage s,
1128 const QRhiShaderResourceBinding::TextureAndSampler &d,
1131 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, d.sampler);
1132 visitorData.samplers[s].append(samplerD->lookupOrCreateShaderVisibleDescriptor());
1135void QD3D12CommandBuffer::visitStorageBuffer(QD3D12Stage s,
1136 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
1137 QD3D12ShaderResourceVisitor::StorageOp,
1140 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1142 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1143 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1144 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
1145 uavDesc.Buffer.FirstElement = d.offset / 4;
1146 uavDesc.Buffer.NumElements = aligned(bufD->m_size - d.offset, 4u) / 4;
1147 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
1148 visitorData.uavs[s].append({ bufD->handles[0], uavDesc });
1151void QD3D12CommandBuffer::visitStorageImage(QD3D12Stage s,
1152 const QRhiShaderResourceBinding::Data::StorageImageData &d,
1153 QD3D12ShaderResourceVisitor::StorageOp,
1156 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1157 const bool isCube = texD->m_flags.testFlag(QRhiTexture::CubeMap);
1158 const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
1159 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1160 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1161 uavDesc.Format = texD->rtFormat;
1163 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1164 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1165 uavDesc.Texture2DArray.FirstArraySlice = 0;
1166 uavDesc.Texture2DArray.ArraySize = 6;
1167 }
else if (isArray) {
1168 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1169 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1170 uavDesc.Texture2DArray.FirstArraySlice = 0;
1171 uavDesc.Texture2DArray.ArraySize = UINT(qMax(0, texD->m_arraySize));
1173 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1174 uavDesc.Texture3D.MipSlice = UINT(d.level);
1175 uavDesc.Texture3D.WSize = UINT(-1);
1177 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
1178 uavDesc.Texture2D.MipSlice = UINT(d.level);
1180 visitorData.uavs[s].append({ texD->handle, uavDesc });
1183void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
1184 int dynamicOffsetCount,
1185 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1187 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1188 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
1189 QD3D12GraphicsPipeline *gfxPsD = QRHI_RES(QD3D12GraphicsPipeline, cbD->currentGraphicsPipeline);
1190 QD3D12ComputePipeline *compPsD = QRHI_RES(QD3D12ComputePipeline, cbD->currentComputePipeline);
1194 srb = gfxPsD->m_shaderResourceBindings;
1196 srb = compPsD->m_shaderResourceBindings;
1199 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, srb);
1201 bool pipelineChanged =
false;
1203 pipelineChanged = srbD->lastUsedGraphicsPipeline != gfxPsD;
1204 srbD->lastUsedGraphicsPipeline = gfxPsD;
1206 pipelineChanged = srbD->lastUsedComputePipeline != compPsD;
1207 srbD->lastUsedComputePipeline = compPsD;
1210 for (
int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
1211 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings[i]);
1213 case QRhiShaderResourceBinding::UniformBuffer:
1215 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.ubuf.buf);
1216 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
1217 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1218 sanityCheckResourceOwnership(bufD);
1219 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1222 case QRhiShaderResourceBinding::SampledTexture:
1223 case QRhiShaderResourceBinding::Texture:
1224 case QRhiShaderResourceBinding::Sampler:
1226 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
1227 for (
int elem = 0; elem < data->count; ++elem) {
1228 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, data->texSamplers[elem].tex);
1229 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, data->texSamplers[elem].sampler);
1233 Q_ASSERT(texD || samplerD);
1234 sanityCheckResourceOwnership(texD);
1235 sanityCheckResourceOwnership(samplerD);
1238 if (b->stage == QRhiShaderResourceBinding::FragmentStage) {
1239 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1240 }
else if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
1241 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1243 state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1245 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATES(state));
1246 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1251 case QRhiShaderResourceBinding::ImageLoad:
1252 case QRhiShaderResourceBinding::ImageStore:
1253 case QRhiShaderResourceBinding::ImageLoadStore:
1255 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, b->u.simage.tex);
1256 sanityCheckResourceOwnership(texD);
1257 if (QD3D12Resource *res = resourcePool.lookupRef(texD->handle)) {
1258 if (res->uavUsage) {
1259 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1261 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1263 if (b->type == QRhiShaderResourceBinding::ImageStore
1264 || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1267 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1272 if (b->type == QRhiShaderResourceBinding::ImageLoad || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1273 res->uavUsage |= QD3D12Resource::UavUsageRead;
1274 if (b->type == QRhiShaderResourceBinding::ImageStore || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1275 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1276 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1277 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1281 case QRhiShaderResourceBinding::BufferLoad:
1282 case QRhiShaderResourceBinding::BufferStore:
1283 case QRhiShaderResourceBinding::BufferLoadStore:
1285 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.sbuf.buf);
1286 sanityCheckResourceOwnership(bufD);
1287 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
1288 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1289 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
1290 if (res->uavUsage) {
1291 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1293 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1295 if (b->type == QRhiShaderResourceBinding::BufferStore
1296 || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1299 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1304 if (b->type == QRhiShaderResourceBinding::BufferLoad || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1305 res->uavUsage |= QD3D12Resource::UavUsageRead;
1306 if (b->type == QRhiShaderResourceBinding::BufferStore || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1307 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1308 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1309 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1316 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1317 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1319 if (pipelineChanged || srbChanged || srbRebuilt || srbD->hasDynamicOffset) {
1320 const QD3D12ShaderStageData *stageData = gfxPsD ? gfxPsD->stageData.data() : &compPsD->stageData;
1326 QD3D12ShaderResourceVisitor visitor(srbD, stageData, gfxPsD ? 5 : 1);
1328 QD3D12CommandBuffer::VisitorData &visitorData(cbD->visitorData);
1331 using namespace std::placeholders;
1332 visitor.uniformBuffer = std::bind(&QD3D12CommandBuffer::visitUniformBuffer, cbD, _1, _2, _3, _4, dynamicOffsetCount, dynamicOffsets);
1333 visitor.texture = std::bind(&QD3D12CommandBuffer::visitTexture, cbD, _1, _2, _3);
1334 visitor.sampler = std::bind(&QD3D12CommandBuffer::visitSampler, cbD, _1, _2, _3);
1335 visitor.storageBuffer = std::bind(&QD3D12CommandBuffer::visitStorageBuffer, cbD, _1, _2, _3, _4);
1336 visitor.storageImage = std::bind(&QD3D12CommandBuffer::visitStorageImage, cbD, _1, _2, _3, _4);
1340 quint32 cbvSrvUavCount = 0;
1341 for (
int s = 0; s < 6; ++s) {
1343 cbvSrvUavCount += visitorData.srvs[s].count();
1344 cbvSrvUavCount += visitorData.uavs[s].count();
1347 bool gotNewHeap =
false;
1348 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
1349 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1357 qCDebug(QRHI_LOG_INFO,
"Created new shader-visible CBV/SRV/UAV descriptor heap,"
1358 " per-frame slice size is now %u,"
1359 " if this happens frequently then that's not great.",
1360 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[0].capacity);
1361 bindShaderVisibleHeaps(cbD);
1364 int rootParamIndex = 0;
1365 for (
int s = 0; s < 6; ++s) {
1366 if (!visitorData.cbufs[s].isEmpty()) {
1367 for (
int i = 0, count = visitorData.cbufs[s].count(); i < count; ++i) {
1368 const auto &cbuf(visitorData.cbufs[s][i]);
1369 if (QD3D12Resource *res = resourcePool.lookupRef(cbuf.first)) {
1370 quint32 offset = cbuf.second;
1371 D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = res->resource->GetGPUVirtualAddress() + offset;
1372 if (cbD->currentGraphicsPipeline)
1373 cbD->cmdList->SetGraphicsRootConstantBufferView(rootParamIndex, gpuAddr);
1375 cbD->cmdList->SetComputeRootConstantBufferView(rootParamIndex, gpuAddr);
1377 rootParamIndex += 1;
1381 for (
int s = 0; s < 6; ++s) {
1382 if (!visitorData.srvs[s].isEmpty()) {
1383 QD3D12DescriptorHeap &gpuSrvHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1384 QD3D12Descriptor startDesc = gpuSrvHeap.get(visitorData.srvs[s].count());
1385 for (
int i = 0, count = visitorData.srvs[s].count(); i < count; ++i) {
1386 const auto &srv(visitorData.srvs[s][i]);
1387 dev->CopyDescriptorsSimple(1, gpuSrvHeap.incremented(startDesc, i).cpuHandle, srv.cpuHandle,
1388 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1391 if (cbD->currentGraphicsPipeline)
1392 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1393 else if (cbD->currentComputePipeline)
1394 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1396 rootParamIndex += 1;
1399 for (
int s = 0; s < 6; ++s) {
1402 for (
const QD3D12Descriptor &samplerDescriptor : visitorData.samplers[s]) {
1403 if (cbD->currentGraphicsPipeline)
1404 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1405 else if (cbD->currentComputePipeline)
1406 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1408 rootParamIndex += 1;
1411 for (
int s = 0; s < 6; ++s) {
1412 if (!visitorData.uavs[s].isEmpty()) {
1413 QD3D12DescriptorHeap &gpuUavHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1414 QD3D12Descriptor startDesc = gpuUavHeap.get(visitorData.uavs[s].count());
1415 for (
int i = 0, count = visitorData.uavs[s].count(); i < count; ++i) {
1416 const auto &uav(visitorData.uavs[s][i]);
1417 if (QD3D12Resource *res = resourcePool.lookupRef(uav.first)) {
1418 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uav.second,
1419 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1421 dev->CreateUnorderedAccessView(
nullptr,
nullptr,
nullptr,
1422 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1426 if (cbD->currentGraphicsPipeline)
1427 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1428 else if (cbD->currentComputePipeline)
1429 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1431 rootParamIndex += 1;
1436 cbD->currentGraphicsSrb = srb;
1437 cbD->currentComputeSrb =
nullptr;
1439 cbD->currentGraphicsSrb =
nullptr;
1440 cbD->currentComputeSrb = srb;
1442 cbD->currentSrbGeneration = srbD->generation;
1446void QRhiD3D12::setVertexInput(QRhiCommandBuffer *cb,
1447 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1448 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1450 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1451 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1453 bool needsBindVBuf =
false;
1454 for (
int i = 0; i < bindingCount; ++i) {
1455 const int inputSlot = startBinding + i;
1456 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1457 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1458 const bool isDynamic = bufD->m_type == QRhiBuffer::Dynamic;
1460 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1462 if (cbD->currentVertexBuffers[inputSlot] != bufD->handles[isDynamic ? currentFrameSlot : 0]
1463 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1465 needsBindVBuf =
true;
1466 cbD->currentVertexBuffers[inputSlot] = bufD->handles[isDynamic ? currentFrameSlot : 0];
1467 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1471 if (needsBindVBuf) {
1472 QVarLengthArray<D3D12_VERTEX_BUFFER_VIEW, 4> vbv;
1473 vbv.reserve(bindingCount);
1475 QD3D12GraphicsPipeline *psD = cbD->currentGraphicsPipeline;
1476 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1477 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1479 for (
int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1480 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1481 const QD3D12ObjectHandle handle = bufD->handles[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
1482 const quint32 offset = bindings[i].second;
1483 const quint32 stride = inputLayout.bindingAt(i)->stride();
1485 if (bufD->m_type != QRhiBuffer::Dynamic) {
1486 barrierGen.addTransitionBarrier(handle, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
1487 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1490 if (QD3D12Resource *res = resourcePool.lookupRef(handle)) {
1492 res->resource->GetGPUVirtualAddress() + offset,
1493 UINT(res->desc.Width - offset),
1499 cbD->cmdList->IASetVertexBuffers(UINT(startBinding), vbv.count(), vbv.constData());
1503 QD3D12Buffer *ibufD = QRHI_RES(QD3D12Buffer, indexBuf);
1504 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1505 const bool isDynamic = ibufD->m_type == QRhiBuffer::Dynamic;
1507 ibufD->executeHostWritesForFrameSlot(currentFrameSlot);
1509 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1510 : DXGI_FORMAT_R32_UINT;
1511 if (cbD->currentIndexBuffer != ibufD->handles[isDynamic ? currentFrameSlot : 0]
1512 || cbD->currentIndexOffset != indexOffset
1513 || cbD->currentIndexFormat != dxgiFormat)
1515 cbD->currentIndexBuffer = ibufD->handles[isDynamic ? currentFrameSlot : 0];
1516 cbD->currentIndexOffset = indexOffset;
1517 cbD->currentIndexFormat = dxgiFormat;
1519 if (ibufD->m_type != QRhiBuffer::Dynamic) {
1520 barrierGen.addTransitionBarrier(cbD->currentIndexBuffer, D3D12_RESOURCE_STATE_INDEX_BUFFER);
1521 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1524 if (QD3D12Resource *res = resourcePool.lookupRef(cbD->currentIndexBuffer)) {
1525 const D3D12_INDEX_BUFFER_VIEW ibv = {
1526 res->resource->GetGPUVirtualAddress() + indexOffset,
1527 UINT(res->desc.Width - indexOffset),
1530 cbD->cmdList->IASetIndexBuffer(&ibv);
1536void QRhiD3D12::setDefaultScissor(QD3D12CommandBuffer *cbD)
1538 cbD->hasCustomScissorSet =
false;
1540 const QSize outputSize = cbD->currentTarget->pixelSize();
1541 std::array<
float, 4> vp = cbD->currentViewport.viewport();
1542 float x = 0, y = 0, w = 0, h = 0;
1544 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
1547 w = outputSize.width();
1548 h = outputSize.height();
1551 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, vp, &x, &y, &w, &h);
1560 cbD->cmdList->RSSetScissorRects(1, &r);
1563void QRhiD3D12::setViewport(QRhiCommandBuffer *cb,
const QRhiViewport &viewport)
1565 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1566 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1567 Q_ASSERT(cbD->currentTarget);
1568 const QSize outputSize = cbD->currentTarget->pixelSize();
1572 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1580 v.MinDepth = viewport.minDepth();
1581 v.MaxDepth = viewport.maxDepth();
1582 cbD->cmdList->RSSetViewports(1, &v);
1584 cbD->currentViewport = viewport;
1585 if (cbD->currentGraphicsPipeline
1586 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
1588 setDefaultScissor(cbD);
1592void QRhiD3D12::setScissor(QRhiCommandBuffer *cb,
const QRhiScissor &scissor)
1594 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1595 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1596 Q_ASSERT(cbD->currentTarget);
1597 const QSize outputSize = cbD->currentTarget->pixelSize();
1601 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
1610 cbD->cmdList->RSSetScissorRects(1, &r);
1612 cbD->hasCustomScissorSet =
true;
1615void QRhiD3D12::setBlendConstants(QRhiCommandBuffer *cb,
const QColor &c)
1617 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1618 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1619 float v[4] = { c.redF(), c.greenF(), c.blueF(), c.alphaF() };
1620 cbD->cmdList->OMSetBlendFactor(v);
1623void QRhiD3D12::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
1625 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1626 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1627 cbD->cmdList->OMSetStencilRef(refValue);
1630static inline D3D12_SHADING_RATE toD3DShadingRate(
const QSize &coarsePixelSize)
1632 if (coarsePixelSize == QSize(1, 2))
1633 return D3D12_SHADING_RATE_1X2;
1634 if (coarsePixelSize == QSize(2, 1))
1635 return D3D12_SHADING_RATE_2X1;
1636 if (coarsePixelSize == QSize(2, 2))
1637 return D3D12_SHADING_RATE_2X2;
1638 if (coarsePixelSize == QSize(2, 4))
1639 return D3D12_SHADING_RATE_2X4;
1640 if (coarsePixelSize == QSize(4, 2))
1641 return D3D12_SHADING_RATE_4X2;
1642 if (coarsePixelSize == QSize(4, 4))
1643 return D3D12_SHADING_RATE_4X4;
1644 return D3D12_SHADING_RATE_1X1;
1647void QRhiD3D12::setShadingRate(QRhiCommandBuffer *cb,
const QSize &coarsePixelSize)
1649 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1650 cbD->hasShadingRateSet =
false;
1652#ifdef QRHI_D3D12_CL5_AVAILABLE
1656 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1657 const D3D12_SHADING_RATE_COMBINER combiners[] = { D3D12_SHADING_RATE_COMBINER_MAX, D3D12_SHADING_RATE_COMBINER_MAX };
1658 cbD->cmdList->RSSetShadingRate(toD3DShadingRate(coarsePixelSize), combiners);
1659 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
1660 cbD->hasShadingRateSet =
true;
1663 Q_UNUSED(coarsePixelSize);
1664 qWarning(
"Attempted to set ShadingRate without building Qt against a sufficiently new Windows SDK and d3d12.h. This cannot work.");
1668void QRhiD3D12::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
1669 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
1671 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1672 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1673 cbD->cmdList->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
1676void QRhiD3D12::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
1677 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
1679 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1680 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1681 cbD->cmdList->DrawIndexedInstanced(indexCount, instanceCount,
1682 firstIndex, vertexOffset,
1686void QRhiD3D12::drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
1687 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
1689 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1690 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1692 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
1693 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
1694 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
1696 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
1698 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
1699 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1701 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
1704 ID3D12Resource *indirectBufferRes = indirectRes->resource;
1706 const bool canUseMulti = (stride ==
sizeof(QRhiIndirectDrawCommand) && drawCommandSignature);
1708 if (canUseMulti && drawCount > 1) {
1709 cbD->cmdList->ExecuteIndirect(drawCommandSignature, drawCount,
1710 indirectBufferRes, indirectBufferOffset,
1713 UINT offset = indirectBufferOffset;
1714 for (quint32 i = 0; i < drawCount; ++i) {
1715 cbD->cmdList->ExecuteIndirect(drawCommandSignature, 1,
1716 indirectBufferRes, offset,
1723void QRhiD3D12::drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
1724 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
1726 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1727 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1729 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
1730 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
1731 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
1733 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
1735 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
1736 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1738 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
1741 ID3D12Resource *indirectBufferRes = indirectRes->resource;
1743 const bool canUseMulti = (stride ==
sizeof(QRhiIndexedIndirectDrawCommand) && drawIndexedCommandSignature);
1745 if (canUseMulti && drawCount > 1) {
1746 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, drawCount,
1747 indirectBufferRes, indirectBufferOffset,
1750 UINT offset = indirectBufferOffset;
1751 for (quint32 i = 0; i < drawCount; ++i) {
1752 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, 1,
1753 indirectBufferRes, offset,
1760void QRhiD3D12::debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name)
1765 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1766#ifdef QRHI_D3D12_HAS_OLD_PIX
1767 PIXBeginEvent(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(name).utf16()));
1774void QRhiD3D12::debugMarkEnd(QRhiCommandBuffer *cb)
1779 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1780#ifdef QRHI_D3D12_HAS_OLD_PIX
1781 PIXEndEvent(cbD->cmdList);
1787void QRhiD3D12::debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg)
1792 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1793#ifdef QRHI_D3D12_HAS_OLD_PIX
1794 PIXSetMarker(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(msg).utf16()));
1801const QRhiNativeHandles *QRhiD3D12::nativeHandles(QRhiCommandBuffer *cb)
1803 return QRHI_RES(QD3D12CommandBuffer, cb)->nativeHandles();
1806void QRhiD3D12::beginExternal(QRhiCommandBuffer *cb)
1811void QRhiD3D12::endExternal(QRhiCommandBuffer *cb)
1813 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1814 cbD->resetPerPassState();
1815 bindShaderVisibleHeaps(cbD);
1816 if (cbD->currentTarget) {
1817 QD3D12RenderTargetData *rtD = rtData(cbD->currentTarget);
1818 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
1821 rtD->dsAttCount ? &rtD->dsv :
nullptr);
1825double QRhiD3D12::lastCompletedGpuTime(QRhiCommandBuffer *cb)
1827 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1828 return cbD->lastGpuTime;
1831static void calculateGpuTime(QD3D12CommandBuffer *cbD,
1832 int timestampPairStartIndex,
1833 const quint8 *readbackBufPtr,
1834 quint64 timestampTicksPerSecond)
1836 const size_t byteOffset = timestampPairStartIndex *
sizeof(quint64);
1837 const quint64 *p =
reinterpret_cast<
const quint64 *>(readbackBufPtr + byteOffset);
1838 const quint64 startTime = *p++;
1839 const quint64 endTime = *p;
1840 if (startTime < endTime) {
1841 const quint64 ticks = endTime - startTime;
1842 const double timeSec = ticks /
double(timestampTicksPerSecond);
1843 cbD->lastGpuTime = timeSec;
1847QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
1851 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
1852 currentSwapChain = swapChainD;
1853 currentFrameSlot = swapChainD->currentFrameSlot;
1854 QD3D12SwapChain::FrameResources &fr(swapChainD->frameRes[currentFrameSlot]);
1867 for (QD3D12SwapChain *sc : std::as_const(swapchains))
1868 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
1870 if (swapChainD->frameLatencyWaitableObject) {
1872 if (swapChainD->lastFrameLatencyWaitSlot != currentFrameSlot) {
1873 WaitForSingleObjectEx(swapChainD->frameLatencyWaitableObject, 1000,
true);
1874 swapChainD->lastFrameLatencyWaitSlot = currentFrameSlot;
1878 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
1880 qWarning(
"Failed to reset command allocator: %s",
1881 qPrintable(QSystemError::windowsComString(hr)));
1882 return QRhi::FrameOpError;
1885 if (!startCommandListForCurrentFrameSlot(&fr.cmdList))
1886 return QRhi::FrameOpError;
1888 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1889 cbD->cmdList = fr.cmdList;
1891 swapChainD->rtWrapper.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1892 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1893 : swapChainD->rtvs[swapChainD->currentBackBufferIndex].cpuHandle;
1895 swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
1896 : D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
1898 if (swapChainD->stereo) {
1899 swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1900 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1901 : swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
1903 swapChainD->rtWrapperRight.d.dsv =
1904 swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
1911 releaseQueue.executeDeferredReleases(currentFrameSlot);
1917 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1919 smallStagingAreas[currentFrameSlot].head = 0;
1921 bindShaderVisibleHeaps(cbD);
1923 finishActiveReadbacks();
1925 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
1928 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1929 calculateGpuTime(cbD,
1930 timestampPairStartIndex,
1931 timestampReadbackArea.mem.p,
1932 timestampTicksPerSecond);
1934 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1935 D3D12_QUERY_TYPE_TIMESTAMP,
1936 timestampPairStartIndex);
1939 QDxgiVSyncService::instance()->beginFrame(adapterLuid);
1941 return QRhi::FrameOpSuccess;
1944QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
1946 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
1947 Q_ASSERT(currentSwapChain == swapChainD);
1948 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1950 QD3D12ObjectHandle backBufferResourceHandle = swapChainD->colorBuffers[swapChainD->currentBackBufferIndex];
1951 if (swapChainD->sampleDesc.Count > 1) {
1952 QD3D12ObjectHandle msaaBackBufferResourceHandle = swapChainD->msaaBuffers[swapChainD->currentBackBufferIndex];
1953 barrierGen.addTransitionBarrier(msaaBackBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
1954 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
1955 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1956 const QD3D12Resource *src = resourcePool.lookupRef(msaaBackBufferResourceHandle);
1957 const QD3D12Resource *dst = resourcePool.lookupRef(backBufferResourceHandle);
1959 cbD->cmdList->ResolveSubresource(dst->resource, 0, src->resource, 0, swapChainD->colorFormat);
1962 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
1963 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1965 if (timestampQueryHeap.isValid()) {
1966 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1967 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1968 D3D12_QUERY_TYPE_TIMESTAMP,
1969 timestampPairStartIndex + 1);
1970 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
1971 D3D12_QUERY_TYPE_TIMESTAMP,
1972 timestampPairStartIndex,
1974 timestampReadbackArea.mem.buffer,
1975 timestampPairStartIndex *
sizeof(quint64));
1978 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
1979 HRESULT hr = cmdList->Close();
1981 qWarning(
"Failed to close command list: %s",
1982 qPrintable(QSystemError::windowsComString(hr)));
1983 return QRhi::FrameOpError;
1986 ID3D12CommandList *execList[] = { cmdList };
1987 cmdQueue->ExecuteCommandLists(1, execList);
1989 if (!flags.testFlag(QRhi::SkipPresent)) {
1990 UINT presentFlags = 0;
1991 if (swapChainD->swapInterval == 0
1992 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
1994 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
1996 if (!swapChainD->swapChain) {
1997 qWarning(
"Failed to present, no swapchain");
1998 return QRhi::FrameOpError;
2000 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
2001 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
2002 qWarning(
"Device loss detected in Present()");
2004 return QRhi::FrameOpDeviceLost;
2005 }
else if (FAILED(hr)) {
2006 qWarning(
"Failed to present: %s", qPrintable(QSystemError::windowsComString(hr)));
2007 return QRhi::FrameOpError;
2010 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
2011 dcompDevice->Commit();
2014 swapChainD->addCommandCompletionSignalForCurrentFrameSlot();
2021 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2023 if (!flags.testFlag(QRhi::SkipPresent)) {
2027 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2028 swapChainD->currentBackBufferIndex = swapChainD->swapChain->GetCurrentBackBufferIndex();
2031 currentSwapChain =
nullptr;
2032 return QRhi::FrameOpSuccess;
2035QRhi::FrameOpResult QRhiD3D12::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
2048 currentFrameSlot = (currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2050 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2051 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2053 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2055 qWarning(
"Failed to reset command allocator: %s",
2056 qPrintable(QSystemError::windowsComString(hr)));
2057 return QRhi::FrameOpError;
2060 if (!offscreenCb[currentFrameSlot])
2061 offscreenCb[currentFrameSlot] =
new QD3D12CommandBuffer(
this);
2062 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2063 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2064 return QRhi::FrameOpError;
2066 releaseQueue.executeDeferredReleases(currentFrameSlot);
2068 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2069 smallStagingAreas[currentFrameSlot].head = 0;
2071 bindShaderVisibleHeaps(cbD);
2073 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2074 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2075 D3D12_QUERY_TYPE_TIMESTAMP,
2076 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT);
2079 offscreenActive =
true;
2082 return QRhi::FrameOpSuccess;
2085QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
2088 Q_ASSERT(offscreenActive);
2089 offscreenActive =
false;
2091 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2092 if (timestampQueryHeap.isValid()) {
2093 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2094 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2095 D3D12_QUERY_TYPE_TIMESTAMP,
2096 timestampPairStartIndex + 1);
2097 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2098 D3D12_QUERY_TYPE_TIMESTAMP,
2099 timestampPairStartIndex,
2101 timestampReadbackArea.mem.buffer,
2102 timestampPairStartIndex *
sizeof(quint64));
2105 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2106 HRESULT hr = cmdList->Close();
2108 qWarning(
"Failed to close command list: %s",
2109 qPrintable(QSystemError::windowsComString(hr)));
2110 return QRhi::FrameOpError;
2113 ID3D12CommandList *execList[] = { cmdList };
2114 cmdQueue->ExecuteCommandLists(1, execList);
2116 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2123 finishActiveReadbacks(
true);
2126 if (timestampQueryHeap.isValid()) {
2127 calculateGpuTime(cbD,
2128 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT,
2129 timestampReadbackArea.mem.p,
2130 timestampTicksPerSecond);
2133 return QRhi::FrameOpSuccess;
2136QRhi::FrameOpResult QRhiD3D12::finish()
2138 QD3D12CommandBuffer *cbD =
nullptr;
2140 if (offscreenActive) {
2141 Q_ASSERT(!currentSwapChain);
2142 cbD = offscreenCb[currentFrameSlot];
2144 Q_ASSERT(currentSwapChain);
2145 cbD = ¤tSwapChain->cbWrapper;
2148 return QRhi::FrameOpError;
2150 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2152 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2153 HRESULT hr = cmdList->Close();
2155 qWarning(
"Failed to close command list: %s",
2156 qPrintable(QSystemError::windowsComString(hr)));
2157 return QRhi::FrameOpError;
2160 ID3D12CommandList *execList[] = { cmdList };
2161 cmdQueue->ExecuteCommandLists(1, execList);
2163 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2170 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2172 qWarning(
"Failed to reset command allocator: %s",
2173 qPrintable(QSystemError::windowsComString(hr)));
2174 return QRhi::FrameOpError;
2177 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2178 return QRhi::FrameOpError;
2182 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2183 smallStagingAreas[currentFrameSlot].head = 0;
2185 bindShaderVisibleHeaps(cbD);
2188 releaseQueue.releaseAll();
2189 finishActiveReadbacks(
true);
2191 return QRhi::FrameOpSuccess;
2194void QRhiD3D12::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2196 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2197 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2198 enqueueResourceUpdates(cbD, resourceUpdates);
2201void QRhiD3D12::beginPass(QRhiCommandBuffer *cb,
2202 QRhiRenderTarget *rt,
2203 const QColor &colorClearValue,
2204 const QRhiDepthStencilClearValue &depthStencilClearValue,
2205 QRhiResourceUpdateBatch *resourceUpdates,
2206 QRhiCommandBuffer::BeginPassFlags)
2208 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2209 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2211 if (resourceUpdates)
2212 enqueueResourceUpdates(cbD, resourceUpdates);
2214 QD3D12RenderTargetData *rtD = rtData(rt);
2215 bool wantsColorClear =
true;
2216 bool wantsDsClear =
true;
2217 if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) {
2218 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, rt);
2219 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2220 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2221 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2224 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); it != itEnd; ++it) {
2225 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
2226 QD3D12Texture *resolveTexD = QRHI_RES(QD3D12Texture, it->resolveTexture());
2227 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
2229 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2231 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2233 barrierGen.addTransitionBarrier(resolveTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2235 if (rtTex->m_desc.depthStencilBuffer()) {
2236 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rtTex->m_desc.depthStencilBuffer());
2237 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
2238 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2239 }
else if (rtTex->m_desc.depthTexture()) {
2240 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, rtTex->m_desc.depthTexture());
2241 barrierGen.addTransitionBarrier(depthTexD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2243 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2245 Q_ASSERT(currentSwapChain);
2246 barrierGen.addTransitionBarrier(currentSwapChain->sampleDesc.Count > 1
2247 ? currentSwapChain->msaaBuffers[currentSwapChain->currentBackBufferIndex]
2248 : currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex],
2249 D3D12_RESOURCE_STATE_RENDER_TARGET);
2250 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2253 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2256 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2258 if (rtD->colorAttCount && wantsColorClear) {
2259 float clearColor[4] = {
2260 colorClearValue.redF(),
2261 colorClearValue.greenF(),
2262 colorClearValue.blueF(),
2263 colorClearValue.alphaF()
2265 for (
int i = 0; i < rtD->colorAttCount; ++i)
2266 cbD->cmdList->ClearRenderTargetView(rtD->rtv[i], clearColor, 0,
nullptr);
2268 if (rtD->dsAttCount && wantsDsClear) {
2269 cbD->cmdList->ClearDepthStencilView(rtD->dsv,
2270 D3D12_CLEAR_FLAGS(D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL),
2271 depthStencilClearValue.depthClearValue(),
2272 UINT8(depthStencilClearValue.stencilClearValue()),
2277 cbD->recordingPass = QD3D12CommandBuffer::RenderPass;
2278 cbD->currentTarget = rt;
2280 bool hasShadingRateMapSet =
false;
2281#ifdef QRHI_D3D12_CL5_AVAILABLE
2282 if (rtD->rp->hasShadingRateMap) {
2283 cbD->setShadingRate(QSize(1, 1));
2284 QD3D12ShadingRateMap *rateMapD = rt->resourceType() == QRhiRenderTarget::TextureRenderTarget
2285 ? QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12TextureRenderTarget, rt)->m_desc.shadingRateMap())
2286 : QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12SwapChainRenderTarget, rt)->swapChain()->shadingRateMap());
2287 if (QD3D12Resource *res = resourcePool.lookupRef(rateMapD->handle)) {
2288 barrierGen.addTransitionBarrier(rateMapD->handle, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
2289 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2290 cbD->cmdList->RSSetShadingRateImage(res->resource);
2291 hasShadingRateMapSet =
true;
2293 }
else if (cbD->hasShadingRateMapSet) {
2294 cbD->cmdList->RSSetShadingRateImage(
nullptr);
2295 cbD->setShadingRate(QSize(1, 1));
2296 }
else if (cbD->hasShadingRateSet) {
2297 cbD->setShadingRate(QSize(1, 1));
2301 cbD->resetPerPassState();
2304 cbD->hasShadingRateMapSet = hasShadingRateMapSet;
2307void QRhiD3D12::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2309 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2310 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2312 if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
2313 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, cbD->currentTarget);
2314 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2317 const QRhiColorAttachment &colorAtt(*it);
2318 if (!colorAtt.resolveTexture())
2321 QD3D12Texture *dstTexD = QRHI_RES(QD3D12Texture, colorAtt.resolveTexture());
2322 QD3D12Resource *dstRes = resourcePool.lookupRef(dstTexD->handle);
2326 QD3D12Texture *srcTexD = QRHI_RES(QD3D12Texture, colorAtt.texture());
2327 QD3D12RenderBuffer *srcRbD = QRHI_RES(QD3D12RenderBuffer, colorAtt.renderBuffer());
2328 Q_ASSERT(srcTexD || srcRbD);
2329 QD3D12Resource *srcRes = resourcePool.lookupRef(srcTexD ? srcTexD->handle : srcRbD->handle);
2334 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2335 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2336 int(srcTexD->dxgiFormat),
int(dstTexD->dxgiFormat));
2339 if (srcTexD->sampleDesc.Count <= 1) {
2340 qWarning(
"Cannot resolve a non-multisample texture");
2343 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2344 qWarning(
"Resolve source and destination sizes do not match");
2348 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2349 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2350 int(srcRbD->dxgiFormat),
int(dstTexD->dxgiFormat));
2353 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2354 qWarning(
"Resolve source and destination sizes do not match");
2359 barrierGen.addTransitionBarrier(srcTexD ? srcTexD->handle : srcRbD->handle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2360 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2361 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2363 const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
2364 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2365 const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
2366 const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
2367 UINT(colorAtt.resolveLayer()) + resolveIdx,
2368 dstTexD->mipLevelCount);
2369 cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresource,
2370 srcRes->resource, srcSubresource,
2371 dstTexD->dxgiFormat);
2374 if (rtTex->m_desc.depthResolveTexture())
2375 qWarning(
"Resolving multisample depth-stencil buffers is not supported with D3D");
2378 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2379 cbD->currentTarget =
nullptr;
2381 if (resourceUpdates)
2382 enqueueResourceUpdates(cbD, resourceUpdates);
2385void QRhiD3D12::beginComputePass(QRhiCommandBuffer *cb,
2386 QRhiResourceUpdateBatch *resourceUpdates,
2387 QRhiCommandBuffer::BeginPassFlags)
2389 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2390 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2392 if (resourceUpdates)
2393 enqueueResourceUpdates(cbD, resourceUpdates);
2395 cbD->recordingPass = QD3D12CommandBuffer::ComputePass;
2397 cbD->resetPerPassState();
2400void QRhiD3D12::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2402 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2403 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2405 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2407 if (resourceUpdates)
2408 enqueueResourceUpdates(cbD, resourceUpdates);
2411void QRhiD3D12::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
2413 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2414 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2415 QD3D12ComputePipeline *psD = QRHI_RES(QD3D12ComputePipeline, ps);
2416 const bool pipelineChanged = cbD->currentComputePipeline != psD || cbD->currentPipelineGeneration != psD->generation;
2418 if (pipelineChanged) {
2419 cbD->currentGraphicsPipeline =
nullptr;
2420 cbD->currentComputePipeline = psD;
2421 cbD->currentPipelineGeneration = psD->generation;
2423 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
2424 Q_ASSERT(pipeline->type == QD3D12Pipeline::Compute);
2425 cbD->cmdList->SetPipelineState(pipeline->pso);
2426 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
2427 cbD->cmdList->SetComputeRootSignature(rs->rootSig);
2432void QRhiD3D12::dispatch(QRhiCommandBuffer *cb,
int x,
int y,
int z)
2434 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2435 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2436 cbD->cmdList->Dispatch(UINT(x), UINT(y), UINT(z));
2439bool QD3D12DescriptorHeap::create(ID3D12Device *device,
2440 quint32 descriptorCount,
2441 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
2442 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags)
2445 capacity = descriptorCount;
2446 this->heapType = heapType;
2447 this->heapFlags = heapFlags;
2449 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
2450 heapDesc.Type = heapType;
2451 heapDesc.NumDescriptors = capacity;
2452 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS(heapFlags);
2454 HRESULT hr = device->CreateDescriptorHeap(&heapDesc, __uuidof(ID3D12DescriptorHeap),
reinterpret_cast<
void **>(&heap));
2456 qWarning(
"Failed to create descriptor heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2458 capacity = descriptorByteSize = 0;
2462 descriptorByteSize = device->GetDescriptorHandleIncrementSize(heapType);
2463 heapStart.cpuHandle = heap->GetCPUDescriptorHandleForHeapStart();
2464 if (heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
2465 heapStart.gpuHandle = heap->GetGPUDescriptorHandleForHeapStart();
2470void QD3D12DescriptorHeap::createWithExisting(
const QD3D12DescriptorHeap &other,
2471 quint32 offsetInDescriptors,
2472 quint32 descriptorCount)
2476 capacity = descriptorCount;
2477 heapType = other.heapType;
2478 heapFlags = other.heapFlags;
2479 descriptorByteSize = other.descriptorByteSize;
2480 heapStart = incremented(other.heapStart, offsetInDescriptors);
2483void QD3D12DescriptorHeap::destroy()
2492void QD3D12DescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2495 releaseQueue->deferredReleaseDescriptorHeap(heap);
2501QD3D12Descriptor QD3D12DescriptorHeap::get(quint32 count)
2503 Q_ASSERT(count > 0);
2504 if (head + count > capacity) {
2505 qWarning(
"Cannot get %u descriptors as that would exceed capacity %u", count, capacity);
2509 return at(head - count);
2512QD3D12Descriptor QD3D12DescriptorHeap::at(quint32 index)
const
2514 const quint32 startOffset = index * descriptorByteSize;
2515 QD3D12Descriptor result;
2516 result.cpuHandle.ptr = heapStart.cpuHandle.ptr + startOffset;
2517 if (heapStart.gpuHandle.ptr != 0)
2518 result.gpuHandle.ptr = heapStart.gpuHandle.ptr + startOffset;
2522bool QD3D12CpuDescriptorPool::create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName)
2524 QD3D12DescriptorHeap firstHeap;
2525 if (!firstHeap.create(device, DESCRIPTORS_PER_HEAP, heapType, D3D12_DESCRIPTOR_HEAP_FLAG_NONE))
2527 heaps.append(HeapWithMap::init(firstHeap, DESCRIPTORS_PER_HEAP));
2528 descriptorByteSize = heaps[0].heap.descriptorByteSize;
2529 this->device = device;
2530 this->debugName = debugName;
2534void QD3D12CpuDescriptorPool::destroy()
2538 static bool leakCheck =
true;
2541 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
2544 for (
const HeapWithMap &heap : std::as_const(heaps)) {
2545 const int leakedDescriptorCount = heap.map.count(
true);
2546 if (leakedDescriptorCount > 0) {
2547 qWarning(
"QD3D12CpuDescriptorPool::destroy(): "
2548 "Heap %p for descriptor pool %p '%s' has %d unreleased descriptors",
2549 &heap.heap,
this, debugName, leakedDescriptorCount);
2553 for (HeapWithMap &heap : heaps)
2554 heap.heap.destroy();
2558QD3D12Descriptor QD3D12CpuDescriptorPool::allocate(quint32 count)
2560 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2562 HeapWithMap &last(heaps.last());
2563 if (last.heap.head + count <= last.heap.capacity) {
2564 quint32 firstIndex = last.heap.head;
2565 for (quint32 i = 0; i < count; ++i)
2566 last.map.setBit(firstIndex + i);
2567 return last.heap.get(count);
2570 for (HeapWithMap &heap : heaps) {
2571 quint32 freeCount = 0;
2572 for (quint32 i = 0; i < DESCRIPTORS_PER_HEAP; ++i) {
2573 if (heap.map.testBit(i)) {
2577 if (freeCount == count) {
2578 quint32 firstIndex = i - (freeCount - 1);
2579 for (quint32 j = 0; j < count; ++j) {
2580 heap.map.setBit(firstIndex + j);
2581 return heap.heap.at(firstIndex);
2588 QD3D12DescriptorHeap newHeap;
2589 if (!newHeap.create(device, DESCRIPTORS_PER_HEAP, last.heap.heapType, last.heap.heapFlags))
2592 heaps.append(HeapWithMap::init(newHeap, DESCRIPTORS_PER_HEAP));
2594 for (quint32 i = 0; i < count; ++i)
2595 heaps.last().map.setBit(i);
2597 return heaps.last().heap.get(count);
2600void QD3D12CpuDescriptorPool::release(
const QD3D12Descriptor &descriptor, quint32 count)
2602 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2603 if (!descriptor.isValid())
2606 const SIZE_T addr = descriptor.cpuHandle.ptr;
2607 for (HeapWithMap &heap : heaps) {
2608 const SIZE_T begin = heap.heap.heapStart.cpuHandle.ptr;
2609 const SIZE_T end = begin + heap.heap.descriptorByteSize * heap.heap.capacity;
2610 if (addr >= begin && addr < end) {
2611 quint32 firstIndex = (addr - begin) / heap.heap.descriptorByteSize;
2612 for (quint32 i = 0; i < count; ++i)
2613 heap.map.setBit(firstIndex + i,
false);
2618 qWarning(
"QD3D12CpuDescriptorPool::release: Descriptor with address %llu is not in any heap",
2619 quint64(descriptor.cpuHandle.ptr));
2622bool QD3D12QueryHeap::create(ID3D12Device *device,
2624 D3D12_QUERY_HEAP_TYPE heapType)
2626 capacity = queryCount;
2628 D3D12_QUERY_HEAP_DESC heapDesc = {};
2629 heapDesc.Type = heapType;
2630 heapDesc.Count = capacity;
2632 HRESULT hr = device->CreateQueryHeap(&heapDesc, __uuidof(ID3D12QueryHeap),
reinterpret_cast<
void **>(&heap));
2634 qWarning(
"Failed to create query heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2643void QD3D12QueryHeap::destroy()
2652bool QD3D12StagingArea::create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType)
2654 Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
2655 D3D12_RESOURCE_DESC resourceDesc = {};
2656 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
2657 resourceDesc.Width = capacity;
2658 resourceDesc.Height = 1;
2659 resourceDesc.DepthOrArraySize = 1;
2660 resourceDesc.MipLevels = 1;
2661 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
2662 resourceDesc.SampleDesc = { 1, 0 };
2663 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2664 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
2665 UINT state = heapType == D3D12_HEAP_TYPE_UPLOAD ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
2666 HRESULT hr = rhi->vma.createResource(heapType,
2668 D3D12_RESOURCE_STATES(state),
2671 __uuidof(ID3D12Resource),
2672 reinterpret_cast<
void **>(&resource));
2674 qWarning(
"Failed to create buffer for staging area: %s",
2675 qPrintable(QSystemError::windowsComString(hr)));
2679 hr = resource->Map(0,
nullptr, &p);
2681 qWarning(
"Failed to map buffer for staging area: %s",
2682 qPrintable(QSystemError::windowsComString(hr)));
2687 mem.p =
static_cast<quint8 *>(p);
2688 mem.gpuAddr = resource->GetGPUVirtualAddress();
2689 mem.buffer = resource;
2690 mem.bufferOffset = 0;
2692 this->capacity = capacity;
2698void QD3D12StagingArea::destroy()
2701 resource->Release();
2705 allocation->Release();
2706 allocation =
nullptr;
2711void QD3D12StagingArea::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2714 releaseQueue->deferredReleaseResourceAndAllocation(resource, allocation);
2718QD3D12StagingArea::Allocation QD3D12StagingArea::get(quint32 byteSize)
2720 const quint32 allocSize = aligned(byteSize, ALIGNMENT);
2721 if (head + allocSize > capacity) {
2722 qWarning(
"Failed to allocate %u (%u) bytes from staging area of size %u with %u bytes left",
2723 allocSize, byteSize, capacity, remainingCapacity());
2726 const quint32 offset = head;
2730 mem.gpuAddr + offset,
2739void QD3D12ReleaseQueue::deferredReleaseResource(
const QD3D12ObjectHandle &handle)
2741 DeferredReleaseEntry e;
2746void QD3D12ReleaseQueue::deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
2747 QD3D12CpuDescriptorPool *pool,
2748 const QD3D12Descriptor &viewsStart,
2751 DeferredReleaseEntry e;
2752 e.type = DeferredReleaseEntry::Resource;
2754 e.poolForViews = pool;
2755 e.viewsStart = viewsStart;
2756 e.viewCount = viewCount;
2760void QD3D12ReleaseQueue::deferredReleasePipeline(
const QD3D12ObjectHandle &handle)
2762 DeferredReleaseEntry e;
2763 e.type = DeferredReleaseEntry::Pipeline;
2768void QD3D12ReleaseQueue::deferredReleaseRootSignature(
const QD3D12ObjectHandle &handle)
2770 DeferredReleaseEntry e;
2771 e.type = DeferredReleaseEntry::RootSignature;
2776void QD3D12ReleaseQueue::deferredReleaseCallback(std::function<
void(
void*)> callback,
void *userData)
2778 DeferredReleaseEntry e;
2779 e.type = DeferredReleaseEntry::Callback;
2780 e.callback = callback;
2781 e.callbackUserData = userData;
2785void QD3D12ReleaseQueue::deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
2786 D3D12MA::Allocation *allocation)
2788 DeferredReleaseEntry e;
2789 e.type = DeferredReleaseEntry::ResourceAndAllocation;
2790 e.resourceAndAllocation = { resource, allocation };
2794void QD3D12ReleaseQueue::deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap)
2796 DeferredReleaseEntry e;
2797 e.type = DeferredReleaseEntry::DescriptorHeap;
2798 e.descriptorHeap = heap;
2802void QD3D12ReleaseQueue::deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
2803 const QD3D12Descriptor &viewsStart,
2806 DeferredReleaseEntry e;
2807 e.type = DeferredReleaseEntry::Views;
2808 e.poolForViews = pool;
2809 e.viewsStart = viewsStart;
2810 e.viewCount = viewCount;
2814void QD3D12ReleaseQueue::activatePendingDeferredReleaseRequests(
int frameSlot)
2816 for (DeferredReleaseEntry &e : queue) {
2817 if (!e.frameSlotToBeReleasedIn.has_value())
2818 e.frameSlotToBeReleasedIn = frameSlot;
2822void QD3D12ReleaseQueue::executeDeferredReleases(
int frameSlot,
bool forced)
2824 for (
int i = queue.count() - 1; i >= 0; --i) {
2825 const DeferredReleaseEntry &e(queue[i]);
2826 if (forced || (e.frameSlotToBeReleasedIn.has_value() && e.frameSlotToBeReleasedIn.value() == frameSlot)) {
2828 case DeferredReleaseEntry::Resource:
2829 resourcePool->remove(e.handle);
2830 if (e.poolForViews && e.viewsStart.isValid() && e.viewCount > 0)
2831 e.poolForViews->release(e.viewsStart, e.viewCount);
2833 case DeferredReleaseEntry::Pipeline:
2834 pipelinePool->remove(e.handle);
2836 case DeferredReleaseEntry::RootSignature:
2837 rootSignaturePool->remove(e.handle);
2839 case DeferredReleaseEntry::Callback:
2840 e.callback(e.callbackUserData);
2842 case DeferredReleaseEntry::ResourceAndAllocation:
2845 e.resourceAndAllocation.first->Release();
2846 if (e.resourceAndAllocation.second)
2847 e.resourceAndAllocation.second->Release();
2849 case DeferredReleaseEntry::DescriptorHeap:
2850 e.descriptorHeap->Release();
2852 case DeferredReleaseEntry::Views:
2853 e.poolForViews->release(e.viewsStart, e.viewCount);
2861void QD3D12ReleaseQueue::releaseAll()
2863 executeDeferredReleases(0,
true);
2866void QD3D12ResourceBarrierGenerator::addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle,
2867 D3D12_RESOURCE_STATES stateAfter)
2869 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2870 if (stateAfter != res->state) {
2871 transitionResourceBarriers.append({ resourceHandle, res->state, stateAfter });
2872 res->state = stateAfter;
2877void QD3D12ResourceBarrierGenerator::enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD)
2879 QVarLengthArray<D3D12_RESOURCE_BARRIER, PREALLOC> barriers;
2880 for (
const TransitionResourceBarrier &trb : transitionResourceBarriers) {
2881 if (QD3D12Resource *res = resourcePool->lookupRef(trb.resourceHandle)) {
2882 D3D12_RESOURCE_BARRIER barrier = {};
2883 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2884 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2885 barrier.Transition.pResource = res->resource;
2886 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
2887 barrier.Transition.StateBefore = trb.stateBefore;
2888 barrier.Transition.StateAfter = trb.stateAfter;
2889 barriers.append(barrier);
2892 transitionResourceBarriers.clear();
2893 if (!barriers.isEmpty())
2894 cbD->cmdList->ResourceBarrier(barriers.count(), barriers.constData());
2897void QD3D12ResourceBarrierGenerator::enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
2898 const QD3D12ObjectHandle &resourceHandle,
2900 D3D12_RESOURCE_STATES stateBefore,
2901 D3D12_RESOURCE_STATES stateAfter)
2903 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2904 D3D12_RESOURCE_BARRIER barrier = {};
2905 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2906 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2907 barrier.Transition.pResource = res->resource;
2908 barrier.Transition.Subresource = subresource;
2909 barrier.Transition.StateBefore = stateBefore;
2910 barrier.Transition.StateAfter = stateAfter;
2911 cbD->cmdList->ResourceBarrier(1, &barrier);
2915void QD3D12ResourceBarrierGenerator::enqueueUavBarrier(QD3D12CommandBuffer *cbD,
2916 const QD3D12ObjectHandle &resourceHandle)
2918 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2919 D3D12_RESOURCE_BARRIER barrier = {};
2920 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
2921 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2922 barrier.UAV.pResource = res->resource;
2923 cbD->cmdList->ResourceBarrier(1, &barrier);
2927void QD3D12ShaderBytecodeCache::insertWithCapacityLimit(
const QRhiShaderStage &key,
const Shader &s)
2929 if (data.count() >= QRhiD3D12::MAX_SHADER_CACHE_ENTRIES)
2931 data.insert(key, s);
2934bool QD3D12ShaderVisibleDescriptorHeap::create(ID3D12Device *device,
2935 D3D12_DESCRIPTOR_HEAP_TYPE type,
2936 quint32 perFrameDescriptorCount)
2938 Q_ASSERT(type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
2940 quint32 size = perFrameDescriptorCount * QD3D12_FRAMES_IN_FLIGHT;
2943 const quint32 CBV_SRV_UAV_MAX = 1000000;
2944 const quint32 SAMPLER_MAX = 2048;
2945 if (type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
2946 size = qMin(size, CBV_SRV_UAV_MAX);
2947 else if (type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
2948 size = qMin(size, SAMPLER_MAX);
2950 if (!heap.create(device, size, type, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
2951 qWarning(
"Failed to create shader-visible descriptor heap of size %u", size);
2955 perFrameDescriptorCount = size / QD3D12_FRAMES_IN_FLIGHT;
2956 quint32 currentOffsetInDescriptors = 0;
2957 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
2958 perFrameHeapSlice[i].createWithExisting(heap, currentOffsetInDescriptors, perFrameDescriptorCount);
2959 currentOffsetInDescriptors += perFrameDescriptorCount;
2965void QD3D12ShaderVisibleDescriptorHeap::destroy()
2970void QD3D12ShaderVisibleDescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2972 heap.destroyWithDeferredRelease(releaseQueue);
2975static inline std::pair<
int,
int> mapBinding(
int binding,
const QShader::NativeResourceBindingMap &map)
2978 return { binding, binding };
2980 auto it = map.constFind(binding);
2981 if (it != map.cend())
2990void QD3D12ShaderResourceVisitor::visit()
2992 for (
int bindingIdx = 0, bindingCount = srb->m_bindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
2993 const QRhiShaderResourceBinding &b(srb->m_bindings[bindingIdx]);
2994 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
2996 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
2997 const QD3D12ShaderStageData *sd = &stageData[stageIdx];
3001 if (!bd->stage.testFlag(qd3d12_stageToSrb(sd->stage)))
3005 case QRhiShaderResourceBinding::UniformBuffer:
3007 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3008 if (shaderRegister >= 0 && uniformBuffer)
3009 uniformBuffer(sd->stage, bd->u.ubuf, shaderRegister, bd->binding);
3012 case QRhiShaderResourceBinding::SampledTexture:
3014 Q_ASSERT(bd->u.stex.count > 0);
3015 const int textureBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3016 const int samplerBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).second;
3017 for (
int i = 0; i < bd->u.stex.count; ++i) {
3018 if (textureBaseShaderRegister >= 0 && texture)
3019 texture(sd->stage, bd->u.stex.texSamplers[i], textureBaseShaderRegister + i);
3020 if (samplerBaseShaderRegister >= 0 && sampler)
3021 sampler(sd->stage, bd->u.stex.texSamplers[i], samplerBaseShaderRegister + i);
3025 case QRhiShaderResourceBinding::Texture:
3027 Q_ASSERT(bd->u.stex.count > 0);
3028 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3029 if (baseShaderRegister >= 0 && texture) {
3030 for (
int i = 0; i < bd->u.stex.count; ++i)
3031 texture(sd->stage, bd->u.stex.texSamplers[i], baseShaderRegister + i);
3035 case QRhiShaderResourceBinding::Sampler:
3037 Q_ASSERT(bd->u.stex.count > 0);
3038 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3039 if (baseShaderRegister >= 0 && sampler) {
3040 for (
int i = 0; i < bd->u.stex.count; ++i)
3041 sampler(sd->stage, bd->u.stex.texSamplers[i], baseShaderRegister + i);
3045 case QRhiShaderResourceBinding::ImageLoad:
3047 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3048 if (shaderRegister >= 0 && storageImage)
3049 storageImage(sd->stage, bd->u.simage, Load, shaderRegister);
3052 case QRhiShaderResourceBinding::ImageStore:
3054 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3055 if (shaderRegister >= 0 && storageImage)
3056 storageImage(sd->stage, bd->u.simage, Store, shaderRegister);
3059 case QRhiShaderResourceBinding::ImageLoadStore:
3061 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3062 if (shaderRegister >= 0 && storageImage)
3063 storageImage(sd->stage, bd->u.simage, LoadStore, shaderRegister);
3066 case QRhiShaderResourceBinding::BufferLoad:
3068 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3069 if (shaderRegister >= 0 && storageBuffer)
3070 storageBuffer(sd->stage, bd->u.sbuf, Load, shaderRegister);
3073 case QRhiShaderResourceBinding::BufferStore:
3075 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3076 if (shaderRegister >= 0 && storageBuffer)
3077 storageBuffer(sd->stage, bd->u.sbuf, Store, shaderRegister);
3080 case QRhiShaderResourceBinding::BufferLoadStore:
3082 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3083 if (shaderRegister >= 0 && storageBuffer)
3084 storageBuffer(sd->stage, bd->u.sbuf, LoadStore, shaderRegister);
3092bool QD3D12SamplerManager::create(ID3D12Device *device)
3095 if (!shaderVisibleSamplerHeap.create(device,
3096 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
3097 MAX_SAMPLERS / QD3D12_FRAMES_IN_FLIGHT))
3099 qWarning(
"Could not create shader-visible SAMPLER heap");
3103 this->device = device;
3107void QD3D12SamplerManager::destroy()
3110 shaderVisibleSamplerHeap.destroy();
3115QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc)
3117 auto it = gpuMap.constFind({desc});
3118 if (it != gpuMap.cend())
3121 QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
3122 if (descriptor.isValid()) {
3123 device->CreateSampler(&desc, descriptor.cpuHandle);
3124 gpuMap.insert({desc}, descriptor);
3126 qWarning(
"Out of shader-visible SAMPLER descriptor heap space,"
3127 " this should not happen, maximum number of unique samplers is %u",
3128 shaderVisibleSamplerHeap.heap.capacity);
3134bool QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
3138 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3139 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3142 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3143 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3144 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3147 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3148 descriptorRanges[0].NumDescriptors = 1;
3149 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3150 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3151 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3152 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3153 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3156 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3157 descriptorRanges[1].NumDescriptors = 4;
3158 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3159 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3160 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3161 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3164 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3165 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3166 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3167 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3168 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3169 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3171 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3172 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3173 rsDesc.Desc_1_1.NumParameters = 3;
3174 rsDesc.Desc_1_1.pParameters = rootParams;
3175 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3176 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3178 ID3DBlob *signature =
nullptr;
3179 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3181 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3184 ID3D12RootSignature *rootSig =
nullptr;
3185 hr = rhiD->dev->CreateRootSignature(0,
3186 signature->GetBufferPointer(),
3187 signature->GetBufferSize(),
3188 __uuidof(ID3D12RootSignature),
3189 reinterpret_cast<
void **>(&rootSig));
3190 signature->Release();
3192 qWarning(
"Failed to create root signature: %s",
3193 qPrintable(QSystemError::windowsComString(hr)));
3197 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3199 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3200 psoDesc.pRootSignature = rootSig;
3201 psoDesc.CS.pShaderBytecode = g_csMipmap;
3202 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap);
3203 ID3D12PipelineState *pso =
nullptr;
3204 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3205 __uuidof(ID3D12PipelineState),
3206 reinterpret_cast<
void **>(&pso));
3208 qWarning(
"Failed to create compute pipeline state: %s",
3209 qPrintable(QSystemError::windowsComString(hr)));
3210 rhiD->rootSignaturePool.remove(rootSigHandle);
3215 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3220void QD3D12MipmapGenerator::destroy()
3222 rhiD->pipelinePool.remove(pipelineHandle);
3223 pipelineHandle = {};
3224 rhiD->rootSignaturePool.remove(rootSigHandle);
3228void QD3D12MipmapGenerator::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3230 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3233 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3236 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3240 const quint32 mipLevelCount = res->desc.MipLevels;
3241 if (mipLevelCount < 2)
3244 if (res->desc.SampleDesc.Count > 1) {
3245 qWarning(
"Cannot generate mipmaps for MSAA texture");
3249 const bool is1D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D;
3251 qWarning(
"Cannot generate mipmaps for 1D texture");
3255 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3256 const bool isCubeOrArray = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
3257 && res->desc.DepthOrArraySize > 1;
3258 const quint32 layerCount = isCubeOrArray ? res->desc.DepthOrArraySize : 1;
3261 qWarning(
"2D mipmap generator invoked for 3D texture, this should not happen");
3265 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3266 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3268 cbD->cmdList->SetPipelineState(pipeline->pso);
3269 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3271 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3274 quint32 srcMipLevel;
3275 quint32 numMipLevels;
3280 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount * layerCount);
3281 std::optional<QD3D12StagingArea> ownStagingArea;
3282 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3283 ownStagingArea = QD3D12StagingArea();
3284 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3285 qWarning(
"Could not create staging area for mipmap generation");
3289 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3290 ? &ownStagingArea.value()
3291 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3293 bool gotNewHeap =
false;
3294 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3295 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3296 rhiD->currentFrameSlot,
3297 (1 + 4) * mipLevelCount * layerCount,
3300 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3304 rhiD->bindShaderVisibleHeaps(cbD);
3306 for (quint32 layer = 0; layer < layerCount; ++layer) {
3307 for (quint32 level = 0; level < mipLevelCount ;) {
3308 UINT subresource = calcSubresource(level, layer, res->desc.MipLevels);
3309 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3310 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3311 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3313 quint32 levelPlusOneMipWidth = res->desc.Width >> (level + 1);
3314 quint32 levelPlusOneMipHeight = res->desc.Height >> (level + 1);
3315 const quint32 dw = levelPlusOneMipWidth == 1 ? levelPlusOneMipHeight : levelPlusOneMipWidth;
3316 const quint32 dh = levelPlusOneMipHeight == 1 ? levelPlusOneMipWidth : levelPlusOneMipHeight;
3318 const quint32 additionalMips = qCountTrailingZeroBits(dw | dh);
3319 const quint32 numGenMips = qMin(1u + qMin(3u, additionalMips), res->desc.MipLevels - level);
3320 levelPlusOneMipWidth = qMax(1u, levelPlusOneMipWidth);
3321 levelPlusOneMipHeight = qMax(1u, levelPlusOneMipHeight);
3323 CBufData cbufData = {
3326 1.0f /
float(levelPlusOneMipWidth),
3327 1.0f /
float(levelPlusOneMipHeight)
3330 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3331 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3332 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3334 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3335 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3336 srvDesc.Format = res->desc.Format;
3337 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3338 if (isCubeOrArray) {
3339 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
3340 srvDesc.Texture2DArray.MipLevels = res->desc.MipLevels;
3341 srvDesc.Texture2DArray.FirstArraySlice = layer;
3342 srvDesc.Texture2DArray.ArraySize = 1;
3344 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
3345 srvDesc.Texture2D.MipLevels = res->desc.MipLevels;
3347 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3348 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3350 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(4);
3351 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
3353 for (quint32 uavIdx = 0; uavIdx < 4; ++uavIdx) {
3354 const quint32 uavMipLevel = qMin(level + 1u + uavIdx, res->desc.MipLevels - 1u);
3355 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
3356 uavDesc.Format = res->desc.Format;
3357 if (isCubeOrArray) {
3358 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
3359 uavDesc.Texture2DArray.MipSlice = uavMipLevel;
3360 uavDesc.Texture2DArray.FirstArraySlice = layer;
3361 uavDesc.Texture2DArray.ArraySize = 1;
3363 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
3364 uavDesc.Texture2D.MipSlice = uavMipLevel;
3366 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
3367 uavCpuHandle.ptr += descriptorByteSize;
3369 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
3371 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, 1);
3373 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
3374 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3375 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
3376 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3378 level += numGenMips;
3382 if (ownStagingArea.has_value())
3383 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
3386bool QD3D12MipmapGenerator3D::create(QRhiD3D12 *rhiD)
3390 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3391 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3394 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3395 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3396 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3399 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3400 descriptorRanges[0].NumDescriptors = 1;
3401 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3402 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3403 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3404 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3405 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3408 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3409 descriptorRanges[1].NumDescriptors = 1;
3410 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3411 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3412 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3413 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3416 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3417 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3418 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3419 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3420 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3421 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3423 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3424 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3425 rsDesc.Desc_1_1.NumParameters = 3;
3426 rsDesc.Desc_1_1.pParameters = rootParams;
3427 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3428 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3430 ID3DBlob *signature =
nullptr;
3431 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3433 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3436 ID3D12RootSignature *rootSig =
nullptr;
3437 hr = rhiD->dev->CreateRootSignature(0,
3438 signature->GetBufferPointer(),
3439 signature->GetBufferSize(),
3440 __uuidof(ID3D12RootSignature),
3441 reinterpret_cast<
void **>(&rootSig));
3442 signature->Release();
3444 qWarning(
"Failed to create root signature: %s",
3445 qPrintable(QSystemError::windowsComString(hr)));
3449 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3451 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3452 psoDesc.pRootSignature = rootSig;
3453 psoDesc.CS.pShaderBytecode = g_csMipmap3D;
3454 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap3D);
3455 ID3D12PipelineState *pso =
nullptr;
3456 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3457 __uuidof(ID3D12PipelineState),
3458 reinterpret_cast<
void **>(&pso));
3460 qWarning(
"Failed to create compute pipeline state: %s",
3461 qPrintable(QSystemError::windowsComString(hr)));
3462 rhiD->rootSignaturePool.remove(rootSigHandle);
3467 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3472void QD3D12MipmapGenerator3D::destroy()
3474 rhiD->pipelinePool.remove(pipelineHandle);
3475 pipelineHandle = {};
3476 rhiD->rootSignaturePool.remove(rootSigHandle);
3480void QD3D12MipmapGenerator3D::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3482 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3485 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3488 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3492 const quint32 mipLevelCount = res->desc.MipLevels;
3493 if (mipLevelCount < 2)
3496 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3498 qWarning(
"3D mipmap generator invoked for non-3D texture, this should not happen");
3502 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3503 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3505 cbD->cmdList->SetPipelineState(pipeline->pso);
3506 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3508 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3514 quint32 srcMipLevel;
3517 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount);
3518 std::optional<QD3D12StagingArea> ownStagingArea;
3519 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3520 ownStagingArea = QD3D12StagingArea();
3521 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3522 qWarning(
"Could not create staging area for mipmap generation");
3526 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3527 ? &ownStagingArea.value()
3528 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3530 bool gotNewHeap =
false;
3531 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3532 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3533 rhiD->currentFrameSlot,
3534 (1 + 1) * mipLevelCount,
3537 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3541 rhiD->bindShaderVisibleHeaps(cbD);
3543 for (quint32 level = 0; level < mipLevelCount; ++level) {
3544 UINT subresource = calcSubresource(level, 0u, res->desc.MipLevels);
3545 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3546 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3547 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3549 quint32 levelPlusOneMipWidth = qMax<quint32>(1, res->desc.Width >> (level + 1));
3550 quint32 levelPlusOneMipHeight = qMax<quint32>(1, res->desc.Height >> (level + 1));
3551 quint32 levelPlusOneMipDepth = qMax<quint32>(1, res->desc.DepthOrArraySize >> (level + 1));
3553 CBufData cbufData = {
3554 1.0f /
float(levelPlusOneMipWidth),
3555 1.0f /
float(levelPlusOneMipHeight),
3556 1.0f /
float(levelPlusOneMipDepth),
3560 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3561 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3562 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3564 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3565 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3566 srvDesc.Format = res->desc.Format;
3567 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3568 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
3569 srvDesc.Texture3D.MipLevels = res->desc.MipLevels;
3571 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3572 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3574 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3575 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
3576 const quint32 uavMipLevel = qMin(level + 1u, res->desc.MipLevels - 1u);
3577 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
3578 uavDesc.Format = res->desc.Format;
3579 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
3580 uavDesc.Texture3D.MipSlice = uavMipLevel;
3581 uavDesc.Texture3D.WSize = UINT(-1);
3582 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
3583 uavCpuHandle.ptr += descriptorByteSize;
3584 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
3586 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, levelPlusOneMipDepth);
3588 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
3589 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3590 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
3591 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3594 if (ownStagingArea.has_value())
3595 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
3598bool QD3D12MemoryAllocator::create(ID3D12Device *device, IDXGIAdapter1 *adapter)
3600 this->device = device;
3607 static bool disableMA = qEnvironmentVariableIntValue(
"QT_D3D_NO_SUBALLOC");
3611 DXGI_ADAPTER_DESC1 desc;
3612 adapter->GetDesc1(&desc);
3613 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
3616 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
3617 allocatorDesc.pDevice = device;
3618 allocatorDesc.pAdapter = adapter;
3621 allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED;
3622 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
3624 qWarning(
"Failed to initialize D3D12 Memory Allocator: %s",
3625 qPrintable(QSystemError::windowsComString(hr)));
3631void QD3D12MemoryAllocator::destroy()
3634 allocator->Release();
3635 allocator =
nullptr;
3639HRESULT QD3D12MemoryAllocator::createResource(D3D12_HEAP_TYPE heapType,
3640 const D3D12_RESOURCE_DESC *resourceDesc,
3641 D3D12_RESOURCE_STATES initialState,
3642 const D3D12_CLEAR_VALUE *optimizedClearValue,
3643 D3D12MA::Allocation **maybeAllocation,
3644 REFIID riidResource,
3648 D3D12MA::ALLOCATION_DESC allocDesc = {};
3649 allocDesc.HeapType = heapType;
3650 return allocator->CreateResource(&allocDesc,
3653 optimizedClearValue,
3658 *maybeAllocation =
nullptr;
3659 D3D12_HEAP_PROPERTIES heapProps = {};
3660 heapProps.Type = heapType;
3661 return device->CreateCommittedResource(&heapProps,
3662 D3D12_HEAP_FLAG_NONE,
3665 optimizedClearValue,
3671void QD3D12MemoryAllocator::getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget)
3674 allocator->GetBudget(localBudget, nonLocalBudget);
3677 *nonLocalBudget = {};
3681void QRhiD3D12::waitGpu()
3683 fullFenceCounter += 1u;
3684 if (SUCCEEDED(cmdQueue->Signal(fullFence, fullFenceCounter))) {
3685 if (SUCCEEDED(fullFence->SetEventOnCompletion(fullFenceCounter, fullFenceEvent)))
3686 WaitForSingleObject(fullFenceEvent, INFINITE);
3690DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleDesc(
int sampleCount, DXGI_FORMAT format)
const
3692 DXGI_SAMPLE_DESC desc;
3696 const int s = effectiveSampleCount(sampleCount);
3699 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
3700 msaaInfo.Format = format;
3701 msaaInfo.SampleCount = UINT(s);
3702 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo,
sizeof(msaaInfo)))) {
3703 if (msaaInfo.NumQualityLevels > 0) {
3704 desc.Count = UINT(s);
3705 desc.Quality = msaaInfo.NumQualityLevels - 1;
3707 qWarning(
"No quality levels for multisampling with sample count %d", s);
3715bool QRhiD3D12::startCommandListForCurrentFrameSlot(D3D12GraphicsCommandList **cmdList)
3717 ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
3719 HRESULT hr = dev->CreateCommandList(0,
3720 D3D12_COMMAND_LIST_TYPE_DIRECT,
3723 __uuidof(D3D12GraphicsCommandList),
3724 reinterpret_cast<
void **>(cmdList));
3726 qWarning(
"Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
3730 HRESULT hr = (*cmdList)->Reset(cmdAlloc,
nullptr);
3732 qWarning(
"Failed to reset command list: %s", qPrintable(QSystemError::windowsComString(hr)));
3739static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
3742 case DXGI_FORMAT_R8G8B8A8_UNORM:
3743 return QRhiTexture::RGBA8;
3744 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
3746 (*flags) |= QRhiTexture::sRGB;
3747 return QRhiTexture::RGBA8;
3748 case DXGI_FORMAT_B8G8R8A8_UNORM:
3749 return QRhiTexture::BGRA8;
3750 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
3752 (*flags) |= QRhiTexture::sRGB;
3753 return QRhiTexture::BGRA8;
3754 case DXGI_FORMAT_R16G16B16A16_FLOAT:
3755 return QRhiTexture::RGBA16F;
3756 case DXGI_FORMAT_R32G32B32A32_FLOAT:
3757 return QRhiTexture::RGBA32F;
3758 case DXGI_FORMAT_R10G10B10A2_UNORM:
3759 return QRhiTexture::RGB10A2;
3761 qWarning(
"DXGI_FORMAT %d cannot be read back", format);
3764 return QRhiTexture::UnknownFormat;
3767void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
3769 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
3771 for (
int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
3772 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
3773 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
3774 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3775 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
3776 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3777 if (u.offset == 0 && u.data.size() == bufD->m_size)
3778 bufD->pendingHostWrites[i].clear();
3779 bufD->pendingHostWrites[i].append({ u.offset, u.data });
3781 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
3782 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3783 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
3784 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
3792 QD3D12StagingArea::Allocation stagingAlloc;
3793 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(bufD->m_size, 1);
3794 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3795 stagingAlloc = smallStagingAreas[currentFrameSlot].get(bufD->m_size);
3797 std::optional<QD3D12StagingArea> ownStagingArea;
3798 if (!stagingAlloc.isValid()) {
3799 ownStagingArea = QD3D12StagingArea();
3800 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3802 stagingAlloc = ownStagingArea->get(allocSize);
3803 if (!stagingAlloc.isValid()) {
3804 ownStagingArea->destroy();
3809 memcpy(stagingAlloc.p + u.offset, u.data.constData(), u.data.size());
3811 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
3812 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3814 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
3815 cbD->cmdList->CopyBufferRegion(res->resource,
3817 stagingAlloc.buffer,
3818 stagingAlloc.bufferOffset + u.offset,
3822 if (ownStagingArea.has_value())
3823 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3824 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
3825 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3826 if (bufD->m_type == QRhiBuffer::Dynamic) {
3827 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
3828 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[currentFrameSlot])) {
3829 Q_ASSERT(res->cpuMapPtr);
3830 u.result->data.resize(u.readSize);
3831 memcpy(u.result->data.data(),
reinterpret_cast<
char *>(res->cpuMapPtr) + u.offset, u.readSize);
3833 if (u.result->completed)
3834 u.result->completed();
3836 QD3D12Readback readback;
3837 readback.frameSlot = currentFrameSlot;
3838 readback.result = u.result;
3839 readback.byteSize = u.readSize;
3840 const quint32 allocSize = aligned(u.readSize, QD3D12StagingArea::ALIGNMENT);
3841 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
3842 if (u.result->completed)
3843 u.result->completed();
3846 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(u.readSize);
3847 if (!stagingAlloc.isValid()) {
3848 readback.staging.destroy();
3849 if (u.result->completed)
3850 u.result->completed();
3853 Q_ASSERT(stagingAlloc.bufferOffset == 0);
3854 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
3855 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3856 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
3857 cbD->cmdList->CopyBufferRegion(stagingAlloc.buffer, 0, res->resource, u.offset, u.readSize);
3858 activeReadbacks.append(readback);
3860 readback.staging.destroy();
3861 if (u.result->completed)
3862 u.result->completed();
3868 for (
int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
3869 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
3870 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
3871 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
3872 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3873 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
3876 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
3877 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3878 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
3879 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
3880 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level])) {
3881 D3D12_SUBRESOURCE_FOOTPRINT footprint = {};
3882 footprint.Format = res->desc.Format;
3883 footprint.Depth = 1;
3884 quint32 totalBytes = 0;
3886 const QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
3887 : subresDesc.sourceSize();
3888 const QPoint srcPos = subresDesc.sourceTopLeft();
3889 QPoint dstPos = subresDesc.destinationTopLeft();
3891 if (!subresDesc.image().isNull()) {
3892 const QImage img = subresDesc.image();
3893 const int bpl = img.bytesPerLine();
3894 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3895 totalBytes = footprint.RowPitch * img.height();
3896 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3899 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3900 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3901 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3902 totalBytes = footprint.RowPitch * rowCount;
3903 }
else if (!subresDesc.data().isEmpty()) {
3905 if (subresDesc.dataStride())
3906 bpl = subresDesc.dataStride();
3908 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
3909 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3910 totalBytes = footprint.RowPitch * subresSize.height();
3912 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
3916 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(totalBytes, 1);
3917 QD3D12StagingArea::Allocation stagingAlloc;
3918 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3919 stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
3921 std::optional<QD3D12StagingArea> ownStagingArea;
3922 if (!stagingAlloc.isValid()) {
3923 ownStagingArea = QD3D12StagingArea();
3924 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3926 stagingAlloc = ownStagingArea->get(allocSize);
3927 if (!stagingAlloc.isValid()) {
3928 ownStagingArea->destroy();
3933 D3D12_TEXTURE_COPY_LOCATION dst;
3934 dst.pResource = res->resource;
3935 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3936 dst.SubresourceIndex = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
3937 D3D12_TEXTURE_COPY_LOCATION src;
3938 src.pResource = stagingAlloc.buffer;
3939 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
3940 src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
3944 if (!subresDesc.image().isNull()) {
3945 const QImage img = subresDesc.image();
3946 const int bpc = qMax(1, img.depth() / 8);
3947 const int bpl = img.bytesPerLine();
3949 QSize size = subresDesc.sourceSize().isEmpty() ? img.size() : subresDesc.sourceSize();
3950 size.setWidth(qMin(size.width(), img.width() - srcPos.x()));
3951 size.setHeight(qMin(size.height(), img.height() - srcPos.y()));
3952 size = clampedSubResourceUploadSize(size, dstPos, level, texD->m_pixelSize);
3954 footprint.Width = size.width();
3955 footprint.Height = size.height();
3959 srcBox.right = UINT(size.width());
3960 srcBox.bottom = UINT(size.height());
3964 const uchar *imgPtr = img.constBits();
3965 const quint32 lineBytes = size.width() * bpc;
3966 for (
int y = 0, h = size.height(); y < h; ++y) {
3967 memcpy(stagingAlloc.p + y * footprint.RowPitch,
3968 imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
3971 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3974 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3976 dstPos.setX(aligned(dstPos.x(), blockDim.width()));
3977 dstPos.setY(aligned(dstPos.y(), blockDim.height()));
3982 srcBox.right = aligned(subresSize.width(), blockDim.width());
3983 srcBox.bottom = aligned(subresSize.height(), blockDim.height());
3988 footprint.Width = aligned(subresSize.width(), blockDim.width());
3989 footprint.Height = aligned(subresSize.height(), blockDim.height());
3991 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
3992 const QByteArray imgData = subresDesc.data();
3993 const char *imgPtr = imgData.constData();
3994 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3995 for (
int y = 0; y < rowCount; ++y)
3996 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
3997 }
else if (!subresDesc.data().isEmpty()) {
4000 srcBox.right = subresSize.width();
4001 srcBox.bottom = subresSize.height();
4005 footprint.Width = subresSize.width();
4006 footprint.Height = subresSize.height();
4009 if (subresDesc.dataStride())
4010 bpl = subresDesc.dataStride();
4012 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4014 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4015 const QByteArray data = subresDesc.data();
4016 const char *imgPtr = data.constData();
4017 for (
int y = 0, h = subresSize.height(); y < h; ++y)
4018 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
4021 src.PlacedFootprint.Footprint = footprint;
4023 cbD->cmdList->CopyTextureRegion(&dst,
4026 is3D ? UINT(layer) : 0u,
4030 if (ownStagingArea.has_value())
4031 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4035 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
4036 Q_ASSERT(u.src && u.dst);
4037 QD3D12Texture *srcD = QRHI_RES(QD3D12Texture, u.src);
4038 QD3D12Texture *dstD = QRHI_RES(QD3D12Texture, u.dst);
4039 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4040 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4041 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
4042 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
4043 if (!srcRes || !dstRes)
4046 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4047 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4048 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4050 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
4051 srcIs3D ? 0u : UINT(u.desc.sourceLayer()),
4052 srcD->mipLevelCount);
4053 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
4054 dstIs3D ? 0u : UINT(u.desc.destinationLayer()),
4055 dstD->mipLevelCount);
4056 const QPoint dp = u.desc.destinationTopLeft();
4057 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4058 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4059 const QPoint sp = u.desc.sourceTopLeft();
4062 srcBox.left = UINT(sp.x());
4063 srcBox.top = UINT(sp.y());
4064 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
4066 srcBox.right = srcBox.left + UINT(copySize.width());
4067 srcBox.bottom = srcBox.top + UINT(copySize.height());
4068 srcBox.back = srcBox.front + 1;
4070 D3D12_TEXTURE_COPY_LOCATION src;
4071 src.pResource = srcRes->resource;
4072 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4073 src.SubresourceIndex = srcSubresource;
4074 D3D12_TEXTURE_COPY_LOCATION dst;
4075 dst.pResource = dstRes->resource;
4076 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4077 dst.SubresourceIndex = dstSubresource;
4079 cbD->cmdList->CopyTextureRegion(&dst,
4082 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
4085 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
4086 QD3D12Readback readback;
4087 readback.frameSlot = currentFrameSlot;
4088 readback.result = u.result;
4090 QD3D12ObjectHandle srcHandle;
4093 if (u.rb.texture()) {
4094 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.rb.texture());
4095 if (texD->sampleDesc.Count > 1) {
4096 qWarning(
"Multisample texture cannot be read back");
4099 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4100 if (u.rb.rect().isValid())
4103 rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4104 readback.format = texD->m_format;
4105 srcHandle = texD->handle;
4107 Q_ASSERT(currentSwapChain);
4108 if (u.rb.rect().isValid())
4111 rect = QRect({0, 0}, currentSwapChain->pixelSize);
4112 readback.format = swapchainReadbackTextureFormat(currentSwapChain->colorFormat,
nullptr);
4113 if (readback.format == QRhiTexture::UnknownFormat)
4115 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
4117 readback.pixelSize = rect.size();
4119 textureFormatInfo(readback.format,
4121 &readback.bytesPerLine,
4125 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
4129 const UINT subresource = calcSubresource(UINT(u.rb.level()),
4130 is3D ? 0u : UINT(u.rb.layer()),
4131 srcRes->desc.MipLevels);
4132 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
4135 UINT64 totalBytes = 0;
4136 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
4137 &layout,
nullptr,
nullptr, &totalBytes);
4138 readback.stagingRowPitch = layout.Footprint.RowPitch;
4140 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT);
4141 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
4142 if (u.result->completed)
4143 u.result->completed();
4146 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
4147 if (!stagingAlloc.isValid()) {
4148 readback.staging.destroy();
4149 if (u.result->completed)
4150 u.result->completed();
4153 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4155 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4156 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4158 D3D12_TEXTURE_COPY_LOCATION dst;
4159 dst.pResource = stagingAlloc.buffer;
4160 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4161 dst.PlacedFootprint.Offset = 0;
4162 dst.PlacedFootprint.Footprint = layout.Footprint;
4164 D3D12_TEXTURE_COPY_LOCATION src;
4165 src.pResource = srcRes->resource;
4166 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4167 src.SubresourceIndex = subresource;
4169 D3D12_BOX srcBox = {};
4170 srcBox.left = UINT(rect.left());
4171 srcBox.top = UINT(rect.top());
4172 srcBox.front = is3D ? UINT(u.rb.layer()) : 0u;
4174 srcBox.right = srcBox.left + UINT(rect.width());
4175 srcBox.bottom = srcBox.top + UINT(rect.height());
4176 srcBox.back = srcBox.front + 1;
4178 cbD->cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &srcBox);
4179 activeReadbacks.append(readback);
4180 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
4181 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4182 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
4183 if (texD->flags().testFlag(QRhiTexture::ThreeDimensional))
4184 mipmapGen3D.generate(cbD, texD->handle);
4186 mipmapGen.generate(cbD, texD->handle);
4193void QRhiD3D12::finishActiveReadbacks(
bool forced)
4195 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4197 for (
int i = activeReadbacks.size() - 1; i >= 0; --i) {
4198 QD3D12Readback &readback(activeReadbacks[i]);
4199 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
4200 readback.result->format = readback.format;
4201 readback.result->pixelSize = readback.pixelSize;
4202 readback.result->data.resize(
int(readback.byteSize));
4204 if (readback.format != QRhiTexture::UnknownFormat) {
4205 quint8 *dstPtr =
reinterpret_cast<quint8 *>(readback.result->data.data());
4206 const quint8 *srcPtr = readback.staging.mem.p;
4207 const quint32 lineSize = qMin(readback.bytesPerLine, readback.stagingRowPitch);
4208 for (
int y = 0, h = readback.pixelSize.height(); y < h; ++y)
4209 memcpy(dstPtr + y * readback.bytesPerLine, srcPtr + y * readback.stagingRowPitch, lineSize);
4211 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
4214 readback.staging.destroy();
4216 if (readback.result->completed)
4217 completedCallbacks.append(readback.result->completed);
4219 activeReadbacks.remove(i);
4223 for (
auto f : completedCallbacks)
4227bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
4228 D3D12_DESCRIPTOR_HEAP_TYPE type,
4230 quint32 neededDescriptorCount,
4238 if (h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
4239 const quint32 newPerFrameSize = qMax(h->perFrameHeapSlice[frameSlot].capacity * 2,
4240 neededDescriptorCount);
4241 QD3D12ShaderVisibleDescriptorHeap newHeap;
4242 if (!newHeap.create(dev, type, newPerFrameSize)) {
4243 qWarning(
"Could not create new shader-visible descriptor heap");
4246 h->destroyWithDeferredRelease(&releaseQueue);
4253void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
4255 ID3D12DescriptorHeap *heaps[] = {
4256 shaderVisibleCbvSrvUavHeap.heap.heap,
4257 samplerMgr.shaderVisibleSamplerHeap.heap.heap
4259 cbD->cmdList->SetDescriptorHeaps(2, heaps);
4262QD3D12Buffer::QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
4263 : QRhiBuffer(rhi, type, usage, size)
4267QD3D12Buffer::~QD3D12Buffer()
4272void QD3D12Buffer::destroy()
4274 if (handles[0].isNull())
4277 QRHI_RES_RHI(QRhiD3D12);
4286 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4288 rhiD->releaseQueue.deferredReleaseResource(handles[i]);
4290 pendingHostWrites[i].clear();
4294 rhiD->unregisterResource(
this);
4297bool QD3D12Buffer::create()
4299 if (!handles[0].isNull())
4302 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
4303 qWarning(
"UniformBuffer must always be Dynamic");
4307 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
4308 qWarning(
"StorageBuffer cannot be combined with Dynamic");
4312 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
4313 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
4315 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
4316 if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
4317 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4319 QRHI_RES_RHI(QRhiD3D12);
4321 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4322 if (i == 0 || m_type == Dynamic) {
4323 D3D12_RESOURCE_DESC resourceDesc = {};
4324 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
4325 resourceDesc.Width = roundedSize;
4326 resourceDesc.Height = 1;
4327 resourceDesc.DepthOrArraySize = 1;
4328 resourceDesc.MipLevels = 1;
4329 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
4330 resourceDesc.SampleDesc = { 1, 0 };
4331 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
4332 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
4333 ID3D12Resource *resource =
nullptr;
4334 D3D12MA::Allocation *allocation =
nullptr;
4336 D3D12_HEAP_TYPE heapType = m_type == Dynamic
4337 ? D3D12_HEAP_TYPE_UPLOAD
4338 : D3D12_HEAP_TYPE_DEFAULT;
4339 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
4340 ? D3D12_RESOURCE_STATE_GENERIC_READ
4341 : D3D12_RESOURCE_STATE_COMMON;
4342 hr = rhiD->vma.createResource(heapType,
4348 reinterpret_cast<
void **>(&resource));
4351 if (!m_objectName.isEmpty()) {
4352 QString decoratedName = QString::fromUtf8(m_objectName);
4353 if (m_type == Dynamic) {
4354 decoratedName += QLatin1Char(
'/');
4355 decoratedName += QString::number(i);
4357 resource->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
4359 void *cpuMemPtr =
nullptr;
4360 if (m_type == Dynamic) {
4362 hr = resource->Map(0,
nullptr, &cpuMemPtr);
4364 qWarning(
"Map() failed to dynamic buffer");
4365 resource->Release();
4367 allocation->Release();
4371 handles[i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
4379 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
4380 qPrintable(QSystemError::windowsComString(hr)),
4383 int(rhiD->vma.isUsingD3D12MA()));
4387 rhiD->registerResource(
this);
4391QRhiBuffer::NativeBuffer QD3D12Buffer::nativeBuffer()
4394 Q_ASSERT(
sizeof(b.objects) /
sizeof(b.objects[0]) >= size_t(QD3D12_FRAMES_IN_FLIGHT));
4395 QRHI_RES_RHI(QRhiD3D12);
4396 if (m_type == Dynamic) {
4397 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4398 executeHostWritesForFrameSlot(i);
4399 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[i]))
4400 b.objects[i] = res->resource;
4402 b.objects[i] =
nullptr;
4404 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
4407 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[0]))
4408 b.objects[0] = res->resource;
4410 b.objects[0] =
nullptr;
4415char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
4423 Q_ASSERT(m_type == Dynamic);
4424 QRHI_RES_RHI(QRhiD3D12);
4425 Q_ASSERT(rhiD->inFrame);
4426 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
4427 return static_cast<
char *>(res->cpuMapPtr);
4432void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
4437void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
4439 if (pendingHostWrites[frameSlot].isEmpty())
4442 Q_ASSERT(m_type == QRhiBuffer::Dynamic);
4443 QRHI_RES_RHI(QRhiD3D12);
4444 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
4445 Q_ASSERT(res->cpuMapPtr);
4446 for (
const QD3D12Buffer::HostWrite &u : std::as_const(pendingHostWrites[frameSlot]))
4447 memcpy(
static_cast<
char *>(res->cpuMapPtr) + u.offset, u.data.constData(), u.data.size());
4449 pendingHostWrites[frameSlot].clear();
4452static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
4454 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
4456 case QRhiTexture::RGBA8:
4457 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
4458 case QRhiTexture::BGRA8:
4459 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
4460 case QRhiTexture::R8:
4461 return DXGI_FORMAT_R8_UNORM;
4462 case QRhiTexture::R8SI:
4463 return DXGI_FORMAT_R8_SINT;
4464 case QRhiTexture::R8UI:
4465 return DXGI_FORMAT_R8_UINT;
4466 case QRhiTexture::RG8:
4467 return DXGI_FORMAT_R8G8_UNORM;
4468 case QRhiTexture::R16:
4469 return DXGI_FORMAT_R16_UNORM;
4470 case QRhiTexture::RG16:
4471 return DXGI_FORMAT_R16G16_UNORM;
4472 case QRhiTexture::RED_OR_ALPHA8:
4473 return DXGI_FORMAT_R8_UNORM;
4475 case QRhiTexture::RGBA16F:
4476 return DXGI_FORMAT_R16G16B16A16_FLOAT;
4477 case QRhiTexture::RGBA32F:
4478 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4479 case QRhiTexture::R16F:
4480 return DXGI_FORMAT_R16_FLOAT;
4481 case QRhiTexture::R32F:
4482 return DXGI_FORMAT_R32_FLOAT;
4484 case QRhiTexture::RGB10A2:
4485 return DXGI_FORMAT_R10G10B10A2_UNORM;
4487 case QRhiTexture::R32SI:
4488 return DXGI_FORMAT_R32_SINT;
4489 case QRhiTexture::R32UI:
4490 return DXGI_FORMAT_R32_UINT;
4491 case QRhiTexture::RG32SI:
4492 return DXGI_FORMAT_R32G32_SINT;
4493 case QRhiTexture::RG32UI:
4494 return DXGI_FORMAT_R32G32_UINT;
4495 case QRhiTexture::RGBA32SI:
4496 return DXGI_FORMAT_R32G32B32A32_SINT;
4497 case QRhiTexture::RGBA32UI:
4498 return DXGI_FORMAT_R32G32B32A32_UINT;
4500 case QRhiTexture::D16:
4501 return DXGI_FORMAT_R16_TYPELESS;
4502 case QRhiTexture::D24:
4503 return DXGI_FORMAT_R24G8_TYPELESS;
4504 case QRhiTexture::D24S8:
4505 return DXGI_FORMAT_R24G8_TYPELESS;
4506 case QRhiTexture::D32F:
4507 return DXGI_FORMAT_R32_TYPELESS;
4508 case QRhiTexture::Format::D32FS8:
4509 return DXGI_FORMAT_R32G8X24_TYPELESS;
4511 case QRhiTexture::BC1:
4512 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
4513 case QRhiTexture::BC2:
4514 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
4515 case QRhiTexture::BC3:
4516 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
4517 case QRhiTexture::BC4:
4518 return DXGI_FORMAT_BC4_UNORM;
4519 case QRhiTexture::BC5:
4520 return DXGI_FORMAT_BC5_UNORM;
4521 case QRhiTexture::BC6H:
4522 return DXGI_FORMAT_BC6H_UF16;
4523 case QRhiTexture::BC7:
4524 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
4526 case QRhiTexture::ETC2_RGB8:
4527 case QRhiTexture::ETC2_RGB8A1:
4528 case QRhiTexture::ETC2_RGBA8:
4529 qWarning(
"QRhiD3D12 does not support ETC2 textures");
4530 return DXGI_FORMAT_R8G8B8A8_UNORM;
4532 case QRhiTexture::ASTC_4x4:
4533 case QRhiTexture::ASTC_5x4:
4534 case QRhiTexture::ASTC_5x5:
4535 case QRhiTexture::ASTC_6x5:
4536 case QRhiTexture::ASTC_6x6:
4537 case QRhiTexture::ASTC_8x5:
4538 case QRhiTexture::ASTC_8x6:
4539 case QRhiTexture::ASTC_8x8:
4540 case QRhiTexture::ASTC_10x5:
4541 case QRhiTexture::ASTC_10x6:
4542 case QRhiTexture::ASTC_10x8:
4543 case QRhiTexture::ASTC_10x10:
4544 case QRhiTexture::ASTC_12x10:
4545 case QRhiTexture::ASTC_12x12:
4546 qWarning(
"QRhiD3D12 does not support ASTC textures");
4547 return DXGI_FORMAT_R8G8B8A8_UNORM;
4552 return DXGI_FORMAT_R8G8B8A8_UNORM;
4555QD3D12RenderBuffer::QD3D12RenderBuffer(QRhiImplementation *rhi,
4557 const QSize &pixelSize,
4560 QRhiTexture::Format backingFormatHint)
4561 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
4565QD3D12RenderBuffer::~QD3D12RenderBuffer()
4570void QD3D12RenderBuffer::destroy()
4572 if (handle.isNull())
4575 QRHI_RES_RHI(QRhiD3D12);
4578 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->rtvPool, rtv, 1);
4579 else if (dsv.isValid())
4580 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->dsvPool, dsv, 1);
4588 rhiD->unregisterResource(
this);
4591bool QD3D12RenderBuffer::create()
4593 if (!handle.isNull())
4596 if (m_pixelSize.isEmpty())
4599 QRHI_RES_RHI(QRhiD3D12);
4602 case QRhiRenderBuffer::Color:
4604 dxgiFormat = toD3DTextureFormat(backingFormat(), {});
4605 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4606 D3D12_RESOURCE_DESC resourceDesc = {};
4607 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4608 resourceDesc.Width = UINT64(m_pixelSize.width());
4609 resourceDesc.Height = UINT(m_pixelSize.height());
4610 resourceDesc.DepthOrArraySize = 1;
4611 resourceDesc.MipLevels = 1;
4612 resourceDesc.Format = dxgiFormat;
4613 resourceDesc.SampleDesc = sampleDesc;
4614 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4615 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4616 D3D12_CLEAR_VALUE clearValue = {};
4617 clearValue.Format = dxgiFormat;
4619 ID3D12Resource *resource =
nullptr;
4620 D3D12MA::Allocation *allocation =
nullptr;
4621 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4623 D3D12_RESOURCE_STATE_RENDER_TARGET,
4626 __uuidof(ID3D12Resource),
4627 reinterpret_cast<
void **>(&resource));
4629 qWarning(
"Failed to create color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4632 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
4633 rtv = rhiD->rtvPool.allocate(1);
4636 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
4637 rtvDesc.Format = dxgiFormat;
4638 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
4639 : D3D12_RTV_DIMENSION_TEXTURE2D;
4640 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
4643 case QRhiRenderBuffer::DepthStencil:
4645 dxgiFormat = DS_FORMAT;
4646 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4647 D3D12_RESOURCE_DESC resourceDesc = {};
4648 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4649 resourceDesc.Width = UINT64(m_pixelSize.width());
4650 resourceDesc.Height = UINT(m_pixelSize.height());
4651 resourceDesc.DepthOrArraySize = 1;
4652 resourceDesc.MipLevels = 1;
4653 resourceDesc.Format = dxgiFormat;
4654 resourceDesc.SampleDesc = sampleDesc;
4655 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4656 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4657 if (m_flags.testFlag(UsedWithSwapChainOnly))
4658 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
4659 D3D12_CLEAR_VALUE clearValue = {};
4660 clearValue.Format = dxgiFormat;
4661 clearValue.DepthStencil.Depth = 1.0f;
4662 clearValue.DepthStencil.Stencil = 0;
4663 ID3D12Resource *resource =
nullptr;
4664 D3D12MA::Allocation *allocation =
nullptr;
4665 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4667 D3D12_RESOURCE_STATE_DEPTH_WRITE,
4670 __uuidof(ID3D12Resource),
4671 reinterpret_cast<
void **>(&resource));
4673 qWarning(
"Failed to create depth-stencil buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4676 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE, allocation);
4677 dsv = rhiD->dsvPool.allocate(1);
4680 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
4681 dsvDesc.Format = dxgiFormat;
4682 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
4683 : D3D12_DSV_DIMENSION_TEXTURE2D;
4684 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
4689 if (!m_objectName.isEmpty()) {
4690 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4691 const QString name = QString::fromUtf8(m_objectName);
4692 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4697 rhiD->registerResource(
this);
4701QRhiTexture::Format QD3D12RenderBuffer::backingFormat()
const
4703 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
4704 return m_backingFormatHint;
4706 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
4709QD3D12Texture::QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
4710 int arraySize,
int sampleCount, Flags flags)
4711 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
4715QD3D12Texture::~QD3D12Texture()
4720void QD3D12Texture::destroy()
4722 if (handle.isNull())
4725 QRHI_RES_RHI(QRhiD3D12);
4727 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->cbvSrvUavPool, srv, 1);
4733 rhiD->unregisterResource(
this);
4736static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
4739 case QRhiTexture::Format::D16:
4740 return DXGI_FORMAT_R16_FLOAT;
4741 case QRhiTexture::Format::D24:
4742 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4743 case QRhiTexture::Format::D24S8:
4744 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4745 case QRhiTexture::Format::D32F:
4746 return DXGI_FORMAT_R32_FLOAT;
4747 case QRhiTexture::Format::D32FS8:
4748 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
4752 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
4755static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
4759 case QRhiTexture::Format::D16:
4760 return DXGI_FORMAT_D16_UNORM;
4761 case QRhiTexture::Format::D24:
4762 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4763 case QRhiTexture::Format::D24S8:
4764 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4765 case QRhiTexture::Format::D32F:
4766 return DXGI_FORMAT_D32_FLOAT;
4767 case QRhiTexture::Format::D32FS8:
4768 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
4772 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
4775static inline bool isDepthTextureFormat(QRhiTexture::Format format)
4778 case QRhiTexture::Format::D16:
4779 case QRhiTexture::Format::D24:
4780 case QRhiTexture::Format::D24S8:
4781 case QRhiTexture::Format::D32F:
4782 case QRhiTexture::Format::D32FS8:
4789bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
4791 if (!handle.isNull())
4794 QRHI_RES_RHI(QRhiD3D12);
4795 if (!rhiD->isTextureFormatSupported(m_format, m_flags))
4798 const bool isDepth = isDepthTextureFormat(m_format);
4799 const bool isCube = m_flags.testFlag(CubeMap);
4800 const bool is3D = m_flags.testFlag(ThreeDimensional);
4801 const bool isArray = m_flags.testFlag(TextureArray);
4802 const bool hasMipMaps = m_flags.testFlag(MipMapped);
4803 const bool is1D = m_flags.testFlag(OneDimensional);
4805 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
4806 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
4808 dxgiFormat = toD3DTextureFormat(m_format, m_flags);
4810 srvFormat = toD3DDepthTextureSRVFormat(m_format);
4811 rtFormat = toD3DDepthTextureDSVFormat(m_format);
4813 srvFormat = dxgiFormat;
4814 rtFormat = dxgiFormat;
4816 if (m_writeViewFormat.format != UnknownFormat) {
4818 rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
4820 rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
4822 if (m_readViewFormat.format != UnknownFormat) {
4824 srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
4826 srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
4829 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
4830 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4831 if (sampleDesc.Count > 1) {
4833 qWarning(
"Cubemap texture cannot be multisample");
4837 qWarning(
"3D texture cannot be multisample");
4841 qWarning(
"Multisample texture cannot have mipmaps");
4845 if (isDepth && hasMipMaps) {
4846 qWarning(
"Depth texture cannot have mipmaps");
4849 if (isCube && is3D) {
4850 qWarning(
"Texture cannot be both cube and 3D");
4853 if (isArray && is3D) {
4854 qWarning(
"Texture cannot be both array and 3D");
4857 if (isCube && is1D) {
4858 qWarning(
"Texture cannot be both cube and 1D");
4862 qWarning(
"Texture cannot be both 1D and 3D");
4865 if (m_depth > 1 && !is3D) {
4866 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
4869 if (m_arraySize > 0 && !isArray) {
4870 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
4873 if (m_arraySize < 1 && isArray) {
4874 qWarning(
"Texture is an array but array size is %d", m_arraySize);
4879 *adjustedSize = size;
4884bool QD3D12Texture::finishCreate()
4886 QRHI_RES_RHI(QRhiD3D12);
4887 const bool isCube = m_flags.testFlag(CubeMap);
4888 const bool is3D = m_flags.testFlag(ThreeDimensional);
4889 const bool isArray = m_flags.testFlag(TextureArray);
4890 const bool is1D = m_flags.testFlag(OneDimensional);
4892 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4893 srvDesc.Format = srvFormat;
4894 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4897 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
4898 srvDesc.TextureCube.MipLevels = mipLevelCount;
4902 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
4903 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
4904 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4905 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4906 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
4908 srvDesc.Texture1DArray.FirstArraySlice = 0;
4909 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
4912 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
4913 srvDesc.Texture1D.MipLevels = mipLevelCount;
4915 }
else if (isArray) {
4916 if (sampleDesc.Count > 1) {
4917 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
4918 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4919 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
4920 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
4922 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
4923 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
4926 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
4927 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
4928 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4929 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4930 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
4932 srvDesc.Texture2DArray.FirstArraySlice = 0;
4933 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
4937 if (sampleDesc.Count > 1) {
4938 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
4940 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4941 srvDesc.Texture3D.MipLevels = mipLevelCount;
4943 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
4944 srvDesc.Texture2D.MipLevels = mipLevelCount;
4949 srv = rhiD->cbvSrvUavPool.allocate(1);
4953 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4954 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4955 if (!m_objectName.isEmpty()) {
4956 const QString name = QString::fromUtf8(m_objectName);
4957 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4967bool QD3D12Texture::create()
4970 if (!prepareCreate(&size))
4973 const bool isDepth = isDepthTextureFormat(m_format);
4974 const bool isCube = m_flags.testFlag(CubeMap);
4975 const bool is3D = m_flags.testFlag(ThreeDimensional);
4976 const bool isArray = m_flags.testFlag(TextureArray);
4977 const bool is1D = m_flags.testFlag(OneDimensional);
4979 QRHI_RES_RHI(QRhiD3D12);
4981 bool needsOptimizedClearValueSpecified =
false;
4982 UINT resourceFlags = 0;
4983 if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
4985 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4987 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4988 needsOptimizedClearValueSpecified =
true;
4990 if (m_flags.testFlag(UsedWithGenerateMips)) {
4992 qWarning(
"Depth texture cannot have mipmaps generated");
4995 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4997 if (m_flags.testFlag(UsedWithLoadStore))
4998 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5000 D3D12_RESOURCE_DESC resourceDesc = {};
5001 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
5002 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
5003 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
5004 resourceDesc.Width = UINT64(size.width());
5005 resourceDesc.Height = UINT(size.height());
5006 resourceDesc.DepthOrArraySize = isCube ? 6
5007 : (isArray ? UINT(qMax(0, m_arraySize))
5008 : (is3D ? qMax(1, m_depth)
5010 resourceDesc.MipLevels = mipLevelCount;
5011 resourceDesc.Format = dxgiFormat;
5012 resourceDesc.SampleDesc = sampleDesc;
5013 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5014 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
5015 D3D12_CLEAR_VALUE clearValue = {};
5016 clearValue.Format = dxgiFormat;
5018 clearValue.Format = toD3DDepthTextureDSVFormat(m_format);
5019 clearValue.DepthStencil.Depth = 1.0f;
5020 clearValue.DepthStencil.Stencil = 0;
5022 ID3D12Resource *resource =
nullptr;
5023 D3D12MA::Allocation *allocation =
nullptr;
5024 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5026 D3D12_RESOURCE_STATE_COMMON,
5027 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
5029 __uuidof(ID3D12Resource),
5030 reinterpret_cast<
void **>(&resource));
5032 qWarning(
"Failed to create texture: '%s'"
5033 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
5034 qPrintable(QSystemError::windowsComString(hr)),
5035 int(resourceDesc.Dimension),
5036 uint(resourceDesc.Width),
5037 uint(resourceDesc.Height),
5038 uint(resourceDesc.DepthOrArraySize),
5039 uint(resourceDesc.MipLevels),
5040 int(resourceDesc.Format),
5041 int(resourceDesc.SampleDesc.Count));
5045 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON, allocation);
5047 if (!finishCreate())
5050 rhiD->registerResource(
this);
5054bool QD3D12Texture::createFrom(QRhiTexture::NativeTexture src)
5059 if (!prepareCreate())
5062 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *>(src.object);
5063 D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(src.layout);
5065 QRHI_RES_RHI(QRhiD3D12);
5066 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource, state);
5068 if (!finishCreate())
5071 rhiD->registerResource(
this);
5075QRhiTexture::NativeTexture QD3D12Texture::nativeTexture()
5077 QRHI_RES_RHI(QRhiD3D12);
5078 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
5079 return { quint64(res->resource),
int(res->state) };
5084void QD3D12Texture::setNativeLayout(
int layout)
5086 QRHI_RES_RHI(QRhiD3D12);
5087 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
5088 res->state = D3D12_RESOURCE_STATES(layout);
5091QD3D12Sampler::QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
5092 AddressMode u, AddressMode v, AddressMode w)
5093 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
5097QD3D12Sampler::~QD3D12Sampler()
5102void QD3D12Sampler::destroy()
5104 shaderVisibleDescriptor = {};
5106 QRHI_RES_RHI(QRhiD3D12);
5108 rhiD->unregisterResource(
this);
5111static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
5113 if (minFilter == QRhiSampler::Nearest) {
5114 if (magFilter == QRhiSampler::Nearest) {
5115 if (mipFilter == QRhiSampler::Linear)
5116 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
5118 return D3D12_FILTER_MIN_MAG_MIP_POINT;
5120 if (mipFilter == QRhiSampler::Linear)
5121 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
5123 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
5126 if (magFilter == QRhiSampler::Nearest) {
5127 if (mipFilter == QRhiSampler::Linear)
5128 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
5130 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
5132 if (mipFilter == QRhiSampler::Linear)
5133 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
5135 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
5138 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
5141static inline D3D12_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
5144 case QRhiSampler::Repeat:
5145 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
5146 case QRhiSampler::ClampToEdge:
5147 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
5148 case QRhiSampler::Mirror:
5149 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
5151 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
5154static inline D3D12_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
5157 case QRhiSampler::Never:
5158 return D3D12_COMPARISON_FUNC_NEVER;
5159 case QRhiSampler::Less:
5160 return D3D12_COMPARISON_FUNC_LESS;
5161 case QRhiSampler::Equal:
5162 return D3D12_COMPARISON_FUNC_EQUAL;
5163 case QRhiSampler::LessOrEqual:
5164 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5165 case QRhiSampler::Greater:
5166 return D3D12_COMPARISON_FUNC_GREATER;
5167 case QRhiSampler::NotEqual:
5168 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5169 case QRhiSampler::GreaterOrEqual:
5170 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5171 case QRhiSampler::Always:
5172 return D3D12_COMPARISON_FUNC_ALWAYS;
5174 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
5177bool QD3D12Sampler::create()
5180 desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
5181 if (m_compareOp != Never)
5182 desc.Filter = D3D12_FILTER(desc.Filter | 0x80);
5183 desc.AddressU = toD3DAddressMode(m_addressU);
5184 desc.AddressV = toD3DAddressMode(m_addressV);
5185 desc.AddressW = toD3DAddressMode(m_addressW);
5186 desc.MaxAnisotropy = 1.0f;
5187 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
5188 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
5190 QRHI_RES_RHI(QRhiD3D12);
5191 rhiD->registerResource(
this,
false);
5195QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
5197 if (!shaderVisibleDescriptor.isValid()) {
5198 QRHI_RES_RHI(QRhiD3D12);
5199 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(desc);
5201 return shaderVisibleDescriptor;
5204QD3D12ShadingRateMap::QD3D12ShadingRateMap(QRhiImplementation *rhi)
5205 : QRhiShadingRateMap(rhi)
5209QD3D12ShadingRateMap::~QD3D12ShadingRateMap()
5214void QD3D12ShadingRateMap::destroy()
5216 if (handle.isNull())
5222bool QD3D12ShadingRateMap::createFrom(QRhiTexture *src)
5224 if (!handle.isNull())
5227 handle = QRHI_RES(QD3D12Texture, src)->handle;
5232QD3D12TextureRenderTarget::QD3D12TextureRenderTarget(QRhiImplementation *rhi,
5233 const QRhiTextureRenderTargetDescription &desc,
5235 : QRhiTextureRenderTarget(rhi, desc, flags),
5240QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
5245void QD3D12TextureRenderTarget::destroy()
5247 if (!rtv[0].isValid() && !dsv.isValid())
5250 QRHI_RES_RHI(QRhiD3D12);
5251 if (dsv.isValid()) {
5252 if (ownsDsv && rhiD)
5253 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
5257 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i) {
5258 if (rtv[i].isValid()) {
5259 if (ownsRtv[i] && rhiD)
5260 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[i], 1);
5266 rhiD->unregisterResource(
this);
5269QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDescriptor()
5273 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
5275 rpD->colorAttachmentCount = 0;
5276 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it) {
5277 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
5278 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
5280 rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
5282 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
5283 rpD->colorAttachmentCount += 1;
5286 rpD->hasDepthStencil =
false;
5287 if (m_desc.depthStencilBuffer()) {
5288 rpD->hasDepthStencil =
true;
5289 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
5290 }
else if (m_desc.depthTexture()) {
5291 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5292 rpD->hasDepthStencil =
true;
5293 rpD->dsFormat = toD3DDepthTextureDSVFormat(depthTexD->format());
5296 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
5298 rpD->updateSerializedFormat();
5300 QRHI_RES_RHI(QRhiD3D12);
5301 rhiD->registerResource(rpD);
5305bool QD3D12TextureRenderTarget::create()
5307 if (rtv[0].isValid() || dsv.isValid())
5310 QRHI_RES_RHI(QRhiD3D12);
5311 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
5312 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
5313 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
5314 d.colorAttCount = 0;
5317 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
5318 d.colorAttCount += 1;
5319 const QRhiColorAttachment &colorAtt(*it);
5320 QRhiTexture *texture = colorAtt.texture();
5321 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
5322 Q_ASSERT(texture || rb);
5324 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, texture);
5325 QD3D12Resource *res = rhiD->resourcePool.lookupRef(texD->handle);
5327 qWarning(
"Could not look up texture handle for render target");
5330 const bool isMultiView = it->multiViewCount() >= 2;
5331 UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
5332 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5333 rtvDesc.Format = texD->rtFormat;
5334 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
5335 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5336 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5337 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5338 rtvDesc.Texture2DArray.ArraySize = layerCount;
5339 }
else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
5340 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5341 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
5342 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
5343 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
5344 rtvDesc.Texture1DArray.ArraySize = layerCount;
5346 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
5347 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
5349 }
else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5350 if (texD->sampleDesc.Count > 1) {
5351 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
5352 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
5353 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
5355 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5356 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5357 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5358 rtvDesc.Texture2DArray.ArraySize = layerCount;
5360 }
else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
5361 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
5362 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
5363 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
5364 rtvDesc.Texture3D.WSize = layerCount;
5366 if (texD->sampleDesc.Count > 1) {
5367 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
5369 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
5370 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
5373 rtv[attIndex] = rhiD->rtvPool.allocate(1);
5374 if (!rtv[attIndex].isValid()) {
5375 qWarning(
"Failed to allocate RTV for texture render target");
5378 rhiD->dev->CreateRenderTargetView(res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
5379 ownsRtv[attIndex] =
true;
5380 if (attIndex == 0) {
5381 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
5382 d.sampleCount =
int(texD->sampleDesc.Count);
5385 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rb);
5386 ownsRtv[attIndex] =
false;
5387 rtv[attIndex] = rbD->rtv;
5388 if (attIndex == 0) {
5389 d.pixelSize = rbD->pixelSize();
5390 d.sampleCount =
int(rbD->sampleDesc.Count);
5397 if (hasDepthStencil) {
5398 if (m_desc.depthTexture()) {
5400 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5401 QD3D12Resource *res = rhiD->resourcePool.lookupRef(depthTexD->handle);
5403 qWarning(
"Could not look up depth texture handle");
5406 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5407 dsvDesc.Format = depthTexD->rtFormat;
5408 const bool isMultisample = depthTexD->sampleDesc.Count > 1;
5409 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
5410 if (isMultisample) {
5411 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
5412 if (m_desc.depthLayer() >= 0) {
5413 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_desc.depthLayer());
5414 dsvDesc.Texture2DMSArray.ArraySize = 1;
5415 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5416 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5417 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5419 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
5420 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5423 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
5424 if (m_desc.depthLayer() >= 0) {
5425 dsvDesc.Texture2DArray.FirstArraySlice = UINT(m_desc.depthLayer());
5426 dsvDesc.Texture2DArray.ArraySize = 1;
5427 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5428 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5429 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5431 dsvDesc.Texture2DArray.FirstArraySlice = 0;
5432 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5437 dsvDesc.ViewDimension = isMultisample ? D3D12_DSV_DIMENSION_TEXTURE2DMS
5438 : D3D12_DSV_DIMENSION_TEXTURE2D;
5440 dsv = rhiD->dsvPool.allocate(1);
5441 if (!dsv.isValid()) {
5442 qWarning(
"Failed to allocate DSV for texture render target");
5445 rhiD->dev->CreateDepthStencilView(res->resource, &dsvDesc, dsv.cpuHandle);
5446 if (d.colorAttCount == 0) {
5447 d.pixelSize = depthTexD->pixelSize();
5448 d.sampleCount =
int(depthTexD->sampleDesc.Count);
5452 QD3D12RenderBuffer *depthRbD = QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
5453 dsv = depthRbD->dsv;
5454 if (d.colorAttCount == 0) {
5455 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
5456 d.sampleCount =
int(depthRbD->sampleDesc.Count);
5464 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
5465 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i)
5466 d.rtv[i] = i < d.colorAttCount ? rtv[i].cpuHandle : nullDescHandle;
5467 d.dsv = dsv.cpuHandle;
5468 d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
5470 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &d.currentResIdList);
5472 rhiD->registerResource(
this);
5476QSize QD3D12TextureRenderTarget::pixelSize()
const
5478 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc, d.currentResIdList))
5479 const_cast<QD3D12TextureRenderTarget *>(
this)->create();
5484float QD3D12TextureRenderTarget::devicePixelRatio()
const
5489int QD3D12TextureRenderTarget::sampleCount()
const
5491 return d.sampleCount;
5494QD3D12ShaderResourceBindings::QD3D12ShaderResourceBindings(QRhiImplementation *rhi)
5495 : QRhiShaderResourceBindings(rhi)
5499QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
5504void QD3D12ShaderResourceBindings::destroy()
5506 QRHI_RES_RHI(QRhiD3D12);
5508 rhiD->unregisterResource(
this);
5511bool QD3D12ShaderResourceBindings::create()
5513 QRHI_RES_RHI(QRhiD3D12);
5514 if (!rhiD->sanityCheckShaderResourceBindings(
this))
5517 rhiD->updateLayoutDesc(
this);
5519 hasDynamicOffset =
false;
5520 for (
const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
5521 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
5522 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
5523 hasDynamicOffset =
true;
5537 rhiD->registerResource(
this,
false);
5541void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
5552void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
5553 const QRhiShaderResourceBinding::Data::UniformBufferData &,
5557 D3D12_ROOT_PARAMETER1 rootParam = {};
5558 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
5559 rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
5560 rootParam.Descriptor.ShaderRegister = shaderRegister;
5561 rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
5562 visitorData.cbParams[s].append(rootParam);
5565void QD3D12ShaderResourceBindings::visitTexture(QD3D12Stage s,
5566 const QRhiShaderResourceBinding::TextureAndSampler &,
5569 D3D12_DESCRIPTOR_RANGE1 range = {};
5570 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
5571 range.NumDescriptors = 1;
5572 range.BaseShaderRegister = shaderRegister;
5573 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[s];
5574 visitorData.currentSrvRangeOffset[s] += 1;
5575 visitorData.srvRanges[s].append(range);
5576 if (visitorData.srvRanges[s].count() == 1) {
5577 visitorData.srvTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5578 visitorData.srvTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5582void QD3D12ShaderResourceBindings::visitSampler(QD3D12Stage s,
5583 const QRhiShaderResourceBinding::TextureAndSampler &,
5589 int &rangeStoreIdx(visitorData.samplerRangeHeads[s]);
5590 if (rangeStoreIdx == 16) {
5591 qWarning(
"Sampler count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi", s);
5594 D3D12_DESCRIPTOR_RANGE1 range = {};
5595 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
5596 range.NumDescriptors = 1;
5597 range.BaseShaderRegister = shaderRegister;
5598 visitorData.samplerRanges[s][rangeStoreIdx] = range;
5599 D3D12_ROOT_PARAMETER1 param = {};
5600 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5601 param.ShaderVisibility = qd3d12_stageToVisibility(s);
5602 param.DescriptorTable.NumDescriptorRanges = 1;
5603 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[s][rangeStoreIdx];
5605 visitorData.samplerTables[s].append(param);
5608void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage s,
5609 const QRhiShaderResourceBinding::Data::StorageBufferData &,
5610 QD3D12ShaderResourceVisitor::StorageOp,
5613 D3D12_DESCRIPTOR_RANGE1 range = {};
5614 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5615 range.NumDescriptors = 1;
5616 range.BaseShaderRegister = shaderRegister;
5617 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5618 visitorData.currentUavRangeOffset[s] += 1;
5619 visitorData.uavRanges[s].append(range);
5620 if (visitorData.uavRanges[s].count() == 1) {
5621 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5622 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5626void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage s,
5627 const QRhiShaderResourceBinding::Data::StorageImageData &,
5628 QD3D12ShaderResourceVisitor::StorageOp,
5631 D3D12_DESCRIPTOR_RANGE1 range = {};
5632 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5633 range.NumDescriptors = 1;
5634 range.BaseShaderRegister = shaderRegister;
5635 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5636 visitorData.currentUavRangeOffset[s] += 1;
5637 visitorData.uavRanges[s].append(range);
5638 if (visitorData.uavRanges[s].count() == 1) {
5639 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5640 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5644QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
5647 QRHI_RES_RHI(QRhiD3D12);
5661 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
5665 using namespace std::placeholders;
5666 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
5667 visitor.texture = std::bind(&QD3D12ShaderResourceBindings::visitTexture,
this, _1, _2, _3);
5668 visitor.sampler = std::bind(&QD3D12ShaderResourceBindings::visitSampler,
this, _1, _2, _3);
5669 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
5670 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
5694 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> rootParams;
5695 for (
int s = 0; s < 6; ++s) {
5696 if (!visitorData.cbParams[s].isEmpty())
5697 rootParams.append(visitorData.cbParams[s].constData(), visitorData.cbParams[s].count());
5699 for (
int s = 0; s < 6; ++s) {
5700 if (!visitorData.srvRanges[s].isEmpty()) {
5701 visitorData.srvTables[s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[s].count();
5702 visitorData.srvTables[s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[s].constData();
5703 rootParams.append(visitorData.srvTables[s]);
5706 for (
int s = 0; s < 6; ++s) {
5707 if (!visitorData.samplerTables[s].isEmpty())
5708 rootParams.append(visitorData.samplerTables[s].constData(), visitorData.samplerTables[s].count());
5710 for (
int s = 0; s < 6; ++s) {
5711 if (!visitorData.uavRanges[s].isEmpty()) {
5712 visitorData.uavTables[s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[s].count();
5713 visitorData.uavTables[s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[s].constData();
5714 rootParams.append(visitorData.uavTables[s]);
5718 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
5719 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
5720 if (!rootParams.isEmpty()) {
5721 rsDesc.Desc_1_1.NumParameters = rootParams.count();
5722 rsDesc.Desc_1_1.pParameters = rootParams.constData();
5726 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
5727 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
5728 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
5730 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
5732 ID3DBlob *signature =
nullptr;
5733 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
5735 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5738 ID3D12RootSignature *rootSig =
nullptr;
5739 hr = rhiD->dev->CreateRootSignature(0,
5740 signature->GetBufferPointer(),
5741 signature->GetBufferSize(),
5742 __uuidof(ID3D12RootSignature),
5743 reinterpret_cast<
void **>(&rootSig));
5744 signature->Release();
5746 qWarning(
"Failed to create root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5750 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
5762static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
5764 const int smMajor = version / 10;
5765 const int smMinor = version % 10;
5766 target[0] = stage[0];
5767 target[1] = stage[1];
5769 target[3] =
'0' + smMajor;
5771 target[5] =
'0' + smMinor;
5775enum class HlslCompileFlag
5777 WithDebugInfo = 0x01
5780static QByteArray legacyCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5782 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
5784 qWarning(
"Unable to resolve function D3DCompile()");
5785 return QByteArray();
5788 ID3DBlob *bytecode =
nullptr;
5789 ID3DBlob *errors =
nullptr;
5790 UINT d3dCompileFlags = 0;
5791 if (flags &
int(HlslCompileFlag::WithDebugInfo))
5792 d3dCompileFlags |= D3DCOMPILE_DEBUG;
5794 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
5795 nullptr,
nullptr,
nullptr,
5796 hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
5797 if (FAILED(hr) || !bytecode) {
5798 qWarning(
"HLSL shader compilation failed: 0x%x", uint(hr));
5800 *error = QString::fromUtf8(
static_cast<
const char *>(errors->GetBufferPointer()),
5801 int(errors->GetBufferSize()));
5804 return QByteArray();
5808 result.resize(
int(bytecode->GetBufferSize()));
5809 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
5810 bytecode->Release();
5814#ifdef QRHI_D3D12_HAS_DXC
5817#define DXC_CP_UTF8 65001
5820#ifndef DXC_ARG_DEBUG
5821#define DXC_ARG_DEBUG L"-Zi"
5824static QByteArray dxcCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5826 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
5827 IDxcCompiler *compiler = dxc.first;
5829 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
5830 "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
5831 return QByteArray();
5833 IDxcLibrary *library = dxc.second;
5835 return QByteArray();
5837 IDxcBlobEncoding *sourceBlob =
nullptr;
5838 HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
5839 UINT32(hlslSource.shader().size()),
5843 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
5845 qPrintable(QSystemError::windowsComString(hr)));
5846 return QByteArray();
5849 const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
5850 const QString targetStr = QString::fromLatin1(target);
5852 QVarLengthArray<LPCWSTR, 4> argPtrs;
5854 if (flags &
int(HlslCompileFlag::WithDebugInfo)) {
5855 debugArg = QString::fromUtf16(
reinterpret_cast<
const char16_t *>(DXC_ARG_DEBUG));
5856 argPtrs.append(
reinterpret_cast<LPCWSTR>(debugArg.utf16()));
5859 IDxcOperationResult *result =
nullptr;
5860 hr = compiler->Compile(sourceBlob,
5862 reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
5863 reinterpret_cast<LPCWSTR>(targetStr.utf16()),
5864 argPtrs.data(), argPtrs.count(),
5868 sourceBlob->Release();
5870 result->GetStatus(&hr);
5872 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
5874 qPrintable(QSystemError::windowsComString(hr)));
5876 IDxcBlobEncoding *errorsBlob =
nullptr;
5877 if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
5879 *error = QString::fromUtf8(
static_cast<
const char *>(errorsBlob->GetBufferPointer()),
5880 int(errorsBlob->GetBufferSize()));
5881 errorsBlob->Release();
5885 return QByteArray();
5888 IDxcBlob *bytecode =
nullptr;
5889 if FAILED(result->GetResult(&bytecode)) {
5890 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
5892 qPrintable(QSystemError::windowsComString(hr)));
5893 return QByteArray();
5897 ba.resize(
int(bytecode->GetBufferSize()));
5898 memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
5899 bytecode->Release();
5905static QByteArray compileHlslShaderSource(
const QShader &shader,
5906 QShader::Variant shaderVariant,
5909 QShaderKey *usedShaderKey)
5912 const int shaderModelMax = 67;
5913 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5914 for (QShader::Source type : { QShader::DxilShader, QShader::DxbcShader }) {
5915 QShaderKey key = { type, sm, shaderVariant };
5916 QShaderCode intermediateBytecodeShader = shader.shader(key);
5917 if (!intermediateBytecodeShader.shader().isEmpty()) {
5919 *usedShaderKey = key;
5920 return intermediateBytecodeShader.shader();
5925 QShaderCode hlslSource;
5927 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5928 key = { QShader::HlslShader, sm, shaderVariant };
5929 hlslSource = shader.shader(key);
5930 if (!hlslSource.shader().isEmpty())
5934 if (hlslSource.shader().isEmpty()) {
5935 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" << shader;
5936 return QByteArray();
5940 *usedShaderKey = key;
5943 switch (shader.stage()) {
5944 case QShader::VertexStage:
5945 makeHlslTargetString(target,
"vs", key.sourceVersion().version());
5947 case QShader::TessellationControlStage:
5948 makeHlslTargetString(target,
"hs", key.sourceVersion().version());
5950 case QShader::TessellationEvaluationStage:
5951 makeHlslTargetString(target,
"ds", key.sourceVersion().version());
5953 case QShader::GeometryStage:
5954 makeHlslTargetString(target,
"gs", key.sourceVersion().version());
5956 case QShader::FragmentStage:
5957 makeHlslTargetString(target,
"ps", key.sourceVersion().version());
5959 case QShader::ComputeStage:
5960 makeHlslTargetString(target,
"cs", key.sourceVersion().version());
5964 if (key.sourceVersion().version() >= 60) {
5965#ifdef QRHI_D3D12_HAS_DXC
5966 return dxcCompile(hlslSource, target, flags, error);
5968 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
5969 "but the Qt build has no support for DXC. "
5970 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
5974 return legacyCompile(hlslSource, target, flags, error);
5977static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
5980 if (c.testFlag(QRhiGraphicsPipeline::R))
5981 f |= D3D12_COLOR_WRITE_ENABLE_RED;
5982 if (c.testFlag(QRhiGraphicsPipeline::G))
5983 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
5984 if (c.testFlag(QRhiGraphicsPipeline::B))
5985 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
5986 if (c.testFlag(QRhiGraphicsPipeline::A))
5987 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
5991static inline D3D12_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f,
bool rgb)
6000 case QRhiGraphicsPipeline::Zero:
6001 return D3D12_BLEND_ZERO;
6002 case QRhiGraphicsPipeline::One:
6003 return D3D12_BLEND_ONE;
6004 case QRhiGraphicsPipeline::SrcColor:
6005 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
6006 case QRhiGraphicsPipeline::OneMinusSrcColor:
6007 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
6008 case QRhiGraphicsPipeline::DstColor:
6009 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
6010 case QRhiGraphicsPipeline::OneMinusDstColor:
6011 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
6012 case QRhiGraphicsPipeline::SrcAlpha:
6013 return D3D12_BLEND_SRC_ALPHA;
6014 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6015 return D3D12_BLEND_INV_SRC_ALPHA;
6016 case QRhiGraphicsPipeline::DstAlpha:
6017 return D3D12_BLEND_DEST_ALPHA;
6018 case QRhiGraphicsPipeline::OneMinusDstAlpha:
6019 return D3D12_BLEND_INV_DEST_ALPHA;
6020 case QRhiGraphicsPipeline::ConstantColor:
6021 case QRhiGraphicsPipeline::ConstantAlpha:
6022 return D3D12_BLEND_BLEND_FACTOR;
6023 case QRhiGraphicsPipeline::OneMinusConstantColor:
6024 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
6025 return D3D12_BLEND_INV_BLEND_FACTOR;
6026 case QRhiGraphicsPipeline::SrcAlphaSaturate:
6027 return D3D12_BLEND_SRC_ALPHA_SAT;
6028 case QRhiGraphicsPipeline::Src1Color:
6029 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
6030 case QRhiGraphicsPipeline::OneMinusSrc1Color:
6031 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
6032 case QRhiGraphicsPipeline::Src1Alpha:
6033 return D3D12_BLEND_SRC1_ALPHA;
6034 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
6035 return D3D12_BLEND_INV_SRC1_ALPHA;
6037 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
6040static inline D3D12_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
6043 case QRhiGraphicsPipeline::Add:
6044 return D3D12_BLEND_OP_ADD;
6045 case QRhiGraphicsPipeline::Subtract:
6046 return D3D12_BLEND_OP_SUBTRACT;
6047 case QRhiGraphicsPipeline::ReverseSubtract:
6048 return D3D12_BLEND_OP_REV_SUBTRACT;
6049 case QRhiGraphicsPipeline::Min:
6050 return D3D12_BLEND_OP_MIN;
6051 case QRhiGraphicsPipeline::Max:
6052 return D3D12_BLEND_OP_MAX;
6054 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
6057static inline D3D12_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
6060 case QRhiGraphicsPipeline::None:
6061 return D3D12_CULL_MODE_NONE;
6062 case QRhiGraphicsPipeline::Front:
6063 return D3D12_CULL_MODE_FRONT;
6064 case QRhiGraphicsPipeline::Back:
6065 return D3D12_CULL_MODE_BACK;
6067 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
6070static inline D3D12_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
6073 case QRhiGraphicsPipeline::Fill:
6074 return D3D12_FILL_MODE_SOLID;
6075 case QRhiGraphicsPipeline::Line:
6076 return D3D12_FILL_MODE_WIREFRAME;
6078 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
6081static inline D3D12_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
6084 case QRhiGraphicsPipeline::Never:
6085 return D3D12_COMPARISON_FUNC_NEVER;
6086 case QRhiGraphicsPipeline::Less:
6087 return D3D12_COMPARISON_FUNC_LESS;
6088 case QRhiGraphicsPipeline::Equal:
6089 return D3D12_COMPARISON_FUNC_EQUAL;
6090 case QRhiGraphicsPipeline::LessOrEqual:
6091 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
6092 case QRhiGraphicsPipeline::Greater:
6093 return D3D12_COMPARISON_FUNC_GREATER;
6094 case QRhiGraphicsPipeline::NotEqual:
6095 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
6096 case QRhiGraphicsPipeline::GreaterOrEqual:
6097 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
6098 case QRhiGraphicsPipeline::Always:
6099 return D3D12_COMPARISON_FUNC_ALWAYS;
6101 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
6104static inline D3D12_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
6107 case QRhiGraphicsPipeline::StencilZero:
6108 return D3D12_STENCIL_OP_ZERO;
6109 case QRhiGraphicsPipeline::Keep:
6110 return D3D12_STENCIL_OP_KEEP;
6111 case QRhiGraphicsPipeline::Replace:
6112 return D3D12_STENCIL_OP_REPLACE;
6113 case QRhiGraphicsPipeline::IncrementAndClamp:
6114 return D3D12_STENCIL_OP_INCR_SAT;
6115 case QRhiGraphicsPipeline::DecrementAndClamp:
6116 return D3D12_STENCIL_OP_DECR_SAT;
6117 case QRhiGraphicsPipeline::Invert:
6118 return D3D12_STENCIL_OP_INVERT;
6119 case QRhiGraphicsPipeline::IncrementAndWrap:
6120 return D3D12_STENCIL_OP_INCR;
6121 case QRhiGraphicsPipeline::DecrementAndWrap:
6122 return D3D12_STENCIL_OP_DECR;
6124 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
6127static inline D3D12_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t,
int patchControlPointCount)
6130 case QRhiGraphicsPipeline::Triangles:
6131 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
6132 case QRhiGraphicsPipeline::TriangleStrip:
6133 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
6134 case QRhiGraphicsPipeline::TriangleFan:
6135 qWarning(
"Triangle fans are not supported with D3D");
6136 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
6137 case QRhiGraphicsPipeline::Lines:
6138 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
6139 case QRhiGraphicsPipeline::LineStrip:
6140 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
6141 case QRhiGraphicsPipeline::Points:
6142 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
6143 case QRhiGraphicsPipeline::Patches:
6144 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
6145 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
6147 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
6150static inline D3D12_PRIMITIVE_TOPOLOGY_TYPE toD3DTopologyType(QRhiGraphicsPipeline::Topology t)
6153 case QRhiGraphicsPipeline::Triangles:
6154 case QRhiGraphicsPipeline::TriangleStrip:
6155 case QRhiGraphicsPipeline::TriangleFan:
6156 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
6157 case QRhiGraphicsPipeline::Lines:
6158 case QRhiGraphicsPipeline::LineStrip:
6159 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
6160 case QRhiGraphicsPipeline::Points:
6161 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
6162 case QRhiGraphicsPipeline::Patches:
6163 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
6165 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
6168static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
6171 case QRhiVertexInputAttribute::Float4:
6172 return DXGI_FORMAT_R32G32B32A32_FLOAT;
6173 case QRhiVertexInputAttribute::Float3:
6174 return DXGI_FORMAT_R32G32B32_FLOAT;
6175 case QRhiVertexInputAttribute::Float2:
6176 return DXGI_FORMAT_R32G32_FLOAT;
6177 case QRhiVertexInputAttribute::Float:
6178 return DXGI_FORMAT_R32_FLOAT;
6179 case QRhiVertexInputAttribute::UNormByte4:
6180 return DXGI_FORMAT_R8G8B8A8_UNORM;
6181 case QRhiVertexInputAttribute::UNormByte2:
6182 return DXGI_FORMAT_R8G8_UNORM;
6183 case QRhiVertexInputAttribute::UNormByte:
6184 return DXGI_FORMAT_R8_UNORM;
6185 case QRhiVertexInputAttribute::UInt4:
6186 return DXGI_FORMAT_R32G32B32A32_UINT;
6187 case QRhiVertexInputAttribute::UInt3:
6188 return DXGI_FORMAT_R32G32B32_UINT;
6189 case QRhiVertexInputAttribute::UInt2:
6190 return DXGI_FORMAT_R32G32_UINT;
6191 case QRhiVertexInputAttribute::UInt:
6192 return DXGI_FORMAT_R32_UINT;
6193 case QRhiVertexInputAttribute::SInt4:
6194 return DXGI_FORMAT_R32G32B32A32_SINT;
6195 case QRhiVertexInputAttribute::SInt3:
6196 return DXGI_FORMAT_R32G32B32_SINT;
6197 case QRhiVertexInputAttribute::SInt2:
6198 return DXGI_FORMAT_R32G32_SINT;
6199 case QRhiVertexInputAttribute::SInt:
6200 return DXGI_FORMAT_R32_SINT;
6201 case QRhiVertexInputAttribute::Half4:
6203 case QRhiVertexInputAttribute::Half3:
6204 return DXGI_FORMAT_R16G16B16A16_FLOAT;
6205 case QRhiVertexInputAttribute::Half2:
6206 return DXGI_FORMAT_R16G16_FLOAT;
6207 case QRhiVertexInputAttribute::Half:
6208 return DXGI_FORMAT_R16_FLOAT;
6209 case QRhiVertexInputAttribute::UShort4:
6211 case QRhiVertexInputAttribute::UShort3:
6212 return DXGI_FORMAT_R16G16B16A16_UINT;
6213 case QRhiVertexInputAttribute::UShort2:
6214 return DXGI_FORMAT_R16G16_UINT;
6215 case QRhiVertexInputAttribute::UShort:
6216 return DXGI_FORMAT_R16_UINT;
6217 case QRhiVertexInputAttribute::SShort4:
6219 case QRhiVertexInputAttribute::SShort3:
6220 return DXGI_FORMAT_R16G16B16A16_SINT;
6221 case QRhiVertexInputAttribute::SShort2:
6222 return DXGI_FORMAT_R16G16_SINT;
6223 case QRhiVertexInputAttribute::SShort:
6224 return DXGI_FORMAT_R16_SINT;
6226 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
6229QD3D12GraphicsPipeline::QD3D12GraphicsPipeline(QRhiImplementation *rhi)
6230 : QRhiGraphicsPipeline(rhi)
6234QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
6239void QD3D12GraphicsPipeline::destroy()
6241 if (handle.isNull())
6244 QRHI_RES_RHI(QRhiD3D12);
6246 rhiD->releaseQueue.deferredReleasePipeline(handle);
6247 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6254 rhiD->unregisterResource(
this);
6257bool QD3D12GraphicsPipeline::create()
6259 if (!handle.isNull())
6262 QRHI_RES_RHI(QRhiD3D12);
6263 if (!rhiD->sanityCheckGraphicsPipeline(
this))
6266 rhiD->pipelineCreationStart();
6268 QByteArray shaderBytecode[5];
6269 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6270 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
6271 stageData[d3dStage].valid =
true;
6272 stageData[d3dStage].stage = d3dStage;
6273 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
6274 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6275 shaderBytecode[d3dStage] = cacheIt->bytecode;
6276 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6279 QShaderKey shaderKey;
6280 int compileFlags = 0;
6281 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6282 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6283 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
6284 shaderStage.shaderVariant(),
6288 if (bytecode.isEmpty()) {
6289 qWarning(
"HLSL graphics shader compilation failed: %s", qPrintable(error));
6293 shaderBytecode[d3dStage] = bytecode;
6294 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
6295 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
6296 { bytecode, stageData[d3dStage].nativeResourceBindingMap });
6300 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6302 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
6303 if (rootSigHandle.isNull()) {
6304 qWarning(
"Failed to create root signature");
6308 ID3D12RootSignature *rootSig =
nullptr;
6309 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6310 rootSig = rs->rootSig;
6312 qWarning(
"Cannot create graphics pipeline state without root signature");
6316 QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6317 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
6318 if (rpD->colorAttachmentCount > 0) {
6319 format = DXGI_FORMAT(rpD->colorFormat[0]);
6320 }
else if (rpD->hasDepthStencil) {
6321 format = DXGI_FORMAT(rpD->dsFormat);
6323 qWarning(
"Cannot create graphics pipeline state without color or depthStencil format");
6326 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
6329 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6330 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
6331 QD3D12PipelineStateSubObject<D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE> primitiveRestartValue;
6332 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
6333 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
6334 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
6335 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
6336 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
6337 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
6338 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
6339 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
6340 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
6341 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
6342 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
6343 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
6344 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
6345 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
6348 stream.rootSig.object = rootSig;
6350 QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
6351 QByteArrayList matrixSliceSemantics;
6352 if (!shaderBytecode[VS].isEmpty()) {
6353 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
6356 D3D12_INPUT_ELEMENT_DESC desc = {};
6361 const int matrixSlice = it->matrixSlice();
6362 if (matrixSlice < 0) {
6363 desc.SemanticName =
"TEXCOORD";
6364 desc.SemanticIndex = UINT(it->location());
6368 std::snprintf(sem.data(), sem.size(),
"TEXCOORD%d_", it->location() - matrixSlice);
6369 matrixSliceSemantics.append(sem);
6370 desc.SemanticName = matrixSliceSemantics.last().constData();
6371 desc.SemanticIndex = UINT(matrixSlice);
6373 desc.Format = toD3DAttributeFormat(it->format());
6374 desc.InputSlot = UINT(it->binding());
6375 desc.AlignedByteOffset = it->offset();
6376 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
6377 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
6378 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
6379 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
6381 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
6383 inputDescs.append(desc);
6387 stream.inputLayout.object.NumElements = inputDescs.count();
6388 stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ?
nullptr : inputDescs.constData();
6390 stream.primitiveRestartValue.object = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
6392 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
6393 topology = toD3DTopology(m_topology, m_patchControlPointCount);
6395 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6396 const int d3dStage = qd3d12_stage(shaderStage.type());
6399 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6400 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6403 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6404 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6407 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6408 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6411 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6412 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6415 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6416 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6424 stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
6425 stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
6426 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
6427 stream.rasterizerState.object.DepthBias = m_depthBias;
6428 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
6429 stream.rasterizerState.object.DepthClipEnable = m_depthClamp ? FALSE : TRUE;
6430 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
6432 stream.depthStencilState.object.DepthEnable = m_depthTest;
6433 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
6434 stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
6435 stream.depthStencilState.object.StencilEnable = m_stencilTest;
6436 if (m_stencilTest) {
6437 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
6438 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
6439 stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
6440 stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
6441 stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
6442 stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
6443 stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
6444 stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
6445 stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
6446 stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
6449 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
6450 for (
int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
6451 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
6452 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6453 blend.BlendEnable = b.enable;
6454 blend.SrcBlend = toD3DBlendFactor(b.srcColor,
true);
6455 blend.DestBlend = toD3DBlendFactor(b.dstColor,
true);
6456 blend.BlendOp = toD3DBlendOp(b.opColor);
6457 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha,
false);
6458 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha,
false);
6459 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
6460 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
6461 stream.blendState.object.RenderTarget[i] = blend;
6463 if (m_targetBlends.isEmpty()) {
6464 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6465 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
6466 stream.blendState.object.RenderTarget[0] = blend;
6469 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
6470 for (
int i = 0; i < rpD->colorAttachmentCount; ++i)
6471 stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
6473 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
6475 stream.sampleDesc.object = sampleDesc;
6477 stream.sampleMask.object = 0xFFFFFFFF;
6479 viewInstanceMask = 0;
6480 const bool isMultiView = m_multiViewCount >= 2;
6481 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
6482 QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
6484 for (
int i = 0; i < m_multiViewCount; ++i) {
6485 viewInstanceMask |= (1 << i);
6486 viewInstanceLocations.append({ 0, UINT(i) });
6488 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
6491 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6493 ID3D12PipelineState *pso =
nullptr;
6494 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6496 qWarning(
"Failed to create graphics pipeline state: %s",
6497 qPrintable(QSystemError::windowsComString(hr)));
6498 rhiD->rootSignaturePool.remove(rootSigHandle);
6503 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
6505 rhiD->pipelineCreationEnd();
6507 rhiD->registerResource(
this);
6511QD3D12ComputePipeline::QD3D12ComputePipeline(QRhiImplementation *rhi)
6512 : QRhiComputePipeline(rhi)
6516QD3D12ComputePipeline::~QD3D12ComputePipeline()
6521void QD3D12ComputePipeline::destroy()
6523 if (handle.isNull())
6526 QRHI_RES_RHI(QRhiD3D12);
6528 rhiD->releaseQueue.deferredReleasePipeline(handle);
6529 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6536 rhiD->unregisterResource(
this);
6539bool QD3D12ComputePipeline::create()
6541 if (!handle.isNull())
6544 QRHI_RES_RHI(QRhiD3D12);
6545 rhiD->pipelineCreationStart();
6547 stageData.valid =
true;
6548 stageData.stage = CS;
6550 QByteArray shaderBytecode;
6551 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(m_shaderStage);
6552 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6553 shaderBytecode = cacheIt->bytecode;
6554 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6557 QShaderKey shaderKey;
6558 int compileFlags = 0;
6559 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6560 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6561 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
6562 m_shaderStage.shaderVariant(),
6566 if (bytecode.isEmpty()) {
6567 qWarning(
"HLSL compute shader compilation failed: %s", qPrintable(error));
6571 shaderBytecode = bytecode;
6572 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
6573 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
6574 stageData.nativeResourceBindingMap });
6577 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6579 rootSigHandle = srbD->createRootSignature(&stageData, 1);
6580 if (rootSigHandle.isNull()) {
6581 qWarning(
"Failed to create root signature");
6585 ID3D12RootSignature *rootSig =
nullptr;
6586 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6587 rootSig = rs->rootSig;
6589 qWarning(
"Cannot create compute pipeline state without root signature");
6594 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6595 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
6597 stream.rootSig.object = rootSig;
6598 stream.CS.object.pShaderBytecode = shaderBytecode.constData();
6599 stream.CS.object.BytecodeLength = shaderBytecode.size();
6600 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6601 ID3D12PipelineState *pso =
nullptr;
6602 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6604 qWarning(
"Failed to create compute pipeline state: %s",
6605 qPrintable(QSystemError::windowsComString(hr)));
6606 rhiD->rootSignaturePool.remove(rootSigHandle);
6611 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
6613 rhiD->pipelineCreationEnd();
6615 rhiD->registerResource(
this);
6622QD3D12RenderPassDescriptor::QD3D12RenderPassDescriptor(QRhiImplementation *rhi)
6623 : QRhiRenderPassDescriptor(rhi)
6625 serializedFormatData.reserve(16);
6628QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
6633void QD3D12RenderPassDescriptor::destroy()
6635 QRHI_RES_RHI(QRhiD3D12);
6637 rhiD->unregisterResource(
this);
6640bool QD3D12RenderPassDescriptor::isCompatible(
const QRhiRenderPassDescriptor *other)
const
6645 const QD3D12RenderPassDescriptor *o = QRHI_RES(
const QD3D12RenderPassDescriptor, other);
6647 if (colorAttachmentCount != o->colorAttachmentCount)
6650 if (hasDepthStencil != o->hasDepthStencil)
6653 for (
int i = 0; i < colorAttachmentCount; ++i) {
6654 if (colorFormat[i] != o->colorFormat[i])
6658 if (hasDepthStencil) {
6659 if (dsFormat != o->dsFormat)
6663 if (hasShadingRateMap != o->hasShadingRateMap)
6669void QD3D12RenderPassDescriptor::updateSerializedFormat()
6671 serializedFormatData.clear();
6672 auto p = std::back_inserter(serializedFormatData);
6674 *p++ = colorAttachmentCount;
6675 *p++ = hasDepthStencil;
6676 for (
int i = 0; i < colorAttachmentCount; ++i)
6677 *p++ = colorFormat[i];
6678 *p++ = hasDepthStencil ? dsFormat : 0;
6681QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor()
const
6683 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6684 rpD->colorAttachmentCount = colorAttachmentCount;
6685 rpD->hasDepthStencil = hasDepthStencil;
6686 memcpy(rpD->colorFormat, colorFormat,
sizeof(colorFormat));
6687 rpD->dsFormat = dsFormat;
6688 rpD->hasShadingRateMap = hasShadingRateMap;
6690 rpD->updateSerializedFormat();
6692 QRHI_RES_RHI(QRhiD3D12);
6693 rhiD->registerResource(rpD);
6697QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat()
const
6699 return serializedFormatData;
6702QD3D12CommandBuffer::QD3D12CommandBuffer(QRhiImplementation *rhi)
6703 : QRhiCommandBuffer(rhi)
6708QD3D12CommandBuffer::~QD3D12CommandBuffer()
6713void QD3D12CommandBuffer::destroy()
6718const QRhiNativeHandles *QD3D12CommandBuffer::nativeHandles()
6720 nativeHandlesStruct.commandList = cmdList;
6721 return &nativeHandlesStruct;
6724QD3D12SwapChainRenderTarget::QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
6725 : QRhiSwapChainRenderTarget(rhi, swapchain),
6730QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
6735void QD3D12SwapChainRenderTarget::destroy()
6740QSize QD3D12SwapChainRenderTarget::pixelSize()
const
6745float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
6750int QD3D12SwapChainRenderTarget::sampleCount()
const
6752 return d.sampleCount;
6755QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
6756 : QRhiSwapChain(rhi),
6757 rtWrapper(rhi,
this),
6758 rtWrapperRight(rhi,
this),
6763QD3D12SwapChain::~QD3D12SwapChain()
6768void QD3D12SwapChain::destroy()
6775 swapChain->Release();
6776 swapChain =
nullptr;
6777 sourceSwapChain1->Release();
6778 sourceSwapChain1 =
nullptr;
6780 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
6781 FrameResources &fr(frameRes[i]);
6783 fr.fence->Release();
6785 CloseHandle(fr.fenceEvent);
6787 fr.cmdList->Release();
6792 dcompVisual->Release();
6793 dcompVisual =
nullptr;
6797 dcompTarget->Release();
6798 dcompTarget =
nullptr;
6801 if (frameLatencyWaitableObject) {
6802 CloseHandle(frameLatencyWaitableObject);
6803 frameLatencyWaitableObject =
nullptr;
6806 QDxgiVSyncService::instance()->unregisterWindow(window);
6808 QRHI_RES_RHI(QRhiD3D12);
6810 rhiD->swapchains.remove(
this);
6811 rhiD->unregisterResource(
this);
6815void QD3D12SwapChain::releaseBuffers()
6817 QRHI_RES_RHI(QRhiD3D12);
6819 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
6820 rhiD->resourcePool.remove(colorBuffers[i]);
6821 rhiD->rtvPool.release(rtvs[i], 1);
6823 rhiD->rtvPool.release(rtvsRight[i], 1);
6824 if (!msaaBuffers[i].isNull())
6825 rhiD->resourcePool.remove(msaaBuffers[i]);
6826 if (msaaRtvs[i].isValid())
6827 rhiD->rtvPool.release(msaaRtvs[i], 1);
6831void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
6833 FrameResources &fr(frameRes[frameSlot]);
6834 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
6835 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
6836 WaitForSingleObject(fr.fenceEvent, INFINITE);
6840void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
6842 QRHI_RES_RHI(QRhiD3D12);
6843 FrameResources &fr(frameRes[currentFrameSlot]);
6844 fr.fenceCounter += 1u;
6845 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
6848QRhiCommandBuffer *QD3D12SwapChain::currentFrameCommandBuffer()
6853QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
6858QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
6860 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
6863QSize QD3D12SwapChain::surfacePixelSize()
6866 return m_window->size() * m_window->devicePixelRatio();
6869bool QD3D12SwapChain::isFormatSupported(Format f)
6875 qWarning(
"Attempted to call isFormatSupported() without a window set");
6879 QRHI_RES_RHI(QRhiD3D12);
6880 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window))
6881 return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
6886QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
6888 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
6891 QRHI_RES_RHI(QRhiD3D12);
6892 info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window);
6897QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
6902 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6903 rpD->colorAttachmentCount = 1;
6904 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
6905 rpD->colorFormat[0] =
int(srgbAdjustedColorFormat);
6906 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
6908 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
6910 rpD->updateSerializedFormat();
6912 QRHI_RES_RHI(QRhiD3D12);
6913 rhiD->registerResource(rpD);
6917bool QRhiD3D12::ensureDirectCompositionDevice()
6922 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
6923 dcompDevice = QRhiD3D::createDirectCompositionDevice();
6924 return dcompDevice ?
true :
false;
6927static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
6928static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
6930void QD3D12SwapChain::chooseFormats()
6932 colorFormat = DEFAULT_FORMAT;
6933 srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
6934 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
6935 QRHI_RES_RHI(QRhiD3D12);
6936 if (m_format != SDR) {
6937 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) {
6940 case HDRExtendedSrgbLinear:
6941 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
6942 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
6943 srgbAdjustedColorFormat = colorFormat;
6946 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
6947 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
6948 srgbAdjustedColorFormat = colorFormat;
6957 qWarning(
"The output associated with the window is not HDR capable "
6958 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
6961 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
6964bool QD3D12SwapChain::createOrResize()
6970 const bool needsRegistration = !window || window != m_window;
6973 if (window && window != m_window)
6977 m_currentPixelSize = surfacePixelSize();
6978 pixelSize = m_currentPixelSize;
6980 if (pixelSize.isEmpty())
6983 HWND hwnd =
reinterpret_cast<HWND>(window->winId());
6985 QRHI_RES_RHI(QRhiD3D12);
6986 stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
6988 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
6989 if (rhiD->ensureDirectCompositionDevice()) {
6991 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
false, &dcompTarget);
6993 qWarning(
"Failed to create Direct Composition target for the window: %s",
6994 qPrintable(QSystemError::windowsComString(hr)));
6997 if (dcompTarget && !dcompVisual) {
6998 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
7000 qWarning(
"Failed to create DirectComposition visual: %s",
7001 qPrintable(QSystemError::windowsComString(hr)));
7006 if (window->requestedFormat().alphaBufferSize() <= 0)
7007 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
7008 "This may lead to problems.");
7011 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
7013 if (swapInterval == 0 && rhiD->supportsAllowTearing)
7014 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
7018 const bool useFrameLatencyWaitableObject = rhiD->maxFrameLatency != 0
7019 && swapInterval != 0
7020 && rhiD->driverInfoStruct.deviceType != QRhiDriverInfo::CpuDevice;
7021 if (useFrameLatencyWaitableObject)
7022 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
7027 DXGI_SWAP_CHAIN_DESC1 desc = {};
7028 desc.Width = UINT(pixelSize.width());
7029 desc.Height = UINT(pixelSize.height());
7030 desc.Format = colorFormat;
7031 desc.SampleDesc.Count = 1;
7032 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
7033 desc.BufferCount = BUFFER_COUNT;
7034 desc.Flags = swapChainFlags;
7035 desc.Scaling = DXGI_SCALING_NONE;
7036 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
7037 desc.Stereo = stereo;
7043 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
7048 desc.Scaling = DXGI_SCALING_STRETCH;
7052 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
7054 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
7059 if (FAILED(hr) && m_format != SDR) {
7060 colorFormat = DEFAULT_FORMAT;
7061 desc.Format = DEFAULT_FORMAT;
7063 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
7065 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
7068 if (SUCCEEDED(hr)) {
7069 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<
void **>(&swapChain)))) {
7070 qWarning(
"IDXGISwapChain3 not available");
7073 if (m_format != SDR) {
7074 hr = swapChain->SetColorSpace1(hdrColorSpace);
7076 qWarning(
"Failed to set color space on swapchain: %s",
7077 qPrintable(QSystemError::windowsComString(hr)));
7080 if (useFrameLatencyWaitableObject) {
7081 swapChain->SetMaximumFrameLatency(rhiD->maxFrameLatency);
7082 frameLatencyWaitableObject = swapChain->GetFrameLatencyWaitableObject();
7085 hr = dcompVisual->SetContent(swapChain);
7086 if (SUCCEEDED(hr)) {
7087 hr = dcompTarget->SetRoot(dcompVisual);
7089 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
7090 qPrintable(QSystemError::windowsComString(hr)));
7093 qWarning(
"Failed to set content for Direct Composition visual: %s",
7094 qPrintable(QSystemError::windowsComString(hr)));
7098 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
7101 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
7102 qWarning(
"Device loss detected during swapchain creation");
7103 rhiD->deviceLost =
true;
7105 }
else if (FAILED(hr)) {
7106 qWarning(
"Failed to create D3D12 swapchain: %s"
7107 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
7108 qPrintable(QSystemError::windowsComString(hr)),
7109 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
7110 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
7114 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7115 hr = rhiD->dev->CreateFence(0,
7116 D3D12_FENCE_FLAG_NONE,
7117 __uuidof(ID3D12Fence),
7118 reinterpret_cast<
void **>(&frameRes[i].fence));
7120 qWarning(
"Failed to create fence for swapchain: %s",
7121 qPrintable(QSystemError::windowsComString(hr)));
7124 frameRes[i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
7126 frameRes[i].fenceCounter = 0;
7130 hr = swapChain->ResizeBuffers(BUFFER_COUNT,
7131 UINT(pixelSize.width()),
7132 UINT(pixelSize.height()),
7135 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
7136 qWarning(
"Device loss detected in ResizeBuffers()");
7137 rhiD->deviceLost =
true;
7139 }
else if (FAILED(hr)) {
7140 qWarning(
"Failed to resize D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
7145 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7146 ID3D12Resource *colorBuffer;
7147 hr = swapChain->GetBuffer(i, __uuidof(ID3D12Resource),
reinterpret_cast<
void **>(&colorBuffer));
7149 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
7150 i, qPrintable(QSystemError::windowsComString(hr)));
7153 colorBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
7154 rtvs[i] = rhiD->rtvPool.allocate(1);
7155 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7156 rtvDesc.Format = srgbAdjustedColorFormat;
7157 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
7158 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
7161 rtvsRight[i] = rhiD->rtvPool.allocate(1);
7162 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7163 rtvDesc.Format = srgbAdjustedColorFormat;
7164 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
7165 rtvDesc.Texture2DArray.ArraySize = 1;
7166 rtvDesc.Texture2DArray.FirstArraySlice = 1;
7167 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
7171 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
7172 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
7173 m_depthStencil->sampleCount(), m_sampleCount);
7175 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
7176 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
7177 m_depthStencil->setPixelSize(pixelSize);
7178 if (!m_depthStencil->create())
7179 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
7180 pixelSize.width(), pixelSize.height());
7182 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
7183 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
7184 pixelSize.width(), pixelSize.height());
7188 ds = m_depthStencil ? QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
7190 if (sampleDesc.Count > 1) {
7191 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7192 D3D12_RESOURCE_DESC resourceDesc = {};
7193 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
7194 resourceDesc.Width = UINT64(pixelSize.width());
7195 resourceDesc.Height = UINT(pixelSize.height());
7196 resourceDesc.DepthOrArraySize = 1;
7197 resourceDesc.MipLevels = 1;
7198 resourceDesc.Format = srgbAdjustedColorFormat;
7199 resourceDesc.SampleDesc = sampleDesc;
7200 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
7201 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
7202 D3D12_CLEAR_VALUE clearValue = {};
7203 clearValue.Format = colorFormat;
7204 ID3D12Resource *resource =
nullptr;
7205 D3D12MA::Allocation *allocation =
nullptr;
7206 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
7208 D3D12_RESOURCE_STATE_RENDER_TARGET,
7211 __uuidof(ID3D12Resource),
7212 reinterpret_cast<
void **>(&resource));
7214 qWarning(
"Failed to create MSAA color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
7217 msaaBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
7218 msaaRtvs[i] = rhiD->rtvPool.allocate(1);
7219 if (!msaaRtvs[i].isValid())
7221 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7222 rtvDesc.Format = srgbAdjustedColorFormat;
7223 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
7224 : D3D12_RTV_DIMENSION_TEXTURE2D;
7225 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[i].cpuHandle);
7229 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
7230 currentFrameSlot = 0;
7231 lastFrameLatencyWaitSlot = -1;
7233 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
7234 QD3D12SwapChainRenderTarget *rtD = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
7235 rtD->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7236 rtD->d.pixelSize = pixelSize;
7237 rtD->d.dpr =
float(window->devicePixelRatio());
7238 rtD->d.sampleCount =
int(sampleDesc.Count);
7239 rtD->d.colorAttCount = 1;
7240 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
7242 rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
7243 QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
7244 rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7245 rtDr->d.pixelSize = pixelSize;
7246 rtDr->d.dpr =
float(window->devicePixelRatio());
7247 rtDr->d.sampleCount =
int(sampleDesc.Count);
7248 rtDr->d.colorAttCount = 1;
7249 rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
7251 QDxgiVSyncService::instance()->registerWindow(window);
7253 if (needsRegistration || !rhiD->swapchains.contains(
this))
7254 rhiD->swapchains.insert(
this);
7256 rhiD->registerResource(
this);