8#include <QtCore/private/qsystemerror_p.h>
9#include <QtCore/qcryptographichash.h>
10#include <QtCore/qendian.h>
20#define QRHI_D3D12_HAS_OLD_PIX
23#ifdef __ID3D12Device2_INTERFACE_DEFINED__
28
29
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
66
67
68
69
70
73
74
75
76
77
78
79
80
81
84
85
86
87
88
89
90
91
92
93
94
95
98
99
100
101
102
103
106
107
108
109
110
111
112
113
114
115
116
119
120
121
122
123
124
127
128
129
130
131
132
135
136
137
138
139
140
141
144
145
146
147
148
149
150
151
152
153
154
155
156
157
160
161
164static const D3D_FEATURE_LEVEL MIN_FEATURE_LEVEL = D3D_FEATURE_LEVEL_11_0;
166QRhiD3D12::QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importParams)
168 debugLayer = params->enableDebugLayer;
170 if (importParams->dev) {
171 ID3D12Device *d3d12Device =
reinterpret_cast<ID3D12Device *>(importParams->dev);
172 if (SUCCEEDED(d3d12Device->QueryInterface(__uuidof(ID3D12Device2),
reinterpret_cast<
void **>(&dev)))) {
174 d3d12Device->Release();
175 importedDevice =
true;
177 qWarning(
"ID3D12Device2 not supported, cannot import device");
180 if (importParams->commandQueue) {
181 cmdQueue =
reinterpret_cast<ID3D12CommandQueue *>(importParams->commandQueue);
182 importedCommandQueue =
true;
184 minimumFeatureLevel = D3D_FEATURE_LEVEL(importParams->minimumFeatureLevel);
185 adapterLuid.LowPart = importParams->adapterLuidLow;
186 adapterLuid.HighPart = importParams->adapterLuidHigh;
191inline Int aligned(Int v, Int byteAlign)
193 return (v + byteAlign - 1) & ~(byteAlign - 1);
196static inline UINT calcSubresource(UINT mipSlice, UINT arraySlice, UINT mipLevels)
198 return mipSlice + arraySlice * mipLevels;
201static inline QD3D12RenderTargetData *rtData(QRhiRenderTarget *rt)
203 switch (rt->resourceType()) {
204 case QRhiResource::SwapChainRenderTarget:
205 return &QRHI_RES(QD3D12SwapChainRenderTarget, rt)->d;
206 case QRhiResource::TextureRenderTarget:
207 return &QRHI_RES(QD3D12TextureRenderTarget, rt)->d;
212 Q_UNREACHABLE_RETURN(
nullptr);
215static D3D12_MESSAGE_ID qd3d12_suppressed_messages[] = {
217 D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
219 D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
221 D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE,
224 D3D12_MESSAGE_ID_LOADPIPELINE_NAMENOTFOUND
227#ifdef QRHI_D3D12_INFOQUEUE1_AVAILABLE
228static void __stdcall qd3d12_message_callback(D3D12_MESSAGE_CATEGORY category,
229 D3D12_MESSAGE_SEVERITY severity,
239 if (severity == D3D12_MESSAGE_SEVERITY_INFO)
241 for (D3D12_MESSAGE_ID suppressedId : qd3d12_suppressed_messages) {
242 if (id == suppressedId)
248 qDebug(
"D3D12: %s", description);
252bool QRhiD3D12::create(QRhi::Flags flags)
256 UINT factoryFlags = 0;
258 factoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
259 HRESULT hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
263 qCDebug(QRHI_LOG_INFO,
"Debug layer was requested but is not available. "
264 "Attempting to create DXGIFactory2 without it.");
265 factoryFlags &= ~DXGI_CREATE_FACTORY_DEBUG;
266 hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
271 qWarning(
"CreateDXGIFactory2() failed to create DXGI factory: %s",
272 qPrintable(QSystemError::windowsComString(hr)));
277 if (qEnvironmentVariableIsSet(
"QT_D3D_MAX_FRAME_LATENCY"))
278 maxFrameLatency = UINT(qMax(0, qEnvironmentVariableIntValue(
"QT_D3D_MAX_FRAME_LATENCY")));
279 if (maxFrameLatency != 0)
280 qCDebug(QRHI_LOG_INFO,
"Using frame latency waitable object with max frame latency %u", maxFrameLatency);
282 supportsAllowTearing =
false;
283 IDXGIFactory5 *factory5 =
nullptr;
284 if (SUCCEEDED(dxgiFactory->QueryInterface(__uuidof(IDXGIFactory5),
reinterpret_cast<
void **>(&factory5)))) {
285 BOOL allowTearing =
false;
286 if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing,
sizeof(allowTearing))))
287 supportsAllowTearing = allowTearing;
292 ID3D12Debug1 *debug =
nullptr;
293 if (SUCCEEDED(D3D12GetDebugInterface(__uuidof(ID3D12Debug1),
reinterpret_cast<
void **>(&debug)))) {
294 qCDebug(QRHI_LOG_INFO,
"Enabling D3D12 debug layer");
295 debug->EnableDebugLayer();
300 activeAdapter =
nullptr;
302 if (!importedDevice) {
303 IDXGIAdapter1 *adapter;
304 int requestedAdapterIndex = -1;
305 if (qEnvironmentVariableIsSet(
"QT_D3D_ADAPTER_INDEX"))
306 requestedAdapterIndex = qEnvironmentVariableIntValue(
"QT_D3D_ADAPTER_INDEX");
308 if (requestedRhiAdapter)
309 adapterLuid =
static_cast<QD3D12Adapter *>(requestedRhiAdapter)->luid;
312 if (requestedAdapterIndex < 0 && (adapterLuid.LowPart || adapterLuid.HighPart)) {
313 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
314 DXGI_ADAPTER_DESC1 desc;
315 adapter->GetDesc1(&desc);
317 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
318 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
320 requestedAdapterIndex = adapterIndex;
326 if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
327 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
328 DXGI_ADAPTER_DESC1 desc;
329 adapter->GetDesc1(&desc);
331 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
332 requestedAdapterIndex = adapterIndex;
338 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
339 DXGI_ADAPTER_DESC1 desc;
340 adapter->GetDesc1(&desc);
341 const QString name = QString::fromUtf16(
reinterpret_cast<
char16_t *>(desc.Description));
342 qCDebug(QRHI_LOG_INFO,
"Adapter %d: '%s' (vendor 0x%X device 0x%X flags 0x%X)",
348 if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
349 activeAdapter = adapter;
350 adapterLuid = desc.AdapterLuid;
351 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
352 qCDebug(QRHI_LOG_INFO,
" using this adapter");
357 if (!activeAdapter) {
358 qWarning(
"No adapter");
362 if (minimumFeatureLevel == 0)
363 minimumFeatureLevel = MIN_FEATURE_LEVEL;
365 hr = D3D12CreateDevice(activeAdapter,
367 __uuidof(ID3D12Device2),
368 reinterpret_cast<
void **>(&dev));
370 qWarning(
"Failed to create D3D12 device: %s", qPrintable(QSystemError::windowsComString(hr)));
376 adapterLuid = dev->GetAdapterLuid();
377 IDXGIAdapter1 *adapter;
378 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
379 DXGI_ADAPTER_DESC1 desc;
380 adapter->GetDesc1(&desc);
381 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
382 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
384 activeAdapter = adapter;
385 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
391 if (!activeAdapter) {
392 qWarning(
"No adapter");
395 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
398 QDxgiVSyncService::instance()->refAdapter(adapterLuid);
401 ID3D12InfoQueue *infoQueue;
402 if (SUCCEEDED(dev->QueryInterface(__uuidof(ID3D12InfoQueue),
reinterpret_cast<
void **>(&infoQueue)))) {
403 if (qEnvironmentVariableIntValue(
"QT_D3D_DEBUG_BREAK")) {
404 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION,
true);
405 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR,
true);
406 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING,
true);
408 D3D12_INFO_QUEUE_FILTER filter = {};
409 filter.DenyList.NumIDs = UINT(std::size(qd3d12_suppressed_messages));
410 filter.DenyList.pIDList = qd3d12_suppressed_messages;
413 D3D12_MESSAGE_SEVERITY infoSev = D3D12_MESSAGE_SEVERITY_INFO;
414 filter.DenyList.NumSeverities = 1;
415 filter.DenyList.pSeverityList = &infoSev;
416 infoQueue->PushStorageFilter(&filter);
417#ifdef QRHI_D3D12_INFOQUEUE1_AVAILABLE
422 if (SUCCEEDED(infoQueue->QueryInterface(__uuidof(ID3D12InfoQueue1),
reinterpret_cast<
void **>(&infoQueue1)))) {
427 if (SUCCEEDED(infoQueue1->RegisterMessageCallback(qd3d12_message_callback,
428 D3D12_MESSAGE_CALLBACK_IGNORE_FILTERS,
430 &infoQueueCallbackCookie)))
434 infoQueue1->SetMuteDebugOutput(
true);
436 infoQueue1->Release();
437 infoQueue1 =
nullptr;
441 infoQueue->Release();
445 if (!importedCommandQueue) {
446 D3D12_COMMAND_QUEUE_DESC queueDesc = {};
447 queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
448 queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
449 hr = dev->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue),
reinterpret_cast<
void **>(&cmdQueue));
451 qWarning(
"Failed to create command queue: %s", qPrintable(QSystemError::windowsComString(hr)));
456 hr = dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence),
reinterpret_cast<
void **>(&fullFence));
458 qWarning(
"Failed to create fence: %s", qPrintable(QSystemError::windowsComString(hr)));
461 fullFenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
462 fullFenceCounter = 0;
464 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
465 hr = dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
466 __uuidof(ID3D12CommandAllocator),
467 reinterpret_cast<
void **>(&cmdAllocators[i]));
469 qWarning(
"Failed to create command allocator: %s", qPrintable(QSystemError::windowsComString(hr)));
474 if (!vma.create(dev, activeAdapter)) {
475 qWarning(
"Failed to initialize graphics memory suballocator");
479 if (!rtvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
"main RTV pool")) {
480 qWarning(
"Could not create RTV pool");
484 if (!dsvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
"main DSV pool")) {
485 qWarning(
"Could not create DSV pool");
489 if (!cbvSrvUavPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
"main CBV-SRV-UAV pool")) {
490 qWarning(
"Could not create CBV-SRV-UAV pool");
494 resourcePool.create(
"main resource pool");
495 pipelinePool.create(
"main pipeline pool");
496 rootSignaturePool.create(
"main root signature pool");
497 releaseQueue.create(&resourcePool, &pipelinePool, &rootSignaturePool);
498 barrierGen.create(&resourcePool);
500 if (!samplerMgr.create(dev)) {
501 qWarning(
"Could not create sampler pool and shader-visible sampler heap");
505 mipmapGen.create(
this);
506 mipmapGen3D.create(
this);
508 const qint32 smallStagingSize = aligned(SMALL_STAGING_AREA_BYTES_PER_FRAME_START, QD3D12StagingArea::ALIGNMENT);
509 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
510 if (!smallStagingAreas[i].create(
this, smallStagingSize, D3D12_HEAP_TYPE_UPLOAD)) {
511 qWarning(
"Could not create host-visible staging area");
514 QString decoratedName = QLatin1String(
"Small staging area buffer/");
515 decoratedName += QString::number(i);
516 smallStagingAreas[i].mem.buffer->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
519 if (!shaderVisibleCbvSrvUavHeap.create(dev,
520 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
521 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE))
523 qWarning(
"Could not create first shader-visible CBV/SRV/UAV heap");
527 if (flags.testFlag(QRhi::EnableTimestamps)) {
528 static bool wantsStablePowerState = qEnvironmentVariableIntValue(
"QT_D3D_STABLE_POWER_STATE");
544 if (wantsStablePowerState)
545 dev->SetStablePowerState(TRUE);
547 hr = cmdQueue->GetTimestampFrequency(×tampTicksPerSecond);
549 qWarning(
"Failed to query timestamp frequency: %s",
550 qPrintable(QSystemError::windowsComString(hr)));
553 if (!timestampQueryHeap.create(dev, QD3D12_FRAMES_IN_FLIGHT * 2, D3D12_QUERY_HEAP_TYPE_TIMESTAMP)) {
554 qWarning(
"Failed to create timestamp query pool");
557 const quint32 readbackBufSize = QD3D12_FRAMES_IN_FLIGHT * 2 *
sizeof(quint64);
558 if (!timestampReadbackArea.create(
this, readbackBufSize, D3D12_HEAP_TYPE_READBACK)) {
559 qWarning(
"Failed to create timestamp readback buffer");
562 timestampReadbackArea.mem.buffer->SetName(L"Timestamp readback buffer");
563 memset(timestampReadbackArea.mem.p, 0, readbackBufSize);
567 D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
568 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3,
sizeof(options3)))) {
569 caps.multiView = options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
571 caps.textureViewFormat = options3.CastingFullyTypedFormatSupported;
574#ifdef QRHI_D3D12_CL5_AVAILABLE
575 D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {};
576 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6,
sizeof(options6)))) {
577 caps.vrs = options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED;
578 caps.vrsMap = options6.VariableShadingRateTier == D3D12_VARIABLE_SHADING_RATE_TIER_2;
579 caps.vrsAdditionalRates = options6.AdditionalShadingRatesSupported;
580 shadingRateImageTileSize = options6.ShadingRateImageTileSize;
585 caps.vrsAdditionalRates =
false;
589 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
590 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
592 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
593 sigDesc.ByteStride =
sizeof(D3D12_DRAW_ARGUMENTS);
594 sigDesc.NumArgumentDescs = 1;
595 sigDesc.pArgumentDescs = &arg;
597 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&drawCommandSignature));
599 qWarning(
"Failed to create draw command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
605 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
606 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
608 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
609 sigDesc.ByteStride =
sizeof(D3D12_DRAW_INDEXED_ARGUMENTS);
610 sigDesc.NumArgumentDescs = 1;
611 sigDesc.pArgumentDescs = &arg;
613 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&drawIndexedCommandSignature));
615 qWarning(
"Failed to create draw indexed command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
621 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
622 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH;
624 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
625 sigDesc.ByteStride =
sizeof(D3D12_DISPATCH_ARGUMENTS);
626 sigDesc.NumArgumentDescs = 1;
627 sigDesc.pArgumentDescs = &arg;
629 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&dispatchCommandSignature));
631 qWarning(
"Failed to create dispatch command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
637 offscreenActive =
false;
639 nativeHandlesStruct.dev = dev;
640 nativeHandlesStruct.minimumFeatureLevel = minimumFeatureLevel;
641 nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
642 nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
643 nativeHandlesStruct.commandQueue = cmdQueue;
648void QRhiD3D12::destroy()
650 if (!deviceLost && fullFence && fullFenceEvent)
653 releaseQueue.releaseAll();
655 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
656 if (offscreenCb[i]) {
657 if (offscreenCb[i]->cmdList)
658 offscreenCb[i]->cmdList->Release();
659 delete offscreenCb[i];
660 offscreenCb[i] =
nullptr;
664 timestampQueryHeap.destroy();
665 timestampReadbackArea.destroy();
667 shaderVisibleCbvSrvUavHeap.destroy();
669 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i)
670 smallStagingAreas[i].destroy();
673 mipmapGen3D.destroy();
674 samplerMgr.destroy();
675 resourcePool.destroy();
676 pipelinePool.destroy();
677 rootSignaturePool.destroy();
680 cbvSrvUavPool.destroy();
682 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
683 if (cmdAllocators[i]) {
684 cmdAllocators[i]->Release();
685 cmdAllocators[i] =
nullptr;
689 if (fullFenceEvent) {
690 CloseHandle(fullFenceEvent);
691 fullFenceEvent =
nullptr;
695 fullFence->Release();
699 if (!importedCommandQueue) {
708#ifdef QRHI_D3D12_INFOQUEUE1_AVAILABLE
710 infoQueue1->UnregisterMessageCallback(infoQueueCallbackCookie);
711 infoQueue1->Release();
712 infoQueue1 =
nullptr;
713 infoQueueCallbackCookie = 0;
717 if (!importedDevice) {
725 dcompDevice->Release();
726 dcompDevice =
nullptr;
730 activeAdapter->Release();
731 activeAdapter =
nullptr;
735 dxgiFactory->Release();
736 dxgiFactory =
nullptr;
739 QDxgiVSyncService::instance()->derefAdapter(adapterLuid);
742 importedDevice =
false;
743 importedCommandQueue =
false;
745 if (drawCommandSignature) {
746 drawCommandSignature->Release();
747 drawCommandSignature =
nullptr;
750 if (drawIndexedCommandSignature) {
751 drawIndexedCommandSignature->Release();
752 drawIndexedCommandSignature =
nullptr;
755 if (dispatchCommandSignature) {
756 dispatchCommandSignature->Release();
757 dispatchCommandSignature =
nullptr;
760 for (ID3D12CommandSignature *sig : std::as_const(drawCommandSignaturesByStride))
762 drawCommandSignaturesByStride.clear();
764 for (ID3D12CommandSignature *sig : std::as_const(drawIndexedCommandSignaturesByStride))
766 drawIndexedCommandSignaturesByStride.clear();
768 destroyPipelineLibrary();
771QRhi::AdapterList QRhiD3D12::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
773 LUID requestedLuid = {};
775 QRhiD3D12NativeHandles *h =
static_cast<QRhiD3D12NativeHandles *>(nativeHandles);
776 const LUID adapterLuid = { h->adapterLuidLow, h->adapterLuidHigh };
777 if (adapterLuid.LowPart || adapterLuid.HighPart)
778 requestedLuid = adapterLuid;
781 IDXGIFactory2 *dxgi =
nullptr;
782 if (FAILED(CreateDXGIFactory2(0, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgi))))
785 QRhi::AdapterList list;
786 IDXGIAdapter1 *adapter;
787 for (
int adapterIndex = 0; dxgi->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
788 DXGI_ADAPTER_DESC1 desc;
789 adapter->GetDesc1(&desc);
791 if (requestedLuid.LowPart || requestedLuid.HighPart) {
792 if (desc.AdapterLuid.LowPart != requestedLuid.LowPart
793 || desc.AdapterLuid.HighPart != requestedLuid.HighPart)
798 QD3D12Adapter *a =
new QD3D12Adapter;
799 a->luid = desc.AdapterLuid;
800 QRhiD3D::fillDriverInfo(&a->adapterInfo, desc);
808QRhiDriverInfo QD3D12Adapter::info()
const
813QList<
int> QRhiD3D12::supportedSampleCounts()
const
815 return { 1, 2, 4, 8 };
818QList<QSize> QRhiD3D12::supportedShadingRates(
int sampleCount)
const
821 switch (sampleCount) {
824 if (caps.vrsAdditionalRates) {
825 sizes.append(QSize(4, 4));
826 sizes.append(QSize(4, 2));
827 sizes.append(QSize(2, 4));
829 sizes.append(QSize(2, 2));
830 sizes.append(QSize(2, 1));
831 sizes.append(QSize(1, 2));
834 if (caps.vrsAdditionalRates)
835 sizes.append(QSize(2, 4));
836 sizes.append(QSize(2, 2));
837 sizes.append(QSize(2, 1));
838 sizes.append(QSize(1, 2));
841 sizes.append(QSize(2, 2));
842 sizes.append(QSize(2, 1));
843 sizes.append(QSize(1, 2));
848 sizes.append(QSize(1, 1));
852QRhiSwapChain *QRhiD3D12::createSwapChain()
854 return new QD3D12SwapChain(
this);
857QRhiBuffer *QRhiD3D12::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
859 return new QD3D12Buffer(
this, type, usage, size);
862int QRhiD3D12::ubufAlignment()
const
864 return D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
867bool QRhiD3D12::isYUpInFramebuffer()
const
872bool QRhiD3D12::isYUpInNDC()
const
877bool QRhiD3D12::isClipDepthZeroToOne()
const
882QMatrix4x4 QRhiD3D12::clipSpaceCorrMatrix()
const
887 static constexpr QMatrix4x4 m(1.0f, 0.0f, 0.0f, 0.0f,
888 0.0f, 1.0f, 0.0f, 0.0f,
889 0.0f, 0.0f, 0.5f, 0.5f,
890 0.0f, 0.0f, 0.0f, 1.0f);
894bool QRhiD3D12::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags)
const
898 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ASTC_12x12)
904bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature)
const
907 case QRhi::MultisampleTexture:
909 case QRhi::MultisampleRenderBuffer:
911 case QRhi::DebugMarkers:
912#ifdef QRHI_D3D12_HAS_OLD_PIX
917 case QRhi::Timestamps:
919 case QRhi::Instancing:
921 case QRhi::CustomInstanceStepRate:
923 case QRhi::PrimitiveRestart:
925 case QRhi::NonDynamicUniformBuffers:
927 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
929 case QRhi::NPOTTextureRepeat:
931 case QRhi::RedOrAlpha8IsRed:
933 case QRhi::ElementIndexUint:
937 case QRhi::FragmentStoresAndAtomics:
939 case QRhi::WideLines:
941 case QRhi::VertexShaderPointSize:
943 case QRhi::BaseVertex:
945 case QRhi::BaseInstance:
947 case QRhi::TriangleFanTopology:
949 case QRhi::ReadBackNonUniformBuffer:
951 case QRhi::ReadBackNonBaseMipLevel:
953 case QRhi::TexelFetch:
955 case QRhi::RenderToNonBaseMipLevel:
957 case QRhi::IntAttributes:
959 case QRhi::ScreenSpaceDerivatives:
961 case QRhi::ReadBackAnyTextureFormat:
963 case QRhi::PipelineCacheDataLoadSave:
964#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
969 case QRhi::ImageDataStride:
971 case QRhi::RenderBufferImport:
973 case QRhi::ThreeDimensionalTextures:
975 case QRhi::RenderTo3DTextureSlice:
977 case QRhi::TextureArrays:
979 case QRhi::Tessellation:
981 case QRhi::GeometryShader:
983 case QRhi::TextureArrayRange:
985 case QRhi::NonFillPolygonMode:
987 case QRhi::OneDimensionalTextures:
989 case QRhi::OneDimensionalTextureMipmaps:
991 case QRhi::HalfAttributes:
993 case QRhi::RenderToOneDimensionalTexture:
995 case QRhi::ThreeDimensionalTextureMipmaps:
997 case QRhi::MultiView:
998 return caps.multiView;
999 case QRhi::TextureViewFormat:
1000 return caps.textureViewFormat;
1001 case QRhi::ResolveDepthStencil:
1005 case QRhi::VariableRateShading:
1007 case QRhi::VariableRateShadingMap:
1008 case QRhi::VariableRateShadingMapWithTexture:
1010 case QRhi::PerRenderTargetBlending:
1011 case QRhi::SampleVariables:
1013 case QRhi::InstanceIndexIncludesBaseInstance:
1015 case QRhi::DepthClamp:
1017 case QRhi::DrawIndirect:
1018 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
1019 case QRhi::DrawIndirectMulti:
1020 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
1021 case QRhi::ShaderDrawParameters:
1023 case QRhi::DispatchIndirect:
1024 return dispatchCommandSignature !=
nullptr;
1025 case QRhi::PushConstants:
1027 case QRhi::DrawIndirectCount:
1029 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
1030 case QRhi::BufferToBufferCopy:
1032 case QRhi::StaticBuffersOnGpuTimeline:
1038int QRhiD3D12::resourceLimit(QRhi::ResourceLimit limit)
const
1041 case QRhi::TextureSizeMin:
1043 case QRhi::TextureSizeMax:
1045 case QRhi::MaxColorAttachments:
1047 case QRhi::FramesInFlight:
1048 return QD3D12_FRAMES_IN_FLIGHT;
1049 case QRhi::MaxAsyncReadbackFrames:
1050 return QD3D12_FRAMES_IN_FLIGHT;
1051 case QRhi::MaxThreadGroupsPerDimension:
1053 case QRhi::MaxThreadsPerThreadGroup:
1055 case QRhi::MaxThreadGroupX:
1057 case QRhi::MaxThreadGroupY:
1059 case QRhi::MaxThreadGroupZ:
1061 case QRhi::TextureArraySizeMax:
1063 case QRhi::MaxUniformBufferRange:
1065 case QRhi::MaxVertexInputs:
1067 case QRhi::MaxVertexOutputs:
1069 case QRhi::MaxPushConstantsSize:
1071 case QRhi::MaxVertexStorageBuffers:
1072 case QRhi::MaxFragmentStorageBuffers:
1074 case QRhi::ShadingRateImageTileSize:
1075 return shadingRateImageTileSize;
1080const QRhiNativeHandles *QRhiD3D12::nativeHandles()
1082 return &nativeHandlesStruct;
1085QRhiDriverInfo QRhiD3D12::driverInfo()
const
1087 return driverInfoStruct;
1090QRhiStats QRhiD3D12::statistics()
1093 result.totalPipelineCreationTime = totalPipelineCreationTime();
1095 D3D12MA::Budget budgets[2];
1096 vma.getBudget(&budgets[0], &budgets[1]);
1097 for (
int i = 0; i < 2; ++i) {
1098 const D3D12MA::Statistics &stats(budgets[i].Stats);
1099 result.blockCount += stats.BlockCount;
1100 result.allocCount += stats.AllocationCount;
1101 result.usedBytes += stats.AllocationBytes;
1102 result.unusedBytes += stats.BlockBytes - stats.AllocationBytes;
1103 result.totalUsageBytes += budgets[i].UsageBytes;
1109bool QRhiD3D12::makeThreadLocalNativeContextCurrent()
1115void QRhiD3D12::setQueueSubmitParams(QRhiNativeHandles *)
1120void QRhiD3D12::releaseCachedResources()
1122 shaderBytecodeCache.clear();
1131static inline void addToKey(QCryptographicHash *h,
const void *p, size_t size)
1133 h->addData(QByteArrayView(
static_cast<
const char *>(p), qsizetype(size)));
1137static inline void addToKey(QCryptographicHash *h,
const T &v)
1139 addToKey(h, &v,
sizeof(T));
1142static inline void addToKey(QCryptographicHash *h,
const QByteArray &b)
1144 const quint32 size = quint32(b.size());
1149static inline void addToKey(QCryptographicHash *h,
const QVector<quint32> &v)
1151 const quint32 count = quint32(v.count());
1153 addToKey(h, v.constData(), v.count() *
sizeof(quint32));
1156bool QRhiD3D12::createPipelineLibrary(
const QByteArray &blob)
1158#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1159 destroyPipelineLibrary();
1161 pipelineLibraryBlob = blob;
1162 HRESULT hr = dev->CreatePipelineLibrary(pipelineLibraryBlob.isEmpty() ?
nullptr
1163 : pipelineLibraryBlob.constData(),
1164 SIZE_T(pipelineLibraryBlob.size()),
1165 __uuidof(ID3D12PipelineLibrary1),
1166 reinterpret_cast<
void **>(&pipelineLibrary));
1172 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline library: %s",
1173 qPrintable(QSystemError::windowsComString(hr)));
1174 pipelineLibrary =
nullptr;
1175 pipelineLibraryBlob.clear();
1185bool QRhiD3D12::ensurePipelineLibrary()
1187#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1188 if (pipelineLibrary)
1190 if (!rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
1192 return createPipelineLibrary(QByteArray());
1198void QRhiD3D12::destroyPipelineLibrary()
1200#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1201 if (pipelineLibrary) {
1202 pipelineLibrary->Release();
1203 pipelineLibrary =
nullptr;
1205 pipelineLibraryBlob.clear();
1206 pipelineLibraryNames.clear();
1210ID3D12PipelineState *QRhiD3D12::loadOrCreatePipelineState(
const D3D12_PIPELINE_STATE_STREAM_DESC *streamDesc,
1211 const QByteArray &cacheKey,
1214 ID3D12PipelineState *pso =
nullptr;
1216#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1217 QVarLengthArray<
wchar_t, 64> name;
1218 if (ensurePipelineLibrary() && !cacheKey.isEmpty()) {
1219 name.resize(cacheKey.size() + 1);
1220 for (qsizetype i = 0; i < cacheKey.size(); ++i)
1221 name[i] =
wchar_t(cacheKey.at(i));
1222 name[cacheKey.size()] = 0;
1223 HRESULT hr = pipelineLibrary->LoadPipeline(name.constData(),
1225 __uuidof(ID3D12PipelineState),
1226 reinterpret_cast<
void **>(&pso));
1232 HRESULT hr = dev->CreatePipelineState(streamDesc,
1233 __uuidof(ID3D12PipelineState),
1234 reinterpret_cast<
void **>(&pso));
1236 qWarning(
"Failed to create %s pipeline state: %s",
1237 what, qPrintable(QSystemError::windowsComString(hr)));
1241#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1242 if (pipelineLibrary && !name.isEmpty() && !pipelineLibraryNames.contains(cacheKey)) {
1243 if (SUCCEEDED(pipelineLibrary->StorePipeline(name.constData(), pso)))
1244 pipelineLibraryNames.insert(cacheKey);
1251struct QD3D12PipelineCacheDataHeader
1259 quint64 adapterLuid;
1262QByteArray QRhiD3D12::pipelineCacheData()
1264 static_assert(
sizeof(QD3D12PipelineCacheDataHeader) == 32);
1267#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1268 if (!pipelineLibrary || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
1271 const SIZE_T dataSize = pipelineLibrary->GetSerializedSize();
1275 const size_t headerSize =
sizeof(QD3D12PipelineCacheDataHeader);
1276 data.resize(qsizetype(headerSize + dataSize));
1277 HRESULT hr = pipelineLibrary->Serialize(data.data() + headerSize, dataSize);
1279 qCDebug(QRHI_LOG_INFO,
"Failed to serialize pipeline library: %s",
1280 qPrintable(QSystemError::windowsComString(hr)));
1281 return QByteArray();
1284 QD3D12PipelineCacheDataHeader header = {};
1285 header.rhiId = pipelineCacheRhiId();
1286 header.arch = quint32(
sizeof(
void *));
1287 header.dataSize = quint32(dataSize);
1288 header.vendorId = quint32(driverInfoStruct.vendorId);
1289 header.deviceId = quint32(driverInfoStruct.deviceId);
1290 header.adapterLuid = (quint64(quint32(adapterLuid.HighPart)) << 32) | quint64(adapterLuid.LowPart);
1291 memcpy(data.data(), &header, headerSize);
1296void QRhiD3D12::setPipelineCacheData(
const QByteArray &data)
1298#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1302 const size_t headerSize =
sizeof(QD3D12PipelineCacheDataHeader);
1303 if (data.size() < qsizetype(headerSize)) {
1304 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
1307 QD3D12PipelineCacheDataHeader header;
1308 memcpy(&header, data.constData(), headerSize);
1310 const quint32 rhiId = pipelineCacheRhiId();
1311 if (header.rhiId != rhiId) {
1312 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
1313 rhiId, header.rhiId);
1316 const quint32 arch = quint32(
sizeof(
void *));
1317 if (header.arch != arch) {
1318 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
1322 if (header.vendorId != quint32(driverInfoStruct.vendorId)) {
1323 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorId does not match (%u, %u)",
1324 quint32(driverInfoStruct.vendorId), header.vendorId);
1327 if (header.deviceId != quint32(driverInfoStruct.deviceId)) {
1328 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceId does not match (%u, %u)",
1329 quint32(driverInfoStruct.deviceId), header.deviceId);
1332 const quint64 luid = (quint64(quint32(adapterLuid.HighPart)) << 32) | quint64(adapterLuid.LowPart);
1333 if (header.adapterLuid != luid) {
1334 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: adapter LUID does not match");
1337 if (quint64(data.size()) < quint64(headerSize) + header.dataSize) {
1338 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
1345 if (createPipelineLibrary(data.mid(qsizetype(headerSize)))) {
1346 qCDebug(QRHI_LOG_INFO,
"Created pipeline library with initial data of %u bytes",
1354bool QRhiD3D12::isDeviceLost()
const
1359QRhiRenderBuffer *QRhiD3D12::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
1360 int sampleCount, QRhiRenderBuffer::Flags flags,
1361 QRhiTexture::Format backingFormatHint)
1363 return new QD3D12RenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
1366QRhiTexture *QRhiD3D12::createTexture(QRhiTexture::Format format,
1367 const QSize &pixelSize,
int depth,
int arraySize,
1368 int sampleCount, QRhiTexture::Flags flags)
1370 return new QD3D12Texture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
1373QRhiSampler *QRhiD3D12::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
1374 QRhiSampler::Filter mipmapMode,
1375 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
1377 return new QD3D12Sampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
1380QRhiTextureRenderTarget *QRhiD3D12::createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
1381 QRhiTextureRenderTarget::Flags flags)
1383 return new QD3D12TextureRenderTarget(
this, desc, flags);
1386QRhiShadingRateMap *QRhiD3D12::createShadingRateMap()
1388 return new QD3D12ShadingRateMap(
this);
1391QRhiGraphicsPipeline *QRhiD3D12::createGraphicsPipeline()
1393 return new QD3D12GraphicsPipeline(
this);
1396QRhiComputePipeline *QRhiD3D12::createComputePipeline()
1398 return new QD3D12ComputePipeline(
this);
1401QRhiShaderResourceBindings *QRhiD3D12::createShaderResourceBindings()
1403 return new QD3D12ShaderResourceBindings(
this);
1406void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
1408 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1409 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1410 QD3D12GraphicsPipeline *psD = QRHI_RES(QD3D12GraphicsPipeline, ps);
1411 const bool pipelineChanged = cbD->currentGraphicsPipeline != psD || cbD->currentPipelineGeneration != psD->generation;
1413 if (pipelineChanged) {
1414 cbD->currentGraphicsPipeline = psD;
1415 cbD->currentComputePipeline =
nullptr;
1416 cbD->currentPipelineGeneration = psD->generation;
1418 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
1419 Q_ASSERT(pipeline->type == QD3D12Pipeline::Graphics);
1420 cbD->cmdList->SetPipelineState(pipeline->pso);
1421 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
1422 cbD->cmdList->SetGraphicsRootSignature(rs->rootSig);
1425 cbD->cmdList->IASetPrimitiveTopology(psD->topology);
1427 if (psD->viewInstanceMask)
1428 cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
1430 if (cbD->hasCustomScissorSet && !psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor))
1431 setDefaultScissor(cbD);
1433 if (psD->m_stencilTest) {
1434 const quint32 ref = psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesStencilRef)
1435 ? cbD->currentStencilRef : 0;
1436 if (cbD->appliedStencilRef != ref) {
1437 cbD->cmdList->OMSetStencilRef(ref);
1438 cbD->appliedStencilRef = ref;
1444void QD3D12ShaderResourceBindings::cacheUniformBuffer(QD3D12Stage s,
1445 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
1452 bindingCache.cbufs[s].append({ QRHI_RES(QD3D12Buffer, d.buf), d.offset, binding });
1455void QD3D12ShaderResourceBindings::cacheTextures(QD3D12Stage s,
1456 const QRhiShaderResourceBinding::TextureAndSampler *d,
1460 for (
int i = 0; i < count; ++i) {
1461 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d[i].tex);
1462 bindingCache.srvs[s].append(texD->srv.cpuHandle);
1466void QD3D12ShaderResourceBindings::cacheSamplers(QD3D12Stage s,
1467 const QRhiShaderResourceBinding::TextureAndSampler *d,
1472 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, d[0].sampler);
1473 bindingCache.samplers[s].append(samplerD->lookupOrCreateShaderVisibleDescriptor().gpuHandle);
1481 QRHI_RES_RHI(QRhiD3D12);
1482 QVarLengthArray<Q_D3D12_SAMPLER_DESC, 8> descs;
1483 for (
int i = 0; i < count; ++i)
1484 descs.append({ QRHI_RES(QD3D12Sampler, d[i].sampler)->desc });
1485 bindingCache.samplers[s].append(rhiD->samplerMgr.getShaderVisibleDescriptors(descs).gpuHandle);
1488void QD3D12ShaderResourceBindings::cacheStorageBuffer(QD3D12Stage s,
1489 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
1490 QD3D12ShaderResourceVisitor::StorageOp,
1493 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1495 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1496 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1497 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
1498 uavDesc.Buffer.FirstElement = d.offset / 4;
1499 uavDesc.Buffer.NumElements = aligned(bufD->m_size - d.offset, 4u) / 4;
1500 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
1501 bindingCache.uavs[s].append({ bufD->handles[0], uavDesc });
1504void QD3D12ShaderResourceBindings::cacheStorageImage(QD3D12Stage s,
1505 const QRhiShaderResourceBinding::Data::StorageImageData &d,
1506 QD3D12ShaderResourceVisitor::StorageOp,
1509 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1510 const bool isCube = texD->m_flags.testFlag(QRhiTexture::CubeMap);
1511 const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
1512 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1513 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1514 uavDesc.Format = texD->rtFormat;
1516 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1517 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1518 uavDesc.Texture2DArray.FirstArraySlice = 0;
1519 uavDesc.Texture2DArray.ArraySize = 6;
1520 }
else if (isArray) {
1521 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1522 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1523 uavDesc.Texture2DArray.FirstArraySlice = 0;
1524 uavDesc.Texture2DArray.ArraySize = UINT(qMax(0, texD->m_arraySize));
1526 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1527 uavDesc.Texture3D.MipSlice = UINT(d.level);
1528 uavDesc.Texture3D.WSize = UINT(-1);
1530 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
1531 uavDesc.Texture2D.MipSlice = UINT(d.level);
1533 bindingCache.uavs[s].append({ texD->handle, uavDesc });
1536void QD3D12ShaderResourceBindings::rebuildBindingCache(
const QD3D12ShaderStageData *stageData,
1539 bindingCache.reset();
1541 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
1543 using namespace std::placeholders;
1544 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::cacheUniformBuffer,
this, _1, _2, _3, _4);
1545 visitor.textures = std::bind(&QD3D12ShaderResourceBindings::cacheTextures,
this, _1, _2, _3, _4);
1546 visitor.samplers = std::bind(&QD3D12ShaderResourceBindings::cacheSamplers,
this, _1, _2, _3, _4);
1547 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::cacheStorageBuffer,
this, _1, _2, _3, _4);
1548 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::cacheStorageImage,
this, _1, _2, _3, _4);
1553 for (
int s = 0; s < 6; ++s) {
1554 bindingCache.srvUavCount += bindingCache.srvs[s].count();
1555 bindingCache.srvUavCount += bindingCache.uavs[s].count();
1558 bindingCacheValid =
true;
1559 bindingCacheGeneration = generation;
1562void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
1563 int dynamicOffsetCount,
1564 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1566 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1567 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
1568 QD3D12GraphicsPipeline *gfxPsD = QRHI_RES(QD3D12GraphicsPipeline, cbD->currentGraphicsPipeline);
1569 QD3D12ComputePipeline *compPsD = QRHI_RES(QD3D12ComputePipeline, cbD->currentComputePipeline);
1573 srb = gfxPsD->m_shaderResourceBindings;
1575 srb = compPsD->m_shaderResourceBindings;
1578 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, srb);
1580 bool pipelineChanged =
false;
1582 pipelineChanged = srbD->lastUsedGraphicsPipeline != gfxPsD
1583 || srbD->lastUsedPipelineGeneration != gfxPsD->generation;
1584 srbD->lastUsedGraphicsPipeline = gfxPsD;
1585 srbD->lastUsedComputePipeline =
nullptr;
1586 srbD->lastUsedPipelineGeneration = gfxPsD->generation;
1588 pipelineChanged = srbD->lastUsedComputePipeline != compPsD
1589 || srbD->lastUsedPipelineGeneration != compPsD->generation;
1590 srbD->lastUsedGraphicsPipeline =
nullptr;
1591 srbD->lastUsedComputePipeline = compPsD;
1592 srbD->lastUsedPipelineGeneration = compPsD->generation;
1595 bool srbUpdate =
false;
1597 for (
int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
1598 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings[i]);
1599 QD3D12ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
1600 switch (b->type()) {
1601 case QRhiShaderResourceBinding::UniformBuffer:
1603 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->ubuf().buf);
1604 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
1605 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1606 sanityCheckResourceOwnership(bufD);
1607 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1608 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
1610 bd.ubuf.id = bufD->m_id;
1611 bd.ubuf.generation = bufD->generation;
1615 case QRhiShaderResourceBinding::SampledTexture:
1616 case QRhiShaderResourceBinding::Texture:
1617 case QRhiShaderResourceBinding::Sampler:
1619 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->stex();
1620 if (bd.stex.d.size() != data->count()) {
1621 bd.stex.d.resize(data->count());
1624 for (
int elem = 0; elem < data->count(); ++elem) {
1625 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, data->texSamplers[elem].tex);
1626 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, data->texSamplers[elem].sampler);
1630 Q_ASSERT(texD || samplerD);
1631 sanityCheckResourceOwnership(texD);
1632 sanityCheckResourceOwnership(samplerD);
1633 const quint64 texId = texD ? texD->m_id : 0;
1634 const uint texGen = texD ? texD->generation : 0;
1635 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
1636 const uint samplerGen = samplerD ? samplerD->generation : 0;
1637 if (texId != bd.stex.d[elem].texId || texGen != bd.stex.d[elem].texGeneration
1638 || samplerId != bd.stex.d[elem].samplerId
1639 || samplerGen != bd.stex.d[elem].samplerGeneration)
1642 bd.stex.d[elem].texId = texId;
1643 bd.stex.d[elem].texGeneration = texGen;
1644 bd.stex.d[elem].samplerId = samplerId;
1645 bd.stex.d[elem].samplerGeneration = samplerGen;
1649 if (b->stage == QRhiShaderResourceBinding::FragmentStage) {
1650 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1651 }
else if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
1652 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1654 state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1656 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATES(state));
1661 case QRhiShaderResourceBinding::ImageLoad:
1662 case QRhiShaderResourceBinding::ImageStore:
1663 case QRhiShaderResourceBinding::ImageLoadStore:
1665 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, b->simage().tex);
1666 sanityCheckResourceOwnership(texD);
1667 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
1669 bd.simage.id = texD->m_id;
1670 bd.simage.generation = texD->generation;
1672 if (QD3D12Resource *res = resourcePool.lookupRef(texD->handle)) {
1673 if (res->uavUsage) {
1674 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1676 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1678 if (b->type() == QRhiShaderResourceBinding::ImageStore
1679 || b->type() == QRhiShaderResourceBinding::ImageLoadStore)
1682 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1687 if (b->type() == QRhiShaderResourceBinding::ImageLoad || b->type() == QRhiShaderResourceBinding::ImageLoadStore)
1688 res->uavUsage |= QD3D12Resource::UavUsageRead;
1689 if (b->type() == QRhiShaderResourceBinding::ImageStore || b->type() == QRhiShaderResourceBinding::ImageLoadStore)
1690 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1691 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1695 case QRhiShaderResourceBinding::BufferLoad:
1696 case QRhiShaderResourceBinding::BufferStore:
1697 case QRhiShaderResourceBinding::BufferLoadStore:
1699 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->sbuf().buf);
1700 sanityCheckResourceOwnership(bufD);
1701 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
1702 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1703 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
1705 bd.sbuf.id = bufD->m_id;
1706 bd.sbuf.generation = bufD->generation;
1708 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
1709 if (res->uavUsage) {
1710 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1712 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1714 if (b->type() == QRhiShaderResourceBinding::BufferStore
1715 || b->type() == QRhiShaderResourceBinding::BufferLoadStore)
1718 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1723 if (b->type() == QRhiShaderResourceBinding::BufferLoad || b->type() == QRhiShaderResourceBinding::BufferLoadStore)
1724 res->uavUsage |= QD3D12Resource::UavUsageRead;
1725 if (b->type() == QRhiShaderResourceBinding::BufferStore || b->type() == QRhiShaderResourceBinding::BufferLoadStore)
1726 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1727 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1734 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1735 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1743 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1749 if (pipelineChanged || srbUpdate || !srbD->bindingCacheValid
1750 || srbD->bindingCacheGeneration != srbD->generation)
1752 const QD3D12ShaderStageData *stageData = gfxPsD ? gfxPsD->stageData.data() : &compPsD->stageData;
1753 srbD->rebuildBindingCache(stageData, gfxPsD ? 5 : 1);
1756 if (pipelineChanged || srbChanged || srbRebuilt || srbUpdate || srbD->hasDynamicOffset) {
1761 const QD3D12ShaderResourceBindings::BindingCache &cache(srbD->bindingCache);
1763 bool gotNewHeap =
false;
1764 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
1765 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1773 qCDebug(QRHI_LOG_INFO,
"Created new shader-visible CBV/SRV/UAV descriptor heap,"
1774 " per-frame slice size is now %u,"
1775 " if this happens frequently then that's not great.",
1776 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[0].capacity);
1777 bindShaderVisibleHeaps(cbD);
1780 int rootParamIndex = 0;
1781 for (
int s = 0; s < 6; ++s) {
1782 for (
const QD3D12ShaderResourceBindings::BindingCache::CBuf &cbuf : cache.cbufs[s]) {
1783 if (QD3D12Resource *res = resourcePool.lookupRef(cbuf.buf->handles[currentFrameSlot])) {
1784 quint32 offset = cbuf.offset;
1785 if (srbD->hasDynamicOffset) {
1786 for (
int i = 0; i < dynamicOffsetCount; ++i) {
1787 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1788 if (dynOfs.first == cbuf.binding) {
1789 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1790 offset += dynOfs.second;
1794 const D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = res->resource->GetGPUVirtualAddress() + offset;
1796 cbD->cmdList->SetGraphicsRootConstantBufferView(rootParamIndex, gpuAddr);
1798 cbD->cmdList->SetComputeRootConstantBufferView(rootParamIndex, gpuAddr);
1800 rootParamIndex += 1;
1803 for (
int s = 0; s < 6; ++s) {
1804 if (!cache.srvs[s].isEmpty()) {
1805 QD3D12DescriptorHeap &gpuSrvHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1806 const UINT count = UINT(cache.srvs[s].count());
1807 const QD3D12Descriptor startDesc = gpuSrvHeap.get(count);
1810 dev->CopyDescriptors(1, &startDesc.cpuHandle, &count,
1811 count, cache.srvs[s].constData(),
nullptr,
1812 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1815 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1817 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1819 rootParamIndex += 1;
1822 for (
int s = 0; s < 6; ++s) {
1825 for (D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor : cache.samplers[s]) {
1827 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerDescriptor);
1829 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, samplerDescriptor);
1831 rootParamIndex += 1;
1834 for (
int s = 0; s < 6; ++s) {
1835 if (!cache.uavs[s].isEmpty()) {
1836 QD3D12DescriptorHeap &gpuUavHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1837 const int count = cache.uavs[s].count();
1838 const QD3D12Descriptor startDesc = gpuUavHeap.get(count);
1839 for (
int i = 0; i < count; ++i) {
1840 const QD3D12ShaderResourceBindings::BindingCache::Uav &uav(cache.uavs[s][i]);
1841 if (QD3D12Resource *res = resourcePool.lookupRef(uav.handle)) {
1842 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uav.desc,
1843 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1845 dev->CreateUnorderedAccessView(
nullptr,
nullptr,
nullptr,
1846 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1851 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1853 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1855 rootParamIndex += 1;
1860 cbD->currentGraphicsSrb = srb;
1861 cbD->currentComputeSrb =
nullptr;
1863 cbD->currentGraphicsSrb =
nullptr;
1864 cbD->currentComputeSrb = srb;
1866 cbD->currentSrbGeneration = srbD->generation;
1870void QRhiD3D12::setVertexInput(QRhiCommandBuffer *cb,
1871 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1872 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1874 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1875 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1877 bool needsBindVBuf =
false;
1878 for (
int i = 0; i < bindingCount; ++i) {
1879 const int inputSlot = startBinding + i;
1880 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1881 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1882 const bool isDynamic = bufD->m_type == QRhiBuffer::Dynamic;
1884 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1886 if (cbD->currentVertexBuffers[inputSlot] != bufD->handles[isDynamic ? currentFrameSlot : 0]
1887 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1889 needsBindVBuf =
true;
1890 cbD->currentVertexBuffers[inputSlot] = bufD->handles[isDynamic ? currentFrameSlot : 0];
1891 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1895 if (needsBindVBuf) {
1896 QVarLengthArray<D3D12_VERTEX_BUFFER_VIEW, 4> vbv;
1897 vbv.reserve(bindingCount);
1899 QD3D12GraphicsPipeline *psD = cbD->currentGraphicsPipeline;
1900 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1901 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1903 for (
int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1904 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1905 const QD3D12ObjectHandle handle = bufD->handles[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
1906 const quint32 offset = bindings[i].second;
1907 const quint32 stride = inputLayout.bindingAt(i)->stride();
1909 if (bufD->m_type != QRhiBuffer::Dynamic) {
1910 barrierGen.addTransitionBarrier(handle, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
1911 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1914 if (QD3D12Resource *res = resourcePool.lookupRef(handle)) {
1916 res->resource->GetGPUVirtualAddress() + offset,
1917 UINT(res->desc.Width - offset),
1923 cbD->cmdList->IASetVertexBuffers(UINT(startBinding), vbv.count(), vbv.constData());
1927 QD3D12Buffer *ibufD = QRHI_RES(QD3D12Buffer, indexBuf);
1928 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1929 const bool isDynamic = ibufD->m_type == QRhiBuffer::Dynamic;
1931 ibufD->executeHostWritesForFrameSlot(currentFrameSlot);
1933 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1934 : DXGI_FORMAT_R32_UINT;
1935 if (cbD->currentIndexBuffer != ibufD->handles[isDynamic ? currentFrameSlot : 0]
1936 || cbD->currentIndexOffset != indexOffset
1937 || cbD->currentIndexFormat != dxgiFormat)
1939 cbD->currentIndexBuffer = ibufD->handles[isDynamic ? currentFrameSlot : 0];
1940 cbD->currentIndexOffset = indexOffset;
1941 cbD->currentIndexFormat = dxgiFormat;
1943 if (ibufD->m_type != QRhiBuffer::Dynamic) {
1944 barrierGen.addTransitionBarrier(cbD->currentIndexBuffer, D3D12_RESOURCE_STATE_INDEX_BUFFER);
1945 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1948 if (QD3D12Resource *res = resourcePool.lookupRef(cbD->currentIndexBuffer)) {
1949 const D3D12_INDEX_BUFFER_VIEW ibv = {
1950 res->resource->GetGPUVirtualAddress() + indexOffset,
1951 UINT(res->desc.Width - indexOffset),
1954 cbD->cmdList->IASetIndexBuffer(&ibv);
1960void QRhiD3D12::setDefaultScissor(QD3D12CommandBuffer *cbD)
1962 cbD->hasCustomScissorSet =
false;
1964 const QSize outputSize = cbD->currentTarget->pixelSize();
1965 std::array<
float, 4> vp = cbD->currentViewport.viewport();
1966 float x = 0, y = 0, w = 0, h = 0;
1968 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
1971 w = outputSize.width();
1972 h = outputSize.height();
1975 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, vp, &x, &y, &w, &h);
1984 cbD->cmdList->RSSetScissorRects(1, &r);
1987void QRhiD3D12::setViewport(QRhiCommandBuffer *cb,
const QRhiViewport &viewport)
1989 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1990 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1991 Q_ASSERT(cbD->currentTarget);
1992 const QSize outputSize = cbD->currentTarget->pixelSize();
1996 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
2004 v.MinDepth = viewport.minDepth();
2005 v.MaxDepth = viewport.maxDepth();
2006 cbD->cmdList->RSSetViewports(1, &v);
2008 cbD->currentViewport = viewport;
2009 if (cbD->currentGraphicsPipeline
2010 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
2012 setDefaultScissor(cbD);
2016void QRhiD3D12::setScissor(QRhiCommandBuffer *cb,
const QRhiScissor &scissor)
2018 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2019 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2020 Q_ASSERT(cbD->currentTarget);
2021 const QSize outputSize = cbD->currentTarget->pixelSize();
2025 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
2034 cbD->cmdList->RSSetScissorRects(1, &r);
2036 cbD->hasCustomScissorSet =
true;
2039void QRhiD3D12::setBlendConstants(QRhiCommandBuffer *cb,
const QColor &c)
2041 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2042 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2043 float v[4] = { c.redF(), c.greenF(), c.blueF(), c.alphaF() };
2044 cbD->cmdList->OMSetBlendFactor(v);
2047void QRhiD3D12::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
2049 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2050 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2051 cbD->cmdList->OMSetStencilRef(refValue);
2052 cbD->currentStencilRef = refValue;
2053 cbD->appliedStencilRef = refValue;
2056void QRhiD3D12::setPushConstants(QRhiCommandBuffer *cb, quint32 offset, quint32 size,
const void *data)
2058 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2059 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
2061 const bool compute = cbD->recordingPass == QD3D12CommandBuffer::ComputePass;
2062 const int index = compute ? (cbD->currentComputePipeline ? cbD->currentComputePipeline->pushConstantRootParamIndex : -1)
2063 : (cbD->currentGraphicsPipeline ? cbD->currentGraphicsPipeline->pushConstantRootParamIndex : -1);
2065 qWarning(
"No pipeline with a push constant block is active; setPushConstants ignored");
2070 cbD->cmdList->SetComputeRoot32BitConstants(UINT(index), size / 4, data, offset / 4);
2072 cbD->cmdList->SetGraphicsRoot32BitConstants(UINT(index), size / 4, data, offset / 4);
2075static inline D3D12_SHADING_RATE toD3DShadingRate(
const QSize &coarsePixelSize)
2077 if (coarsePixelSize == QSize(1, 2))
2078 return D3D12_SHADING_RATE_1X2;
2079 if (coarsePixelSize == QSize(2, 1))
2080 return D3D12_SHADING_RATE_2X1;
2081 if (coarsePixelSize == QSize(2, 2))
2082 return D3D12_SHADING_RATE_2X2;
2083 if (coarsePixelSize == QSize(2, 4))
2084 return D3D12_SHADING_RATE_2X4;
2085 if (coarsePixelSize == QSize(4, 2))
2086 return D3D12_SHADING_RATE_4X2;
2087 if (coarsePixelSize == QSize(4, 4))
2088 return D3D12_SHADING_RATE_4X4;
2089 return D3D12_SHADING_RATE_1X1;
2092void QRhiD3D12::setShadingRate(QRhiCommandBuffer *cb,
const QSize &coarsePixelSize)
2094 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2095 cbD->hasShadingRateSet =
false;
2097#ifdef QRHI_D3D12_CL5_AVAILABLE
2101 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2102 const D3D12_SHADING_RATE_COMBINER combiners[] = { D3D12_SHADING_RATE_COMBINER_MAX, D3D12_SHADING_RATE_COMBINER_MAX };
2103 cbD->cmdList->RSSetShadingRate(toD3DShadingRate(coarsePixelSize), combiners);
2104 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
2105 cbD->hasShadingRateSet =
true;
2108 Q_UNUSED(coarsePixelSize);
2109 qWarning(
"Attempted to set ShadingRate without building Qt against a sufficiently new Windows SDK and d3d12.h. This cannot work.");
2113void QRhiD3D12::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
2114 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
2116 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2117 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2118 cbD->cmdList->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
2121void QRhiD3D12::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
2122 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
2124 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2125 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2126 cbD->cmdList->DrawIndexedInstanced(indexCount, instanceCount,
2127 firstIndex, vertexOffset,
2131void QRhiD3D12::drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
2132 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
2134 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2135 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2137 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2138 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2139 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
2141 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2143 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2144 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2146 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
2149 ID3D12Resource *indirectBufferRes = indirectRes->resource;
2151 const bool canUseMulti = (stride ==
sizeof(QRhiIndirectDrawCommand) && drawCommandSignature);
2153 if (canUseMulti && drawCount > 1) {
2154 cbD->cmdList->ExecuteIndirect(drawCommandSignature, drawCount,
2155 indirectBufferRes, indirectBufferOffset,
2158 UINT offset = indirectBufferOffset;
2159 for (quint32 i = 0; i < drawCount; ++i) {
2160 cbD->cmdList->ExecuteIndirect(drawCommandSignature, 1,
2161 indirectBufferRes, offset,
2168void QRhiD3D12::drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
2169 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
2171 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2172 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2174 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2175 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2176 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
2178 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2180 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2181 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2183 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
2186 ID3D12Resource *indirectBufferRes = indirectRes->resource;
2188 const bool canUseMulti = (stride ==
sizeof(QRhiIndexedIndirectDrawCommand) && drawIndexedCommandSignature);
2190 if (canUseMulti && drawCount > 1) {
2191 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, drawCount,
2192 indirectBufferRes, indirectBufferOffset,
2195 UINT offset = indirectBufferOffset;
2196 for (quint32 i = 0; i < drawCount; ++i) {
2197 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, 1,
2198 indirectBufferRes, offset,
2205void QRhiD3D12::debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name)
2210 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2211#ifdef QRHI_D3D12_HAS_OLD_PIX
2212 PIXBeginEvent(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(name).utf16()));
2219void QRhiD3D12::debugMarkEnd(QRhiCommandBuffer *cb)
2224 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2225#ifdef QRHI_D3D12_HAS_OLD_PIX
2226 PIXEndEvent(cbD->cmdList);
2232void QRhiD3D12::debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg)
2237 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2238#ifdef QRHI_D3D12_HAS_OLD_PIX
2239 PIXSetMarker(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(msg).utf16()));
2246const QRhiNativeHandles *QRhiD3D12::nativeHandles(QRhiCommandBuffer *cb)
2248 return QRHI_RES(QD3D12CommandBuffer, cb)->nativeHandles();
2251void QRhiD3D12::beginExternal(QRhiCommandBuffer *cb)
2256void QRhiD3D12::endExternal(QRhiCommandBuffer *cb)
2258 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2259 cbD->resetPerPassState();
2260 bindShaderVisibleHeaps(cbD);
2261 if (cbD->currentTarget) {
2262 QD3D12RenderTargetData *rtD = rtData(cbD->currentTarget);
2263 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2266 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2270double QRhiD3D12::lastCompletedGpuTime(QRhiCommandBuffer *cb)
2272 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2273 return cbD->lastGpuTime;
2276static void calculateGpuTime(QD3D12CommandBuffer *cbD,
2277 int timestampPairStartIndex,
2278 const quint8 *readbackBufPtr,
2279 quint64 timestampTicksPerSecond)
2281 const size_t byteOffset = timestampPairStartIndex *
sizeof(quint64);
2282 const quint64 *p =
reinterpret_cast<
const quint64 *>(readbackBufPtr + byteOffset);
2283 const quint64 startTime = *p++;
2284 const quint64 endTime = *p;
2285 if (startTime < endTime) {
2286 const quint64 ticks = endTime - startTime;
2287 const double timeSec = ticks /
double(timestampTicksPerSecond);
2288 cbD->lastGpuTime = timeSec;
2292QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
2302 return QRhi::FrameOpDeviceLost;
2304 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
2305 currentSwapChain = swapChainD;
2306 currentFrameSlot = swapChainD->currentFrameSlot;
2307 QD3D12SwapChain::FrameResources &fr(swapChainD->frameRes[currentFrameSlot]);
2320 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2321 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2323 if (swapChainD->frameLatencyWaitableObject) {
2325 if (swapChainD->lastFrameLatencyWaitSlot != currentFrameSlot) {
2326 WaitForSingleObjectEx(swapChainD->frameLatencyWaitableObject, 1000,
true);
2327 swapChainD->lastFrameLatencyWaitSlot = currentFrameSlot;
2331 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2333 qWarning(
"Failed to reset command allocator: %s",
2334 qPrintable(QSystemError::windowsComString(hr)));
2335 return QRhi::FrameOpError;
2338 if (!startCommandListForCurrentFrameSlot(&fr.cmdList))
2339 return QRhi::FrameOpError;
2341 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
2342 cbD->cmdList = fr.cmdList;
2344 swapChainD->rtWrapper.d.rtv[0] = swapChainD->sampleDesc.Count > 1
2345 ? swapChainD->msaaRtvs[currentFrameSlot].cpuHandle
2346 : swapChainD->rtvs[swapChainD->currentBackBufferIndex].cpuHandle;
2348 swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
2349 : D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
2351 if (swapChainD->stereo) {
2352 swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
2353 ? swapChainD->msaaRtvs[currentFrameSlot].cpuHandle
2354 : swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
2356 swapChainD->rtWrapperRight.d.dsv =
2357 swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
2364 releaseQueue.executeDeferredReleases(currentFrameSlot);
2370 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2373 resetAndResizeSmallStagingArea(currentFrameSlot);
2375 bindShaderVisibleHeaps(cbD);
2377 finishActiveReadbacks();
2379 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2382 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2383 calculateGpuTime(cbD,
2384 timestampPairStartIndex,
2385 timestampReadbackArea.mem.p,
2386 timestampTicksPerSecond);
2388 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2389 D3D12_QUERY_TYPE_TIMESTAMP,
2390 timestampPairStartIndex);
2393 QDxgiVSyncService::instance()->beginFrame(adapterLuid);
2395 return QRhi::FrameOpSuccess;
2398QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
2400 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
2401 Q_ASSERT(currentSwapChain == swapChainD);
2402 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
2404 QD3D12ObjectHandle backBufferResourceHandle = swapChainD->colorBuffers[swapChainD->currentBackBufferIndex];
2405 if (swapChainD->sampleDesc.Count > 1) {
2406 QD3D12ObjectHandle msaaBackBufferResourceHandle = swapChainD->msaaBuffers[currentFrameSlot];
2407 barrierGen.addTransitionBarrier(msaaBackBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2408 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2409 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2410 const QD3D12Resource *src = resourcePool.lookupRef(msaaBackBufferResourceHandle);
2411 const QD3D12Resource *dst = resourcePool.lookupRef(backBufferResourceHandle);
2413 cbD->cmdList->ResolveSubresource(dst->resource, 0, src->resource, 0, swapChainD->colorFormat);
2416 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
2417 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2419 if (timestampQueryHeap.isValid()) {
2420 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2421 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2422 D3D12_QUERY_TYPE_TIMESTAMP,
2423 timestampPairStartIndex + 1);
2424 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2425 D3D12_QUERY_TYPE_TIMESTAMP,
2426 timestampPairStartIndex,
2428 timestampReadbackArea.mem.buffer,
2429 timestampPairStartIndex *
sizeof(quint64));
2432 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2433 HRESULT hr = cmdList->Close();
2435 qWarning(
"Failed to close command list: %s",
2436 qPrintable(QSystemError::windowsComString(hr)));
2437 return QRhi::FrameOpError;
2440 ID3D12CommandList *execList[] = { cmdList };
2441 cmdQueue->ExecuteCommandLists(1, execList);
2443 if (!flags.testFlag(QRhi::SkipPresent)) {
2444 UINT presentFlags = 0;
2445 if (swapChainD->swapInterval == 0
2446 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
2448 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
2450 if (!swapChainD->swapChain) {
2451 qWarning(
"Failed to present, no swapchain");
2452 return QRhi::FrameOpError;
2454 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
2455 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
2456 qWarning(
"Device loss detected in Present()");
2458 return QRhi::FrameOpDeviceLost;
2459 }
else if (FAILED(hr)) {
2460 qWarning(
"Failed to present: %s", qPrintable(QSystemError::windowsComString(hr)));
2461 return QRhi::FrameOpError;
2464 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
2465 dcompDevice->Commit();
2468 swapChainD->addCommandCompletionSignalForCurrentFrameSlot();
2475 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2477 if (!flags.testFlag(QRhi::SkipPresent)) {
2481 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2482 swapChainD->currentBackBufferIndex = swapChainD->swapChain->GetCurrentBackBufferIndex();
2485 currentSwapChain =
nullptr;
2486 return QRhi::FrameOpSuccess;
2489QRhi::FrameOpResult QRhiD3D12::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
2502 currentFrameSlot = (currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2504 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2505 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2507 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2509 qWarning(
"Failed to reset command allocator: %s",
2510 qPrintable(QSystemError::windowsComString(hr)));
2511 return QRhi::FrameOpError;
2514 if (!offscreenCb[currentFrameSlot])
2515 offscreenCb[currentFrameSlot] =
new QD3D12CommandBuffer(
this);
2516 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2517 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2518 return QRhi::FrameOpError;
2520 releaseQueue.executeDeferredReleases(currentFrameSlot);
2522 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2523 resetAndResizeSmallStagingArea(currentFrameSlot);
2525 bindShaderVisibleHeaps(cbD);
2527 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2528 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2529 D3D12_QUERY_TYPE_TIMESTAMP,
2530 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT);
2533 offscreenActive =
true;
2536 return QRhi::FrameOpSuccess;
2539QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
2542 Q_ASSERT(offscreenActive);
2543 offscreenActive =
false;
2545 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2546 if (timestampQueryHeap.isValid()) {
2547 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2548 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2549 D3D12_QUERY_TYPE_TIMESTAMP,
2550 timestampPairStartIndex + 1);
2551 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2552 D3D12_QUERY_TYPE_TIMESTAMP,
2553 timestampPairStartIndex,
2555 timestampReadbackArea.mem.buffer,
2556 timestampPairStartIndex *
sizeof(quint64));
2559 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2560 HRESULT hr = cmdList->Close();
2562 qWarning(
"Failed to close command list: %s",
2563 qPrintable(QSystemError::windowsComString(hr)));
2564 return QRhi::FrameOpError;
2567 ID3D12CommandList *execList[] = { cmdList };
2568 cmdQueue->ExecuteCommandLists(1, execList);
2570 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2577 finishActiveReadbacks(
true);
2580 if (timestampQueryHeap.isValid()) {
2581 calculateGpuTime(cbD,
2582 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT,
2583 timestampReadbackArea.mem.p,
2584 timestampTicksPerSecond);
2587 return QRhi::FrameOpSuccess;
2590QRhi::FrameOpResult QRhiD3D12::finish()
2592 QD3D12CommandBuffer *cbD =
nullptr;
2594 if (offscreenActive) {
2595 Q_ASSERT(!currentSwapChain);
2596 cbD = offscreenCb[currentFrameSlot];
2598 Q_ASSERT(currentSwapChain);
2599 cbD = ¤tSwapChain->cbWrapper;
2602 return QRhi::FrameOpError;
2604 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2606 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2607 HRESULT hr = cmdList->Close();
2609 qWarning(
"Failed to close command list: %s",
2610 qPrintable(QSystemError::windowsComString(hr)));
2611 return QRhi::FrameOpError;
2614 ID3D12CommandList *execList[] = { cmdList };
2615 cmdQueue->ExecuteCommandLists(1, execList);
2617 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2624 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2626 qWarning(
"Failed to reset command allocator: %s",
2627 qPrintable(QSystemError::windowsComString(hr)));
2628 return QRhi::FrameOpError;
2631 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2632 return QRhi::FrameOpError;
2636 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2637 smallStagingAreas[currentFrameSlot].head = 0;
2639 bindShaderVisibleHeaps(cbD);
2642 releaseQueue.releaseAll();
2643 finishActiveReadbacks(
true);
2645 return QRhi::FrameOpSuccess;
2648void QRhiD3D12::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2650 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2651 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2652 enqueueResourceUpdates(cbD, resourceUpdates);
2655void QRhiD3D12::beginPass(QRhiCommandBuffer *cb,
2656 QRhiRenderTarget *rt,
2657 const QColor &colorClearValue,
2658 const QRhiDepthStencilClearValue &depthStencilClearValue,
2659 QRhiResourceUpdateBatch *resourceUpdates,
2660 QRhiCommandBuffer::BeginPassFlags)
2662 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2663 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2665 if (resourceUpdates)
2666 enqueueResourceUpdates(cbD, resourceUpdates);
2668 QD3D12RenderTargetData *rtD = rtData(rt);
2669 bool wantsColorClear =
true;
2670 bool wantsDsClear =
true;
2671 if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) {
2672 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, rt);
2673 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2674 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2675 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2678 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); it != itEnd; ++it) {
2679 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
2680 QD3D12Texture *resolveTexD = QRHI_RES(QD3D12Texture, it->resolveTexture());
2681 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
2683 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2685 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2687 barrierGen.addTransitionBarrier(resolveTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2689 if (rtTex->m_desc.depthStencilBuffer()) {
2690 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rtTex->m_desc.depthStencilBuffer());
2691 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
2692 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2693 }
else if (rtTex->m_desc.depthTexture()) {
2694 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, rtTex->m_desc.depthTexture());
2695 barrierGen.addTransitionBarrier(depthTexD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2697 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2699 Q_ASSERT(currentSwapChain);
2700 barrierGen.addTransitionBarrier(currentSwapChain->sampleDesc.Count > 1
2701 ? currentSwapChain->msaaBuffers[currentFrameSlot]
2702 : currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex],
2703 D3D12_RESOURCE_STATE_RENDER_TARGET);
2704 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2707 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2710 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2712 if (rtD->colorAttCount && wantsColorClear) {
2713 float clearColor[4] = {
2714 colorClearValue.redF(),
2715 colorClearValue.greenF(),
2716 colorClearValue.blueF(),
2717 colorClearValue.alphaF()
2719 for (
int i = 0; i < rtD->colorAttCount; ++i)
2720 cbD->cmdList->ClearRenderTargetView(rtD->rtv[i], clearColor, 0,
nullptr);
2722 if (rtD->dsAttCount && wantsDsClear) {
2723 cbD->cmdList->ClearDepthStencilView(rtD->dsv,
2724 D3D12_CLEAR_FLAGS(D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL),
2725 depthStencilClearValue.depthClearValue(),
2726 UINT8(depthStencilClearValue.stencilClearValue()),
2731 cbD->recordingPass = QD3D12CommandBuffer::RenderPass;
2732 cbD->currentTarget = rt;
2734 bool hasShadingRateMapSet =
false;
2735#ifdef QRHI_D3D12_CL5_AVAILABLE
2736 if (rtD->rp->hasShadingRateMap) {
2737 cbD->setShadingRate(QSize(1, 1));
2738 QD3D12ShadingRateMap *rateMapD = rt->resourceType() == QRhiRenderTarget::TextureRenderTarget
2739 ? QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12TextureRenderTarget, rt)->m_desc.shadingRateMap())
2740 : QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12SwapChainRenderTarget, rt)->swapChain()->shadingRateMap());
2741 if (QD3D12Resource *res = resourcePool.lookupRef(rateMapD->handle)) {
2742 barrierGen.addTransitionBarrier(rateMapD->handle, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
2743 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2744 cbD->cmdList->RSSetShadingRateImage(res->resource);
2745 hasShadingRateMapSet =
true;
2747 }
else if (cbD->hasShadingRateMapSet) {
2748 cbD->cmdList->RSSetShadingRateImage(
nullptr);
2749 cbD->setShadingRate(QSize(1, 1));
2750 }
else if (cbD->hasShadingRateSet) {
2751 cbD->setShadingRate(QSize(1, 1));
2755 cbD->resetPerPassState();
2758 cbD->hasShadingRateMapSet = hasShadingRateMapSet;
2761void QRhiD3D12::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2763 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2764 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2766 if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
2767 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, cbD->currentTarget);
2768 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2771 const QRhiColorAttachment &colorAtt(*it);
2772 if (!colorAtt.resolveTexture())
2775 QD3D12Texture *dstTexD = QRHI_RES(QD3D12Texture, colorAtt.resolveTexture());
2776 QD3D12Resource *dstRes = resourcePool.lookupRef(dstTexD->handle);
2780 QD3D12Texture *srcTexD = QRHI_RES(QD3D12Texture, colorAtt.texture());
2781 QD3D12RenderBuffer *srcRbD = QRHI_RES(QD3D12RenderBuffer, colorAtt.renderBuffer());
2782 Q_ASSERT(srcTexD || srcRbD);
2783 QD3D12Resource *srcRes = resourcePool.lookupRef(srcTexD ? srcTexD->handle : srcRbD->handle);
2788 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2789 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2790 int(srcTexD->dxgiFormat),
int(dstTexD->dxgiFormat));
2793 if (srcTexD->sampleDesc.Count <= 1) {
2794 qWarning(
"Cannot resolve a non-multisample texture");
2797 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2798 qWarning(
"Resolve source and destination sizes do not match");
2802 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2803 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2804 int(srcRbD->dxgiFormat),
int(dstTexD->dxgiFormat));
2807 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2808 qWarning(
"Resolve source and destination sizes do not match");
2819 const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
2820 QBitArray &initialized(dstTexD->subresourceInitialized);
2821 QVarLengthArray<UINT, 4> dstSubresources;
2822 QVarLengthArray<UINT, 4> subresourcesToDiscard;
2823 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2824 const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
2825 UINT(colorAtt.resolveLayer()) + resolveIdx,
2826 dstTexD->mipLevelCount);
2827 dstSubresources.append(dstSubresource);
2828 if (
int(dstSubresource) >= initialized.size())
2829 initialized.resize(
int(dstSubresource) + 1);
2830 if (!initialized.testBit(
int(dstSubresource))) {
2831 initialized.setBit(
int(dstSubresource));
2832 subresourcesToDiscard.append(dstSubresource);
2836 barrierGen.addTransitionBarrier(srcTexD ? srcTexD->handle : srcRbD->handle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2839 if (!subresourcesToDiscard.isEmpty()) {
2840 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2841 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2842 for (UINT dstSubresource : subresourcesToDiscard) {
2843 D3D12_DISCARD_REGION region = {};
2844 region.FirstSubresource = dstSubresource;
2845 region.NumSubresources = 1;
2846 cbD->cmdList->DiscardResource(dstRes->resource, ®ion);
2850 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2851 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2853 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2854 const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
2855 cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresources[resolveIdx],
2856 srcRes->resource, srcSubresource,
2857 dstTexD->dxgiFormat);
2860 if (rtTex->m_desc.depthResolveTexture())
2861 qWarning(
"Resolving multisample depth-stencil buffers is not supported with D3D");
2864 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2865 cbD->currentTarget =
nullptr;
2867 if (resourceUpdates)
2868 enqueueResourceUpdates(cbD, resourceUpdates);
2871void QRhiD3D12::beginComputePass(QRhiCommandBuffer *cb,
2872 QRhiResourceUpdateBatch *resourceUpdates,
2873 QRhiCommandBuffer::BeginPassFlags)
2875 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2876 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2878 if (resourceUpdates)
2879 enqueueResourceUpdates(cbD, resourceUpdates);
2881 cbD->recordingPass = QD3D12CommandBuffer::ComputePass;
2883 cbD->resetPerPassState();
2886void QRhiD3D12::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2888 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2889 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2891 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2893 if (resourceUpdates)
2894 enqueueResourceUpdates(cbD, resourceUpdates);
2897void QRhiD3D12::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
2899 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2900 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2901 QD3D12ComputePipeline *psD = QRHI_RES(QD3D12ComputePipeline, ps);
2902 const bool pipelineChanged = cbD->currentComputePipeline != psD || cbD->currentPipelineGeneration != psD->generation;
2904 if (pipelineChanged) {
2905 cbD->currentGraphicsPipeline =
nullptr;
2906 cbD->currentComputePipeline = psD;
2907 cbD->currentPipelineGeneration = psD->generation;
2909 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
2910 Q_ASSERT(pipeline->type == QD3D12Pipeline::Compute);
2911 cbD->cmdList->SetPipelineState(pipeline->pso);
2912 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
2913 cbD->cmdList->SetComputeRootSignature(rs->rootSig);
2918void QRhiD3D12::dispatch(QRhiCommandBuffer *cb,
int x,
int y,
int z)
2920 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2921 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2922 cbD->cmdList->Dispatch(UINT(x), UINT(y), UINT(z));
2928ID3D12CommandSignature *QRhiD3D12::indirectDrawCommandSignature(
bool indexed, quint32 stride)
2930 const quint32 canonicalStride = indexed ?
sizeof(QRhiIndexedIndirectDrawCommand)
2931 :
sizeof(QRhiIndirectDrawCommand);
2932 if (stride == canonicalStride)
2933 return indexed ? drawIndexedCommandSignature : drawCommandSignature;
2935 QHash<quint32, ID3D12CommandSignature *> &cache(indexed ? drawIndexedCommandSignaturesByStride
2936 : drawCommandSignaturesByStride);
2937 auto it = cache.constFind(stride);
2938 if (it != cache.constEnd())
2941 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
2942 arg.Type = indexed ? D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED : D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
2944 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
2945 sigDesc.ByteStride = stride;
2946 sigDesc.NumArgumentDescs = 1;
2947 sigDesc.pArgumentDescs = &arg;
2949 ID3D12CommandSignature *sig =
nullptr;
2950 HRESULT hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&sig));
2952 qWarning(
"Failed to create indirect draw command signature with stride %u: %s",
2953 stride, qPrintable(QSystemError::windowsComString(hr)));
2957 cache.insert(stride, sig);
2961void QRhiD3D12::drawIndirectCount(QRhiCommandBuffer *cb,
2962 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
2963 QRhiBuffer *countBuffer, quint32 countBufferOffset,
2964 quint32 maxDrawCount, quint32 stride)
2966 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2967 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2969 ID3D12CommandSignature *sig = indirectDrawCommandSignature(
false, stride);
2973 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2974 const bool indirectIsDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2975 const QD3D12ObjectHandle indirectHandle = indirectBufferD->handles[indirectIsDynamic ? currentFrameSlot : 0];
2976 if (indirectIsDynamic)
2977 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2979 barrierGen.addTransitionBarrier(indirectHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2981 QD3D12Buffer *countBufferD = QRHI_RES(QD3D12Buffer, countBuffer);
2982 const bool countIsDynamic = countBufferD->m_type == QRhiBuffer::Dynamic;
2983 const QD3D12ObjectHandle countHandle = countBufferD->handles[countIsDynamic ? currentFrameSlot : 0];
2985 countBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2987 barrierGen.addTransitionBarrier(countHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2989 if (!indirectIsDynamic || !countIsDynamic)
2990 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2992 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectHandle);
2993 QD3D12Resource *countRes = resourcePool.lookupRef(countHandle);
2994 if (!indirectRes || !countRes)
2997 cbD->cmdList->ExecuteIndirect(sig, maxDrawCount,
2998 indirectRes->resource, indirectBufferOffset,
2999 countRes->resource, countBufferOffset);
3002void QRhiD3D12::drawIndexedIndirectCount(QRhiCommandBuffer *cb,
3003 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
3004 QRhiBuffer *countBuffer, quint32 countBufferOffset,
3005 quint32 maxDrawCount, quint32 stride)
3007 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
3008 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
3010 ID3D12CommandSignature *sig = indirectDrawCommandSignature(
true, stride);
3014 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
3015 const bool indirectIsDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
3016 const QD3D12ObjectHandle indirectHandle = indirectBufferD->handles[indirectIsDynamic ? currentFrameSlot : 0];
3017 if (indirectIsDynamic)
3018 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
3020 barrierGen.addTransitionBarrier(indirectHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
3022 QD3D12Buffer *countBufferD = QRHI_RES(QD3D12Buffer, countBuffer);
3023 const bool countIsDynamic = countBufferD->m_type == QRhiBuffer::Dynamic;
3024 const QD3D12ObjectHandle countHandle = countBufferD->handles[countIsDynamic ? currentFrameSlot : 0];
3026 countBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
3028 barrierGen.addTransitionBarrier(countHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
3030 if (!indirectIsDynamic || !countIsDynamic)
3031 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3033 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectHandle);
3034 QD3D12Resource *countRes = resourcePool.lookupRef(countHandle);
3035 if (!indirectRes || !countRes)
3038 cbD->cmdList->ExecuteIndirect(sig, maxDrawCount,
3039 indirectRes->resource, indirectBufferOffset,
3040 countRes->resource, countBufferOffset);
3043void QRhiD3D12::dispatchIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
3044 quint32 indirectBufferOffset)
3046 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
3047 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
3049 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
3050 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
3051 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
3053 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
3058 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
3059 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3061 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
3065 cbD->cmdList->ExecuteIndirect(dispatchCommandSignature, 1,
3066 indirectRes->resource, indirectBufferOffset,
3070bool QD3D12DescriptorHeap::create(ID3D12Device *device,
3071 quint32 descriptorCount,
3072 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
3073 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags)
3076 capacity = descriptorCount;
3077 this->heapType = heapType;
3078 this->heapFlags = heapFlags;
3080 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
3081 heapDesc.Type = heapType;
3082 heapDesc.NumDescriptors = capacity;
3083 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS(heapFlags);
3085 HRESULT hr = device->CreateDescriptorHeap(&heapDesc, __uuidof(ID3D12DescriptorHeap),
reinterpret_cast<
void **>(&heap));
3087 qWarning(
"Failed to create descriptor heap: %s", qPrintable(QSystemError::windowsComString(hr)));
3089 capacity = descriptorByteSize = 0;
3093 descriptorByteSize = device->GetDescriptorHandleIncrementSize(heapType);
3094 heapStart.cpuHandle = heap->GetCPUDescriptorHandleForHeapStart();
3095 if (heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
3096 heapStart.gpuHandle = heap->GetGPUDescriptorHandleForHeapStart();
3101void QD3D12DescriptorHeap::createWithExisting(
const QD3D12DescriptorHeap &other,
3102 quint32 offsetInDescriptors,
3103 quint32 descriptorCount)
3107 capacity = descriptorCount;
3108 heapType = other.heapType;
3109 heapFlags = other.heapFlags;
3110 descriptorByteSize = other.descriptorByteSize;
3111 heapStart = incremented(other.heapStart, offsetInDescriptors);
3114void QD3D12DescriptorHeap::destroy()
3123void QD3D12DescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3126 releaseQueue->deferredReleaseDescriptorHeap(heap);
3132QD3D12Descriptor QD3D12DescriptorHeap::get(quint32 count)
3134 Q_ASSERT(count > 0);
3135 if (head + count > capacity) {
3136 qWarning(
"Cannot get %u descriptors as that would exceed capacity %u", count, capacity);
3140 return at(head - count);
3143QD3D12Descriptor QD3D12DescriptorHeap::at(quint32 index)
const
3145 const quint32 startOffset = index * descriptorByteSize;
3146 QD3D12Descriptor result;
3147 result.cpuHandle.ptr = heapStart.cpuHandle.ptr + startOffset;
3148 if (heapStart.gpuHandle.ptr != 0)
3149 result.gpuHandle.ptr = heapStart.gpuHandle.ptr + startOffset;
3153bool QD3D12CpuDescriptorPool::create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName)
3155 QD3D12DescriptorHeap firstHeap;
3156 if (!firstHeap.create(device, DESCRIPTORS_PER_HEAP, heapType, D3D12_DESCRIPTOR_HEAP_FLAG_NONE))
3158 heaps.append(HeapWithMap::init(firstHeap, DESCRIPTORS_PER_HEAP));
3159 descriptorByteSize = heaps[0].heap.descriptorByteSize;
3160 this->device = device;
3161 this->debugName = debugName;
3165void QD3D12CpuDescriptorPool::destroy()
3169 static bool leakCheck =
true;
3172 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
3175 for (
const HeapWithMap &heap : std::as_const(heaps)) {
3176 const int leakedDescriptorCount = heap.map.count(
true);
3177 if (leakedDescriptorCount > 0) {
3178 qWarning(
"QD3D12CpuDescriptorPool::destroy(): "
3179 "Heap %p for descriptor pool %p '%s' has %d unreleased descriptors",
3180 &heap.heap,
this, debugName, leakedDescriptorCount);
3184 for (HeapWithMap &heap : heaps)
3185 heap.heap.destroy();
3189QD3D12Descriptor QD3D12CpuDescriptorPool::allocate(quint32 count)
3191 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
3193 HeapWithMap &last(heaps.last());
3194 if (last.heap.head + count <= last.heap.capacity) {
3195 quint32 firstIndex = last.heap.head;
3196 for (quint32 i = 0; i < count; ++i)
3197 last.map.setBit(firstIndex + i);
3198 return last.heap.get(count);
3201 for (HeapWithMap &heap : heaps) {
3202 quint32 freeCount = 0;
3203 for (quint32 i = 0; i < DESCRIPTORS_PER_HEAP; ++i) {
3204 if (heap.map.testBit(i)) {
3208 if (freeCount == count) {
3209 const quint32 firstIndex = i - (freeCount - 1);
3210 for (quint32 j = 0; j < count; ++j)
3211 heap.map.setBit(firstIndex + j);
3215 if (firstIndex + count > heap.heap.head)
3216 heap.heap.head = firstIndex + count;
3217 return heap.heap.at(firstIndex);
3223 QD3D12DescriptorHeap newHeap;
3224 if (!newHeap.create(device, DESCRIPTORS_PER_HEAP, last.heap.heapType, last.heap.heapFlags))
3227 heaps.append(HeapWithMap::init(newHeap, DESCRIPTORS_PER_HEAP));
3229 for (quint32 i = 0; i < count; ++i)
3230 heaps.last().map.setBit(i);
3232 return heaps.last().heap.get(count);
3235void QD3D12CpuDescriptorPool::release(
const QD3D12Descriptor &descriptor, quint32 count)
3237 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
3238 if (!descriptor.isValid())
3241 const SIZE_T addr = descriptor.cpuHandle.ptr;
3242 for (HeapWithMap &heap : heaps) {
3243 const SIZE_T begin = heap.heap.heapStart.cpuHandle.ptr;
3244 const SIZE_T end = begin + heap.heap.descriptorByteSize * heap.heap.capacity;
3245 if (addr >= begin && addr < end) {
3246 quint32 firstIndex = (addr - begin) / heap.heap.descriptorByteSize;
3247 for (quint32 i = 0; i < count; ++i)
3248 heap.map.setBit(firstIndex + i,
false);
3253 qWarning(
"QD3D12CpuDescriptorPool::release: Descriptor with address %llu is not in any heap",
3254 quint64(descriptor.cpuHandle.ptr));
3257bool QD3D12QueryHeap::create(ID3D12Device *device,
3259 D3D12_QUERY_HEAP_TYPE heapType)
3261 capacity = queryCount;
3263 D3D12_QUERY_HEAP_DESC heapDesc = {};
3264 heapDesc.Type = heapType;
3265 heapDesc.Count = capacity;
3267 HRESULT hr = device->CreateQueryHeap(&heapDesc, __uuidof(ID3D12QueryHeap),
reinterpret_cast<
void **>(&heap));
3269 qWarning(
"Failed to create query heap: %s", qPrintable(QSystemError::windowsComString(hr)));
3278void QD3D12QueryHeap::destroy()
3287bool QD3D12StagingArea::create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType)
3289 Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
3290 D3D12_RESOURCE_DESC resourceDesc = {};
3291 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
3292 resourceDesc.Width = capacity;
3293 resourceDesc.Height = 1;
3294 resourceDesc.DepthOrArraySize = 1;
3295 resourceDesc.MipLevels = 1;
3296 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
3297 resourceDesc.SampleDesc = { 1, 0 };
3298 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
3299 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
3300 UINT state = heapType == D3D12_HEAP_TYPE_UPLOAD ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
3301 HRESULT hr = rhi->vma.createResource(heapType,
3303 D3D12_RESOURCE_STATES(state),
3306 __uuidof(ID3D12Resource),
3307 reinterpret_cast<
void **>(&resource));
3309 qWarning(
"Failed to create buffer for staging area: %s",
3310 qPrintable(QSystemError::windowsComString(hr)));
3314 hr = resource->Map(0,
nullptr, &p);
3316 qWarning(
"Failed to map buffer for staging area: %s",
3317 qPrintable(QSystemError::windowsComString(hr)));
3322 mem.p =
static_cast<quint8 *>(p);
3323 mem.gpuAddr = resource->GetGPUVirtualAddress();
3324 mem.buffer = resource;
3325 mem.bufferOffset = 0;
3327 this->capacity = capacity;
3333void QD3D12StagingArea::destroy()
3336 resource->Release();
3340 allocation->Release();
3341 allocation =
nullptr;
3346void QD3D12StagingArea::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3349 releaseQueue->deferredReleaseResourceAndAllocation(resource, allocation);
3353QD3D12StagingArea::Allocation QD3D12StagingArea::get(quint32 byteSize)
3355 const quint32 allocSize = aligned(byteSize, ALIGNMENT);
3356 if (head + allocSize > capacity) {
3357 qWarning(
"Failed to allocate %u (%u) bytes from staging area of size %u with %u bytes left",
3358 allocSize, byteSize, capacity, remainingCapacity());
3361 const quint32 offset = head;
3365 mem.gpuAddr + offset,
3374void QD3D12ReleaseQueue::deferredReleaseResource(
const QD3D12ObjectHandle &handle)
3376 DeferredReleaseEntry e;
3381void QD3D12ReleaseQueue::deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
3382 QD3D12CpuDescriptorPool *pool,
3383 const QD3D12Descriptor &viewsStart,
3386 DeferredReleaseEntry e;
3387 e.type = DeferredReleaseEntry::Resource;
3389 e.poolForViews = pool;
3390 e.viewsStart = viewsStart;
3391 e.viewCount = viewCount;
3395void QD3D12ReleaseQueue::deferredReleasePipeline(
const QD3D12ObjectHandle &handle)
3397 DeferredReleaseEntry e;
3398 e.type = DeferredReleaseEntry::Pipeline;
3403void QD3D12ReleaseQueue::deferredReleaseRootSignature(
const QD3D12ObjectHandle &handle)
3405 DeferredReleaseEntry e;
3406 e.type = DeferredReleaseEntry::RootSignature;
3411void QD3D12ReleaseQueue::deferredReleaseCallback(std::function<
void(
void*)> callback,
void *userData)
3413 DeferredReleaseEntry e;
3414 e.type = DeferredReleaseEntry::Callback;
3415 e.callback = callback;
3416 e.callbackUserData = userData;
3420void QD3D12ReleaseQueue::deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
3421 D3D12MA::Allocation *allocation)
3423 DeferredReleaseEntry e;
3424 e.type = DeferredReleaseEntry::ResourceAndAllocation;
3425 e.resourceAndAllocation = { resource, allocation };
3429void QD3D12ReleaseQueue::deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap)
3431 DeferredReleaseEntry e;
3432 e.type = DeferredReleaseEntry::DescriptorHeap;
3433 e.descriptorHeap = heap;
3437void QD3D12ReleaseQueue::deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
3438 const QD3D12Descriptor &viewsStart,
3441 DeferredReleaseEntry e;
3442 e.type = DeferredReleaseEntry::Views;
3443 e.poolForViews = pool;
3444 e.viewsStart = viewsStart;
3445 e.viewCount = viewCount;
3449void QD3D12ReleaseQueue::activatePendingDeferredReleaseRequests(
int frameSlot)
3451 for (DeferredReleaseEntry &e : queue) {
3452 if (!e.frameSlotToBeReleasedIn.has_value())
3453 e.frameSlotToBeReleasedIn = frameSlot;
3457void QD3D12ReleaseQueue::executeDeferredReleases(
int frameSlot,
bool forced)
3459 qsizetype keepBegin = queue.size();
3460 for (qsizetype i = keepBegin - 1; i >= 0; --i) {
3461 const DeferredReleaseEntry &e(queue[i]);
3462 if (forced || (e.frameSlotToBeReleasedIn.has_value() && e.frameSlotToBeReleasedIn.value() == frameSlot)) {
3464 case DeferredReleaseEntry::Resource:
3465 resourcePool->remove(e.handle);
3466 if (e.poolForViews && e.viewsStart.isValid() && e.viewCount > 0)
3467 e.poolForViews->release(e.viewsStart, e.viewCount);
3469 case DeferredReleaseEntry::Pipeline:
3470 pipelinePool->remove(e.handle);
3472 case DeferredReleaseEntry::RootSignature:
3473 rootSignaturePool->remove(e.handle);
3475 case DeferredReleaseEntry::Callback:
3476 e.callback(e.callbackUserData);
3478 case DeferredReleaseEntry::ResourceAndAllocation:
3481 e.resourceAndAllocation.first->Release();
3482 if (e.resourceAndAllocation.second)
3483 e.resourceAndAllocation.second->Release();
3485 case DeferredReleaseEntry::DescriptorHeap:
3486 e.descriptorHeap->Release();
3488 case DeferredReleaseEntry::Views:
3489 e.poolForViews->release(e.viewsStart, e.viewCount);
3492 }
else if (--keepBegin != i) {
3493 queue[keepBegin] = std::move(queue[i]);
3497 queue.remove(0, keepBegin);
3500void QD3D12ReleaseQueue::releaseAll()
3502 executeDeferredReleases(0,
true);
3505void QD3D12ResourceBarrierGenerator::addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle,
3506 D3D12_RESOURCE_STATES stateAfter)
3508 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3509 if (stateAfter != res->state) {
3510 transitionResourceBarriers.append({ resourceHandle, res->state, stateAfter });
3511 res->state = stateAfter;
3516void QD3D12ResourceBarrierGenerator::enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD)
3518 QVarLengthArray<D3D12_RESOURCE_BARRIER, PREALLOC> barriers;
3519 for (
const TransitionResourceBarrier &trb : transitionResourceBarriers) {
3520 if (QD3D12Resource *res = resourcePool->lookupRef(trb.resourceHandle)) {
3521 D3D12_RESOURCE_BARRIER barrier = {};
3522 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
3523 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3524 barrier.Transition.pResource = res->resource;
3525 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
3526 barrier.Transition.StateBefore = trb.stateBefore;
3527 barrier.Transition.StateAfter = trb.stateAfter;
3528 barriers.append(barrier);
3531 transitionResourceBarriers.clear();
3532 if (!barriers.isEmpty())
3533 cbD->cmdList->ResourceBarrier(barriers.count(), barriers.constData());
3536void QD3D12ResourceBarrierGenerator::enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
3537 const QD3D12ObjectHandle &resourceHandle,
3539 D3D12_RESOURCE_STATES stateBefore,
3540 D3D12_RESOURCE_STATES stateAfter)
3542 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3543 D3D12_RESOURCE_BARRIER barrier = {};
3544 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
3545 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3546 barrier.Transition.pResource = res->resource;
3547 barrier.Transition.Subresource = subresource;
3548 barrier.Transition.StateBefore = stateBefore;
3549 barrier.Transition.StateAfter = stateAfter;
3550 cbD->cmdList->ResourceBarrier(1, &barrier);
3554void QD3D12ResourceBarrierGenerator::enqueueUavBarrier(QD3D12CommandBuffer *cbD,
3555 const QD3D12ObjectHandle &resourceHandle)
3557 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3558 D3D12_RESOURCE_BARRIER barrier = {};
3559 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
3560 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3561 barrier.UAV.pResource = res->resource;
3562 cbD->cmdList->ResourceBarrier(1, &barrier);
3566bool QD3D12ShaderVisibleDescriptorHeap::create(ID3D12Device *device,
3567 D3D12_DESCRIPTOR_HEAP_TYPE type,
3568 quint32 perFrameDescriptorCount)
3570 Q_ASSERT(type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
3572 quint32 size = perFrameDescriptorCount * QD3D12_FRAMES_IN_FLIGHT;
3575 const quint32 CBV_SRV_UAV_MAX = 1000000;
3576 const quint32 SAMPLER_MAX = 2048;
3577 if (type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
3578 size = qMin(size, CBV_SRV_UAV_MAX);
3579 else if (type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
3580 size = qMin(size, SAMPLER_MAX);
3582 if (!heap.create(device, size, type, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
3583 qWarning(
"Failed to create shader-visible descriptor heap of size %u", size);
3587 perFrameDescriptorCount = size / QD3D12_FRAMES_IN_FLIGHT;
3588 quint32 currentOffsetInDescriptors = 0;
3589 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3590 perFrameHeapSlice[i].createWithExisting(heap, currentOffsetInDescriptors, perFrameDescriptorCount);
3591 currentOffsetInDescriptors += perFrameDescriptorCount;
3597void QD3D12ShaderVisibleDescriptorHeap::destroy()
3602void QD3D12ShaderVisibleDescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3604 heap.destroyWithDeferredRelease(releaseQueue);
3607static inline std::pair<
int,
int> mapBinding(
int binding,
const QD3D12ShaderStageData *sd)
3609 const QShader::NativeResourceBindingMap &map(sd->nativeResourceBindingMap);
3610 if (map.isEmpty()) {
3618 if (sd->pushConstantRegister >= 0)
3620 return { binding, binding };
3623 auto it = map.constFind(binding);
3624 if (it != map.cend())
3633void QD3D12ShaderResourceVisitor::visit()
3635 for (
int bindingIdx = 0, bindingCount = srb->m_bindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
3636 const QRhiShaderResourceBinding &b(srb->m_bindings[bindingIdx]);
3637 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
3639 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
3640 const QD3D12ShaderStageData *sd = &stageData[stageIdx];
3644 if (!bd->stage.testFlag(qd3d12_stageToSrb(sd->stage)))
3647 switch (bd->type()) {
3648 case QRhiShaderResourceBinding::UniformBuffer:
3650 const int shaderRegister = mapBinding(bd->binding, sd).first;
3651 if (shaderRegister >= 0 && uniformBuffer)
3652 uniformBuffer(sd->stage, bd->ubuf(), shaderRegister, bd->binding);
3655 case QRhiShaderResourceBinding::SampledTexture:
3657 Q_ASSERT(bd->stex().count() > 0);
3658 const int textureBaseShaderRegister = mapBinding(bd->binding, sd).first;
3659 const int samplerBaseShaderRegister = mapBinding(bd->binding, sd).second;
3660 if (textureBaseShaderRegister >= 0 && textures)
3661 textures(sd->stage, bd->stex().texSamplers.constData(), bd->stex().count(), textureBaseShaderRegister);
3662 if (samplerBaseShaderRegister >= 0 && samplers)
3663 samplers(sd->stage, bd->stex().texSamplers.constData(), bd->stex().count(), samplerBaseShaderRegister);
3666 case QRhiShaderResourceBinding::Texture:
3668 Q_ASSERT(bd->stex().count() > 0);
3669 const int baseShaderRegister = mapBinding(bd->binding, sd).first;
3670 if (baseShaderRegister >= 0 && textures)
3671 textures(sd->stage, bd->stex().texSamplers.constData(), bd->stex().count(), baseShaderRegister);
3674 case QRhiShaderResourceBinding::Sampler:
3676 Q_ASSERT(bd->stex().count() > 0);
3677 const int baseShaderRegister = mapBinding(bd->binding, sd).first;
3678 if (baseShaderRegister >= 0 && samplers)
3679 samplers(sd->stage, bd->stex().texSamplers.constData(), bd->stex().count(), baseShaderRegister);
3682 case QRhiShaderResourceBinding::ImageLoad:
3684 const int shaderRegister = mapBinding(bd->binding, sd).first;
3685 if (shaderRegister >= 0 && storageImage)
3686 storageImage(sd->stage, bd->simage(), Load, shaderRegister);
3689 case QRhiShaderResourceBinding::ImageStore:
3691 const int shaderRegister = mapBinding(bd->binding, sd).first;
3692 if (shaderRegister >= 0 && storageImage)
3693 storageImage(sd->stage, bd->simage(), Store, shaderRegister);
3696 case QRhiShaderResourceBinding::ImageLoadStore:
3698 const int shaderRegister = mapBinding(bd->binding, sd).first;
3699 if (shaderRegister >= 0 && storageImage)
3700 storageImage(sd->stage, bd->simage(), LoadStore, shaderRegister);
3703 case QRhiShaderResourceBinding::BufferLoad:
3705 const int shaderRegister = mapBinding(bd->binding, sd).first;
3706 if (shaderRegister >= 0 && storageBuffer)
3707 storageBuffer(sd->stage, bd->sbuf(), Load, shaderRegister);
3710 case QRhiShaderResourceBinding::BufferStore:
3712 const int shaderRegister = mapBinding(bd->binding, sd).first;
3713 if (shaderRegister >= 0 && storageBuffer)
3714 storageBuffer(sd->stage, bd->sbuf(), Store, shaderRegister);
3717 case QRhiShaderResourceBinding::BufferLoadStore:
3719 const int shaderRegister = mapBinding(bd->binding, sd).first;
3720 if (shaderRegister >= 0 && storageBuffer)
3721 storageBuffer(sd->stage, bd->sbuf(), LoadStore, shaderRegister);
3729bool QD3D12SamplerManager::create(ID3D12Device *device)
3732 if (!shaderVisibleSamplerHeap.create(device,
3733 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
3734 MAX_SAMPLERS / QD3D12_FRAMES_IN_FLIGHT))
3736 qWarning(
"Could not create shader-visible SAMPLER heap");
3740 this->device = device;
3744void QD3D12SamplerManager::destroy()
3747 shaderVisibleSamplerHeap.destroy();
3752QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc)
3754 auto it = gpuMap.constFind({desc});
3755 if (it != gpuMap.cend())
3758 QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
3759 if (descriptor.isValid()) {
3760 device->CreateSampler(&desc, descriptor.cpuHandle);
3761 gpuMap.insert({desc}, descriptor);
3763 qWarning(
"Out of shader-visible SAMPLER descriptor heap space,"
3764 " this should not happen, maximum number of unique samplers is %u",
3765 shaderVisibleSamplerHeap.heap.capacity);
3771QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptors(
const QVarLengthArray<Q_D3D12_SAMPLER_DESC, 8> &descs)
3777 auto it = gpuArrayMap.constFind({ descs });
3778 if (it != gpuArrayMap.cend())
3781 const quint32 count = quint32(descs.count());
3782 QD3D12Descriptor startDescriptor = shaderVisibleSamplerHeap.heap.get(count);
3783 if (startDescriptor.isValid()) {
3784 for (quint32 i = 0; i < count; ++i) {
3785 device->CreateSampler(&descs[
int(i)].desc,
3786 shaderVisibleSamplerHeap.heap.incremented(startDescriptor, i).cpuHandle);
3788 gpuArrayMap.insert({ descs }, startDescriptor);
3795 qWarning(
"Out of shader-visible SAMPLER descriptor heap space when reserving"
3796 " %u consecutive descriptors for a sampler array, maximum number of"
3797 " sampler descriptors is %u",
3798 count, shaderVisibleSamplerHeap.heap.capacity);
3801 return startDescriptor;
3804void QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
3809bool QD3D12MipmapGenerator::ensureCreated()
3811 if (!pipelineHandle.isNull())
3817 if (!buildPipeline()) {
3818 createFailed =
true;
3825bool QD3D12MipmapGenerator::buildPipeline()
3827 qCDebug(QRHI_LOG_INFO,
"Building mipmap generator compute pipeline on first use");
3829 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3830 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3833 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3834 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3835 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3838 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3839 descriptorRanges[0].NumDescriptors = 1;
3840 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3841 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3842 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3843 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3844 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3847 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3848 descriptorRanges[1].NumDescriptors = 4;
3849 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3850 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3851 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3852 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3855 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3856 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3857 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3858 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3859 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3860 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3862 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3863 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3864 rsDesc.Desc_1_1.NumParameters = 3;
3865 rsDesc.Desc_1_1.pParameters = rootParams;
3866 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3867 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3869 ID3DBlob *signature =
nullptr;
3870 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3872 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3875 ID3D12RootSignature *rootSig =
nullptr;
3876 hr = rhiD->dev->CreateRootSignature(0,
3877 signature->GetBufferPointer(),
3878 signature->GetBufferSize(),
3879 __uuidof(ID3D12RootSignature),
3880 reinterpret_cast<
void **>(&rootSig));
3881 signature->Release();
3883 qWarning(
"Failed to create root signature: %s",
3884 qPrintable(QSystemError::windowsComString(hr)));
3888 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3890 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3891 psoDesc.pRootSignature = rootSig;
3892 psoDesc.CS.pShaderBytecode = g_csMipmap;
3893 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap);
3894 ID3D12PipelineState *pso =
nullptr;
3895 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3896 __uuidof(ID3D12PipelineState),
3897 reinterpret_cast<
void **>(&pso));
3899 qWarning(
"Failed to create compute pipeline state: %s",
3900 qPrintable(QSystemError::windowsComString(hr)));
3901 rhiD->rootSignaturePool.remove(rootSigHandle);
3906 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3911void QD3D12MipmapGenerator::destroy()
3918 rhiD->pipelinePool.remove(pipelineHandle);
3919 pipelineHandle = {};
3920 rhiD->rootSignaturePool.remove(rootSigHandle);
3922 createFailed =
false;
3925void QD3D12MipmapGenerator::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3927 if (!ensureCreated())
3930 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3933 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3936 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3940 const quint32 mipLevelCount = res->desc.MipLevels;
3941 if (mipLevelCount < 2)
3944 if (res->desc.SampleDesc.Count > 1) {
3945 qWarning(
"Cannot generate mipmaps for MSAA texture");
3949 const bool is1D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D;
3951 qWarning(
"Cannot generate mipmaps for 1D texture");
3955 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3956 const bool isCubeOrArray = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
3957 && res->desc.DepthOrArraySize > 1;
3958 const quint32 layerCount = isCubeOrArray ? res->desc.DepthOrArraySize : 1;
3961 qWarning(
"2D mipmap generator invoked for 3D texture, this should not happen");
3965 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3966 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3968 cbD->cmdList->SetPipelineState(pipeline->pso);
3969 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3971 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3974 quint32 srcMipLevel;
3975 quint32 numMipLevels;
3980 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount * layerCount);
3981 std::optional<QD3D12StagingArea> ownStagingArea;
3982 rhiD->recordSmallStagingAreaDemand(allocSize);
3983 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3984 ownStagingArea = QD3D12StagingArea();
3985 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3986 qWarning(
"Could not create staging area for mipmap generation");
3990 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3991 ? &ownStagingArea.value()
3992 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3994 bool gotNewHeap =
false;
3995 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3996 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3997 rhiD->currentFrameSlot,
3998 (1 + 4) * mipLevelCount * layerCount,
4001 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
4005 rhiD->bindShaderVisibleHeaps(cbD);
4007 for (quint32 layer = 0; layer < layerCount; ++layer) {
4008 for (quint32 level = 0; level < mipLevelCount ;) {
4009 UINT subresource = calcSubresource(level, layer, res->desc.MipLevels);
4010 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4011 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
4012 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
4014 quint32 levelPlusOneMipWidth = res->desc.Width >> (level + 1);
4015 quint32 levelPlusOneMipHeight = res->desc.Height >> (level + 1);
4016 const quint32 dw = levelPlusOneMipWidth == 1 ? levelPlusOneMipHeight : levelPlusOneMipWidth;
4017 const quint32 dh = levelPlusOneMipHeight == 1 ? levelPlusOneMipWidth : levelPlusOneMipHeight;
4019 const quint32 additionalMips = qCountTrailingZeroBits(dw | dh);
4020 const quint32 numGenMips = qMin(1u + qMin(3u, additionalMips), res->desc.MipLevels - level);
4021 levelPlusOneMipWidth = qMax(1u, levelPlusOneMipWidth);
4022 levelPlusOneMipHeight = qMax(1u, levelPlusOneMipHeight);
4024 CBufData cbufData = {
4027 1.0f /
float(levelPlusOneMipWidth),
4028 1.0f /
float(levelPlusOneMipHeight)
4031 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
4032 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
4033 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
4035 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4036 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4037 srvDesc.Format = res->desc.Format;
4038 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4039 if (isCubeOrArray) {
4040 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
4041 srvDesc.Texture2DArray.MipLevels = res->desc.MipLevels;
4042 srvDesc.Texture2DArray.FirstArraySlice = layer;
4043 srvDesc.Texture2DArray.ArraySize = 1;
4045 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
4046 srvDesc.Texture2D.MipLevels = res->desc.MipLevels;
4048 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4049 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
4051 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(4);
4052 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
4054 for (quint32 uavIdx = 0; uavIdx < 4; ++uavIdx) {
4055 const quint32 uavMipLevel = qMin(level + 1u + uavIdx, res->desc.MipLevels - 1u);
4056 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
4057 uavDesc.Format = res->desc.Format;
4058 if (isCubeOrArray) {
4059 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
4060 uavDesc.Texture2DArray.MipSlice = uavMipLevel;
4061 uavDesc.Texture2DArray.FirstArraySlice = layer;
4062 uavDesc.Texture2DArray.ArraySize = 1;
4064 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
4065 uavDesc.Texture2D.MipSlice = uavMipLevel;
4067 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
4068 uavCpuHandle.ptr += descriptorByteSize;
4070 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
4072 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, 1);
4074 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
4075 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4076 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
4077 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4079 level += numGenMips;
4083 if (ownStagingArea.has_value())
4084 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
4087void QD3D12MipmapGenerator3D::create(QRhiD3D12 *rhiD)
4092bool QD3D12MipmapGenerator3D::ensureCreated()
4094 if (!pipelineHandle.isNull())
4100 if (!buildPipeline()) {
4101 createFailed =
true;
4108bool QD3D12MipmapGenerator3D::buildPipeline()
4110 qCDebug(QRHI_LOG_INFO,
"Building 3D texture mipmap generator compute pipeline on first use");
4112 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
4113 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
4116 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
4117 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4118 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
4121 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
4122 descriptorRanges[0].NumDescriptors = 1;
4123 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
4124 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
4125 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4126 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
4127 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
4130 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
4131 descriptorRanges[1].NumDescriptors = 1;
4132 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
4133 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4134 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
4135 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
4138 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
4139 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
4140 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4141 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4142 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4143 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4145 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
4146 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
4147 rsDesc.Desc_1_1.NumParameters = 3;
4148 rsDesc.Desc_1_1.pParameters = rootParams;
4149 rsDesc.Desc_1_1.NumStaticSamplers = 1;
4150 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
4152 ID3DBlob *signature =
nullptr;
4153 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
4155 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
4158 ID3D12RootSignature *rootSig =
nullptr;
4159 hr = rhiD->dev->CreateRootSignature(0,
4160 signature->GetBufferPointer(),
4161 signature->GetBufferSize(),
4162 __uuidof(ID3D12RootSignature),
4163 reinterpret_cast<
void **>(&rootSig));
4164 signature->Release();
4166 qWarning(
"Failed to create root signature: %s",
4167 qPrintable(QSystemError::windowsComString(hr)));
4171 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
4173 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
4174 psoDesc.pRootSignature = rootSig;
4175 psoDesc.CS.pShaderBytecode = g_csMipmap3D;
4176 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap3D);
4177 ID3D12PipelineState *pso =
nullptr;
4178 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
4179 __uuidof(ID3D12PipelineState),
4180 reinterpret_cast<
void **>(&pso));
4182 qWarning(
"Failed to create compute pipeline state: %s",
4183 qPrintable(QSystemError::windowsComString(hr)));
4184 rhiD->rootSignaturePool.remove(rootSigHandle);
4189 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
4194void QD3D12MipmapGenerator3D::destroy()
4199 rhiD->pipelinePool.remove(pipelineHandle);
4200 pipelineHandle = {};
4201 rhiD->rootSignaturePool.remove(rootSigHandle);
4203 createFailed =
false;
4206void QD3D12MipmapGenerator3D::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
4208 if (!ensureCreated())
4211 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
4214 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
4217 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
4221 const quint32 mipLevelCount = res->desc.MipLevels;
4222 if (mipLevelCount < 2)
4225 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
4227 qWarning(
"3D mipmap generator invoked for non-3D texture, this should not happen");
4231 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4232 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
4234 cbD->cmdList->SetPipelineState(pipeline->pso);
4235 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
4237 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
4243 quint32 srcMipLevel;
4246 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount);
4247 std::optional<QD3D12StagingArea> ownStagingArea;
4248 rhiD->recordSmallStagingAreaDemand(allocSize);
4249 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
4250 ownStagingArea = QD3D12StagingArea();
4251 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
4252 qWarning(
"Could not create staging area for mipmap generation");
4256 QD3D12StagingArea *workArea = ownStagingArea.has_value()
4257 ? &ownStagingArea.value()
4258 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
4260 bool gotNewHeap =
false;
4261 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
4262 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
4263 rhiD->currentFrameSlot,
4264 (1 + 1) * mipLevelCount,
4267 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
4271 rhiD->bindShaderVisibleHeaps(cbD);
4273 for (quint32 level = 0; level < mipLevelCount; ++level) {
4274 UINT subresource = calcSubresource(level, 0u, res->desc.MipLevels);
4275 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4276 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
4277 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
4279 quint32 levelPlusOneMipWidth = qMax<quint32>(1, res->desc.Width >> (level + 1));
4280 quint32 levelPlusOneMipHeight = qMax<quint32>(1, res->desc.Height >> (level + 1));
4281 quint32 levelPlusOneMipDepth = qMax<quint32>(1, res->desc.DepthOrArraySize >> (level + 1));
4283 CBufData cbufData = {
4284 1.0f /
float(levelPlusOneMipWidth),
4285 1.0f /
float(levelPlusOneMipHeight),
4286 1.0f /
float(levelPlusOneMipDepth),
4290 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
4291 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
4292 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
4294 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4295 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4296 srvDesc.Format = res->desc.Format;
4297 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4298 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4299 srvDesc.Texture3D.MipLevels = res->desc.MipLevels;
4301 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4302 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
4304 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4305 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
4306 const quint32 uavMipLevel = qMin(level + 1u, res->desc.MipLevels - 1u);
4307 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
4308 uavDesc.Format = res->desc.Format;
4309 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
4310 uavDesc.Texture3D.MipSlice = uavMipLevel;
4311 uavDesc.Texture3D.WSize = UINT(-1);
4312 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
4313 uavCpuHandle.ptr += descriptorByteSize;
4314 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
4316 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, levelPlusOneMipDepth);
4318 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
4319 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4320 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
4321 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4324 if (ownStagingArea.has_value())
4325 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
4328bool QD3D12MemoryAllocator::create(ID3D12Device *device, IDXGIAdapter1 *adapter)
4330 this->device = device;
4337 static bool disableMA = qEnvironmentVariableIntValue(
"QT_D3D_NO_SUBALLOC");
4341 DXGI_ADAPTER_DESC1 desc;
4342 adapter->GetDesc1(&desc);
4343 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
4346 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
4347 allocatorDesc.pDevice = device;
4348 allocatorDesc.pAdapter = adapter;
4351 allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED;
4352 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
4354 qWarning(
"Failed to initialize D3D12 Memory Allocator: %s",
4355 qPrintable(QSystemError::windowsComString(hr)));
4361void QD3D12MemoryAllocator::destroy()
4364 allocator->Release();
4365 allocator =
nullptr;
4369HRESULT QD3D12MemoryAllocator::createResource(D3D12_HEAP_TYPE heapType,
4370 const D3D12_RESOURCE_DESC *resourceDesc,
4371 D3D12_RESOURCE_STATES initialState,
4372 const D3D12_CLEAR_VALUE *optimizedClearValue,
4373 D3D12MA::Allocation **maybeAllocation,
4374 REFIID riidResource,
4378 D3D12MA::ALLOCATION_DESC allocDesc = {};
4379 allocDesc.HeapType = heapType;
4380 return allocator->CreateResource(&allocDesc,
4383 optimizedClearValue,
4388 *maybeAllocation =
nullptr;
4389 D3D12_HEAP_PROPERTIES heapProps = {};
4390 heapProps.Type = heapType;
4391 return device->CreateCommittedResource(&heapProps,
4392 D3D12_HEAP_FLAG_NONE,
4395 optimizedClearValue,
4401void QD3D12MemoryAllocator::getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget)
4404 allocator->GetBudget(localBudget, nonLocalBudget);
4407 *nonLocalBudget = {};
4411void QRhiD3D12::waitGpu()
4413 fullFenceCounter += 1u;
4414 if (SUCCEEDED(cmdQueue->Signal(fullFence, fullFenceCounter))) {
4415 if (SUCCEEDED(fullFence->SetEventOnCompletion(fullFenceCounter, fullFenceEvent)))
4416 WaitForSingleObject(fullFenceEvent, INFINITE);
4420DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleDesc(
int sampleCount, DXGI_FORMAT format)
const
4422 DXGI_SAMPLE_DESC desc;
4426 const int s = effectiveSampleCount(sampleCount);
4429 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
4430 msaaInfo.Format = format;
4431 msaaInfo.SampleCount = UINT(s);
4432 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo,
sizeof(msaaInfo)))) {
4433 if (msaaInfo.NumQualityLevels > 0) {
4434 desc.Count = UINT(s);
4435 desc.Quality = msaaInfo.NumQualityLevels - 1;
4437 qWarning(
"No quality levels for multisampling with sample count %d", s);
4445bool QRhiD3D12::startCommandListForCurrentFrameSlot(D3D12GraphicsCommandList **cmdList)
4447 ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
4449 HRESULT hr = dev->CreateCommandList(0,
4450 D3D12_COMMAND_LIST_TYPE_DIRECT,
4453 __uuidof(D3D12GraphicsCommandList),
4454 reinterpret_cast<
void **>(cmdList));
4456 qWarning(
"Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
4460 HRESULT hr = (*cmdList)->Reset(cmdAlloc,
nullptr);
4462 qWarning(
"Failed to reset command list: %s", qPrintable(QSystemError::windowsComString(hr)));
4469static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
4472 case DXGI_FORMAT_R8G8B8A8_UNORM:
4473 return QRhiTexture::RGBA8;
4474 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
4476 (*flags) |= QRhiTexture::sRGB;
4477 return QRhiTexture::RGBA8;
4478 case DXGI_FORMAT_B8G8R8A8_UNORM:
4479 return QRhiTexture::BGRA8;
4480 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
4482 (*flags) |= QRhiTexture::sRGB;
4483 return QRhiTexture::BGRA8;
4484 case DXGI_FORMAT_R16G16B16A16_FLOAT:
4485 return QRhiTexture::RGBA16F;
4486 case DXGI_FORMAT_R32G32B32A32_FLOAT:
4487 return QRhiTexture::RGBA32F;
4488 case DXGI_FORMAT_R10G10B10A2_UNORM:
4489 return QRhiTexture::RGB10A2;
4491 qWarning(
"DXGI_FORMAT %d cannot be read back", format);
4494 return QRhiTexture::UnknownFormat;
4497static inline bool isDepthTextureFormat(QRhiTexture::Format format)
4500 case QRhiTexture::Format::D16:
4501 case QRhiTexture::Format::D24:
4502 case QRhiTexture::Format::D24S8:
4503 case QRhiTexture::Format::D32F:
4504 case QRhiTexture::Format::D32FS8:
4511void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
4513 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
4515 for (
int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
4516 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
4517 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
4518 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4519 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4520 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4521 if (u.offset == 0 && u.data.size() == bufD->m_size)
4522 bufD->pendingHostWrites[i].clear();
4523 bufD->pendingHostWrites[i].append({ u.offset, u.data });
4525 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
4526 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4527 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4528 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
4536 QD3D12StagingArea::Allocation stagingAlloc;
4537 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(bufD->m_size, 1);
4538 recordSmallStagingAreaDemand(allocSize);
4539 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
4540 stagingAlloc = smallStagingAreas[currentFrameSlot].get(bufD->m_size);
4542 std::optional<QD3D12StagingArea> ownStagingArea;
4543 if (!stagingAlloc.isValid()) {
4544 ownStagingArea = QD3D12StagingArea();
4545 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
4547 stagingAlloc = ownStagingArea->get(allocSize);
4548 if (!stagingAlloc.isValid()) {
4549 ownStagingArea->destroy();
4554 memcpy(stagingAlloc.p + u.offset, u.data.constData(), u.data.size());
4556 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
4557 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4559 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
4560 cbD->cmdList->CopyBufferRegion(res->resource,
4562 stagingAlloc.buffer,
4563 stagingAlloc.bufferOffset + u.offset,
4567 if (ownStagingArea.has_value())
4568 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4569 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
4570 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4571 if (bufD->m_type == QRhiBuffer::Dynamic) {
4572 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
4573 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[currentFrameSlot])) {
4574 Q_ASSERT(res->cpuMapPtr);
4575 u.result->data.resize(u.readSize);
4576 memcpy(u.result->data.data(),
reinterpret_cast<
char *>(res->cpuMapPtr) + u.offset, u.readSize);
4578 if (u.result->completed)
4579 u.result->completed();
4581 QD3D12Readback readback;
4582 readback.frameSlot = currentFrameSlot;
4583 readback.result = u.result;
4584 readback.byteSize = u.readSize;
4585 const quint32 allocSize = aligned(u.readSize, QD3D12StagingArea::ALIGNMENT);
4586 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
4587 if (u.result->completed)
4588 u.result->completed();
4591 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(u.readSize);
4592 if (!stagingAlloc.isValid()) {
4593 readback.staging.destroy();
4594 if (u.result->completed)
4595 u.result->completed();
4598 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4599 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
4600 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4601 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
4602 cbD->cmdList->CopyBufferRegion(stagingAlloc.buffer, 0, res->resource, u.offset, u.readSize);
4603 activeReadbacks.append(readback);
4605 readback.staging.destroy();
4606 if (u.result->completed)
4607 u.result->completed();
4610 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Copy) {
4611 QD3D12Buffer *dstD = QRHI_RES(QD3D12Buffer, u.buf);
4612 QD3D12Buffer *srcD = QRHI_RES(QD3D12Buffer, u.src);
4613 Q_ASSERT(dstD->m_type != QRhiBuffer::Dynamic && srcD->m_type != QRhiBuffer::Dynamic);
4615 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handles[0]);
4616 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handles[0]);
4617 if (!dstRes || !srcRes)
4620 barrierGen.addTransitionBarrier(srcD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
4621 barrierGen.addTransitionBarrier(dstD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
4622 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4624 cbD->cmdList->CopyBufferRegion(dstRes->resource, u.offset,
4625 srcRes->resource, u.srcOffset,
4627 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Clear) {
4628 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4629 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4631 QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0]);
4635 bool gotNewHeap =
false;
4636 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
4637 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
4638 currentFrameSlot, 1, &gotNewHeap))
4643 bindShaderVisibleHeaps(cbD);
4645 const QD3D12Descriptor cpuDesc = cbvSrvUavPool.allocate(1);
4646 if (!cpuDesc.isValid())
4648 const QD3D12Descriptor gpuDesc = shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].get(1);
4651 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
4652 uavDesc.Format = DXGI_FORMAT_R32_UINT;
4653 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
4654 uavDesc.Buffer.FirstElement = u.offset / 4u;
4655 uavDesc.Buffer.NumElements = u.readSize / 4u;
4656 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, cpuDesc.cpuHandle);
4657 dev->CopyDescriptorsSimple(1, gpuDesc.cpuHandle, cpuDesc.cpuHandle,
4658 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
4660 if (res->state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS && res->uavUsage)
4661 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
4662 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4663 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4665 const UINT values[4] = { u.fillValue32(), u.fillValue32(), u.fillValue32(), u.fillValue32() };
4666 cbD->cmdList->ClearUnorderedAccessViewUint(gpuDesc.gpuHandle, cpuDesc.cpuHandle,
4667 res->resource, values, 0,
nullptr);
4669 res->uavUsage = QD3D12Resource::UavUsageWrite;
4671 releaseQueue.deferredReleaseViews(&cbvSrvUavPool, cpuDesc, 1);
4675 for (
int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
4676 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
4677 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
4678 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4679 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4680 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
4683 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4684 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4685 for (
const auto &subres : u.subresDesc) {
4686 const int layer = subres.layer;
4687 const int level = subres.level;
4688 const QRhiTextureSubresourceUploadDescription &subresDesc(subres.desc);
4689 D3D12_SUBRESOURCE_FOOTPRINT footprint = {};
4690 footprint.Format = res->desc.Format;
4691 footprint.Depth = 1;
4692 quint32 totalBytes = 0;
4694 QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
4695 : subresDesc.sourceSize();
4696 const QPoint srcPos = subresDesc.sourceTopLeft();
4697 QPoint dstPos = subresDesc.destinationTopLeft();
4699 if (subresDesc.image().isNull()
4700 && !subresDesc.data().isEmpty()
4701 && !isCompressedFormat(texD->m_format))
4703 subresSize = clampedSubResourceUploadSize(subresSize, dstPos, level, texD->m_pixelSize);
4704 quint32 bytesPerPixel = 0;
4705 textureFormatInfo(texD->m_format, subresSize,
nullptr,
nullptr, &bytesPerPixel);
4706 subresSize = clampedSubResourceUploadSizeForSourceData(subresSize,
4707 subresDesc.dataStride(),
4709 subresDesc.data().size());
4710 if (subresSize.isEmpty())
4714 if (!subresDesc.image().isNull()) {
4715 const QImage img = subresDesc.image();
4716 const int bpl = img.bytesPerLine();
4717 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4718 totalBytes = footprint.RowPitch * img.height();
4719 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
4722 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
4723 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4724 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
4725 totalBytes = footprint.RowPitch * rowCount;
4726 }
else if (!subresDesc.data().isEmpty()) {
4728 if (subresDesc.dataStride())
4729 bpl = subresDesc.dataStride();
4731 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4732 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4733 totalBytes = footprint.RowPitch * subresSize.height();
4735 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4739 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(totalBytes, 1);
4740 QD3D12StagingArea::Allocation stagingAlloc;
4741 recordSmallStagingAreaDemand(allocSize);
4742 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
4743 stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
4745 std::optional<QD3D12StagingArea> ownStagingArea;
4746 if (!stagingAlloc.isValid()) {
4747 ownStagingArea = QD3D12StagingArea();
4748 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
4750 stagingAlloc = ownStagingArea->get(allocSize);
4751 if (!stagingAlloc.isValid()) {
4752 ownStagingArea->destroy();
4757 D3D12_TEXTURE_COPY_LOCATION dst;
4758 dst.pResource = res->resource;
4759 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4760 dst.SubresourceIndex = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
4761 D3D12_TEXTURE_COPY_LOCATION src;
4762 src.pResource = stagingAlloc.buffer;
4763 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4764 src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
4768 if (!subresDesc.image().isNull()) {
4769 const QImage img = subresDesc.image();
4770 const int bpc = qMax(1, img.depth() / 8);
4771 const int bpl = img.bytesPerLine();
4773 QSize size = subresDesc.sourceSize().isEmpty() ? img.size() : subresDesc.sourceSize();
4774 size.setWidth(qMin(size.width(), img.width() - srcPos.x()));
4775 size.setHeight(qMin(size.height(), img.height() - srcPos.y()));
4776 size = clampedSubResourceUploadSize(size, dstPos, level, texD->m_pixelSize);
4778 footprint.Width = size.width();
4779 footprint.Height = size.height();
4783 srcBox.right = UINT(size.width());
4784 srcBox.bottom = UINT(size.height());
4788 const uchar *imgPtr = img.constBits();
4789 const quint32 lineBytes = size.width() * bpc;
4790 for (
int y = 0, h = size.height(); y < h; ++y) {
4791 memcpy(stagingAlloc.p + y * footprint.RowPitch,
4792 imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
4795 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
4798 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
4800 dstPos.setX(aligned(dstPos.x(), blockDim.width()));
4801 dstPos.setY(aligned(dstPos.y(), blockDim.height()));
4806 srcBox.right = aligned(subresSize.width(), blockDim.width());
4807 srcBox.bottom = aligned(subresSize.height(), blockDim.height());
4812 footprint.Width = aligned(subresSize.width(), blockDim.width());
4813 footprint.Height = aligned(subresSize.height(), blockDim.height());
4815 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4816 const QByteArray imgData = subresDesc.data();
4817 const char *imgPtr = imgData.constData();
4818 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
4819 for (
int y = 0; y < rowCount; ++y) {
4820 const quint64 srcOffset = quint64(y) * bpl;
4821 if (srcOffset >= quint64(imgData.size()))
4823 const quint32 n = quint32(qMin(quint64(copyBytes),
4824 quint64(imgData.size()) - srcOffset));
4825 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + srcOffset, n);
4827 }
else if (!subresDesc.data().isEmpty()) {
4830 srcBox.right = subresSize.width();
4831 srcBox.bottom = subresSize.height();
4835 footprint.Width = subresSize.width();
4836 footprint.Height = subresSize.height();
4839 if (subresDesc.dataStride())
4840 bpl = subresDesc.dataStride();
4842 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4844 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4845 const QByteArray data = subresDesc.data();
4846 const char *imgPtr = data.constData();
4847 for (
int y = 0, h = subresSize.height(); y < h; ++y) {
4852 const quint64 srcOffset = quint64(y) * bpl;
4853 if (srcOffset >= quint64(data.size()))
4855 const quint32 n = quint32(qMin(quint64(copyBytes),
4856 quint64(data.size()) - srcOffset));
4857 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + srcOffset, n);
4861 src.PlacedFootprint.Footprint = footprint;
4863 cbD->cmdList->CopyTextureRegion(&dst,
4866 is3D ? UINT(layer) : 0u,
4870 if (ownStagingArea.has_value())
4871 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4873 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
4874 Q_ASSERT(u.src && u.dst);
4875 QD3D12Texture *srcD = QRHI_RES(QD3D12Texture, u.src);
4876 QD3D12Texture *dstD = QRHI_RES(QD3D12Texture, u.dst);
4877 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4878 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4879 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
4880 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
4881 if (!srcRes || !dstRes)
4884 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4885 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4886 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4888 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
4889 srcIs3D ? 0u : UINT(u.desc.sourceLayer()),
4890 srcD->mipLevelCount);
4891 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
4892 dstIs3D ? 0u : UINT(u.desc.destinationLayer()),
4893 dstD->mipLevelCount);
4894 const QPoint dp = u.desc.destinationTopLeft();
4895 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4896 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4897 const QPoint sp = u.desc.sourceTopLeft();
4900 srcBox.left = UINT(sp.x());
4901 srcBox.top = UINT(sp.y());
4902 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
4904 srcBox.right = srcBox.left + UINT(copySize.width());
4905 srcBox.bottom = srcBox.top + UINT(copySize.height());
4906 srcBox.back = srcBox.front + 1;
4908 D3D12_TEXTURE_COPY_LOCATION src;
4909 src.pResource = srcRes->resource;
4910 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4911 src.SubresourceIndex = srcSubresource;
4912 D3D12_TEXTURE_COPY_LOCATION dst;
4913 dst.pResource = dstRes->resource;
4914 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4915 dst.SubresourceIndex = dstSubresource;
4917 cbD->cmdList->CopyTextureRegion(&dst,
4920 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
4923 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
4924 QD3D12Readback readback;
4925 readback.frameSlot = currentFrameSlot;
4926 readback.result = u.result;
4928 QD3D12ObjectHandle srcHandle;
4931 if (u.rb.texture()) {
4932 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.rb.texture());
4933 if (texD->sampleDesc.Count > 1) {
4934 qWarning(
"Multisample texture cannot be read back");
4937 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4938 const QRect levelRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4939 readback.format = texD->m_format;
4940 rect = u.rb.rect().isValid() ? u.rb.rect() : levelRect;
4941 if (isDepthTextureFormat(readback.format)) {
4946 rect = rect.intersected(levelRect);
4947 readback.cropOrigin = rect.topLeft();
4949 srcHandle = texD->handle;
4951 Q_ASSERT(currentSwapChain);
4952 if (u.rb.rect().isValid())
4955 rect = QRect({0, 0}, currentSwapChain->pixelSize);
4956 readback.format = swapchainReadbackTextureFormat(currentSwapChain->colorFormat,
nullptr);
4957 if (readback.format == QRhiTexture::UnknownFormat)
4959 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
4961 readback.pixelSize = rect.size();
4963 textureFormatInfo(readback.format,
4965 &readback.bytesPerLine,
4967 &readback.bytesPerPixel);
4969 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
4980 const bool combinedDepthStencil = u.rb.texture() && isStencilSupportingFormat(readback.format);
4981 const bool depthTexture = u.rb.texture() && isDepthTextureFormat(readback.format);
4983 const UINT subresource = calcSubresource(UINT(u.rb.level()),
4984 is3D ? 0u : UINT(u.rb.layer()),
4985 srcRes->desc.MipLevels);
4986 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
4989 UINT64 totalBytes = 0;
4990 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
4991 &layout,
nullptr,
nullptr, &totalBytes);
4992 readback.stagingRowPitch = layout.Footprint.RowPitch;
4994 UINT stencilSubresource = 0;
4995 D3D12_PLACED_SUBRESOURCE_FOOTPRINT stencilLayout;
4996 UINT64 stencilTotalBytes = 0;
4997 if (combinedDepthStencil) {
4998 stencilSubresource = subresource
4999 + srcRes->desc.MipLevels * UINT(srcRes->desc.DepthOrArraySize);
5000 dev->GetCopyableFootprints(&srcRes->desc, stencilSubresource, 1, 0,
5001 &stencilLayout,
nullptr,
nullptr, &stencilTotalBytes);
5002 readback.stencilStagingRowPitch = stencilLayout.Footprint.RowPitch;
5005 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT)
5006 + (combinedDepthStencil ? aligned<quint32>(stencilTotalBytes, QD3D12StagingArea::ALIGNMENT) : 0);
5007 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
5008 if (u.result->completed)
5009 u.result->completed();
5012 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
5013 QD3D12StagingArea::Allocation stencilStagingAlloc;
5014 if (combinedDepthStencil)
5015 stencilStagingAlloc = readback.staging.get(stencilTotalBytes);
5016 if (!stagingAlloc.isValid() || (combinedDepthStencil && !stencilStagingAlloc.isValid())) {
5017 readback.staging.destroy();
5018 if (u.result->completed)
5019 u.result->completed();
5022 Q_ASSERT(stagingAlloc.bufferOffset == 0);
5023 readback.stencilStagingOffset = stencilStagingAlloc.bufferOffset;
5025 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
5026 barrierGen.enqueueBufferedTransitionBarriers(cbD);
5028 D3D12_TEXTURE_COPY_LOCATION dst;
5029 dst.pResource = stagingAlloc.buffer;
5030 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
5031 dst.PlacedFootprint.Offset = 0;
5032 dst.PlacedFootprint.Footprint = layout.Footprint;
5034 D3D12_TEXTURE_COPY_LOCATION src;
5035 src.pResource = srcRes->resource;
5036 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
5037 src.SubresourceIndex = subresource;
5039 D3D12_BOX srcBox = {};
5040 srcBox.left = UINT(rect.left());
5041 srcBox.top = UINT(rect.top());
5042 srcBox.front = is3D ? UINT(u.rb.layer()) : 0u;
5044 srcBox.right = srcBox.left + UINT(rect.width());
5045 srcBox.bottom = srcBox.top + UINT(rect.height());
5046 srcBox.back = srcBox.front + 1;
5049 const D3D12_BOX *srcBoxPtr = depthTexture ?
nullptr : &srcBox;
5051 cbD->cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, srcBoxPtr);
5053 if (combinedDepthStencil) {
5054 D3D12_TEXTURE_COPY_LOCATION stencilDst;
5055 stencilDst.pResource = stencilStagingAlloc.buffer;
5056 stencilDst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
5057 stencilDst.PlacedFootprint.Offset = stencilStagingAlloc.bufferOffset;
5058 stencilDst.PlacedFootprint.Footprint = stencilLayout.Footprint;
5060 D3D12_TEXTURE_COPY_LOCATION stencilSrc;
5061 stencilSrc.pResource = srcRes->resource;
5062 stencilSrc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
5063 stencilSrc.SubresourceIndex = stencilSubresource;
5065 cbD->cmdList->CopyTextureRegion(&stencilDst, 0, 0, 0, &stencilSrc, srcBoxPtr);
5068 activeReadbacks.append(readback);
5069 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
5070 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
5071 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
5077 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
5078 if (res && texD->mipLevelCount >= 2
5079 && (res->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET))
5081 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
5082 const UINT layerCount = is3D ? 1u : UINT(res->desc.DepthOrArraySize);
5083 QBitArray &initialized(texD->subresourceInitialized);
5084 QVarLengthArray<UINT, 16> subresourcesToDiscard;
5085 for (UINT layer = 0; layer < layerCount; ++layer) {
5086 for (UINT level = 1; level < texD->mipLevelCount; ++level) {
5087 const UINT subresource = calcSubresource(level, layer, texD->mipLevelCount);
5088 if (
int(subresource) >= initialized.size())
5089 initialized.resize(
int(subresource) + 1);
5090 if (!initialized.testBit(
int(subresource))) {
5091 initialized.setBit(
int(subresource));
5092 subresourcesToDiscard.append(subresource);
5096 if (!subresourcesToDiscard.isEmpty()) {
5098 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
5099 barrierGen.enqueueBufferedTransitionBarriers(cbD);
5100 for (UINT subresource : subresourcesToDiscard) {
5101 D3D12_DISCARD_REGION region = {};
5102 region.FirstSubresource = subresource;
5103 region.NumSubresources = 1;
5104 cbD->cmdList->DiscardResource(res->resource, ®ion);
5109 if (texD->flags().testFlag(QRhiTexture::ThreeDimensional))
5110 mipmapGen3D.generate(cbD, texD->handle);
5112 mipmapGen.generate(cbD, texD->handle);
5119void QRhiD3D12::finishActiveReadbacks(
bool forced)
5121 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
5123 for (
int i = activeReadbacks.size() - 1; i >= 0; --i) {
5124 QD3D12Readback &readback(activeReadbacks[i]);
5125 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
5126 readback.result->format = readback.format;
5127 readback.result->pixelSize = readback.pixelSize;
5128 readback.result->data.resize(
int(readback.byteSize));
5130 if (readback.format != QRhiTexture::UnknownFormat) {
5131 if (isStencilSupportingFormat(readback.format)) {
5143 const quint8 *depthBase = readback.staging.mem.p
5144 + readback.cropOrigin.y() * readback.stagingRowPitch
5145 + readback.cropOrigin.x() * 4;
5146 const quint8 *stencilBase = readback.staging.mem.p + readback.stencilStagingOffset
5147 + readback.cropOrigin.y() * readback.stencilStagingRowPitch
5148 + readback.cropOrigin.x();
5149 char *dst = readback.result->data.data();
5150 const int w = readback.pixelSize.width();
5151 const int h = readback.pixelSize.height();
5152 if (readback.format == QRhiTexture::D32FS8) {
5155 for (
int y = 0; y < h; ++y) {
5156 const quint8 *depthRow = depthBase + y * readback.stagingRowPitch;
5157 const quint8 *stencilRow = stencilBase + y * readback.stencilStagingRowPitch;
5158 for (
int x = 0; x < w; ++x) {
5159 const quint32 stencilWord = stencilRow[x];
5160 char *dstPixel = dst + (y * w + x) * 8;
5161 memcpy(dstPixel, depthRow + x * 4,
sizeof(quint32));
5162 memcpy(dstPixel + 4, &stencilWord,
sizeof(quint32));
5168 for (
int y = 0; y < h; ++y) {
5169 const quint8 *depthRow = depthBase + y * readback.stagingRowPitch;
5170 const quint8 *stencilRow = stencilBase + y * readback.stencilStagingRowPitch;
5171 for (
int x = 0; x < w; ++x) {
5176 memcpy(&depthWord, depthRow + x * 4,
sizeof(quint32));
5177 const quint32 combined = ((depthWord & 0x00FFFFFFu) << 8) | stencilRow[x];
5178 memcpy(dst + (y * w + x) * 4, &combined,
sizeof(quint32));
5183 quint8 *dstPtr =
reinterpret_cast<quint8 *>(readback.result->data.data());
5184 const quint8 *srcPtr = readback.staging.mem.p
5185 + readback.cropOrigin.y() * readback.stagingRowPitch
5186 + readback.cropOrigin.x() * readback.bytesPerPixel;
5187 const quint32 lineSize = qMin(readback.bytesPerLine, readback.stagingRowPitch);
5188 for (
int y = 0, h = readback.pixelSize.height(); y < h; ++y)
5189 memcpy(dstPtr + y * readback.bytesPerLine, srcPtr + y * readback.stagingRowPitch, lineSize);
5190 if (readback.format == QRhiTexture::D24) {
5194 char *p = readback.result->data.data();
5195 for (qsizetype px = 0, count = readback.result->data.size() / 4; px < count; ++px)
5196 qToUnaligned((qFromUnaligned<quint32>(p + px * 4) & 0x00FFFFFFu) << 8, p + px * 4);
5200 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
5203 readback.staging.destroy();
5205 if (readback.result->completed)
5206 completedCallbacks.append(readback.result->completed);
5208 activeReadbacks.remove(i);
5212 for (
auto f : completedCallbacks)
5216bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
5217 D3D12_DESCRIPTOR_HEAP_TYPE type,
5219 quint32 neededDescriptorCount,
5227 if (h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
5228 const quint32 newPerFrameSize = qMax(h->perFrameHeapSlice[frameSlot].capacity * 2,
5229 neededDescriptorCount);
5230 QD3D12ShaderVisibleDescriptorHeap newHeap;
5231 if (!newHeap.create(dev, type, newPerFrameSize)) {
5232 qWarning(
"Could not create new shader-visible descriptor heap");
5235 h->destroyWithDeferredRelease(&releaseQueue);
5242void QRhiD3D12::resetAndResizeSmallStagingArea(
int frameSlot)
5244 QD3D12StagingArea &area(smallStagingAreas[frameSlot]);
5250 const quint32 needed = smallStagingAreaBytesNeeded[frameSlot];
5251 smallStagingAreaBytesNeeded[frameSlot] = 0;
5253 quint32 newCapacity = 0;
5254 if (needed > area.capacity) {
5257 smallStagingAreaLowDemandFrames[frameSlot] = 0;
5258 newCapacity = qMin(qNextPowerOfTwo(needed), SMALL_STAGING_AREA_BYTES_PER_FRAME_MAX);
5259 }
else if (needed <= area.capacity / 4 && area.capacity > SMALL_STAGING_AREA_BYTES_PER_FRAME_START) {
5260 if (++smallStagingAreaLowDemandFrames[frameSlot] >= SMALL_STAGING_AREA_LOW_DEMAND_FRAMES) {
5261 smallStagingAreaLowDemandFrames[frameSlot] = 0;
5262 newCapacity = qMax(area.capacity / 2, SMALL_STAGING_AREA_BYTES_PER_FRAME_START);
5265 smallStagingAreaLowDemandFrames[frameSlot] = 0;
5268 if (newCapacity && newCapacity != area.capacity) {
5269 QD3D12StagingArea newArea;
5270 if (newArea.create(
this, aligned(newCapacity, QD3D12StagingArea::ALIGNMENT), D3D12_HEAP_TYPE_UPLOAD)) {
5271 area.destroyWithDeferredRelease(&releaseQueue);
5273 QString decoratedName = QLatin1String(
"Small staging area buffer/");
5274 decoratedName += QString::number(frameSlot);
5275 area.mem.buffer->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
5284void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
5286 ID3D12DescriptorHeap *heaps[] = {
5287 shaderVisibleCbvSrvUavHeap.heap.heap,
5288 samplerMgr.shaderVisibleSamplerHeap.heap.heap
5290 cbD->cmdList->SetDescriptorHeaps(2, heaps);
5293QD3D12Buffer::QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
5294 : QRhiBuffer(rhi, type, usage, size)
5298QD3D12Buffer::~QD3D12Buffer()
5303void QD3D12Buffer::destroy()
5305 if (handles[0].isNull())
5308 QRHI_RES_RHI(QRhiD3D12);
5317 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
5319 rhiD->releaseQueue.deferredReleaseResource(handles[i]);
5321 pendingHostWrites[i].clear();
5325 rhiD->unregisterResource(
this);
5328bool QD3D12Buffer::create()
5330 if (!handles[0].isNull())
5333 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
5334 qWarning(
"UniformBuffer must always be Dynamic");
5338 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
5339 qWarning(
"StorageBuffer cannot be combined with Dynamic");
5343 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
5344 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
5346 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
5347 if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
5348 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5350 QRHI_RES_RHI(QRhiD3D12);
5352 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
5353 if (i == 0 || m_type == Dynamic) {
5354 D3D12_RESOURCE_DESC resourceDesc = {};
5355 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
5356 resourceDesc.Width = roundedSize;
5357 resourceDesc.Height = 1;
5358 resourceDesc.DepthOrArraySize = 1;
5359 resourceDesc.MipLevels = 1;
5360 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
5361 resourceDesc.SampleDesc = { 1, 0 };
5362 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
5363 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
5364 ID3D12Resource *resource =
nullptr;
5365 D3D12MA::Allocation *allocation =
nullptr;
5367 D3D12_HEAP_TYPE heapType = m_type == Dynamic
5368 ? D3D12_HEAP_TYPE_UPLOAD
5369 : D3D12_HEAP_TYPE_DEFAULT;
5370 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
5371 ? D3D12_RESOURCE_STATE_GENERIC_READ
5372 : D3D12_RESOURCE_STATE_COMMON;
5373 hr = rhiD->vma.createResource(heapType,
5379 reinterpret_cast<
void **>(&resource));
5382 if (!m_objectName.isEmpty()) {
5383 QString decoratedName = QString::fromUtf8(m_objectName);
5384 if (m_type == Dynamic) {
5385 decoratedName += QLatin1Char(
'/');
5386 decoratedName += QString::number(i);
5388 resource->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
5390 void *cpuMemPtr =
nullptr;
5391 if (m_type == Dynamic) {
5393 hr = resource->Map(0,
nullptr, &cpuMemPtr);
5395 qWarning(
"Map() failed to dynamic buffer");
5396 resource->Release();
5398 allocation->Release();
5402 handles[i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
5410 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
5411 qPrintable(QSystemError::windowsComString(hr)),
5414 int(rhiD->vma.isUsingD3D12MA()));
5419 rhiD->registerResource(
this);
5423QRhiBuffer::NativeBuffer QD3D12Buffer::nativeBuffer()
5426 Q_ASSERT(
sizeof(b.objects) /
sizeof(b.objects[0]) >= size_t(QD3D12_FRAMES_IN_FLIGHT));
5427 QRHI_RES_RHI(QRhiD3D12);
5428 if (m_type == Dynamic) {
5429 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
5430 executeHostWritesForFrameSlot(i);
5431 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[i]))
5432 b.objects[i] = res->resource;
5434 b.objects[i] =
nullptr;
5436 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
5439 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[0]))
5440 b.objects[0] = res->resource;
5442 b.objects[0] =
nullptr;
5447char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
5455 Q_ASSERT(m_type == Dynamic);
5456 QRHI_RES_RHI(QRhiD3D12);
5457 Q_ASSERT(rhiD->inFrame);
5458 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
5459 return static_cast<
char *>(res->cpuMapPtr);
5464void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
5469void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
5471 if (pendingHostWrites[frameSlot].isEmpty())
5474 Q_ASSERT(m_type == QRhiBuffer::Dynamic);
5475 QRHI_RES_RHI(QRhiD3D12);
5476 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
5477 Q_ASSERT(res->cpuMapPtr);
5478 for (
const QD3D12Buffer::HostWrite &u : std::as_const(pendingHostWrites[frameSlot]))
5479 memcpy(
static_cast<
char *>(res->cpuMapPtr) + u.offset, u.data.constData(), u.data.size());
5481 pendingHostWrites[frameSlot].clear();
5484static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
5486 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
5488 case QRhiTexture::RGBA8:
5489 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
5490 case QRhiTexture::BGRA8:
5491 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
5492 case QRhiTexture::R8:
5493 return DXGI_FORMAT_R8_UNORM;
5494 case QRhiTexture::R8SI:
5495 return DXGI_FORMAT_R8_SINT;
5496 case QRhiTexture::R8UI:
5497 return DXGI_FORMAT_R8_UINT;
5498 case QRhiTexture::RG8:
5499 return DXGI_FORMAT_R8G8_UNORM;
5500 case QRhiTexture::R16:
5501 return DXGI_FORMAT_R16_UNORM;
5502 case QRhiTexture::RG16:
5503 return DXGI_FORMAT_R16G16_UNORM;
5504 case QRhiTexture::RED_OR_ALPHA8:
5505 return DXGI_FORMAT_R8_UNORM;
5507 case QRhiTexture::RGBA16F:
5508 return DXGI_FORMAT_R16G16B16A16_FLOAT;
5509 case QRhiTexture::RGBA32F:
5510 return DXGI_FORMAT_R32G32B32A32_FLOAT;
5511 case QRhiTexture::R16F:
5512 return DXGI_FORMAT_R16_FLOAT;
5513 case QRhiTexture::R32F:
5514 return DXGI_FORMAT_R32_FLOAT;
5516 case QRhiTexture::RGB10A2:
5517 return DXGI_FORMAT_R10G10B10A2_UNORM;
5519 case QRhiTexture::R32SI:
5520 return DXGI_FORMAT_R32_SINT;
5521 case QRhiTexture::R32UI:
5522 return DXGI_FORMAT_R32_UINT;
5523 case QRhiTexture::RG32SI:
5524 return DXGI_FORMAT_R32G32_SINT;
5525 case QRhiTexture::RG32UI:
5526 return DXGI_FORMAT_R32G32_UINT;
5527 case QRhiTexture::RGBA32SI:
5528 return DXGI_FORMAT_R32G32B32A32_SINT;
5529 case QRhiTexture::RGBA32UI:
5530 return DXGI_FORMAT_R32G32B32A32_UINT;
5532 case QRhiTexture::D16:
5533 return DXGI_FORMAT_R16_TYPELESS;
5534 case QRhiTexture::D24:
5535 return DXGI_FORMAT_R24G8_TYPELESS;
5536 case QRhiTexture::D24S8:
5537 return DXGI_FORMAT_R24G8_TYPELESS;
5538 case QRhiTexture::D32F:
5539 return DXGI_FORMAT_R32_TYPELESS;
5540 case QRhiTexture::Format::D32FS8:
5541 return DXGI_FORMAT_R32G8X24_TYPELESS;
5543 case QRhiTexture::BC1:
5544 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
5545 case QRhiTexture::BC2:
5546 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
5547 case QRhiTexture::BC3:
5548 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
5549 case QRhiTexture::BC4:
5550 return DXGI_FORMAT_BC4_UNORM;
5551 case QRhiTexture::BC5:
5552 return DXGI_FORMAT_BC5_UNORM;
5553 case QRhiTexture::BC6H:
5554 return DXGI_FORMAT_BC6H_UF16;
5555 case QRhiTexture::BC7:
5556 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
5558 case QRhiTexture::ETC2_RGB8:
5559 case QRhiTexture::ETC2_RGB8A1:
5560 case QRhiTexture::ETC2_RGBA8:
5561 qWarning(
"QRhiD3D12 does not support ETC2 textures");
5562 return DXGI_FORMAT_R8G8B8A8_UNORM;
5564 case QRhiTexture::ASTC_4x4:
5565 case QRhiTexture::ASTC_5x4:
5566 case QRhiTexture::ASTC_5x5:
5567 case QRhiTexture::ASTC_6x5:
5568 case QRhiTexture::ASTC_6x6:
5569 case QRhiTexture::ASTC_8x5:
5570 case QRhiTexture::ASTC_8x6:
5571 case QRhiTexture::ASTC_8x8:
5572 case QRhiTexture::ASTC_10x5:
5573 case QRhiTexture::ASTC_10x6:
5574 case QRhiTexture::ASTC_10x8:
5575 case QRhiTexture::ASTC_10x10:
5576 case QRhiTexture::ASTC_12x10:
5577 case QRhiTexture::ASTC_12x12:
5578 qWarning(
"QRhiD3D12 does not support ASTC textures");
5579 return DXGI_FORMAT_R8G8B8A8_UNORM;
5584 return DXGI_FORMAT_R8G8B8A8_UNORM;
5587QD3D12RenderBuffer::QD3D12RenderBuffer(QRhiImplementation *rhi,
5589 const QSize &pixelSize,
5592 QRhiTexture::Format backingFormatHint)
5593 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
5597QD3D12RenderBuffer::~QD3D12RenderBuffer()
5602void QD3D12RenderBuffer::destroy()
5604 if (handle.isNull())
5607 QRHI_RES_RHI(QRhiD3D12);
5610 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->rtvPool, rtv, 1);
5611 else if (dsv.isValid())
5612 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->dsvPool, dsv, 1);
5620 rhiD->unregisterResource(
this);
5623bool QD3D12RenderBuffer::create()
5625 if (!handle.isNull())
5628 if (m_pixelSize.isEmpty())
5631 QRHI_RES_RHI(QRhiD3D12);
5634 case QRhiRenderBuffer::Color:
5636 dxgiFormat = toD3DTextureFormat(backingFormat(), {});
5637 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5638 D3D12_RESOURCE_DESC resourceDesc = {};
5639 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
5640 resourceDesc.Width = UINT64(m_pixelSize.width());
5641 resourceDesc.Height = UINT(m_pixelSize.height());
5642 resourceDesc.DepthOrArraySize = 1;
5643 resourceDesc.MipLevels = 1;
5644 resourceDesc.Format = dxgiFormat;
5645 resourceDesc.SampleDesc = sampleDesc;
5646 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5647 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
5648 D3D12_CLEAR_VALUE clearValue = {};
5649 clearValue.Format = dxgiFormat;
5651 ID3D12Resource *resource =
nullptr;
5652 D3D12MA::Allocation *allocation =
nullptr;
5653 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5655 D3D12_RESOURCE_STATE_RENDER_TARGET,
5658 __uuidof(ID3D12Resource),
5659 reinterpret_cast<
void **>(&resource));
5661 qWarning(
"Failed to create color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
5664 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
5665 rtv = rhiD->rtvPool.allocate(1);
5668 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5669 rtvDesc.Format = dxgiFormat;
5670 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
5671 : D3D12_RTV_DIMENSION_TEXTURE2D;
5672 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
5675 case QRhiRenderBuffer::DepthStencil:
5677 dxgiFormat = DS_FORMAT;
5678 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5679 D3D12_RESOURCE_DESC resourceDesc = {};
5680 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
5681 resourceDesc.Width = UINT64(m_pixelSize.width());
5682 resourceDesc.Height = UINT(m_pixelSize.height());
5683 resourceDesc.DepthOrArraySize = 1;
5684 resourceDesc.MipLevels = 1;
5685 resourceDesc.Format = dxgiFormat;
5686 resourceDesc.SampleDesc = sampleDesc;
5687 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5688 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
5689 if (m_flags.testFlag(UsedWithSwapChainOnly))
5690 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
5691 D3D12_CLEAR_VALUE clearValue = {};
5692 clearValue.Format = dxgiFormat;
5693 clearValue.DepthStencil.Depth = 1.0f;
5694 clearValue.DepthStencil.Stencil = 0;
5695 ID3D12Resource *resource =
nullptr;
5696 D3D12MA::Allocation *allocation =
nullptr;
5697 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5699 D3D12_RESOURCE_STATE_DEPTH_WRITE,
5702 __uuidof(ID3D12Resource),
5703 reinterpret_cast<
void **>(&resource));
5705 qWarning(
"Failed to create depth-stencil buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
5708 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE, allocation);
5709 dsv = rhiD->dsvPool.allocate(1);
5712 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5713 dsvDesc.Format = dxgiFormat;
5714 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
5715 : D3D12_DSV_DIMENSION_TEXTURE2D;
5716 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
5721 if (!m_objectName.isEmpty()) {
5722 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
5723 const QString name = QString::fromUtf8(m_objectName);
5724 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
5729 rhiD->registerResource(
this);
5733QRhiTexture::Format QD3D12RenderBuffer::backingFormat()
const
5735 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
5736 return m_backingFormatHint;
5738 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
5741QD3D12Texture::QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
5742 int arraySize,
int sampleCount, Flags flags)
5743 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
5747QD3D12Texture::~QD3D12Texture()
5752void QD3D12Texture::destroy()
5754 if (handle.isNull())
5757 QRHI_RES_RHI(QRhiD3D12);
5759 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->cbvSrvUavPool, srv, 1);
5763 subresourceInitialized.clear();
5766 rhiD->unregisterResource(
this);
5769static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
5772 case QRhiTexture::Format::D16:
5773 return DXGI_FORMAT_R16_FLOAT;
5774 case QRhiTexture::Format::D24:
5775 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
5776 case QRhiTexture::Format::D24S8:
5777 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
5778 case QRhiTexture::Format::D32F:
5779 return DXGI_FORMAT_R32_FLOAT;
5780 case QRhiTexture::Format::D32FS8:
5781 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
5785 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
5788static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
5792 case QRhiTexture::Format::D16:
5793 return DXGI_FORMAT_D16_UNORM;
5794 case QRhiTexture::Format::D24:
5795 return DXGI_FORMAT_D24_UNORM_S8_UINT;
5796 case QRhiTexture::Format::D24S8:
5797 return DXGI_FORMAT_D24_UNORM_S8_UINT;
5798 case QRhiTexture::Format::D32F:
5799 return DXGI_FORMAT_D32_FLOAT;
5800 case QRhiTexture::Format::D32FS8:
5801 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
5805 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
5808bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
5810 if (!handle.isNull())
5813 QRHI_RES_RHI(QRhiD3D12);
5814 if (!rhiD->isTextureFormatSupported(m_format, m_flags))
5817 const bool isDepth = isDepthTextureFormat(m_format);
5818 const bool isCube = m_flags.testFlag(CubeMap);
5819 const bool is3D = m_flags.testFlag(ThreeDimensional);
5820 const bool isArray = m_flags.testFlag(TextureArray);
5821 const bool hasMipMaps = m_flags.testFlag(MipMapped);
5822 const bool is1D = m_flags.testFlag(OneDimensional);
5824 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
5825 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
5827 dxgiFormat = toD3DTextureFormat(m_format, m_flags);
5829 srvFormat = toD3DDepthTextureSRVFormat(m_format);
5830 rtFormat = toD3DDepthTextureDSVFormat(m_format);
5832 srvFormat = dxgiFormat;
5833 rtFormat = dxgiFormat;
5835 if (m_writeViewFormat.format != UnknownFormat) {
5837 rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
5839 rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
5841 if (m_readViewFormat.format != UnknownFormat) {
5843 srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
5845 srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
5848 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
5849 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5850 if (sampleDesc.Count > 1) {
5852 qWarning(
"Cubemap texture cannot be multisample");
5856 qWarning(
"3D texture cannot be multisample");
5860 qWarning(
"Multisample texture cannot have mipmaps");
5864 if (isDepth && hasMipMaps) {
5865 qWarning(
"Depth texture cannot have mipmaps");
5868 if (isCube && is3D) {
5869 qWarning(
"Texture cannot be both cube and 3D");
5872 if (isArray && is3D) {
5873 qWarning(
"Texture cannot be both array and 3D");
5876 if (isCube && is1D) {
5877 qWarning(
"Texture cannot be both cube and 1D");
5881 qWarning(
"Texture cannot be both 1D and 3D");
5884 if (m_depth > 1 && !is3D) {
5885 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
5888 if (m_arraySize > 0 && !isArray) {
5889 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
5892 if (m_arraySize < 1 && isArray) {
5893 qWarning(
"Texture is an array but array size is %d", m_arraySize);
5897 if (!rhiD->textureFormatInfo(m_format, size,
nullptr,
nullptr,
nullptr))
5901 *adjustedSize = size;
5906bool QD3D12Texture::finishCreate()
5908 QRHI_RES_RHI(QRhiD3D12);
5909 const bool isCube = m_flags.testFlag(CubeMap);
5910 const bool is3D = m_flags.testFlag(ThreeDimensional);
5911 const bool isArray = m_flags.testFlag(TextureArray);
5912 const bool is1D = m_flags.testFlag(OneDimensional);
5914 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
5915 srvDesc.Format = srvFormat;
5916 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
5919 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
5920 srvDesc.TextureCube.MipLevels = mipLevelCount;
5924 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
5925 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
5926 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5927 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
5928 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
5930 srvDesc.Texture1DArray.FirstArraySlice = 0;
5931 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
5934 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
5935 srvDesc.Texture1D.MipLevels = mipLevelCount;
5937 }
else if (isArray) {
5938 if (sampleDesc.Count > 1) {
5939 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
5940 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5941 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
5942 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
5944 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
5945 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
5948 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
5949 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
5950 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5951 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
5952 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
5954 srvDesc.Texture2DArray.FirstArraySlice = 0;
5955 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
5959 if (sampleDesc.Count > 1) {
5960 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
5962 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
5963 srvDesc.Texture3D.MipLevels = mipLevelCount;
5965 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
5966 srvDesc.Texture2D.MipLevels = mipLevelCount;
5971 srv = rhiD->cbvSrvUavPool.allocate(1);
5975 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
5976 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
5977 if (!m_objectName.isEmpty()) {
5978 const QString name = QString::fromUtf8(m_objectName);
5979 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
5989bool QD3D12Texture::create()
5992 if (!prepareCreate(&size))
5995 const bool isDepth = isDepthTextureFormat(m_format);
5996 const bool isCube = m_flags.testFlag(CubeMap);
5997 const bool is3D = m_flags.testFlag(ThreeDimensional);
5998 const bool isArray = m_flags.testFlag(TextureArray);
5999 const bool is1D = m_flags.testFlag(OneDimensional);
6001 QRHI_RES_RHI(QRhiD3D12);
6003 bool needsOptimizedClearValueSpecified =
false;
6004 UINT resourceFlags = 0;
6005 if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
6007 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
6009 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
6010 needsOptimizedClearValueSpecified =
true;
6012 if (m_flags.testFlag(UsedWithGenerateMips)) {
6014 qWarning(
"Depth texture cannot have mipmaps generated");
6017 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
6019 if (m_flags.testFlag(UsedWithLoadStore))
6020 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
6022 D3D12_RESOURCE_DESC resourceDesc = {};
6023 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
6024 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
6025 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
6026 resourceDesc.Width = UINT64(size.width());
6027 resourceDesc.Height = UINT(size.height());
6028 resourceDesc.DepthOrArraySize = isCube ? 6
6029 : (isArray ? UINT(qMax(0, m_arraySize))
6030 : (is3D ? qMax(1, m_depth)
6032 resourceDesc.MipLevels = mipLevelCount;
6033 resourceDesc.Format = dxgiFormat;
6034 resourceDesc.SampleDesc = sampleDesc;
6035 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
6036 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
6037 D3D12_CLEAR_VALUE clearValue = {};
6038 clearValue.Format = dxgiFormat;
6040 clearValue.Format = toD3DDepthTextureDSVFormat(m_format);
6041 clearValue.DepthStencil.Depth = 1.0f;
6042 clearValue.DepthStencil.Stencil = 0;
6044 ID3D12Resource *resource =
nullptr;
6045 D3D12MA::Allocation *allocation =
nullptr;
6046 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
6048 D3D12_RESOURCE_STATE_COMMON,
6049 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
6051 __uuidof(ID3D12Resource),
6052 reinterpret_cast<
void **>(&resource));
6054 qWarning(
"Failed to create texture: '%s'"
6055 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
6056 qPrintable(QSystemError::windowsComString(hr)),
6057 int(resourceDesc.Dimension),
6058 uint(resourceDesc.Width),
6059 uint(resourceDesc.Height),
6060 uint(resourceDesc.DepthOrArraySize),
6061 uint(resourceDesc.MipLevels),
6062 int(resourceDesc.Format),
6063 int(resourceDesc.SampleDesc.Count));
6064 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
6065 rhiD->deviceLost =
true;
6069 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON, allocation);
6071 if (!finishCreate())
6074 rhiD->registerResource(
this);
6078bool QD3D12Texture::createFrom(QRhiTexture::NativeTexture src)
6083 if (!prepareCreate())
6086 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *>(src.object);
6087 D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(src.layout);
6089 QRHI_RES_RHI(QRhiD3D12);
6090 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource, state);
6092 if (!finishCreate())
6095 rhiD->registerResource(
this);
6099QRhiTexture::NativeTexture QD3D12Texture::nativeTexture()
6101 QRHI_RES_RHI(QRhiD3D12);
6102 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
6103 return { quint64(res->resource),
int(res->state) };
6108void QD3D12Texture::setNativeLayout(
int layout)
6110 QRHI_RES_RHI(QRhiD3D12);
6111 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
6112 res->state = D3D12_RESOURCE_STATES(layout);
6115QD3D12Sampler::QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
6116 AddressMode u, AddressMode v, AddressMode w)
6117 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
6121QD3D12Sampler::~QD3D12Sampler()
6126void QD3D12Sampler::destroy()
6128 shaderVisibleDescriptor = {};
6130 QRHI_RES_RHI(QRhiD3D12);
6132 rhiD->unregisterResource(
this);
6135static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
6137 if (minFilter == QRhiSampler::Nearest) {
6138 if (magFilter == QRhiSampler::Nearest) {
6139 if (mipFilter == QRhiSampler::Linear)
6140 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
6142 return D3D12_FILTER_MIN_MAG_MIP_POINT;
6144 if (mipFilter == QRhiSampler::Linear)
6145 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
6147 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
6150 if (magFilter == QRhiSampler::Nearest) {
6151 if (mipFilter == QRhiSampler::Linear)
6152 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
6154 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
6156 if (mipFilter == QRhiSampler::Linear)
6157 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
6159 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
6162 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
6165static inline D3D12_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
6168 case QRhiSampler::Repeat:
6169 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
6170 case QRhiSampler::ClampToEdge:
6171 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
6172 case QRhiSampler::Mirror:
6173 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
6175 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
6178static inline D3D12_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
6181 case QRhiSampler::Never:
6182 return D3D12_COMPARISON_FUNC_NEVER;
6183 case QRhiSampler::Less:
6184 return D3D12_COMPARISON_FUNC_LESS;
6185 case QRhiSampler::Equal:
6186 return D3D12_COMPARISON_FUNC_EQUAL;
6187 case QRhiSampler::LessOrEqual:
6188 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
6189 case QRhiSampler::Greater:
6190 return D3D12_COMPARISON_FUNC_GREATER;
6191 case QRhiSampler::NotEqual:
6192 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
6193 case QRhiSampler::GreaterOrEqual:
6194 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
6195 case QRhiSampler::Always:
6196 return D3D12_COMPARISON_FUNC_ALWAYS;
6198 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
6201bool QD3D12Sampler::create()
6204 desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
6205 if (m_compareOp != Never)
6206 desc.Filter = D3D12_FILTER(desc.Filter | 0x80);
6207 desc.AddressU = toD3DAddressMode(m_addressU);
6208 desc.AddressV = toD3DAddressMode(m_addressV);
6209 desc.AddressW = toD3DAddressMode(m_addressW);
6210 desc.MaxAnisotropy = 1.0f;
6211 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
6212 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
6216 shaderVisibleDescriptor = {};
6220 QRHI_RES_RHI(QRhiD3D12);
6221 rhiD->registerResource(
this,
false);
6225QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
6227 if (!shaderVisibleDescriptor.isValid()) {
6228 QRHI_RES_RHI(QRhiD3D12);
6229 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(desc);
6231 return shaderVisibleDescriptor;
6234QD3D12ShadingRateMap::QD3D12ShadingRateMap(QRhiImplementation *rhi)
6235 : QRhiShadingRateMap(rhi)
6239QD3D12ShadingRateMap::~QD3D12ShadingRateMap()
6244void QD3D12ShadingRateMap::destroy()
6246 if (handle.isNull())
6252bool QD3D12ShadingRateMap::createFrom(QRhiTexture *src)
6254 if (!handle.isNull())
6257 handle = QRHI_RES(QD3D12Texture, src)->handle;
6262QD3D12TextureRenderTarget::QD3D12TextureRenderTarget(QRhiImplementation *rhi,
6263 const QRhiTextureRenderTargetDescription &desc,
6265 : QRhiTextureRenderTarget(rhi, desc, flags),
6270QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
6275void QD3D12TextureRenderTarget::destroy()
6277 if (!rtv[0].isValid() && !dsv.isValid())
6280 QRHI_RES_RHI(QRhiD3D12);
6281 if (dsv.isValid()) {
6282 if (ownsDsv && rhiD)
6283 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
6287 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i) {
6288 if (rtv[i].isValid()) {
6289 if (ownsRtv[i] && rhiD)
6290 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[i], 1);
6296 rhiD->unregisterResource(
this);
6299QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDescriptor()
6303 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6305 rpD->colorAttachmentCount = 0;
6306 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it) {
6307 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
6308 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
6310 rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
6312 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
6313 rpD->colorAttachmentCount += 1;
6316 rpD->hasDepthStencil =
false;
6317 if (m_desc.depthStencilBuffer()) {
6318 rpD->hasDepthStencil =
true;
6319 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
6320 }
else if (m_desc.depthTexture()) {
6321 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
6322 rpD->hasDepthStencil =
true;
6323 rpD->dsFormat = toD3DDepthTextureDSVFormat(depthTexD->format());
6326 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
6328 rpD->updateSerializedFormat();
6330 QRHI_RES_RHI(QRhiD3D12);
6331 rhiD->registerResource(rpD);
6335bool QD3D12TextureRenderTarget::create()
6337 if (rtv[0].isValid() || dsv.isValid())
6340 QRHI_RES_RHI(QRhiD3D12);
6341 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
6342 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
6343 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
6344 d.colorAttCount = 0;
6347 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
6348 d.colorAttCount += 1;
6349 const QRhiColorAttachment &colorAtt(*it);
6350 QRhiTexture *texture = colorAtt.texture();
6351 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
6352 Q_ASSERT(texture || rb);
6354 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, texture);
6355 QD3D12Resource *res = rhiD->resourcePool.lookupRef(texD->handle);
6357 qWarning(
"Could not look up texture handle for render target");
6360 const bool isMultiView = it->multiViewCount() >= 2;
6361 UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
6362 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6363 rtvDesc.Format = texD->rtFormat;
6364 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
6365 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
6366 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
6367 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
6368 rtvDesc.Texture2DArray.ArraySize = layerCount;
6369 }
else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
6370 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
6371 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
6372 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
6373 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
6374 rtvDesc.Texture1DArray.ArraySize = layerCount;
6376 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
6377 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
6379 }
else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
6380 if (texD->sampleDesc.Count > 1) {
6381 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
6382 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
6383 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
6385 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
6386 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
6387 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
6388 rtvDesc.Texture2DArray.ArraySize = layerCount;
6390 }
else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
6391 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
6392 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
6393 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
6394 rtvDesc.Texture3D.WSize = layerCount;
6396 if (texD->sampleDesc.Count > 1) {
6397 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
6399 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
6400 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
6403 rtv[attIndex] = rhiD->rtvPool.allocate(1);
6404 if (!rtv[attIndex].isValid()) {
6405 qWarning(
"Failed to allocate RTV for texture render target");
6408 rhiD->dev->CreateRenderTargetView(res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
6409 ownsRtv[attIndex] =
true;
6410 if (attIndex == 0) {
6411 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
6412 d.sampleCount =
int(texD->sampleDesc.Count);
6415 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rb);
6416 ownsRtv[attIndex] =
false;
6417 rtv[attIndex] = rbD->rtv;
6418 if (attIndex == 0) {
6419 d.pixelSize = rbD->pixelSize();
6420 d.sampleCount =
int(rbD->sampleDesc.Count);
6427 if (hasDepthStencil) {
6428 if (m_desc.depthTexture()) {
6430 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
6431 QD3D12Resource *res = rhiD->resourcePool.lookupRef(depthTexD->handle);
6433 qWarning(
"Could not look up depth texture handle");
6436 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
6437 dsvDesc.Format = depthTexD->rtFormat;
6438 const bool isMultisample = depthTexD->sampleDesc.Count > 1;
6439 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
6440 if (isMultisample) {
6441 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
6442 if (m_desc.depthLayer() >= 0) {
6443 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_desc.depthLayer());
6444 dsvDesc.Texture2DMSArray.ArraySize = 1;
6445 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
6446 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
6447 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
6449 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
6450 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
6453 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
6454 if (m_desc.depthLayer() >= 0) {
6455 dsvDesc.Texture2DArray.FirstArraySlice = UINT(m_desc.depthLayer());
6456 dsvDesc.Texture2DArray.ArraySize = 1;
6457 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
6458 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
6459 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
6461 dsvDesc.Texture2DArray.FirstArraySlice = 0;
6462 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
6467 dsvDesc.ViewDimension = isMultisample ? D3D12_DSV_DIMENSION_TEXTURE2DMS
6468 : D3D12_DSV_DIMENSION_TEXTURE2D;
6470 dsv = rhiD->dsvPool.allocate(1);
6471 if (!dsv.isValid()) {
6472 qWarning(
"Failed to allocate DSV for texture render target");
6475 rhiD->dev->CreateDepthStencilView(res->resource, &dsvDesc, dsv.cpuHandle);
6476 if (d.colorAttCount == 0) {
6477 d.pixelSize = depthTexD->pixelSize();
6478 d.sampleCount =
int(depthTexD->sampleDesc.Count);
6482 QD3D12RenderBuffer *depthRbD = QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
6483 dsv = depthRbD->dsv;
6484 if (d.colorAttCount == 0) {
6485 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
6486 d.sampleCount =
int(depthRbD->sampleDesc.Count);
6494 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
6495 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i)
6496 d.rtv[i] = i < d.colorAttCount ? rtv[i].cpuHandle : nullDescHandle;
6497 d.dsv = dsv.cpuHandle;
6498 d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6500 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &d.currentResIdList);
6502 rhiD->registerResource(
this);
6506QSize QD3D12TextureRenderTarget::pixelSize()
const
6508 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc, d.currentResIdList))
6509 const_cast<QD3D12TextureRenderTarget *>(
this)->create();
6514float QD3D12TextureRenderTarget::devicePixelRatio()
const
6519int QD3D12TextureRenderTarget::sampleCount()
const
6521 return d.sampleCount;
6524QD3D12ShaderResourceBindings::QD3D12ShaderResourceBindings(QRhiImplementation *rhi)
6525 : QRhiShaderResourceBindings(rhi)
6529QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
6534void QD3D12ShaderResourceBindings::destroy()
6536 bindingCache.reset();
6537 bindingCacheValid =
false;
6538 boundResourceData.clear();
6540 QRHI_RES_RHI(QRhiD3D12);
6542 rhiD->unregisterResource(
this);
6545bool QD3D12ShaderResourceBindings::create()
6547 QRHI_RES_RHI(QRhiD3D12);
6548 if (!rhiD->sanityCheckShaderResourceBindings(
this))
6551 rhiD->updateLayoutDesc(
this);
6553 boundResourceData.resize(m_bindings.count());
6554 for (BoundResourceData &bd : boundResourceData)
6557 bindingCache.reset();
6558 bindingCacheValid =
false;
6560 hasDynamicOffset =
false;
6561 for (
const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
6562 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
6563 if (bd->type() == QRhiShaderResourceBinding::UniformBuffer && bd->ubuf().hasDynamicOffset) {
6564 hasDynamicOffset =
true;
6578 rhiD->registerResource(
this,
false);
6582void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
6586 Q_ASSERT(boundResourceData.count() == m_bindings.count());
6587 for (BoundResourceData &bd : boundResourceData)
6590 bindingCache.reset();
6591 bindingCacheValid =
false;
6601void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
6602 const QRhiShaderResourceBinding::Data::UniformBufferData &,
6606 D3D12_ROOT_PARAMETER1 rootParam = {};
6607 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
6608 rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
6609 rootParam.Descriptor.ShaderRegister = shaderRegister;
6610 rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
6611 visitorData.cbParams[s].append(rootParam);
6614void QD3D12ShaderResourceBindings::visitTextures(QD3D12Stage s,
6615 const QRhiShaderResourceBinding::TextureAndSampler *,
6617 int baseShaderRegister)
6622 D3D12_DESCRIPTOR_RANGE1 range = {};
6623 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
6624 range.NumDescriptors = UINT(count);
6625 range.BaseShaderRegister = baseShaderRegister;
6626 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[s];
6627 visitorData.currentSrvRangeOffset[s] += UINT(count);
6628 visitorData.srvRanges[s].append(range);
6629 if (visitorData.srvRanges[s].count() == 1) {
6630 visitorData.srvTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6631 visitorData.srvTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6635void QD3D12ShaderResourceBindings::visitSamplers(QD3D12Stage s,
6636 const QRhiShaderResourceBinding::TextureAndSampler *,
6638 int baseShaderRegister)
6646 int &rangeStoreIdx(visitorData.samplerRangeHeads[s]);
6647 if (rangeStoreIdx == 16) {
6648 qWarning(
"Sampler binding count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi", s);
6651 D3D12_DESCRIPTOR_RANGE1 range = {};
6652 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
6653 range.NumDescriptors = UINT(count);
6654 range.BaseShaderRegister = baseShaderRegister;
6655 visitorData.samplerRanges[s][rangeStoreIdx] = range;
6656 D3D12_ROOT_PARAMETER1 param = {};
6657 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6658 param.ShaderVisibility = qd3d12_stageToVisibility(s);
6659 param.DescriptorTable.NumDescriptorRanges = 1;
6660 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[s][rangeStoreIdx];
6662 visitorData.samplerTables[s].append(param);
6665void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage s,
6666 const QRhiShaderResourceBinding::Data::StorageBufferData &,
6667 QD3D12ShaderResourceVisitor::StorageOp,
6670 D3D12_DESCRIPTOR_RANGE1 range = {};
6671 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
6672 range.NumDescriptors = 1;
6673 range.BaseShaderRegister = shaderRegister;
6674 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
6675 visitorData.currentUavRangeOffset[s] += 1;
6676 visitorData.uavRanges[s].append(range);
6677 if (visitorData.uavRanges[s].count() == 1) {
6678 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6679 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6683void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage s,
6684 const QRhiShaderResourceBinding::Data::StorageImageData &,
6685 QD3D12ShaderResourceVisitor::StorageOp,
6688 D3D12_DESCRIPTOR_RANGE1 range = {};
6689 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
6690 range.NumDescriptors = 1;
6691 range.BaseShaderRegister = shaderRegister;
6692 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
6693 visitorData.currentUavRangeOffset[s] += 1;
6694 visitorData.uavRanges[s].append(range);
6695 if (visitorData.uavRanges[s].count() == 1) {
6696 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6697 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6701static void qd3d12_setPushConstantInfo(QD3D12ShaderStageData *sd,
const QShader &shader,
const QShaderKey &key)
6703 const QList<QShaderDescription::PushConstantBlock> blocks = shader.description().pushConstantBlocks();
6704 if (blocks.isEmpty())
6706 sd->pushConstantRegister = shader.nativeShaderInfo(key).extraBufferBindings.value(
6707 QShaderPrivate::HlslPushConstantBufferBinding, -1);
6708 sd->pushConstantSize = quint32((blocks.first().size + 3) & ~3);
6711QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
6714 QRHI_RES_RHI(QRhiD3D12);
6728 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
6732 using namespace std::placeholders;
6733 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
6734 visitor.textures = std::bind(&QD3D12ShaderResourceBindings::visitTextures,
this, _1, _2, _3, _4);
6735 visitor.samplers = std::bind(&QD3D12ShaderResourceBindings::visitSamplers,
this, _1, _2, _3, _4);
6736 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
6737 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
6761 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> rootParams;
6762 for (
int s = 0; s < 6; ++s) {
6763 if (!visitorData.cbParams[s].isEmpty())
6764 rootParams.append(visitorData.cbParams[s].constData(), visitorData.cbParams[s].count());
6766 for (
int s = 0; s < 6; ++s) {
6767 if (!visitorData.srvRanges[s].isEmpty()) {
6768 visitorData.srvTables[s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[s].count();
6769 visitorData.srvTables[s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[s].constData();
6770 rootParams.append(visitorData.srvTables[s]);
6773 for (
int s = 0; s < 6; ++s) {
6774 if (!visitorData.samplerTables[s].isEmpty())
6775 rootParams.append(visitorData.samplerTables[s].constData(), visitorData.samplerTables[s].count());
6777 for (
int s = 0; s < 6; ++s) {
6778 if (!visitorData.uavRanges[s].isEmpty()) {
6779 visitorData.uavTables[s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[s].count();
6780 visitorData.uavTables[s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[s].constData();
6781 rootParams.append(visitorData.uavTables[s]);
6787 pushConstantRootParamIndex = -1;
6788 UINT pushConstantReg = 0;
6789 quint32 pushConstantSize = 0;
6790 int pushConstantStages = 0;
6791 D3D12_SHADER_VISIBILITY pushConstantVis = D3D12_SHADER_VISIBILITY_ALL;
6792 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
6793 const QD3D12ShaderStageData &sd(stageData[stageIdx]);
6794 if (!sd.valid || !sd.pushConstantSize || sd.pushConstantRegister < 0)
6796 pushConstantReg = UINT(sd.pushConstantRegister);
6797 pushConstantSize = qMax(pushConstantSize, sd.pushConstantSize);
6798 pushConstantVis = qd3d12_stageToVisibility(sd.stage);
6799 ++pushConstantStages;
6801 if (pushConstantSize) {
6805 D3D12_ROOT_PARAMETER1 param = {};
6806 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
6807 param.ShaderVisibility = pushConstantStages > 1 ? D3D12_SHADER_VISIBILITY_ALL : pushConstantVis;
6808 param.Constants.ShaderRegister = pushConstantReg;
6809 param.Constants.Num32BitValues = pushConstantSize / 4;
6810 pushConstantRootParamIndex = rootParams.count();
6811 rootParams.append(param);
6814 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
6815 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
6816 if (!rootParams.isEmpty()) {
6817 rsDesc.Desc_1_1.NumParameters = rootParams.count();
6818 rsDesc.Desc_1_1.pParameters = rootParams.constData();
6822 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
6823 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
6824 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
6826 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
6828 ID3DBlob *signature =
nullptr;
6829 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
6831 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
6834 ID3D12RootSignature *rootSig =
nullptr;
6835 hr = rhiD->dev->CreateRootSignature(0,
6836 signature->GetBufferPointer(),
6837 signature->GetBufferSize(),
6838 __uuidof(ID3D12RootSignature),
6839 reinterpret_cast<
void **>(&rootSig));
6840 signature->Release();
6842 qWarning(
"Failed to create root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
6846 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
6858static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
6860 const int smMajor = version / 10;
6861 const int smMinor = version % 10;
6862 target[0] = stage[0];
6863 target[1] = stage[1];
6865 target[3] =
'0' + smMajor;
6867 target[5] =
'0' + smMinor;
6871enum class HlslCompileFlag
6873 WithDebugInfo = 0x01
6876static QByteArray legacyCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
6878 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
6880 qWarning(
"Unable to resolve function D3DCompile()");
6881 return QByteArray();
6884 ID3DBlob *bytecode =
nullptr;
6885 ID3DBlob *errors =
nullptr;
6886 UINT d3dCompileFlags = 0;
6887 if (flags &
int(HlslCompileFlag::WithDebugInfo))
6888 d3dCompileFlags |= D3DCOMPILE_DEBUG;
6890 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
6891 nullptr,
nullptr,
nullptr,
6892 hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
6893 if (FAILED(hr) || !bytecode) {
6894 qWarning(
"HLSL shader compilation failed: 0x%x", uint(hr));
6896 *error = QString::fromUtf8(
static_cast<
const char *>(errors->GetBufferPointer()),
6897 int(errors->GetBufferSize()));
6900 return QByteArray();
6904 result.resize(
int(bytecode->GetBufferSize()));
6905 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
6906 bytecode->Release();
6910#ifdef QRHI_D3D12_HAS_DXC
6913#define DXC_CP_UTF8 65001
6916#ifndef DXC_ARG_DEBUG
6917#define DXC_ARG_DEBUG L"-Zi"
6920static QByteArray dxcCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
6922 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
6923 IDxcCompiler *compiler = dxc.first;
6925 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
6926 "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
6927 return QByteArray();
6929 IDxcLibrary *library = dxc.second;
6931 return QByteArray();
6933 IDxcBlobEncoding *sourceBlob =
nullptr;
6934 HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
6935 UINT32(hlslSource.shader().size()),
6939 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
6941 qPrintable(QSystemError::windowsComString(hr)));
6942 return QByteArray();
6945 const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
6946 const QString targetStr = QString::fromLatin1(target);
6948 QVarLengthArray<LPCWSTR, 4> argPtrs;
6950 if (flags &
int(HlslCompileFlag::WithDebugInfo)) {
6951 debugArg = QString::fromUtf16(
reinterpret_cast<
const char16_t *>(DXC_ARG_DEBUG));
6952 argPtrs.append(
reinterpret_cast<LPCWSTR>(debugArg.utf16()));
6955 IDxcOperationResult *result =
nullptr;
6956 hr = compiler->Compile(sourceBlob,
6958 reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
6959 reinterpret_cast<LPCWSTR>(targetStr.utf16()),
6960 argPtrs.data(), argPtrs.count(),
6964 sourceBlob->Release();
6966 result->GetStatus(&hr);
6968 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
6970 qPrintable(QSystemError::windowsComString(hr)));
6972 IDxcBlobEncoding *errorsBlob =
nullptr;
6973 if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
6975 *error = QString::fromUtf8(
static_cast<
const char *>(errorsBlob->GetBufferPointer()),
6976 int(errorsBlob->GetBufferSize()));
6977 errorsBlob->Release();
6981 return QByteArray();
6984 IDxcBlob *bytecode =
nullptr;
6985 if FAILED(result->GetResult(&bytecode)) {
6986 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
6988 qPrintable(QSystemError::windowsComString(hr)));
6989 return QByteArray();
6993 ba.resize(
int(bytecode->GetBufferSize()));
6994 memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
6995 bytecode->Release();
7001static QByteArray compileHlslShaderSource(
const QShader &shader,
7002 QShader::Variant shaderVariant,
7005 QShaderKey *usedShaderKey)
7008 const int shaderModelMax = 67;
7009 for (
int sm = shaderModelMax; sm >= 50; --sm) {
7010 for (QShader::Source type : { QShader::DxilShader, QShader::DxbcShader }) {
7011 QShaderKey key = { type, sm, shaderVariant };
7012 QShaderCode intermediateBytecodeShader = shader.shader(key);
7013 if (!intermediateBytecodeShader.shader().isEmpty()) {
7015 *usedShaderKey = key;
7016 return intermediateBytecodeShader.shader();
7021 QShaderCode hlslSource;
7023 for (
int sm = shaderModelMax; sm >= 50; --sm) {
7024 key = { QShader::HlslShader, sm, shaderVariant };
7025 hlslSource = shader.shader(key);
7026 if (!hlslSource.shader().isEmpty())
7030 if (hlslSource.shader().isEmpty()) {
7031 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" << shader;
7032 return QByteArray();
7036 *usedShaderKey = key;
7039 switch (shader.stage()) {
7040 case QShader::VertexStage:
7041 makeHlslTargetString(target,
"vs", key.sourceVersion().version());
7043 case QShader::TessellationControlStage:
7044 makeHlslTargetString(target,
"hs", key.sourceVersion().version());
7046 case QShader::TessellationEvaluationStage:
7047 makeHlslTargetString(target,
"ds", key.sourceVersion().version());
7049 case QShader::GeometryStage:
7050 makeHlslTargetString(target,
"gs", key.sourceVersion().version());
7052 case QShader::FragmentStage:
7053 makeHlslTargetString(target,
"ps", key.sourceVersion().version());
7055 case QShader::ComputeStage:
7056 makeHlslTargetString(target,
"cs", key.sourceVersion().version());
7059 qWarning(
"compileHlslShaderSource: Unknown stage (%d)",
int(shader.stage()));
7060 return QByteArray();
7063 if (key.sourceVersion().version() >= 60) {
7064#ifdef QRHI_D3D12_HAS_DXC
7065 return dxcCompile(hlslSource, target, flags, error);
7067 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
7068 "but the Qt build has no support for DXC. "
7069 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
7073 return legacyCompile(hlslSource, target, flags, error);
7076static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
7079 if (c.testFlag(QRhiGraphicsPipeline::R))
7080 f |= D3D12_COLOR_WRITE_ENABLE_RED;
7081 if (c.testFlag(QRhiGraphicsPipeline::G))
7082 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
7083 if (c.testFlag(QRhiGraphicsPipeline::B))
7084 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
7085 if (c.testFlag(QRhiGraphicsPipeline::A))
7086 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
7090static inline D3D12_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f,
bool rgb)
7099 case QRhiGraphicsPipeline::Zero:
7100 return D3D12_BLEND_ZERO;
7101 case QRhiGraphicsPipeline::One:
7102 return D3D12_BLEND_ONE;
7103 case QRhiGraphicsPipeline::SrcColor:
7104 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
7105 case QRhiGraphicsPipeline::OneMinusSrcColor:
7106 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
7107 case QRhiGraphicsPipeline::DstColor:
7108 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
7109 case QRhiGraphicsPipeline::OneMinusDstColor:
7110 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
7111 case QRhiGraphicsPipeline::SrcAlpha:
7112 return D3D12_BLEND_SRC_ALPHA;
7113 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
7114 return D3D12_BLEND_INV_SRC_ALPHA;
7115 case QRhiGraphicsPipeline::DstAlpha:
7116 return D3D12_BLEND_DEST_ALPHA;
7117 case QRhiGraphicsPipeline::OneMinusDstAlpha:
7118 return D3D12_BLEND_INV_DEST_ALPHA;
7119 case QRhiGraphicsPipeline::ConstantColor:
7120 case QRhiGraphicsPipeline::ConstantAlpha:
7121 return D3D12_BLEND_BLEND_FACTOR;
7122 case QRhiGraphicsPipeline::OneMinusConstantColor:
7123 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
7124 return D3D12_BLEND_INV_BLEND_FACTOR;
7125 case QRhiGraphicsPipeline::SrcAlphaSaturate:
7126 return D3D12_BLEND_SRC_ALPHA_SAT;
7127 case QRhiGraphicsPipeline::Src1Color:
7128 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
7129 case QRhiGraphicsPipeline::OneMinusSrc1Color:
7130 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
7131 case QRhiGraphicsPipeline::Src1Alpha:
7132 return D3D12_BLEND_SRC1_ALPHA;
7133 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
7134 return D3D12_BLEND_INV_SRC1_ALPHA;
7136 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
7139static inline D3D12_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
7142 case QRhiGraphicsPipeline::Add:
7143 return D3D12_BLEND_OP_ADD;
7144 case QRhiGraphicsPipeline::Subtract:
7145 return D3D12_BLEND_OP_SUBTRACT;
7146 case QRhiGraphicsPipeline::ReverseSubtract:
7147 return D3D12_BLEND_OP_REV_SUBTRACT;
7148 case QRhiGraphicsPipeline::Min:
7149 return D3D12_BLEND_OP_MIN;
7150 case QRhiGraphicsPipeline::Max:
7151 return D3D12_BLEND_OP_MAX;
7153 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
7156static inline D3D12_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
7159 case QRhiGraphicsPipeline::None:
7160 return D3D12_CULL_MODE_NONE;
7161 case QRhiGraphicsPipeline::Front:
7162 return D3D12_CULL_MODE_FRONT;
7163 case QRhiGraphicsPipeline::Back:
7164 return D3D12_CULL_MODE_BACK;
7166 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
7169static inline D3D12_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
7172 case QRhiGraphicsPipeline::Fill:
7173 return D3D12_FILL_MODE_SOLID;
7174 case QRhiGraphicsPipeline::Line:
7175 return D3D12_FILL_MODE_WIREFRAME;
7177 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
7180static inline D3D12_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
7183 case QRhiGraphicsPipeline::Never:
7184 return D3D12_COMPARISON_FUNC_NEVER;
7185 case QRhiGraphicsPipeline::Less:
7186 return D3D12_COMPARISON_FUNC_LESS;
7187 case QRhiGraphicsPipeline::Equal:
7188 return D3D12_COMPARISON_FUNC_EQUAL;
7189 case QRhiGraphicsPipeline::LessOrEqual:
7190 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
7191 case QRhiGraphicsPipeline::Greater:
7192 return D3D12_COMPARISON_FUNC_GREATER;
7193 case QRhiGraphicsPipeline::NotEqual:
7194 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
7195 case QRhiGraphicsPipeline::GreaterOrEqual:
7196 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
7197 case QRhiGraphicsPipeline::Always:
7198 return D3D12_COMPARISON_FUNC_ALWAYS;
7200 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
7203static inline D3D12_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
7206 case QRhiGraphicsPipeline::StencilZero:
7207 return D3D12_STENCIL_OP_ZERO;
7208 case QRhiGraphicsPipeline::Keep:
7209 return D3D12_STENCIL_OP_KEEP;
7210 case QRhiGraphicsPipeline::Replace:
7211 return D3D12_STENCIL_OP_REPLACE;
7212 case QRhiGraphicsPipeline::IncrementAndClamp:
7213 return D3D12_STENCIL_OP_INCR_SAT;
7214 case QRhiGraphicsPipeline::DecrementAndClamp:
7215 return D3D12_STENCIL_OP_DECR_SAT;
7216 case QRhiGraphicsPipeline::Invert:
7217 return D3D12_STENCIL_OP_INVERT;
7218 case QRhiGraphicsPipeline::IncrementAndWrap:
7219 return D3D12_STENCIL_OP_INCR;
7220 case QRhiGraphicsPipeline::DecrementAndWrap:
7221 return D3D12_STENCIL_OP_DECR;
7223 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
7226static inline D3D12_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t,
int patchControlPointCount)
7229 case QRhiGraphicsPipeline::Triangles:
7230 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
7231 case QRhiGraphicsPipeline::TriangleStrip:
7232 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
7233 case QRhiGraphicsPipeline::TriangleFan:
7234 qWarning(
"Triangle fans are not supported with D3D");
7235 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
7236 case QRhiGraphicsPipeline::Lines:
7237 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
7238 case QRhiGraphicsPipeline::LineStrip:
7239 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
7240 case QRhiGraphicsPipeline::Points:
7241 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
7242 case QRhiGraphicsPipeline::Patches:
7243 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
7244 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
7246 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
7249static inline D3D12_PRIMITIVE_TOPOLOGY_TYPE toD3DTopologyType(QRhiGraphicsPipeline::Topology t)
7252 case QRhiGraphicsPipeline::Triangles:
7253 case QRhiGraphicsPipeline::TriangleStrip:
7254 case QRhiGraphicsPipeline::TriangleFan:
7255 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
7256 case QRhiGraphicsPipeline::Lines:
7257 case QRhiGraphicsPipeline::LineStrip:
7258 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
7259 case QRhiGraphicsPipeline::Points:
7260 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
7261 case QRhiGraphicsPipeline::Patches:
7262 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
7264 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
7267static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
7270 case QRhiVertexInputAttribute::Float4:
7271 return DXGI_FORMAT_R32G32B32A32_FLOAT;
7272 case QRhiVertexInputAttribute::Float3:
7273 return DXGI_FORMAT_R32G32B32_FLOAT;
7274 case QRhiVertexInputAttribute::Float2:
7275 return DXGI_FORMAT_R32G32_FLOAT;
7276 case QRhiVertexInputAttribute::Float:
7277 return DXGI_FORMAT_R32_FLOAT;
7278 case QRhiVertexInputAttribute::UNormByte4:
7279 return DXGI_FORMAT_R8G8B8A8_UNORM;
7280 case QRhiVertexInputAttribute::UNormByte2:
7281 return DXGI_FORMAT_R8G8_UNORM;
7282 case QRhiVertexInputAttribute::UNormByte:
7283 return DXGI_FORMAT_R8_UNORM;
7284 case QRhiVertexInputAttribute::UInt4:
7285 return DXGI_FORMAT_R32G32B32A32_UINT;
7286 case QRhiVertexInputAttribute::UInt3:
7287 return DXGI_FORMAT_R32G32B32_UINT;
7288 case QRhiVertexInputAttribute::UInt2:
7289 return DXGI_FORMAT_R32G32_UINT;
7290 case QRhiVertexInputAttribute::UInt:
7291 return DXGI_FORMAT_R32_UINT;
7292 case QRhiVertexInputAttribute::SInt4:
7293 return DXGI_FORMAT_R32G32B32A32_SINT;
7294 case QRhiVertexInputAttribute::SInt3:
7295 return DXGI_FORMAT_R32G32B32_SINT;
7296 case QRhiVertexInputAttribute::SInt2:
7297 return DXGI_FORMAT_R32G32_SINT;
7298 case QRhiVertexInputAttribute::SInt:
7299 return DXGI_FORMAT_R32_SINT;
7300 case QRhiVertexInputAttribute::Half4:
7302 case QRhiVertexInputAttribute::Half3:
7303 return DXGI_FORMAT_R16G16B16A16_FLOAT;
7304 case QRhiVertexInputAttribute::Half2:
7305 return DXGI_FORMAT_R16G16_FLOAT;
7306 case QRhiVertexInputAttribute::Half:
7307 return DXGI_FORMAT_R16_FLOAT;
7308 case QRhiVertexInputAttribute::UShort4:
7310 case QRhiVertexInputAttribute::UShort3:
7311 return DXGI_FORMAT_R16G16B16A16_UINT;
7312 case QRhiVertexInputAttribute::UShort2:
7313 return DXGI_FORMAT_R16G16_UINT;
7314 case QRhiVertexInputAttribute::UShort:
7315 return DXGI_FORMAT_R16_UINT;
7316 case QRhiVertexInputAttribute::SShort4:
7318 case QRhiVertexInputAttribute::SShort3:
7319 return DXGI_FORMAT_R16G16B16A16_SINT;
7320 case QRhiVertexInputAttribute::SShort2:
7321 return DXGI_FORMAT_R16G16_SINT;
7322 case QRhiVertexInputAttribute::SShort:
7323 return DXGI_FORMAT_R16_SINT;
7325 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
7328QD3D12GraphicsPipeline::QD3D12GraphicsPipeline(QRhiImplementation *rhi)
7329 : QRhiGraphicsPipeline(rhi)
7333QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
7338void QD3D12GraphicsPipeline::destroy()
7340 if (handle.isNull())
7343 QRHI_RES_RHI(QRhiD3D12);
7345 rhiD->releaseQueue.deferredReleasePipeline(handle);
7346 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
7353 rhiD->unregisterResource(
this);
7356bool QD3D12GraphicsPipeline::create()
7358 if (!handle.isNull())
7361 QRHI_RES_RHI(QRhiD3D12);
7362 if (!rhiD->sanityCheckGraphicsPipeline(
this))
7365 rhiD->pipelineCreationStart();
7367 QByteArray shaderBytecode[5];
7368 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
7369 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
7370 stageData[d3dStage].valid =
true;
7371 stageData[d3dStage].stage = d3dStage;
7372 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
7373 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
7374 shaderBytecode[d3dStage] = cacheIt->bytecode;
7375 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
7376 stageData[d3dStage].pushConstantRegister = cacheIt->pushConstantRegister;
7377 stageData[d3dStage].pushConstantSize = cacheIt->pushConstantSize;
7380 QShaderKey shaderKey;
7381 int compileFlags = 0;
7382 if (m_flags.testFlag(CompileShadersWithDebugInfo))
7383 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
7384 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
7385 shaderStage.shaderVariant(),
7389 if (bytecode.isEmpty()) {
7390 qWarning(
"HLSL graphics shader compilation failed: %s", qPrintable(error));
7394 shaderBytecode[d3dStage] = bytecode;
7395 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
7396 qd3d12_setPushConstantInfo(&stageData[d3dStage], shaderStage.shader(), shaderKey);
7397 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
7398 { bytecode, stageData[d3dStage].nativeResourceBindingMap,
7399 stageData[d3dStage].pushConstantRegister,
7400 stageData[d3dStage].pushConstantSize });
7404 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
7406 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
7407 pushConstantRootParamIndex = srbD->pushConstantRootParamIndex;
7408 if (rootSigHandle.isNull()) {
7409 qWarning(
"Failed to create root signature");
7413 ID3D12RootSignature *rootSig =
nullptr;
7414 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
7415 rootSig = rs->rootSig;
7417 qWarning(
"Cannot create graphics pipeline state without root signature");
7421 QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7422 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
7423 if (rpD->colorAttachmentCount > 0) {
7424 format = DXGI_FORMAT(rpD->colorFormat[0]);
7425 }
else if (rpD->hasDepthStencil) {
7426 format = DXGI_FORMAT(rpD->dsFormat);
7428 qWarning(
"Cannot create graphics pipeline state without color or depthStencil format");
7431 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
7434 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
7435 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
7436 QD3D12PipelineStateSubObject<D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE> primitiveRestartValue;
7437 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
7438 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
7439 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
7440 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
7441 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
7442 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
7443 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
7444 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
7445 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
7446 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
7447 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
7448 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
7449 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
7450 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
7453 stream.rootSig.object = rootSig;
7455 QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
7456 QByteArrayList matrixSliceSemantics;
7457 if (!shaderBytecode[VS].isEmpty()) {
7458 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
7461 D3D12_INPUT_ELEMENT_DESC desc = {};
7466 const int matrixSlice = it->matrixSlice();
7467 if (matrixSlice < 0) {
7468 desc.SemanticName =
"TEXCOORD";
7469 desc.SemanticIndex = UINT(it->location());
7473 std::snprintf(sem.data(), sem.size(),
"TEXCOORD%d_", it->location() - matrixSlice);
7474 matrixSliceSemantics.append(sem);
7475 desc.SemanticName = matrixSliceSemantics.last().constData();
7476 desc.SemanticIndex = UINT(matrixSlice);
7478 desc.Format = toD3DAttributeFormat(it->format());
7479 desc.InputSlot = UINT(it->binding());
7480 desc.AlignedByteOffset = it->offset();
7481 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
7482 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
7483 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
7484 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
7486 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
7488 inputDescs.append(desc);
7492 stream.inputLayout.object.NumElements = inputDescs.count();
7493 stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ?
nullptr : inputDescs.constData();
7495 stream.primitiveRestartValue.object = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
7497 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
7498 topology = toD3DTopology(m_topology, m_patchControlPointCount);
7500 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
7501 const int d3dStage = qd3d12_stage(shaderStage.type());
7504 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7505 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7508 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7509 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7512 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7513 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7516 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7517 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7520 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7521 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7529 stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
7530 stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
7531 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
7532 stream.rasterizerState.object.DepthBias = m_depthBias;
7533 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
7534 stream.rasterizerState.object.DepthClipEnable = m_depthClamp ? FALSE : TRUE;
7535 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
7537 stream.depthStencilState.object.DepthEnable = m_depthTest;
7538 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
7539 stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
7540 stream.depthStencilState.object.StencilEnable = m_stencilTest;
7541 if (m_stencilTest) {
7542 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
7543 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
7544 stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
7545 stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
7546 stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
7547 stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
7548 stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
7549 stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
7550 stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
7551 stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
7554 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
7555 for (
int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
7556 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
7557 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
7558 blend.BlendEnable = b.enable;
7559 blend.SrcBlend = toD3DBlendFactor(b.srcColor,
true);
7560 blend.DestBlend = toD3DBlendFactor(b.dstColor,
true);
7561 blend.BlendOp = toD3DBlendOp(b.opColor);
7562 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha,
false);
7563 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha,
false);
7564 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
7565 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
7566 stream.blendState.object.RenderTarget[i] = blend;
7568 if (m_targetBlends.isEmpty()) {
7569 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
7570 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
7571 stream.blendState.object.RenderTarget[0] = blend;
7574 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
7575 for (
int i = 0; i < rpD->colorAttachmentCount; ++i)
7576 stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
7578 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
7580 stream.sampleDesc.object = sampleDesc;
7582 stream.sampleMask.object = 0xFFFFFFFF;
7584 viewInstanceMask = 0;
7585 const bool isMultiView = m_multiViewCount >= 2;
7586 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
7587 QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
7589 for (
int i = 0; i < m_multiViewCount; ++i) {
7590 viewInstanceMask |= (1 << i);
7591 viewInstanceLocations.append({ 0, UINT(i) });
7593 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
7596 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
7598 QCryptographicHash keyHash(QCryptographicHash::Sha1);
7599 for (
const QByteArray &bytecode : shaderBytecode)
7600 addToKey(&keyHash, bytecode);
7601 for (
const D3D12_INPUT_ELEMENT_DESC &desc : inputDescs) {
7602 keyHash.addData(QByteArrayView(desc.SemanticName));
7603 addToKey(&keyHash, desc.SemanticIndex);
7604 addToKey(&keyHash, desc.Format);
7605 addToKey(&keyHash, desc.InputSlot);
7606 addToKey(&keyHash, desc.AlignedByteOffset);
7607 addToKey(&keyHash, desc.InputSlotClass);
7608 addToKey(&keyHash, desc.InstanceDataStepRate);
7610 addToKey(&keyHash, stream.primitiveRestartValue.object);
7611 addToKey(&keyHash, stream.primitiveTopology.object);
7612 addToKey(&keyHash, stream.rasterizerState.object);
7613 addToKey(&keyHash, stream.depthStencilState.object);
7614 addToKey(&keyHash, stream.blendState.object);
7615 addToKey(&keyHash, stream.rtFormats.object);
7616 addToKey(&keyHash, stream.dsFormat.object);
7617 addToKey(&keyHash, stream.sampleDesc.object);
7618 addToKey(&keyHash, stream.sampleMask.object);
7619 addToKey(&keyHash, stream.viewInstancingDesc.object.ViewInstanceCount);
7620 addToKey(&keyHash, stream.viewInstancingDesc.object.Flags);
7621 addToKey(&keyHash, viewInstanceLocations.constData(),
7622 viewInstanceLocations.count() *
sizeof(D3D12_VIEW_INSTANCE_LOCATION));
7625 addToKey(&keyHash, srbD->serializedLayoutDescription());
7627 ID3D12PipelineState *pso = rhiD->loadOrCreatePipelineState(&streamDesc, keyHash.result().toHex(),
"graphics");
7629 rhiD->rootSignaturePool.remove(rootSigHandle);
7634 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
7636 rhiD->pipelineCreationEnd();
7638 rhiD->registerResource(
this);
7642QD3D12ComputePipeline::QD3D12ComputePipeline(QRhiImplementation *rhi)
7643 : QRhiComputePipeline(rhi)
7647QD3D12ComputePipeline::~QD3D12ComputePipeline()
7652void QD3D12ComputePipeline::destroy()
7654 if (handle.isNull())
7657 QRHI_RES_RHI(QRhiD3D12);
7659 rhiD->releaseQueue.deferredReleasePipeline(handle);
7660 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
7667 rhiD->unregisterResource(
this);
7670bool QD3D12ComputePipeline::create()
7672 if (!handle.isNull())
7675 QRHI_RES_RHI(QRhiD3D12);
7676 rhiD->pipelineCreationStart();
7678 stageData.valid =
true;
7679 stageData.stage = CS;
7681 QByteArray shaderBytecode;
7682 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(m_shaderStage);
7683 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
7684 shaderBytecode = cacheIt->bytecode;
7685 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
7686 stageData.pushConstantRegister = cacheIt->pushConstantRegister;
7687 stageData.pushConstantSize = cacheIt->pushConstantSize;
7690 QShaderKey shaderKey;
7691 int compileFlags = 0;
7692 if (m_flags.testFlag(CompileShadersWithDebugInfo))
7693 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
7694 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
7695 m_shaderStage.shaderVariant(),
7699 if (bytecode.isEmpty()) {
7700 qWarning(
"HLSL compute shader compilation failed: %s", qPrintable(error));
7704 shaderBytecode = bytecode;
7705 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
7706 qd3d12_setPushConstantInfo(&stageData, m_shaderStage.shader(), shaderKey);
7707 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
7708 stageData.nativeResourceBindingMap,
7709 stageData.pushConstantRegister,
7710 stageData.pushConstantSize });
7713 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
7715 rootSigHandle = srbD->createRootSignature(&stageData, 1);
7716 pushConstantRootParamIndex = srbD->pushConstantRootParamIndex;
7717 if (rootSigHandle.isNull()) {
7718 qWarning(
"Failed to create root signature");
7722 ID3D12RootSignature *rootSig =
nullptr;
7723 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
7724 rootSig = rs->rootSig;
7726 qWarning(
"Cannot create compute pipeline state without root signature");
7731 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
7732 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
7734 stream.rootSig.object = rootSig;
7735 stream.CS.object.pShaderBytecode = shaderBytecode.constData();
7736 stream.CS.object.BytecodeLength = shaderBytecode.size();
7737 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
7739 QCryptographicHash keyHash(QCryptographicHash::Sha1);
7740 addToKey(&keyHash, shaderBytecode);
7741 addToKey(&keyHash, srbD->serializedLayoutDescription());
7743 ID3D12PipelineState *pso = rhiD->loadOrCreatePipelineState(&streamDesc, keyHash.result().toHex(),
"compute");
7745 rhiD->rootSignaturePool.remove(rootSigHandle);
7750 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
7752 rhiD->pipelineCreationEnd();
7754 rhiD->registerResource(
this);
7761QD3D12RenderPassDescriptor::QD3D12RenderPassDescriptor(QRhiImplementation *rhi)
7762 : QRhiRenderPassDescriptor(rhi)
7764 serializedFormatData.reserve(16);
7767QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
7772void QD3D12RenderPassDescriptor::destroy()
7774 QRHI_RES_RHI(QRhiD3D12);
7776 rhiD->unregisterResource(
this);
7779bool QD3D12RenderPassDescriptor::isCompatible(
const QRhiRenderPassDescriptor *other)
const
7784 const QD3D12RenderPassDescriptor *o = QRHI_RES(
const QD3D12RenderPassDescriptor, other);
7786 if (colorAttachmentCount != o->colorAttachmentCount)
7789 if (hasDepthStencil != o->hasDepthStencil)
7792 for (
int i = 0; i < colorAttachmentCount; ++i) {
7793 if (colorFormat[i] != o->colorFormat[i])
7797 if (hasDepthStencil) {
7798 if (dsFormat != o->dsFormat)
7802 if (hasShadingRateMap != o->hasShadingRateMap)
7808void QD3D12RenderPassDescriptor::updateSerializedFormat()
7810 serializedFormatData.clear();
7811 auto p = std::back_inserter(serializedFormatData);
7813 *p++ = colorAttachmentCount;
7814 *p++ = hasDepthStencil;
7815 for (
int i = 0; i < colorAttachmentCount; ++i)
7816 *p++ = colorFormat[i];
7817 *p++ = hasDepthStencil ? dsFormat : 0;
7820QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor()
const
7822 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
7823 rpD->colorAttachmentCount = colorAttachmentCount;
7824 rpD->hasDepthStencil = hasDepthStencil;
7825 memcpy(rpD->colorFormat, colorFormat,
sizeof(colorFormat));
7826 rpD->dsFormat = dsFormat;
7827 rpD->hasShadingRateMap = hasShadingRateMap;
7829 rpD->updateSerializedFormat();
7831 QRHI_RES_RHI(QRhiD3D12);
7832 rhiD->registerResource(rpD);
7836QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat()
const
7838 return serializedFormatData;
7841QD3D12CommandBuffer::QD3D12CommandBuffer(QRhiImplementation *rhi)
7842 : QRhiCommandBuffer(rhi)
7847QD3D12CommandBuffer::~QD3D12CommandBuffer()
7852void QD3D12CommandBuffer::destroy()
7857const QRhiNativeHandles *QD3D12CommandBuffer::nativeHandles()
7859 nativeHandlesStruct.commandList = cmdList;
7860 return &nativeHandlesStruct;
7863QD3D12SwapChainRenderTarget::QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
7864 : QRhiSwapChainRenderTarget(rhi, swapchain),
7869QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
7874void QD3D12SwapChainRenderTarget::destroy()
7879QSize QD3D12SwapChainRenderTarget::pixelSize()
const
7884float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
7889int QD3D12SwapChainRenderTarget::sampleCount()
const
7891 return d.sampleCount;
7894QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
7895 : QRhiSwapChain(rhi),
7896 rtWrapper(rhi,
this),
7897 rtWrapperRight(rhi,
this),
7902QD3D12SwapChain::~QD3D12SwapChain()
7907void QD3D12SwapChain::destroy()
7910 dcompVisual->Release();
7911 dcompVisual =
nullptr;
7915 dcompTarget->Release();
7916 dcompTarget =
nullptr;
7924 swapChain->Release();
7925 swapChain =
nullptr;
7926 sourceSwapChain1->Release();
7927 sourceSwapChain1 =
nullptr;
7929 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7930 FrameResources &fr(frameRes[i]);
7932 fr.fence->Release();
7934 CloseHandle(fr.fenceEvent);
7936 fr.cmdList->Release();
7940 if (frameLatencyWaitableObject) {
7941 CloseHandle(frameLatencyWaitableObject);
7942 frameLatencyWaitableObject =
nullptr;
7945 QDxgiVSyncService::instance()->unregisterWindow(window);
7947 QRHI_RES_RHI(QRhiD3D12);
7949 rhiD->swapchains.remove(
this);
7950 rhiD->unregisterResource(
this);
7954void QD3D12SwapChain::releaseBuffers()
7956 QRHI_RES_RHI(QRhiD3D12);
7958 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7959 rhiD->resourcePool.remove(colorBuffers[i]);
7960 rhiD->rtvPool.release(rtvs[i], 1);
7962 rhiD->rtvPool.release(rtvsRight[i], 1);
7964 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7965 if (!msaaBuffers[i].isNull())
7966 rhiD->resourcePool.remove(msaaBuffers[i]);
7967 if (msaaRtvs[i].isValid())
7968 rhiD->rtvPool.release(msaaRtvs[i], 1);
7972void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
7974 FrameResources &fr(frameRes[frameSlot]);
7975 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
7976 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
7977 WaitForSingleObject(fr.fenceEvent, INFINITE);
7981void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
7983 QRHI_RES_RHI(QRhiD3D12);
7984 FrameResources &fr(frameRes[currentFrameSlot]);
7985 fr.fenceCounter += 1u;
7986 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
7989QRhiCommandBuffer *QD3D12SwapChain::currentFrameCommandBuffer()
7994QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
7999QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
8001 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
8004QSize QD3D12SwapChain::surfacePixelSize()
8007 return m_window->size() * m_window->devicePixelRatio();
8010bool QD3D12SwapChain::isFormatSupported(Format f)
8016 qWarning(
"Attempted to call isFormatSupported() without a window set");
8020 QRHI_RES_RHI(QRhiD3D12);
8021 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window))
8022 return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
8027QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
8029 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
8032 QRHI_RES_RHI(QRhiD3D12);
8033 info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window);
8038QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
8043 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
8044 rpD->colorAttachmentCount = 1;
8045 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
8046 rpD->colorFormat[0] =
int(srgbAdjustedColorFormat);
8047 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
8049 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
8051 rpD->updateSerializedFormat();
8053 QRHI_RES_RHI(QRhiD3D12);
8054 rhiD->registerResource(rpD);
8058bool QRhiD3D12::ensureDirectCompositionDevice()
8063 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
8064 dcompDevice = QRhiD3D::createDirectCompositionDevice();
8065 return dcompDevice ?
true :
false;
8068static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
8069static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
8071void QD3D12SwapChain::chooseFormats()
8073 colorFormat = DEFAULT_FORMAT;
8074 srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
8075 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
8076 QRHI_RES_RHI(QRhiD3D12);
8077 if (m_format != SDR) {
8078 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) {
8081 case HDRExtendedSrgbLinear:
8082 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
8083 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
8084 srgbAdjustedColorFormat = colorFormat;
8087 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
8088 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
8089 srgbAdjustedColorFormat = colorFormat;
8098 qWarning(
"The output associated with the window is not HDR capable "
8099 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
8102 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
8105bool QD3D12SwapChain::createOrResize()
8111 const bool needsRegistration = !window || window != m_window;
8114 if (window && window != m_window)
8118 m_currentPixelSize = surfacePixelSize();
8119 pixelSize = m_currentPixelSize;
8121 if (pixelSize.isEmpty())
8124 HWND hwnd =
reinterpret_cast<HWND>(window->winId());
8126 QRHI_RES_RHI(QRhiD3D12);
8127 stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
8129 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
8130 if (rhiD->ensureDirectCompositionDevice()) {
8132 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
false, &dcompTarget);
8134 qWarning(
"Failed to create Direct Composition target for the window: %s",
8135 qPrintable(QSystemError::windowsComString(hr)));
8138 if (dcompTarget && !dcompVisual) {
8139 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
8141 qWarning(
"Failed to create DirectComposition visual: %s",
8142 qPrintable(QSystemError::windowsComString(hr)));
8147 if (window->requestedFormat().alphaBufferSize() <= 0)
8148 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
8149 "This may lead to problems.");
8152 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
8154 if (swapInterval == 0 && rhiD->supportsAllowTearing)
8155 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
8159 const bool useFrameLatencyWaitableObject = rhiD->maxFrameLatency != 0
8160 && swapInterval != 0
8161 && rhiD->driverInfoStruct.deviceType != QRhiDriverInfo::CpuDevice;
8162 if (useFrameLatencyWaitableObject)
8163 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
8168 DXGI_SWAP_CHAIN_DESC1 desc = {};
8169 desc.Width = UINT(pixelSize.width());
8170 desc.Height = UINT(pixelSize.height());
8171 desc.Format = colorFormat;
8172 desc.SampleDesc.Count = 1;
8173 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
8174 desc.BufferCount = BUFFER_COUNT;
8175 desc.Flags = swapChainFlags;
8176 desc.Scaling = DXGI_SCALING_NONE;
8177 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
8178 desc.Stereo = stereo;
8184 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
8189 desc.Scaling = DXGI_SCALING_STRETCH;
8193 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
8195 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
8200 if (FAILED(hr) && m_format != SDR) {
8201 colorFormat = DEFAULT_FORMAT;
8202 desc.Format = DEFAULT_FORMAT;
8204 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
8206 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
8209 if (SUCCEEDED(hr)) {
8210 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<
void **>(&swapChain)))) {
8211 qWarning(
"IDXGISwapChain3 not available");
8214 if (m_format != SDR) {
8215 hr = swapChain->SetColorSpace1(hdrColorSpace);
8217 qWarning(
"Failed to set color space on swapchain: %s",
8218 qPrintable(QSystemError::windowsComString(hr)));
8221 if (useFrameLatencyWaitableObject) {
8222 swapChain->SetMaximumFrameLatency(rhiD->maxFrameLatency);
8223 frameLatencyWaitableObject = swapChain->GetFrameLatencyWaitableObject();
8226 hr = dcompVisual->SetContent(swapChain);
8227 if (SUCCEEDED(hr)) {
8228 hr = dcompTarget->SetRoot(dcompVisual);
8230 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
8231 qPrintable(QSystemError::windowsComString(hr)));
8234 qWarning(
"Failed to set content for Direct Composition visual: %s",
8235 qPrintable(QSystemError::windowsComString(hr)));
8239 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
8242 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
8243 qWarning(
"Device loss detected during swapchain creation");
8244 rhiD->deviceLost =
true;
8246 }
else if (FAILED(hr)) {
8247 qWarning(
"Failed to create D3D12 swapchain: %s"
8248 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
8249 qPrintable(QSystemError::windowsComString(hr)),
8250 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
8251 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
8255 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
8256 hr = rhiD->dev->CreateFence(0,
8257 D3D12_FENCE_FLAG_NONE,
8258 __uuidof(ID3D12Fence),
8259 reinterpret_cast<
void **>(&frameRes[i].fence));
8261 qWarning(
"Failed to create fence for swapchain: %s",
8262 qPrintable(QSystemError::windowsComString(hr)));
8265 frameRes[i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
8267 frameRes[i].fenceCounter = 0;
8271 hr = swapChain->ResizeBuffers(BUFFER_COUNT,
8272 UINT(pixelSize.width()),
8273 UINT(pixelSize.height()),
8276 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
8277 qWarning(
"Device loss detected in ResizeBuffers()");
8278 rhiD->deviceLost =
true;
8280 }
else if (FAILED(hr)) {
8281 qWarning(
"Failed to resize D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
8286 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
8287 ID3D12Resource *colorBuffer;
8288 hr = swapChain->GetBuffer(i, __uuidof(ID3D12Resource),
reinterpret_cast<
void **>(&colorBuffer));
8290 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
8291 i, qPrintable(QSystemError::windowsComString(hr)));
8294 colorBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
8295 rtvs[i] = rhiD->rtvPool.allocate(1);
8296 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
8297 rtvDesc.Format = srgbAdjustedColorFormat;
8298 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
8299 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
8302 rtvsRight[i] = rhiD->rtvPool.allocate(1);
8303 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
8304 rtvDesc.Format = srgbAdjustedColorFormat;
8305 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
8306 rtvDesc.Texture2DArray.ArraySize = 1;
8307 rtvDesc.Texture2DArray.FirstArraySlice = 1;
8308 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
8312 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
8313 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
8314 m_depthStencil->sampleCount(), m_sampleCount);
8316 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
8317 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
8318 m_depthStencil->setPixelSize(pixelSize);
8319 if (!m_depthStencil->create())
8320 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
8321 pixelSize.width(), pixelSize.height());
8323 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
8324 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
8325 pixelSize.width(), pixelSize.height());
8329 ds = m_depthStencil ? QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
8331 if (sampleDesc.Count > 1) {
8332 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
8333 D3D12_RESOURCE_DESC resourceDesc = {};
8334 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
8335 resourceDesc.Width = UINT64(pixelSize.width());
8336 resourceDesc.Height = UINT(pixelSize.height());
8337 resourceDesc.DepthOrArraySize = 1;
8338 resourceDesc.MipLevels = 1;
8339 resourceDesc.Format = srgbAdjustedColorFormat;
8340 resourceDesc.SampleDesc = sampleDesc;
8341 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
8342 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
8343 D3D12_CLEAR_VALUE clearValue = {};
8344 clearValue.Format = colorFormat;
8345 ID3D12Resource *resource =
nullptr;
8346 D3D12MA::Allocation *allocation =
nullptr;
8347 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
8349 D3D12_RESOURCE_STATE_RENDER_TARGET,
8352 __uuidof(ID3D12Resource),
8353 reinterpret_cast<
void **>(&resource));
8355 qWarning(
"Failed to create MSAA color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
8358 msaaBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
8359 msaaRtvs[i] = rhiD->rtvPool.allocate(1);
8360 if (!msaaRtvs[i].isValid())
8362 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
8363 rtvDesc.Format = srgbAdjustedColorFormat;
8364 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
8365 : D3D12_RTV_DIMENSION_TEXTURE2D;
8366 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[i].cpuHandle);
8370 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
8371 currentFrameSlot = 0;
8372 lastFrameLatencyWaitSlot = -1;
8374 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
8375 QD3D12SwapChainRenderTarget *rtD = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
8376 rtD->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
8377 rtD->d.pixelSize = pixelSize;
8378 rtD->d.dpr =
float(window->devicePixelRatio());
8379 rtD->d.sampleCount =
int(sampleDesc.Count);
8380 rtD->d.colorAttCount = 1;
8381 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
8383 rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
8384 QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
8385 rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
8386 rtDr->d.pixelSize = pixelSize;
8387 rtDr->d.dpr =
float(window->devicePixelRatio());
8388 rtDr->d.sampleCount =
int(sampleDesc.Count);
8389 rtDr->d.colorAttCount = 1;
8390 rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
8392 QDxgiVSyncService::instance()->registerWindow(window);
8394 if (needsRegistration || !rhiD->swapchains.contains(
this))
8395 rhiD->swapchains.insert(
this);
8397 rhiD->registerResource(
this);