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::WideLines:
939 case QRhi::VertexShaderPointSize:
941 case QRhi::BaseVertex:
943 case QRhi::BaseInstance:
945 case QRhi::TriangleFanTopology:
947 case QRhi::ReadBackNonUniformBuffer:
949 case QRhi::ReadBackNonBaseMipLevel:
951 case QRhi::TexelFetch:
953 case QRhi::RenderToNonBaseMipLevel:
955 case QRhi::IntAttributes:
957 case QRhi::ScreenSpaceDerivatives:
959 case QRhi::ReadBackAnyTextureFormat:
961 case QRhi::PipelineCacheDataLoadSave:
962#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
967 case QRhi::ImageDataStride:
969 case QRhi::RenderBufferImport:
971 case QRhi::ThreeDimensionalTextures:
973 case QRhi::RenderTo3DTextureSlice:
975 case QRhi::TextureArrays:
977 case QRhi::Tessellation:
979 case QRhi::GeometryShader:
981 case QRhi::TextureArrayRange:
983 case QRhi::NonFillPolygonMode:
985 case QRhi::OneDimensionalTextures:
987 case QRhi::OneDimensionalTextureMipmaps:
989 case QRhi::HalfAttributes:
991 case QRhi::RenderToOneDimensionalTexture:
993 case QRhi::ThreeDimensionalTextureMipmaps:
995 case QRhi::MultiView:
996 return caps.multiView;
997 case QRhi::TextureViewFormat:
998 return caps.textureViewFormat;
999 case QRhi::ResolveDepthStencil:
1003 case QRhi::VariableRateShading:
1005 case QRhi::VariableRateShadingMap:
1006 case QRhi::VariableRateShadingMapWithTexture:
1008 case QRhi::PerRenderTargetBlending:
1009 case QRhi::SampleVariables:
1011 case QRhi::InstanceIndexIncludesBaseInstance:
1013 case QRhi::DepthClamp:
1015 case QRhi::DrawIndirect:
1016 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
1017 case QRhi::DrawIndirectMulti:
1018 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
1019 case QRhi::ShaderDrawParameters:
1021 case QRhi::DispatchIndirect:
1022 return dispatchCommandSignature !=
nullptr;
1023 case QRhi::PushConstants:
1025 case QRhi::DrawIndirectCount:
1027 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
1028 case QRhi::BufferToBufferCopy:
1030 case QRhi::StaticBuffersOnGpuTimeline:
1036int QRhiD3D12::resourceLimit(QRhi::ResourceLimit limit)
const
1039 case QRhi::TextureSizeMin:
1041 case QRhi::TextureSizeMax:
1043 case QRhi::MaxColorAttachments:
1045 case QRhi::FramesInFlight:
1046 return QD3D12_FRAMES_IN_FLIGHT;
1047 case QRhi::MaxAsyncReadbackFrames:
1048 return QD3D12_FRAMES_IN_FLIGHT;
1049 case QRhi::MaxThreadGroupsPerDimension:
1051 case QRhi::MaxThreadsPerThreadGroup:
1053 case QRhi::MaxThreadGroupX:
1055 case QRhi::MaxThreadGroupY:
1057 case QRhi::MaxThreadGroupZ:
1059 case QRhi::TextureArraySizeMax:
1061 case QRhi::MaxUniformBufferRange:
1063 case QRhi::MaxVertexInputs:
1065 case QRhi::MaxVertexOutputs:
1067 case QRhi::MaxPushConstantsSize:
1069 case QRhi::MaxVertexStorageBuffers:
1070 case QRhi::MaxFragmentStorageBuffers:
1072 case QRhi::ShadingRateImageTileSize:
1073 return shadingRateImageTileSize;
1078const QRhiNativeHandles *QRhiD3D12::nativeHandles()
1080 return &nativeHandlesStruct;
1083QRhiDriverInfo QRhiD3D12::driverInfo()
const
1085 return driverInfoStruct;
1088QRhiStats QRhiD3D12::statistics()
1091 result.totalPipelineCreationTime = totalPipelineCreationTime();
1093 D3D12MA::Budget budgets[2];
1094 vma.getBudget(&budgets[0], &budgets[1]);
1095 for (
int i = 0; i < 2; ++i) {
1096 const D3D12MA::Statistics &stats(budgets[i].Stats);
1097 result.blockCount += stats.BlockCount;
1098 result.allocCount += stats.AllocationCount;
1099 result.usedBytes += stats.AllocationBytes;
1100 result.unusedBytes += stats.BlockBytes - stats.AllocationBytes;
1101 result.totalUsageBytes += budgets[i].UsageBytes;
1107bool QRhiD3D12::makeThreadLocalNativeContextCurrent()
1113void QRhiD3D12::setQueueSubmitParams(QRhiNativeHandles *)
1118void QRhiD3D12::releaseCachedResources()
1120 shaderBytecodeCache.clear();
1129static inline void addToKey(QCryptographicHash *h,
const void *p, size_t size)
1131 h->addData(QByteArrayView(
static_cast<
const char *>(p), qsizetype(size)));
1135static inline void addToKey(QCryptographicHash *h,
const T &v)
1137 addToKey(h, &v,
sizeof(T));
1140static inline void addToKey(QCryptographicHash *h,
const QByteArray &b)
1142 const quint32 size = quint32(b.size());
1147static inline void addToKey(QCryptographicHash *h,
const QVector<quint32> &v)
1149 const quint32 count = quint32(v.count());
1151 addToKey(h, v.constData(), v.count() *
sizeof(quint32));
1154bool QRhiD3D12::createPipelineLibrary(
const QByteArray &blob)
1156#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1157 destroyPipelineLibrary();
1159 pipelineLibraryBlob = blob;
1160 HRESULT hr = dev->CreatePipelineLibrary(pipelineLibraryBlob.isEmpty() ?
nullptr
1161 : pipelineLibraryBlob.constData(),
1162 SIZE_T(pipelineLibraryBlob.size()),
1163 __uuidof(ID3D12PipelineLibrary1),
1164 reinterpret_cast<
void **>(&pipelineLibrary));
1170 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline library: %s",
1171 qPrintable(QSystemError::windowsComString(hr)));
1172 pipelineLibrary =
nullptr;
1173 pipelineLibraryBlob.clear();
1183bool QRhiD3D12::ensurePipelineLibrary()
1185#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1186 if (pipelineLibrary)
1188 if (!rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
1190 return createPipelineLibrary(QByteArray());
1196void QRhiD3D12::destroyPipelineLibrary()
1198#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1199 if (pipelineLibrary) {
1200 pipelineLibrary->Release();
1201 pipelineLibrary =
nullptr;
1203 pipelineLibraryBlob.clear();
1204 pipelineLibraryNames.clear();
1208ID3D12PipelineState *QRhiD3D12::loadOrCreatePipelineState(
const D3D12_PIPELINE_STATE_STREAM_DESC *streamDesc,
1209 const QByteArray &cacheKey,
1212 ID3D12PipelineState *pso =
nullptr;
1214#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1215 QVarLengthArray<
wchar_t, 64> name;
1216 if (ensurePipelineLibrary() && !cacheKey.isEmpty()) {
1217 name.resize(cacheKey.size() + 1);
1218 for (qsizetype i = 0; i < cacheKey.size(); ++i)
1219 name[i] =
wchar_t(cacheKey.at(i));
1220 name[cacheKey.size()] = 0;
1221 HRESULT hr = pipelineLibrary->LoadPipeline(name.constData(),
1223 __uuidof(ID3D12PipelineState),
1224 reinterpret_cast<
void **>(&pso));
1230 HRESULT hr = dev->CreatePipelineState(streamDesc,
1231 __uuidof(ID3D12PipelineState),
1232 reinterpret_cast<
void **>(&pso));
1234 qWarning(
"Failed to create %s pipeline state: %s",
1235 what, qPrintable(QSystemError::windowsComString(hr)));
1239#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1240 if (pipelineLibrary && !name.isEmpty() && !pipelineLibraryNames.contains(cacheKey)) {
1241 if (SUCCEEDED(pipelineLibrary->StorePipeline(name.constData(), pso)))
1242 pipelineLibraryNames.insert(cacheKey);
1249struct QD3D12PipelineCacheDataHeader
1257 quint64 adapterLuid;
1260QByteArray QRhiD3D12::pipelineCacheData()
1262 static_assert(
sizeof(QD3D12PipelineCacheDataHeader) == 32);
1265#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1266 if (!pipelineLibrary || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
1269 const SIZE_T dataSize = pipelineLibrary->GetSerializedSize();
1273 const size_t headerSize =
sizeof(QD3D12PipelineCacheDataHeader);
1274 data.resize(qsizetype(headerSize + dataSize));
1275 HRESULT hr = pipelineLibrary->Serialize(data.data() + headerSize, dataSize);
1277 qCDebug(QRHI_LOG_INFO,
"Failed to serialize pipeline library: %s",
1278 qPrintable(QSystemError::windowsComString(hr)));
1279 return QByteArray();
1282 QD3D12PipelineCacheDataHeader header = {};
1283 header.rhiId = pipelineCacheRhiId();
1284 header.arch = quint32(
sizeof(
void *));
1285 header.dataSize = quint32(dataSize);
1286 header.vendorId = quint32(driverInfoStruct.vendorId);
1287 header.deviceId = quint32(driverInfoStruct.deviceId);
1288 header.adapterLuid = (quint64(quint32(adapterLuid.HighPart)) << 32) | quint64(adapterLuid.LowPart);
1289 memcpy(data.data(), &header, headerSize);
1294void QRhiD3D12::setPipelineCacheData(
const QByteArray &data)
1296#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1300 const size_t headerSize =
sizeof(QD3D12PipelineCacheDataHeader);
1301 if (data.size() < qsizetype(headerSize)) {
1302 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
1305 QD3D12PipelineCacheDataHeader header;
1306 memcpy(&header, data.constData(), headerSize);
1308 const quint32 rhiId = pipelineCacheRhiId();
1309 if (header.rhiId != rhiId) {
1310 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
1311 rhiId, header.rhiId);
1314 const quint32 arch = quint32(
sizeof(
void *));
1315 if (header.arch != arch) {
1316 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
1320 if (header.vendorId != quint32(driverInfoStruct.vendorId)) {
1321 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorId does not match (%u, %u)",
1322 quint32(driverInfoStruct.vendorId), header.vendorId);
1325 if (header.deviceId != quint32(driverInfoStruct.deviceId)) {
1326 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceId does not match (%u, %u)",
1327 quint32(driverInfoStruct.deviceId), header.deviceId);
1330 const quint64 luid = (quint64(quint32(adapterLuid.HighPart)) << 32) | quint64(adapterLuid.LowPart);
1331 if (header.adapterLuid != luid) {
1332 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: adapter LUID does not match");
1335 if (quint64(data.size()) < quint64(headerSize) + header.dataSize) {
1336 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
1343 if (createPipelineLibrary(data.mid(qsizetype(headerSize)))) {
1344 qCDebug(QRHI_LOG_INFO,
"Created pipeline library with initial data of %u bytes",
1352bool QRhiD3D12::isDeviceLost()
const
1357QRhiRenderBuffer *QRhiD3D12::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
1358 int sampleCount, QRhiRenderBuffer::Flags flags,
1359 QRhiTexture::Format backingFormatHint)
1361 return new QD3D12RenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
1364QRhiTexture *QRhiD3D12::createTexture(QRhiTexture::Format format,
1365 const QSize &pixelSize,
int depth,
int arraySize,
1366 int sampleCount, QRhiTexture::Flags flags)
1368 return new QD3D12Texture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
1371QRhiSampler *QRhiD3D12::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
1372 QRhiSampler::Filter mipmapMode,
1373 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
1375 return new QD3D12Sampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
1378QRhiTextureRenderTarget *QRhiD3D12::createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
1379 QRhiTextureRenderTarget::Flags flags)
1381 return new QD3D12TextureRenderTarget(
this, desc, flags);
1384QRhiShadingRateMap *QRhiD3D12::createShadingRateMap()
1386 return new QD3D12ShadingRateMap(
this);
1389QRhiGraphicsPipeline *QRhiD3D12::createGraphicsPipeline()
1391 return new QD3D12GraphicsPipeline(
this);
1394QRhiComputePipeline *QRhiD3D12::createComputePipeline()
1396 return new QD3D12ComputePipeline(
this);
1399QRhiShaderResourceBindings *QRhiD3D12::createShaderResourceBindings()
1401 return new QD3D12ShaderResourceBindings(
this);
1404void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
1406 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1407 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1408 QD3D12GraphicsPipeline *psD = QRHI_RES(QD3D12GraphicsPipeline, ps);
1409 const bool pipelineChanged = cbD->currentGraphicsPipeline != psD || cbD->currentPipelineGeneration != psD->generation;
1411 if (pipelineChanged) {
1412 cbD->currentGraphicsPipeline = psD;
1413 cbD->currentComputePipeline =
nullptr;
1414 cbD->currentPipelineGeneration = psD->generation;
1416 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
1417 Q_ASSERT(pipeline->type == QD3D12Pipeline::Graphics);
1418 cbD->cmdList->SetPipelineState(pipeline->pso);
1419 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
1420 cbD->cmdList->SetGraphicsRootSignature(rs->rootSig);
1423 cbD->cmdList->IASetPrimitiveTopology(psD->topology);
1425 if (psD->viewInstanceMask)
1426 cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
1428 if (cbD->hasCustomScissorSet && !psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor))
1429 setDefaultScissor(cbD);
1433void QD3D12ShaderResourceBindings::cacheUniformBuffer(QD3D12Stage s,
1434 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
1441 bindingCache.cbufs[s].append({ QRHI_RES(QD3D12Buffer, d.buf), d.offset, binding });
1444void QD3D12ShaderResourceBindings::cacheTextures(QD3D12Stage s,
1445 const QRhiShaderResourceBinding::TextureAndSampler *d,
1449 for (
int i = 0; i < count; ++i) {
1450 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d[i].tex);
1451 bindingCache.srvs[s].append(texD->srv.cpuHandle);
1455void QD3D12ShaderResourceBindings::cacheSamplers(QD3D12Stage s,
1456 const QRhiShaderResourceBinding::TextureAndSampler *d,
1461 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, d[0].sampler);
1462 bindingCache.samplers[s].append(samplerD->lookupOrCreateShaderVisibleDescriptor().gpuHandle);
1470 QRHI_RES_RHI(QRhiD3D12);
1471 QVarLengthArray<Q_D3D12_SAMPLER_DESC, 8> descs;
1472 for (
int i = 0; i < count; ++i)
1473 descs.append({ QRHI_RES(QD3D12Sampler, d[i].sampler)->desc });
1474 bindingCache.samplers[s].append(rhiD->samplerMgr.getShaderVisibleDescriptors(descs).gpuHandle);
1477void QD3D12ShaderResourceBindings::cacheStorageBuffer(QD3D12Stage s,
1478 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
1479 QD3D12ShaderResourceVisitor::StorageOp,
1482 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1484 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1485 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1486 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
1487 uavDesc.Buffer.FirstElement = d.offset / 4;
1488 uavDesc.Buffer.NumElements = aligned(bufD->m_size - d.offset, 4u) / 4;
1489 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
1490 bindingCache.uavs[s].append({ bufD->handles[0], uavDesc });
1493void QD3D12ShaderResourceBindings::cacheStorageImage(QD3D12Stage s,
1494 const QRhiShaderResourceBinding::Data::StorageImageData &d,
1495 QD3D12ShaderResourceVisitor::StorageOp,
1498 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1499 const bool isCube = texD->m_flags.testFlag(QRhiTexture::CubeMap);
1500 const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
1501 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1502 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1503 uavDesc.Format = texD->rtFormat;
1505 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1506 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1507 uavDesc.Texture2DArray.FirstArraySlice = 0;
1508 uavDesc.Texture2DArray.ArraySize = 6;
1509 }
else if (isArray) {
1510 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1511 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1512 uavDesc.Texture2DArray.FirstArraySlice = 0;
1513 uavDesc.Texture2DArray.ArraySize = UINT(qMax(0, texD->m_arraySize));
1515 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1516 uavDesc.Texture3D.MipSlice = UINT(d.level);
1517 uavDesc.Texture3D.WSize = UINT(-1);
1519 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
1520 uavDesc.Texture2D.MipSlice = UINT(d.level);
1522 bindingCache.uavs[s].append({ texD->handle, uavDesc });
1525void QD3D12ShaderResourceBindings::rebuildBindingCache(
const QD3D12ShaderStageData *stageData,
1528 bindingCache.reset();
1530 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
1532 using namespace std::placeholders;
1533 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::cacheUniformBuffer,
this, _1, _2, _3, _4);
1534 visitor.textures = std::bind(&QD3D12ShaderResourceBindings::cacheTextures,
this, _1, _2, _3, _4);
1535 visitor.samplers = std::bind(&QD3D12ShaderResourceBindings::cacheSamplers,
this, _1, _2, _3, _4);
1536 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::cacheStorageBuffer,
this, _1, _2, _3, _4);
1537 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::cacheStorageImage,
this, _1, _2, _3, _4);
1542 for (
int s = 0; s < 6; ++s) {
1543 bindingCache.srvUavCount += bindingCache.srvs[s].count();
1544 bindingCache.srvUavCount += bindingCache.uavs[s].count();
1547 bindingCacheValid =
true;
1548 bindingCacheGeneration = generation;
1551void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
1552 int dynamicOffsetCount,
1553 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1555 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1556 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
1557 QD3D12GraphicsPipeline *gfxPsD = QRHI_RES(QD3D12GraphicsPipeline, cbD->currentGraphicsPipeline);
1558 QD3D12ComputePipeline *compPsD = QRHI_RES(QD3D12ComputePipeline, cbD->currentComputePipeline);
1562 srb = gfxPsD->m_shaderResourceBindings;
1564 srb = compPsD->m_shaderResourceBindings;
1567 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, srb);
1569 bool pipelineChanged =
false;
1571 pipelineChanged = srbD->lastUsedGraphicsPipeline != gfxPsD
1572 || srbD->lastUsedPipelineGeneration != gfxPsD->generation;
1573 srbD->lastUsedGraphicsPipeline = gfxPsD;
1574 srbD->lastUsedComputePipeline =
nullptr;
1575 srbD->lastUsedPipelineGeneration = gfxPsD->generation;
1577 pipelineChanged = srbD->lastUsedComputePipeline != compPsD
1578 || srbD->lastUsedPipelineGeneration != compPsD->generation;
1579 srbD->lastUsedGraphicsPipeline =
nullptr;
1580 srbD->lastUsedComputePipeline = compPsD;
1581 srbD->lastUsedPipelineGeneration = compPsD->generation;
1584 bool srbUpdate =
false;
1586 for (
int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
1587 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings[i]);
1588 QD3D12ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
1590 case QRhiShaderResourceBinding::UniformBuffer:
1592 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.ubuf.buf);
1593 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
1594 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1595 sanityCheckResourceOwnership(bufD);
1596 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1597 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
1599 bd.ubuf.id = bufD->m_id;
1600 bd.ubuf.generation = bufD->generation;
1604 case QRhiShaderResourceBinding::SampledTexture:
1605 case QRhiShaderResourceBinding::Texture:
1606 case QRhiShaderResourceBinding::Sampler:
1608 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->stex;
1609 if (bd.stex.d.size() != data->count()) {
1610 bd.stex.d.resize(data->count());
1613 for (
int elem = 0; elem < data->count(); ++elem) {
1614 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, data->texSamplers[elem].tex);
1615 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, data->texSamplers[elem].sampler);
1619 Q_ASSERT(texD || samplerD);
1620 sanityCheckResourceOwnership(texD);
1621 sanityCheckResourceOwnership(samplerD);
1622 const quint64 texId = texD ? texD->m_id : 0;
1623 const uint texGen = texD ? texD->generation : 0;
1624 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
1625 const uint samplerGen = samplerD ? samplerD->generation : 0;
1626 if (texId != bd.stex.d[elem].texId || texGen != bd.stex.d[elem].texGeneration
1627 || samplerId != bd.stex.d[elem].samplerId
1628 || samplerGen != bd.stex.d[elem].samplerGeneration)
1631 bd.stex.d[elem].texId = texId;
1632 bd.stex.d[elem].texGeneration = texGen;
1633 bd.stex.d[elem].samplerId = samplerId;
1634 bd.stex.d[elem].samplerGeneration = samplerGen;
1638 if (b->stage == QRhiShaderResourceBinding::FragmentStage) {
1639 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1640 }
else if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
1641 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1643 state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1645 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATES(state));
1650 case QRhiShaderResourceBinding::ImageLoad:
1651 case QRhiShaderResourceBinding::ImageStore:
1652 case QRhiShaderResourceBinding::ImageLoadStore:
1654 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, b->u.simage.tex);
1655 sanityCheckResourceOwnership(texD);
1656 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
1658 bd.simage.id = texD->m_id;
1659 bd.simage.generation = texD->generation;
1661 if (QD3D12Resource *res = resourcePool.lookupRef(texD->handle)) {
1662 if (res->uavUsage) {
1663 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1665 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1667 if (b->type == QRhiShaderResourceBinding::ImageStore
1668 || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1671 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1676 if (b->type == QRhiShaderResourceBinding::ImageLoad || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1677 res->uavUsage |= QD3D12Resource::UavUsageRead;
1678 if (b->type == QRhiShaderResourceBinding::ImageStore || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1679 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1680 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1684 case QRhiShaderResourceBinding::BufferLoad:
1685 case QRhiShaderResourceBinding::BufferStore:
1686 case QRhiShaderResourceBinding::BufferLoadStore:
1688 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.sbuf.buf);
1689 sanityCheckResourceOwnership(bufD);
1690 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
1691 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1692 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
1694 bd.sbuf.id = bufD->m_id;
1695 bd.sbuf.generation = bufD->generation;
1697 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
1698 if (res->uavUsage) {
1699 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1701 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1703 if (b->type == QRhiShaderResourceBinding::BufferStore
1704 || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1707 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1712 if (b->type == QRhiShaderResourceBinding::BufferLoad || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1713 res->uavUsage |= QD3D12Resource::UavUsageRead;
1714 if (b->type == QRhiShaderResourceBinding::BufferStore || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1715 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1716 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1723 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1724 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1732 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1738 if (pipelineChanged || srbUpdate || !srbD->bindingCacheValid
1739 || srbD->bindingCacheGeneration != srbD->generation)
1741 const QD3D12ShaderStageData *stageData = gfxPsD ? gfxPsD->stageData.data() : &compPsD->stageData;
1742 srbD->rebuildBindingCache(stageData, gfxPsD ? 5 : 1);
1745 if (pipelineChanged || srbChanged || srbRebuilt || srbUpdate || srbD->hasDynamicOffset) {
1750 const QD3D12ShaderResourceBindings::BindingCache &cache(srbD->bindingCache);
1752 bool gotNewHeap =
false;
1753 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
1754 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1762 qCDebug(QRHI_LOG_INFO,
"Created new shader-visible CBV/SRV/UAV descriptor heap,"
1763 " per-frame slice size is now %u,"
1764 " if this happens frequently then that's not great.",
1765 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[0].capacity);
1766 bindShaderVisibleHeaps(cbD);
1769 int rootParamIndex = 0;
1770 for (
int s = 0; s < 6; ++s) {
1771 for (
const QD3D12ShaderResourceBindings::BindingCache::CBuf &cbuf : cache.cbufs[s]) {
1772 if (QD3D12Resource *res = resourcePool.lookupRef(cbuf.buf->handles[currentFrameSlot])) {
1773 quint32 offset = cbuf.offset;
1774 if (srbD->hasDynamicOffset) {
1775 for (
int i = 0; i < dynamicOffsetCount; ++i) {
1776 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1777 if (dynOfs.first == cbuf.binding) {
1778 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1779 offset += dynOfs.second;
1783 const D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = res->resource->GetGPUVirtualAddress() + offset;
1785 cbD->cmdList->SetGraphicsRootConstantBufferView(rootParamIndex, gpuAddr);
1787 cbD->cmdList->SetComputeRootConstantBufferView(rootParamIndex, gpuAddr);
1789 rootParamIndex += 1;
1792 for (
int s = 0; s < 6; ++s) {
1793 if (!cache.srvs[s].isEmpty()) {
1794 QD3D12DescriptorHeap &gpuSrvHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1795 const UINT count = UINT(cache.srvs[s].count());
1796 const QD3D12Descriptor startDesc = gpuSrvHeap.get(count);
1799 dev->CopyDescriptors(1, &startDesc.cpuHandle, &count,
1800 count, cache.srvs[s].constData(),
nullptr,
1801 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1804 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1806 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1808 rootParamIndex += 1;
1811 for (
int s = 0; s < 6; ++s) {
1814 for (D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor : cache.samplers[s]) {
1816 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerDescriptor);
1818 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, samplerDescriptor);
1820 rootParamIndex += 1;
1823 for (
int s = 0; s < 6; ++s) {
1824 if (!cache.uavs[s].isEmpty()) {
1825 QD3D12DescriptorHeap &gpuUavHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1826 const int count = cache.uavs[s].count();
1827 const QD3D12Descriptor startDesc = gpuUavHeap.get(count);
1828 for (
int i = 0; i < count; ++i) {
1829 const QD3D12ShaderResourceBindings::BindingCache::Uav &uav(cache.uavs[s][i]);
1830 if (QD3D12Resource *res = resourcePool.lookupRef(uav.handle)) {
1831 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uav.desc,
1832 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1834 dev->CreateUnorderedAccessView(
nullptr,
nullptr,
nullptr,
1835 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1840 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1842 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1844 rootParamIndex += 1;
1849 cbD->currentGraphicsSrb = srb;
1850 cbD->currentComputeSrb =
nullptr;
1852 cbD->currentGraphicsSrb =
nullptr;
1853 cbD->currentComputeSrb = srb;
1855 cbD->currentSrbGeneration = srbD->generation;
1859void QRhiD3D12::setVertexInput(QRhiCommandBuffer *cb,
1860 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1861 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1863 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1864 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1866 bool needsBindVBuf =
false;
1867 for (
int i = 0; i < bindingCount; ++i) {
1868 const int inputSlot = startBinding + i;
1869 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1870 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1871 const bool isDynamic = bufD->m_type == QRhiBuffer::Dynamic;
1873 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1875 if (cbD->currentVertexBuffers[inputSlot] != bufD->handles[isDynamic ? currentFrameSlot : 0]
1876 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1878 needsBindVBuf =
true;
1879 cbD->currentVertexBuffers[inputSlot] = bufD->handles[isDynamic ? currentFrameSlot : 0];
1880 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1884 if (needsBindVBuf) {
1885 QVarLengthArray<D3D12_VERTEX_BUFFER_VIEW, 4> vbv;
1886 vbv.reserve(bindingCount);
1888 QD3D12GraphicsPipeline *psD = cbD->currentGraphicsPipeline;
1889 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1890 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1892 for (
int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1893 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1894 const QD3D12ObjectHandle handle = bufD->handles[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
1895 const quint32 offset = bindings[i].second;
1896 const quint32 stride = inputLayout.bindingAt(i)->stride();
1898 if (bufD->m_type != QRhiBuffer::Dynamic) {
1899 barrierGen.addTransitionBarrier(handle, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
1900 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1903 if (QD3D12Resource *res = resourcePool.lookupRef(handle)) {
1905 res->resource->GetGPUVirtualAddress() + offset,
1906 UINT(res->desc.Width - offset),
1912 cbD->cmdList->IASetVertexBuffers(UINT(startBinding), vbv.count(), vbv.constData());
1916 QD3D12Buffer *ibufD = QRHI_RES(QD3D12Buffer, indexBuf);
1917 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1918 const bool isDynamic = ibufD->m_type == QRhiBuffer::Dynamic;
1920 ibufD->executeHostWritesForFrameSlot(currentFrameSlot);
1922 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1923 : DXGI_FORMAT_R32_UINT;
1924 if (cbD->currentIndexBuffer != ibufD->handles[isDynamic ? currentFrameSlot : 0]
1925 || cbD->currentIndexOffset != indexOffset
1926 || cbD->currentIndexFormat != dxgiFormat)
1928 cbD->currentIndexBuffer = ibufD->handles[isDynamic ? currentFrameSlot : 0];
1929 cbD->currentIndexOffset = indexOffset;
1930 cbD->currentIndexFormat = dxgiFormat;
1932 if (ibufD->m_type != QRhiBuffer::Dynamic) {
1933 barrierGen.addTransitionBarrier(cbD->currentIndexBuffer, D3D12_RESOURCE_STATE_INDEX_BUFFER);
1934 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1937 if (QD3D12Resource *res = resourcePool.lookupRef(cbD->currentIndexBuffer)) {
1938 const D3D12_INDEX_BUFFER_VIEW ibv = {
1939 res->resource->GetGPUVirtualAddress() + indexOffset,
1940 UINT(res->desc.Width - indexOffset),
1943 cbD->cmdList->IASetIndexBuffer(&ibv);
1949void QRhiD3D12::setDefaultScissor(QD3D12CommandBuffer *cbD)
1951 cbD->hasCustomScissorSet =
false;
1953 const QSize outputSize = cbD->currentTarget->pixelSize();
1954 std::array<
float, 4> vp = cbD->currentViewport.viewport();
1955 float x = 0, y = 0, w = 0, h = 0;
1957 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
1960 w = outputSize.width();
1961 h = outputSize.height();
1964 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, vp, &x, &y, &w, &h);
1973 cbD->cmdList->RSSetScissorRects(1, &r);
1976void QRhiD3D12::setViewport(QRhiCommandBuffer *cb,
const QRhiViewport &viewport)
1978 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1979 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1980 Q_ASSERT(cbD->currentTarget);
1981 const QSize outputSize = cbD->currentTarget->pixelSize();
1985 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1993 v.MinDepth = viewport.minDepth();
1994 v.MaxDepth = viewport.maxDepth();
1995 cbD->cmdList->RSSetViewports(1, &v);
1997 cbD->currentViewport = viewport;
1998 if (cbD->currentGraphicsPipeline
1999 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
2001 setDefaultScissor(cbD);
2005void QRhiD3D12::setScissor(QRhiCommandBuffer *cb,
const QRhiScissor &scissor)
2007 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2008 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2009 Q_ASSERT(cbD->currentTarget);
2010 const QSize outputSize = cbD->currentTarget->pixelSize();
2014 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
2023 cbD->cmdList->RSSetScissorRects(1, &r);
2025 cbD->hasCustomScissorSet =
true;
2028void QRhiD3D12::setBlendConstants(QRhiCommandBuffer *cb,
const QColor &c)
2030 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2031 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2032 float v[4] = { c.redF(), c.greenF(), c.blueF(), c.alphaF() };
2033 cbD->cmdList->OMSetBlendFactor(v);
2036void QRhiD3D12::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
2038 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2039 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2040 cbD->cmdList->OMSetStencilRef(refValue);
2043void QRhiD3D12::setPushConstants(QRhiCommandBuffer *cb, quint32 offset, quint32 size,
const void *data)
2045 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2046 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
2048 const bool compute = cbD->recordingPass == QD3D12CommandBuffer::ComputePass;
2049 const int index = compute ? (cbD->currentComputePipeline ? cbD->currentComputePipeline->pushConstantRootParamIndex : -1)
2050 : (cbD->currentGraphicsPipeline ? cbD->currentGraphicsPipeline->pushConstantRootParamIndex : -1);
2052 qWarning(
"No pipeline with a push constant block is active; setPushConstants ignored");
2057 cbD->cmdList->SetComputeRoot32BitConstants(UINT(index), size / 4, data, offset / 4);
2059 cbD->cmdList->SetGraphicsRoot32BitConstants(UINT(index), size / 4, data, offset / 4);
2062static inline D3D12_SHADING_RATE toD3DShadingRate(
const QSize &coarsePixelSize)
2064 if (coarsePixelSize == QSize(1, 2))
2065 return D3D12_SHADING_RATE_1X2;
2066 if (coarsePixelSize == QSize(2, 1))
2067 return D3D12_SHADING_RATE_2X1;
2068 if (coarsePixelSize == QSize(2, 2))
2069 return D3D12_SHADING_RATE_2X2;
2070 if (coarsePixelSize == QSize(2, 4))
2071 return D3D12_SHADING_RATE_2X4;
2072 if (coarsePixelSize == QSize(4, 2))
2073 return D3D12_SHADING_RATE_4X2;
2074 if (coarsePixelSize == QSize(4, 4))
2075 return D3D12_SHADING_RATE_4X4;
2076 return D3D12_SHADING_RATE_1X1;
2079void QRhiD3D12::setShadingRate(QRhiCommandBuffer *cb,
const QSize &coarsePixelSize)
2081 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2082 cbD->hasShadingRateSet =
false;
2084#ifdef QRHI_D3D12_CL5_AVAILABLE
2088 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2089 const D3D12_SHADING_RATE_COMBINER combiners[] = { D3D12_SHADING_RATE_COMBINER_MAX, D3D12_SHADING_RATE_COMBINER_MAX };
2090 cbD->cmdList->RSSetShadingRate(toD3DShadingRate(coarsePixelSize), combiners);
2091 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
2092 cbD->hasShadingRateSet =
true;
2095 Q_UNUSED(coarsePixelSize);
2096 qWarning(
"Attempted to set ShadingRate without building Qt against a sufficiently new Windows SDK and d3d12.h. This cannot work.");
2100void QRhiD3D12::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
2101 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
2103 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2104 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2105 cbD->cmdList->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
2108void QRhiD3D12::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
2109 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
2111 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2112 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2113 cbD->cmdList->DrawIndexedInstanced(indexCount, instanceCount,
2114 firstIndex, vertexOffset,
2118void QRhiD3D12::drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
2119 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
2121 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2122 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2124 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2125 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2126 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
2128 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2130 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2131 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2133 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
2136 ID3D12Resource *indirectBufferRes = indirectRes->resource;
2138 const bool canUseMulti = (stride ==
sizeof(QRhiIndirectDrawCommand) && drawCommandSignature);
2140 if (canUseMulti && drawCount > 1) {
2141 cbD->cmdList->ExecuteIndirect(drawCommandSignature, drawCount,
2142 indirectBufferRes, indirectBufferOffset,
2145 UINT offset = indirectBufferOffset;
2146 for (quint32 i = 0; i < drawCount; ++i) {
2147 cbD->cmdList->ExecuteIndirect(drawCommandSignature, 1,
2148 indirectBufferRes, offset,
2155void QRhiD3D12::drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
2156 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
2158 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2159 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2161 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2162 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2163 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
2165 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2167 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2168 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2170 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
2173 ID3D12Resource *indirectBufferRes = indirectRes->resource;
2175 const bool canUseMulti = (stride ==
sizeof(QRhiIndexedIndirectDrawCommand) && drawIndexedCommandSignature);
2177 if (canUseMulti && drawCount > 1) {
2178 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, drawCount,
2179 indirectBufferRes, indirectBufferOffset,
2182 UINT offset = indirectBufferOffset;
2183 for (quint32 i = 0; i < drawCount; ++i) {
2184 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, 1,
2185 indirectBufferRes, offset,
2192void QRhiD3D12::debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name)
2197 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2198#ifdef QRHI_D3D12_HAS_OLD_PIX
2199 PIXBeginEvent(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(name).utf16()));
2206void QRhiD3D12::debugMarkEnd(QRhiCommandBuffer *cb)
2211 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2212#ifdef QRHI_D3D12_HAS_OLD_PIX
2213 PIXEndEvent(cbD->cmdList);
2219void QRhiD3D12::debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg)
2224 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2225#ifdef QRHI_D3D12_HAS_OLD_PIX
2226 PIXSetMarker(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(msg).utf16()));
2233const QRhiNativeHandles *QRhiD3D12::nativeHandles(QRhiCommandBuffer *cb)
2235 return QRHI_RES(QD3D12CommandBuffer, cb)->nativeHandles();
2238void QRhiD3D12::beginExternal(QRhiCommandBuffer *cb)
2243void QRhiD3D12::endExternal(QRhiCommandBuffer *cb)
2245 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2246 cbD->resetPerPassState();
2247 bindShaderVisibleHeaps(cbD);
2248 if (cbD->currentTarget) {
2249 QD3D12RenderTargetData *rtD = rtData(cbD->currentTarget);
2250 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2253 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2257double QRhiD3D12::lastCompletedGpuTime(QRhiCommandBuffer *cb)
2259 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2260 return cbD->lastGpuTime;
2263static void calculateGpuTime(QD3D12CommandBuffer *cbD,
2264 int timestampPairStartIndex,
2265 const quint8 *readbackBufPtr,
2266 quint64 timestampTicksPerSecond)
2268 const size_t byteOffset = timestampPairStartIndex *
sizeof(quint64);
2269 const quint64 *p =
reinterpret_cast<
const quint64 *>(readbackBufPtr + byteOffset);
2270 const quint64 startTime = *p++;
2271 const quint64 endTime = *p;
2272 if (startTime < endTime) {
2273 const quint64 ticks = endTime - startTime;
2274 const double timeSec = ticks /
double(timestampTicksPerSecond);
2275 cbD->lastGpuTime = timeSec;
2279QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
2289 return QRhi::FrameOpDeviceLost;
2291 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
2292 currentSwapChain = swapChainD;
2293 currentFrameSlot = swapChainD->currentFrameSlot;
2294 QD3D12SwapChain::FrameResources &fr(swapChainD->frameRes[currentFrameSlot]);
2307 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2308 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2310 if (swapChainD->frameLatencyWaitableObject) {
2312 if (swapChainD->lastFrameLatencyWaitSlot != currentFrameSlot) {
2313 WaitForSingleObjectEx(swapChainD->frameLatencyWaitableObject, 1000,
true);
2314 swapChainD->lastFrameLatencyWaitSlot = currentFrameSlot;
2318 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2320 qWarning(
"Failed to reset command allocator: %s",
2321 qPrintable(QSystemError::windowsComString(hr)));
2322 return QRhi::FrameOpError;
2325 if (!startCommandListForCurrentFrameSlot(&fr.cmdList))
2326 return QRhi::FrameOpError;
2328 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
2329 cbD->cmdList = fr.cmdList;
2331 swapChainD->rtWrapper.d.rtv[0] = swapChainD->sampleDesc.Count > 1
2332 ? swapChainD->msaaRtvs[currentFrameSlot].cpuHandle
2333 : swapChainD->rtvs[swapChainD->currentBackBufferIndex].cpuHandle;
2335 swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
2336 : D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
2338 if (swapChainD->stereo) {
2339 swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
2340 ? swapChainD->msaaRtvs[currentFrameSlot].cpuHandle
2341 : swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
2343 swapChainD->rtWrapperRight.d.dsv =
2344 swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
2351 releaseQueue.executeDeferredReleases(currentFrameSlot);
2357 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2360 resetAndResizeSmallStagingArea(currentFrameSlot);
2362 bindShaderVisibleHeaps(cbD);
2364 finishActiveReadbacks();
2366 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2369 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2370 calculateGpuTime(cbD,
2371 timestampPairStartIndex,
2372 timestampReadbackArea.mem.p,
2373 timestampTicksPerSecond);
2375 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2376 D3D12_QUERY_TYPE_TIMESTAMP,
2377 timestampPairStartIndex);
2380 QDxgiVSyncService::instance()->beginFrame(adapterLuid);
2382 return QRhi::FrameOpSuccess;
2385QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
2387 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
2388 Q_ASSERT(currentSwapChain == swapChainD);
2389 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
2391 QD3D12ObjectHandle backBufferResourceHandle = swapChainD->colorBuffers[swapChainD->currentBackBufferIndex];
2392 if (swapChainD->sampleDesc.Count > 1) {
2393 QD3D12ObjectHandle msaaBackBufferResourceHandle = swapChainD->msaaBuffers[currentFrameSlot];
2394 barrierGen.addTransitionBarrier(msaaBackBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2395 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2396 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2397 const QD3D12Resource *src = resourcePool.lookupRef(msaaBackBufferResourceHandle);
2398 const QD3D12Resource *dst = resourcePool.lookupRef(backBufferResourceHandle);
2400 cbD->cmdList->ResolveSubresource(dst->resource, 0, src->resource, 0, swapChainD->colorFormat);
2403 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
2404 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2406 if (timestampQueryHeap.isValid()) {
2407 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2408 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2409 D3D12_QUERY_TYPE_TIMESTAMP,
2410 timestampPairStartIndex + 1);
2411 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2412 D3D12_QUERY_TYPE_TIMESTAMP,
2413 timestampPairStartIndex,
2415 timestampReadbackArea.mem.buffer,
2416 timestampPairStartIndex *
sizeof(quint64));
2419 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2420 HRESULT hr = cmdList->Close();
2422 qWarning(
"Failed to close command list: %s",
2423 qPrintable(QSystemError::windowsComString(hr)));
2424 return QRhi::FrameOpError;
2427 ID3D12CommandList *execList[] = { cmdList };
2428 cmdQueue->ExecuteCommandLists(1, execList);
2430 if (!flags.testFlag(QRhi::SkipPresent)) {
2431 UINT presentFlags = 0;
2432 if (swapChainD->swapInterval == 0
2433 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
2435 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
2437 if (!swapChainD->swapChain) {
2438 qWarning(
"Failed to present, no swapchain");
2439 return QRhi::FrameOpError;
2441 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
2442 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
2443 qWarning(
"Device loss detected in Present()");
2445 return QRhi::FrameOpDeviceLost;
2446 }
else if (FAILED(hr)) {
2447 qWarning(
"Failed to present: %s", qPrintable(QSystemError::windowsComString(hr)));
2448 return QRhi::FrameOpError;
2451 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
2452 dcompDevice->Commit();
2455 swapChainD->addCommandCompletionSignalForCurrentFrameSlot();
2462 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2464 if (!flags.testFlag(QRhi::SkipPresent)) {
2468 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2469 swapChainD->currentBackBufferIndex = swapChainD->swapChain->GetCurrentBackBufferIndex();
2472 currentSwapChain =
nullptr;
2473 return QRhi::FrameOpSuccess;
2476QRhi::FrameOpResult QRhiD3D12::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
2489 currentFrameSlot = (currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2491 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2492 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2494 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2496 qWarning(
"Failed to reset command allocator: %s",
2497 qPrintable(QSystemError::windowsComString(hr)));
2498 return QRhi::FrameOpError;
2501 if (!offscreenCb[currentFrameSlot])
2502 offscreenCb[currentFrameSlot] =
new QD3D12CommandBuffer(
this);
2503 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2504 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2505 return QRhi::FrameOpError;
2507 releaseQueue.executeDeferredReleases(currentFrameSlot);
2509 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2510 resetAndResizeSmallStagingArea(currentFrameSlot);
2512 bindShaderVisibleHeaps(cbD);
2514 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2515 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2516 D3D12_QUERY_TYPE_TIMESTAMP,
2517 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT);
2520 offscreenActive =
true;
2523 return QRhi::FrameOpSuccess;
2526QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
2529 Q_ASSERT(offscreenActive);
2530 offscreenActive =
false;
2532 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2533 if (timestampQueryHeap.isValid()) {
2534 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2535 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2536 D3D12_QUERY_TYPE_TIMESTAMP,
2537 timestampPairStartIndex + 1);
2538 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2539 D3D12_QUERY_TYPE_TIMESTAMP,
2540 timestampPairStartIndex,
2542 timestampReadbackArea.mem.buffer,
2543 timestampPairStartIndex *
sizeof(quint64));
2546 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2547 HRESULT hr = cmdList->Close();
2549 qWarning(
"Failed to close command list: %s",
2550 qPrintable(QSystemError::windowsComString(hr)));
2551 return QRhi::FrameOpError;
2554 ID3D12CommandList *execList[] = { cmdList };
2555 cmdQueue->ExecuteCommandLists(1, execList);
2557 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2564 finishActiveReadbacks(
true);
2567 if (timestampQueryHeap.isValid()) {
2568 calculateGpuTime(cbD,
2569 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT,
2570 timestampReadbackArea.mem.p,
2571 timestampTicksPerSecond);
2574 return QRhi::FrameOpSuccess;
2577QRhi::FrameOpResult QRhiD3D12::finish()
2579 QD3D12CommandBuffer *cbD =
nullptr;
2581 if (offscreenActive) {
2582 Q_ASSERT(!currentSwapChain);
2583 cbD = offscreenCb[currentFrameSlot];
2585 Q_ASSERT(currentSwapChain);
2586 cbD = ¤tSwapChain->cbWrapper;
2589 return QRhi::FrameOpError;
2591 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2593 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2594 HRESULT hr = cmdList->Close();
2596 qWarning(
"Failed to close command list: %s",
2597 qPrintable(QSystemError::windowsComString(hr)));
2598 return QRhi::FrameOpError;
2601 ID3D12CommandList *execList[] = { cmdList };
2602 cmdQueue->ExecuteCommandLists(1, execList);
2604 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2611 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2613 qWarning(
"Failed to reset command allocator: %s",
2614 qPrintable(QSystemError::windowsComString(hr)));
2615 return QRhi::FrameOpError;
2618 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2619 return QRhi::FrameOpError;
2623 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2624 smallStagingAreas[currentFrameSlot].head = 0;
2626 bindShaderVisibleHeaps(cbD);
2629 releaseQueue.releaseAll();
2630 finishActiveReadbacks(
true);
2632 return QRhi::FrameOpSuccess;
2635void QRhiD3D12::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2637 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2638 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2639 enqueueResourceUpdates(cbD, resourceUpdates);
2642void QRhiD3D12::beginPass(QRhiCommandBuffer *cb,
2643 QRhiRenderTarget *rt,
2644 const QColor &colorClearValue,
2645 const QRhiDepthStencilClearValue &depthStencilClearValue,
2646 QRhiResourceUpdateBatch *resourceUpdates,
2647 QRhiCommandBuffer::BeginPassFlags)
2649 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2650 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2652 if (resourceUpdates)
2653 enqueueResourceUpdates(cbD, resourceUpdates);
2655 QD3D12RenderTargetData *rtD = rtData(rt);
2656 bool wantsColorClear =
true;
2657 bool wantsDsClear =
true;
2658 if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) {
2659 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, rt);
2660 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2661 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2662 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2665 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); it != itEnd; ++it) {
2666 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
2667 QD3D12Texture *resolveTexD = QRHI_RES(QD3D12Texture, it->resolveTexture());
2668 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
2670 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2672 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2674 barrierGen.addTransitionBarrier(resolveTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2676 if (rtTex->m_desc.depthStencilBuffer()) {
2677 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rtTex->m_desc.depthStencilBuffer());
2678 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
2679 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2680 }
else if (rtTex->m_desc.depthTexture()) {
2681 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, rtTex->m_desc.depthTexture());
2682 barrierGen.addTransitionBarrier(depthTexD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2684 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2686 Q_ASSERT(currentSwapChain);
2687 barrierGen.addTransitionBarrier(currentSwapChain->sampleDesc.Count > 1
2688 ? currentSwapChain->msaaBuffers[currentFrameSlot]
2689 : currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex],
2690 D3D12_RESOURCE_STATE_RENDER_TARGET);
2691 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2694 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2697 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2699 if (rtD->colorAttCount && wantsColorClear) {
2700 float clearColor[4] = {
2701 colorClearValue.redF(),
2702 colorClearValue.greenF(),
2703 colorClearValue.blueF(),
2704 colorClearValue.alphaF()
2706 for (
int i = 0; i < rtD->colorAttCount; ++i)
2707 cbD->cmdList->ClearRenderTargetView(rtD->rtv[i], clearColor, 0,
nullptr);
2709 if (rtD->dsAttCount && wantsDsClear) {
2710 cbD->cmdList->ClearDepthStencilView(rtD->dsv,
2711 D3D12_CLEAR_FLAGS(D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL),
2712 depthStencilClearValue.depthClearValue(),
2713 UINT8(depthStencilClearValue.stencilClearValue()),
2718 cbD->recordingPass = QD3D12CommandBuffer::RenderPass;
2719 cbD->currentTarget = rt;
2721 bool hasShadingRateMapSet =
false;
2722#ifdef QRHI_D3D12_CL5_AVAILABLE
2723 if (rtD->rp->hasShadingRateMap) {
2724 cbD->setShadingRate(QSize(1, 1));
2725 QD3D12ShadingRateMap *rateMapD = rt->resourceType() == QRhiRenderTarget::TextureRenderTarget
2726 ? QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12TextureRenderTarget, rt)->m_desc.shadingRateMap())
2727 : QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12SwapChainRenderTarget, rt)->swapChain()->shadingRateMap());
2728 if (QD3D12Resource *res = resourcePool.lookupRef(rateMapD->handle)) {
2729 barrierGen.addTransitionBarrier(rateMapD->handle, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
2730 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2731 cbD->cmdList->RSSetShadingRateImage(res->resource);
2732 hasShadingRateMapSet =
true;
2734 }
else if (cbD->hasShadingRateMapSet) {
2735 cbD->cmdList->RSSetShadingRateImage(
nullptr);
2736 cbD->setShadingRate(QSize(1, 1));
2737 }
else if (cbD->hasShadingRateSet) {
2738 cbD->setShadingRate(QSize(1, 1));
2742 cbD->resetPerPassState();
2745 cbD->hasShadingRateMapSet = hasShadingRateMapSet;
2748void QRhiD3D12::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2750 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2751 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2753 if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
2754 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, cbD->currentTarget);
2755 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2758 const QRhiColorAttachment &colorAtt(*it);
2759 if (!colorAtt.resolveTexture())
2762 QD3D12Texture *dstTexD = QRHI_RES(QD3D12Texture, colorAtt.resolveTexture());
2763 QD3D12Resource *dstRes = resourcePool.lookupRef(dstTexD->handle);
2767 QD3D12Texture *srcTexD = QRHI_RES(QD3D12Texture, colorAtt.texture());
2768 QD3D12RenderBuffer *srcRbD = QRHI_RES(QD3D12RenderBuffer, colorAtt.renderBuffer());
2769 Q_ASSERT(srcTexD || srcRbD);
2770 QD3D12Resource *srcRes = resourcePool.lookupRef(srcTexD ? srcTexD->handle : srcRbD->handle);
2775 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2776 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2777 int(srcTexD->dxgiFormat),
int(dstTexD->dxgiFormat));
2780 if (srcTexD->sampleDesc.Count <= 1) {
2781 qWarning(
"Cannot resolve a non-multisample texture");
2784 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2785 qWarning(
"Resolve source and destination sizes do not match");
2789 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2790 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2791 int(srcRbD->dxgiFormat),
int(dstTexD->dxgiFormat));
2794 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2795 qWarning(
"Resolve source and destination sizes do not match");
2806 const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
2807 QBitArray &initialized(dstTexD->subresourceInitialized);
2808 QVarLengthArray<UINT, 4> dstSubresources;
2809 QVarLengthArray<UINT, 4> subresourcesToDiscard;
2810 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2811 const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
2812 UINT(colorAtt.resolveLayer()) + resolveIdx,
2813 dstTexD->mipLevelCount);
2814 dstSubresources.append(dstSubresource);
2815 if (
int(dstSubresource) >= initialized.size())
2816 initialized.resize(
int(dstSubresource) + 1);
2817 if (!initialized.testBit(
int(dstSubresource))) {
2818 initialized.setBit(
int(dstSubresource));
2819 subresourcesToDiscard.append(dstSubresource);
2823 barrierGen.addTransitionBarrier(srcTexD ? srcTexD->handle : srcRbD->handle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2826 if (!subresourcesToDiscard.isEmpty()) {
2827 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2828 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2829 for (UINT dstSubresource : subresourcesToDiscard) {
2830 D3D12_DISCARD_REGION region = {};
2831 region.FirstSubresource = dstSubresource;
2832 region.NumSubresources = 1;
2833 cbD->cmdList->DiscardResource(dstRes->resource, ®ion);
2837 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2838 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2840 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2841 const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
2842 cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresources[resolveIdx],
2843 srcRes->resource, srcSubresource,
2844 dstTexD->dxgiFormat);
2847 if (rtTex->m_desc.depthResolveTexture())
2848 qWarning(
"Resolving multisample depth-stencil buffers is not supported with D3D");
2851 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2852 cbD->currentTarget =
nullptr;
2854 if (resourceUpdates)
2855 enqueueResourceUpdates(cbD, resourceUpdates);
2858void QRhiD3D12::beginComputePass(QRhiCommandBuffer *cb,
2859 QRhiResourceUpdateBatch *resourceUpdates,
2860 QRhiCommandBuffer::BeginPassFlags)
2862 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2863 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2865 if (resourceUpdates)
2866 enqueueResourceUpdates(cbD, resourceUpdates);
2868 cbD->recordingPass = QD3D12CommandBuffer::ComputePass;
2870 cbD->resetPerPassState();
2873void QRhiD3D12::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2875 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2876 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2878 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2880 if (resourceUpdates)
2881 enqueueResourceUpdates(cbD, resourceUpdates);
2884void QRhiD3D12::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
2886 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2887 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2888 QD3D12ComputePipeline *psD = QRHI_RES(QD3D12ComputePipeline, ps);
2889 const bool pipelineChanged = cbD->currentComputePipeline != psD || cbD->currentPipelineGeneration != psD->generation;
2891 if (pipelineChanged) {
2892 cbD->currentGraphicsPipeline =
nullptr;
2893 cbD->currentComputePipeline = psD;
2894 cbD->currentPipelineGeneration = psD->generation;
2896 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
2897 Q_ASSERT(pipeline->type == QD3D12Pipeline::Compute);
2898 cbD->cmdList->SetPipelineState(pipeline->pso);
2899 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
2900 cbD->cmdList->SetComputeRootSignature(rs->rootSig);
2905void QRhiD3D12::dispatch(QRhiCommandBuffer *cb,
int x,
int y,
int z)
2907 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2908 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2909 cbD->cmdList->Dispatch(UINT(x), UINT(y), UINT(z));
2915ID3D12CommandSignature *QRhiD3D12::indirectDrawCommandSignature(
bool indexed, quint32 stride)
2917 const quint32 canonicalStride = indexed ?
sizeof(QRhiIndexedIndirectDrawCommand)
2918 :
sizeof(QRhiIndirectDrawCommand);
2919 if (stride == canonicalStride)
2920 return indexed ? drawIndexedCommandSignature : drawCommandSignature;
2922 QHash<quint32, ID3D12CommandSignature *> &cache(indexed ? drawIndexedCommandSignaturesByStride
2923 : drawCommandSignaturesByStride);
2924 auto it = cache.constFind(stride);
2925 if (it != cache.constEnd())
2928 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
2929 arg.Type = indexed ? D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED : D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
2931 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
2932 sigDesc.ByteStride = stride;
2933 sigDesc.NumArgumentDescs = 1;
2934 sigDesc.pArgumentDescs = &arg;
2936 ID3D12CommandSignature *sig =
nullptr;
2937 HRESULT hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&sig));
2939 qWarning(
"Failed to create indirect draw command signature with stride %u: %s",
2940 stride, qPrintable(QSystemError::windowsComString(hr)));
2944 cache.insert(stride, sig);
2948void QRhiD3D12::drawIndirectCount(QRhiCommandBuffer *cb,
2949 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
2950 QRhiBuffer *countBuffer, quint32 countBufferOffset,
2951 quint32 maxDrawCount, quint32 stride)
2953 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2954 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2956 ID3D12CommandSignature *sig = indirectDrawCommandSignature(
false, stride);
2960 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2961 const bool indirectIsDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2962 const QD3D12ObjectHandle indirectHandle = indirectBufferD->handles[indirectIsDynamic ? currentFrameSlot : 0];
2963 if (indirectIsDynamic)
2964 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2966 barrierGen.addTransitionBarrier(indirectHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2968 QD3D12Buffer *countBufferD = QRHI_RES(QD3D12Buffer, countBuffer);
2969 const bool countIsDynamic = countBufferD->m_type == QRhiBuffer::Dynamic;
2970 const QD3D12ObjectHandle countHandle = countBufferD->handles[countIsDynamic ? currentFrameSlot : 0];
2972 countBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2974 barrierGen.addTransitionBarrier(countHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2976 if (!indirectIsDynamic || !countIsDynamic)
2977 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2979 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectHandle);
2980 QD3D12Resource *countRes = resourcePool.lookupRef(countHandle);
2981 if (!indirectRes || !countRes)
2984 cbD->cmdList->ExecuteIndirect(sig, maxDrawCount,
2985 indirectRes->resource, indirectBufferOffset,
2986 countRes->resource, countBufferOffset);
2989void QRhiD3D12::drawIndexedIndirectCount(QRhiCommandBuffer *cb,
2990 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
2991 QRhiBuffer *countBuffer, quint32 countBufferOffset,
2992 quint32 maxDrawCount, quint32 stride)
2994 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2995 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2997 ID3D12CommandSignature *sig = indirectDrawCommandSignature(
true, stride);
3001 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
3002 const bool indirectIsDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
3003 const QD3D12ObjectHandle indirectHandle = indirectBufferD->handles[indirectIsDynamic ? currentFrameSlot : 0];
3004 if (indirectIsDynamic)
3005 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
3007 barrierGen.addTransitionBarrier(indirectHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
3009 QD3D12Buffer *countBufferD = QRHI_RES(QD3D12Buffer, countBuffer);
3010 const bool countIsDynamic = countBufferD->m_type == QRhiBuffer::Dynamic;
3011 const QD3D12ObjectHandle countHandle = countBufferD->handles[countIsDynamic ? currentFrameSlot : 0];
3013 countBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
3015 barrierGen.addTransitionBarrier(countHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
3017 if (!indirectIsDynamic || !countIsDynamic)
3018 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3020 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectHandle);
3021 QD3D12Resource *countRes = resourcePool.lookupRef(countHandle);
3022 if (!indirectRes || !countRes)
3025 cbD->cmdList->ExecuteIndirect(sig, maxDrawCount,
3026 indirectRes->resource, indirectBufferOffset,
3027 countRes->resource, countBufferOffset);
3030void QRhiD3D12::dispatchIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
3031 quint32 indirectBufferOffset)
3033 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
3034 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
3036 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
3037 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
3038 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
3040 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
3045 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
3046 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3048 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
3052 cbD->cmdList->ExecuteIndirect(dispatchCommandSignature, 1,
3053 indirectRes->resource, indirectBufferOffset,
3057bool QD3D12DescriptorHeap::create(ID3D12Device *device,
3058 quint32 descriptorCount,
3059 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
3060 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags)
3063 capacity = descriptorCount;
3064 this->heapType = heapType;
3065 this->heapFlags = heapFlags;
3067 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
3068 heapDesc.Type = heapType;
3069 heapDesc.NumDescriptors = capacity;
3070 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS(heapFlags);
3072 HRESULT hr = device->CreateDescriptorHeap(&heapDesc, __uuidof(ID3D12DescriptorHeap),
reinterpret_cast<
void **>(&heap));
3074 qWarning(
"Failed to create descriptor heap: %s", qPrintable(QSystemError::windowsComString(hr)));
3076 capacity = descriptorByteSize = 0;
3080 descriptorByteSize = device->GetDescriptorHandleIncrementSize(heapType);
3081 heapStart.cpuHandle = heap->GetCPUDescriptorHandleForHeapStart();
3082 if (heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
3083 heapStart.gpuHandle = heap->GetGPUDescriptorHandleForHeapStart();
3088void QD3D12DescriptorHeap::createWithExisting(
const QD3D12DescriptorHeap &other,
3089 quint32 offsetInDescriptors,
3090 quint32 descriptorCount)
3094 capacity = descriptorCount;
3095 heapType = other.heapType;
3096 heapFlags = other.heapFlags;
3097 descriptorByteSize = other.descriptorByteSize;
3098 heapStart = incremented(other.heapStart, offsetInDescriptors);
3101void QD3D12DescriptorHeap::destroy()
3110void QD3D12DescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3113 releaseQueue->deferredReleaseDescriptorHeap(heap);
3119QD3D12Descriptor QD3D12DescriptorHeap::get(quint32 count)
3121 Q_ASSERT(count > 0);
3122 if (head + count > capacity) {
3123 qWarning(
"Cannot get %u descriptors as that would exceed capacity %u", count, capacity);
3127 return at(head - count);
3130QD3D12Descriptor QD3D12DescriptorHeap::at(quint32 index)
const
3132 const quint32 startOffset = index * descriptorByteSize;
3133 QD3D12Descriptor result;
3134 result.cpuHandle.ptr = heapStart.cpuHandle.ptr + startOffset;
3135 if (heapStart.gpuHandle.ptr != 0)
3136 result.gpuHandle.ptr = heapStart.gpuHandle.ptr + startOffset;
3140bool QD3D12CpuDescriptorPool::create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName)
3142 QD3D12DescriptorHeap firstHeap;
3143 if (!firstHeap.create(device, DESCRIPTORS_PER_HEAP, heapType, D3D12_DESCRIPTOR_HEAP_FLAG_NONE))
3145 heaps.append(HeapWithMap::init(firstHeap, DESCRIPTORS_PER_HEAP));
3146 descriptorByteSize = heaps[0].heap.descriptorByteSize;
3147 this->device = device;
3148 this->debugName = debugName;
3152void QD3D12CpuDescriptorPool::destroy()
3156 static bool leakCheck =
true;
3159 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
3162 for (
const HeapWithMap &heap : std::as_const(heaps)) {
3163 const int leakedDescriptorCount = heap.map.count(
true);
3164 if (leakedDescriptorCount > 0) {
3165 qWarning(
"QD3D12CpuDescriptorPool::destroy(): "
3166 "Heap %p for descriptor pool %p '%s' has %d unreleased descriptors",
3167 &heap.heap,
this, debugName, leakedDescriptorCount);
3171 for (HeapWithMap &heap : heaps)
3172 heap.heap.destroy();
3176QD3D12Descriptor QD3D12CpuDescriptorPool::allocate(quint32 count)
3178 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
3180 HeapWithMap &last(heaps.last());
3181 if (last.heap.head + count <= last.heap.capacity) {
3182 quint32 firstIndex = last.heap.head;
3183 for (quint32 i = 0; i < count; ++i)
3184 last.map.setBit(firstIndex + i);
3185 return last.heap.get(count);
3188 for (HeapWithMap &heap : heaps) {
3189 quint32 freeCount = 0;
3190 for (quint32 i = 0; i < DESCRIPTORS_PER_HEAP; ++i) {
3191 if (heap.map.testBit(i)) {
3195 if (freeCount == count) {
3196 const quint32 firstIndex = i - (freeCount - 1);
3197 for (quint32 j = 0; j < count; ++j)
3198 heap.map.setBit(firstIndex + j);
3202 if (firstIndex + count > heap.heap.head)
3203 heap.heap.head = firstIndex + count;
3204 return heap.heap.at(firstIndex);
3210 QD3D12DescriptorHeap newHeap;
3211 if (!newHeap.create(device, DESCRIPTORS_PER_HEAP, last.heap.heapType, last.heap.heapFlags))
3214 heaps.append(HeapWithMap::init(newHeap, DESCRIPTORS_PER_HEAP));
3216 for (quint32 i = 0; i < count; ++i)
3217 heaps.last().map.setBit(i);
3219 return heaps.last().heap.get(count);
3222void QD3D12CpuDescriptorPool::release(
const QD3D12Descriptor &descriptor, quint32 count)
3224 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
3225 if (!descriptor.isValid())
3228 const SIZE_T addr = descriptor.cpuHandle.ptr;
3229 for (HeapWithMap &heap : heaps) {
3230 const SIZE_T begin = heap.heap.heapStart.cpuHandle.ptr;
3231 const SIZE_T end = begin + heap.heap.descriptorByteSize * heap.heap.capacity;
3232 if (addr >= begin && addr < end) {
3233 quint32 firstIndex = (addr - begin) / heap.heap.descriptorByteSize;
3234 for (quint32 i = 0; i < count; ++i)
3235 heap.map.setBit(firstIndex + i,
false);
3240 qWarning(
"QD3D12CpuDescriptorPool::release: Descriptor with address %llu is not in any heap",
3241 quint64(descriptor.cpuHandle.ptr));
3244bool QD3D12QueryHeap::create(ID3D12Device *device,
3246 D3D12_QUERY_HEAP_TYPE heapType)
3248 capacity = queryCount;
3250 D3D12_QUERY_HEAP_DESC heapDesc = {};
3251 heapDesc.Type = heapType;
3252 heapDesc.Count = capacity;
3254 HRESULT hr = device->CreateQueryHeap(&heapDesc, __uuidof(ID3D12QueryHeap),
reinterpret_cast<
void **>(&heap));
3256 qWarning(
"Failed to create query heap: %s", qPrintable(QSystemError::windowsComString(hr)));
3265void QD3D12QueryHeap::destroy()
3274bool QD3D12StagingArea::create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType)
3276 Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
3277 D3D12_RESOURCE_DESC resourceDesc = {};
3278 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
3279 resourceDesc.Width = capacity;
3280 resourceDesc.Height = 1;
3281 resourceDesc.DepthOrArraySize = 1;
3282 resourceDesc.MipLevels = 1;
3283 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
3284 resourceDesc.SampleDesc = { 1, 0 };
3285 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
3286 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
3287 UINT state = heapType == D3D12_HEAP_TYPE_UPLOAD ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
3288 HRESULT hr = rhi->vma.createResource(heapType,
3290 D3D12_RESOURCE_STATES(state),
3293 __uuidof(ID3D12Resource),
3294 reinterpret_cast<
void **>(&resource));
3296 qWarning(
"Failed to create buffer for staging area: %s",
3297 qPrintable(QSystemError::windowsComString(hr)));
3301 hr = resource->Map(0,
nullptr, &p);
3303 qWarning(
"Failed to map buffer for staging area: %s",
3304 qPrintable(QSystemError::windowsComString(hr)));
3309 mem.p =
static_cast<quint8 *>(p);
3310 mem.gpuAddr = resource->GetGPUVirtualAddress();
3311 mem.buffer = resource;
3312 mem.bufferOffset = 0;
3314 this->capacity = capacity;
3320void QD3D12StagingArea::destroy()
3323 resource->Release();
3327 allocation->Release();
3328 allocation =
nullptr;
3333void QD3D12StagingArea::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3336 releaseQueue->deferredReleaseResourceAndAllocation(resource, allocation);
3340QD3D12StagingArea::Allocation QD3D12StagingArea::get(quint32 byteSize)
3342 const quint32 allocSize = aligned(byteSize, ALIGNMENT);
3343 if (head + allocSize > capacity) {
3344 qWarning(
"Failed to allocate %u (%u) bytes from staging area of size %u with %u bytes left",
3345 allocSize, byteSize, capacity, remainingCapacity());
3348 const quint32 offset = head;
3352 mem.gpuAddr + offset,
3361void QD3D12ReleaseQueue::deferredReleaseResource(
const QD3D12ObjectHandle &handle)
3363 DeferredReleaseEntry e;
3368void QD3D12ReleaseQueue::deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
3369 QD3D12CpuDescriptorPool *pool,
3370 const QD3D12Descriptor &viewsStart,
3373 DeferredReleaseEntry e;
3374 e.type = DeferredReleaseEntry::Resource;
3376 e.poolForViews = pool;
3377 e.viewsStart = viewsStart;
3378 e.viewCount = viewCount;
3382void QD3D12ReleaseQueue::deferredReleasePipeline(
const QD3D12ObjectHandle &handle)
3384 DeferredReleaseEntry e;
3385 e.type = DeferredReleaseEntry::Pipeline;
3390void QD3D12ReleaseQueue::deferredReleaseRootSignature(
const QD3D12ObjectHandle &handle)
3392 DeferredReleaseEntry e;
3393 e.type = DeferredReleaseEntry::RootSignature;
3398void QD3D12ReleaseQueue::deferredReleaseCallback(std::function<
void(
void*)> callback,
void *userData)
3400 DeferredReleaseEntry e;
3401 e.type = DeferredReleaseEntry::Callback;
3402 e.callback = callback;
3403 e.callbackUserData = userData;
3407void QD3D12ReleaseQueue::deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
3408 D3D12MA::Allocation *allocation)
3410 DeferredReleaseEntry e;
3411 e.type = DeferredReleaseEntry::ResourceAndAllocation;
3412 e.resourceAndAllocation = { resource, allocation };
3416void QD3D12ReleaseQueue::deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap)
3418 DeferredReleaseEntry e;
3419 e.type = DeferredReleaseEntry::DescriptorHeap;
3420 e.descriptorHeap = heap;
3424void QD3D12ReleaseQueue::deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
3425 const QD3D12Descriptor &viewsStart,
3428 DeferredReleaseEntry e;
3429 e.type = DeferredReleaseEntry::Views;
3430 e.poolForViews = pool;
3431 e.viewsStart = viewsStart;
3432 e.viewCount = viewCount;
3436void QD3D12ReleaseQueue::activatePendingDeferredReleaseRequests(
int frameSlot)
3438 for (DeferredReleaseEntry &e : queue) {
3439 if (!e.frameSlotToBeReleasedIn.has_value())
3440 e.frameSlotToBeReleasedIn = frameSlot;
3444void QD3D12ReleaseQueue::executeDeferredReleases(
int frameSlot,
bool forced)
3446 qsizetype keepBegin = queue.size();
3447 for (qsizetype i = keepBegin - 1; i >= 0; --i) {
3448 const DeferredReleaseEntry &e(queue[i]);
3449 if (forced || (e.frameSlotToBeReleasedIn.has_value() && e.frameSlotToBeReleasedIn.value() == frameSlot)) {
3451 case DeferredReleaseEntry::Resource:
3452 resourcePool->remove(e.handle);
3453 if (e.poolForViews && e.viewsStart.isValid() && e.viewCount > 0)
3454 e.poolForViews->release(e.viewsStart, e.viewCount);
3456 case DeferredReleaseEntry::Pipeline:
3457 pipelinePool->remove(e.handle);
3459 case DeferredReleaseEntry::RootSignature:
3460 rootSignaturePool->remove(e.handle);
3462 case DeferredReleaseEntry::Callback:
3463 e.callback(e.callbackUserData);
3465 case DeferredReleaseEntry::ResourceAndAllocation:
3468 e.resourceAndAllocation.first->Release();
3469 if (e.resourceAndAllocation.second)
3470 e.resourceAndAllocation.second->Release();
3472 case DeferredReleaseEntry::DescriptorHeap:
3473 e.descriptorHeap->Release();
3475 case DeferredReleaseEntry::Views:
3476 e.poolForViews->release(e.viewsStart, e.viewCount);
3479 }
else if (--keepBegin != i) {
3480 queue[keepBegin] = std::move(queue[i]);
3484 queue.remove(0, keepBegin);
3487void QD3D12ReleaseQueue::releaseAll()
3489 executeDeferredReleases(0,
true);
3492void QD3D12ResourceBarrierGenerator::addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle,
3493 D3D12_RESOURCE_STATES stateAfter)
3495 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3496 if (stateAfter != res->state) {
3497 transitionResourceBarriers.append({ resourceHandle, res->state, stateAfter });
3498 res->state = stateAfter;
3503void QD3D12ResourceBarrierGenerator::enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD)
3505 QVarLengthArray<D3D12_RESOURCE_BARRIER, PREALLOC> barriers;
3506 for (
const TransitionResourceBarrier &trb : transitionResourceBarriers) {
3507 if (QD3D12Resource *res = resourcePool->lookupRef(trb.resourceHandle)) {
3508 D3D12_RESOURCE_BARRIER barrier = {};
3509 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
3510 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3511 barrier.Transition.pResource = res->resource;
3512 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
3513 barrier.Transition.StateBefore = trb.stateBefore;
3514 barrier.Transition.StateAfter = trb.stateAfter;
3515 barriers.append(barrier);
3518 transitionResourceBarriers.clear();
3519 if (!barriers.isEmpty())
3520 cbD->cmdList->ResourceBarrier(barriers.count(), barriers.constData());
3523void QD3D12ResourceBarrierGenerator::enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
3524 const QD3D12ObjectHandle &resourceHandle,
3526 D3D12_RESOURCE_STATES stateBefore,
3527 D3D12_RESOURCE_STATES stateAfter)
3529 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3530 D3D12_RESOURCE_BARRIER barrier = {};
3531 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
3532 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3533 barrier.Transition.pResource = res->resource;
3534 barrier.Transition.Subresource = subresource;
3535 barrier.Transition.StateBefore = stateBefore;
3536 barrier.Transition.StateAfter = stateAfter;
3537 cbD->cmdList->ResourceBarrier(1, &barrier);
3541void QD3D12ResourceBarrierGenerator::enqueueUavBarrier(QD3D12CommandBuffer *cbD,
3542 const QD3D12ObjectHandle &resourceHandle)
3544 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3545 D3D12_RESOURCE_BARRIER barrier = {};
3546 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
3547 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3548 barrier.UAV.pResource = res->resource;
3549 cbD->cmdList->ResourceBarrier(1, &barrier);
3553bool QD3D12ShaderVisibleDescriptorHeap::create(ID3D12Device *device,
3554 D3D12_DESCRIPTOR_HEAP_TYPE type,
3555 quint32 perFrameDescriptorCount)
3557 Q_ASSERT(type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
3559 quint32 size = perFrameDescriptorCount * QD3D12_FRAMES_IN_FLIGHT;
3562 const quint32 CBV_SRV_UAV_MAX = 1000000;
3563 const quint32 SAMPLER_MAX = 2048;
3564 if (type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
3565 size = qMin(size, CBV_SRV_UAV_MAX);
3566 else if (type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
3567 size = qMin(size, SAMPLER_MAX);
3569 if (!heap.create(device, size, type, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
3570 qWarning(
"Failed to create shader-visible descriptor heap of size %u", size);
3574 perFrameDescriptorCount = size / QD3D12_FRAMES_IN_FLIGHT;
3575 quint32 currentOffsetInDescriptors = 0;
3576 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3577 perFrameHeapSlice[i].createWithExisting(heap, currentOffsetInDescriptors, perFrameDescriptorCount);
3578 currentOffsetInDescriptors += perFrameDescriptorCount;
3584void QD3D12ShaderVisibleDescriptorHeap::destroy()
3589void QD3D12ShaderVisibleDescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3591 heap.destroyWithDeferredRelease(releaseQueue);
3594static inline std::pair<
int,
int> mapBinding(
int binding,
const QD3D12ShaderStageData *sd)
3596 const QShader::NativeResourceBindingMap &map(sd->nativeResourceBindingMap);
3597 if (map.isEmpty()) {
3605 if (sd->pushConstantRegister >= 0)
3607 return { binding, binding };
3610 auto it = map.constFind(binding);
3611 if (it != map.cend())
3620void QD3D12ShaderResourceVisitor::visit()
3622 for (
int bindingIdx = 0, bindingCount = srb->m_bindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
3623 const QRhiShaderResourceBinding &b(srb->m_bindings[bindingIdx]);
3624 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
3626 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
3627 const QD3D12ShaderStageData *sd = &stageData[stageIdx];
3631 if (!bd->stage.testFlag(qd3d12_stageToSrb(sd->stage)))
3635 case QRhiShaderResourceBinding::UniformBuffer:
3637 const int shaderRegister = mapBinding(bd->binding, sd).first;
3638 if (shaderRegister >= 0 && uniformBuffer)
3639 uniformBuffer(sd->stage, bd->u.ubuf, shaderRegister, bd->binding);
3642 case QRhiShaderResourceBinding::SampledTexture:
3644 Q_ASSERT(bd->stex.count() > 0);
3645 const int textureBaseShaderRegister = mapBinding(bd->binding, sd).first;
3646 const int samplerBaseShaderRegister = mapBinding(bd->binding, sd).second;
3647 if (textureBaseShaderRegister >= 0 && textures)
3648 textures(sd->stage, bd->stex.texSamplers.constData(), bd->stex.count(), textureBaseShaderRegister);
3649 if (samplerBaseShaderRegister >= 0 && samplers)
3650 samplers(sd->stage, bd->stex.texSamplers.constData(), bd->stex.count(), samplerBaseShaderRegister);
3653 case QRhiShaderResourceBinding::Texture:
3655 Q_ASSERT(bd->stex.count() > 0);
3656 const int baseShaderRegister = mapBinding(bd->binding, sd).first;
3657 if (baseShaderRegister >= 0 && textures)
3658 textures(sd->stage, bd->stex.texSamplers.constData(), bd->stex.count(), baseShaderRegister);
3661 case QRhiShaderResourceBinding::Sampler:
3663 Q_ASSERT(bd->stex.count() > 0);
3664 const int baseShaderRegister = mapBinding(bd->binding, sd).first;
3665 if (baseShaderRegister >= 0 && samplers)
3666 samplers(sd->stage, bd->stex.texSamplers.constData(), bd->stex.count(), baseShaderRegister);
3669 case QRhiShaderResourceBinding::ImageLoad:
3671 const int shaderRegister = mapBinding(bd->binding, sd).first;
3672 if (shaderRegister >= 0 && storageImage)
3673 storageImage(sd->stage, bd->u.simage, Load, shaderRegister);
3676 case QRhiShaderResourceBinding::ImageStore:
3678 const int shaderRegister = mapBinding(bd->binding, sd).first;
3679 if (shaderRegister >= 0 && storageImage)
3680 storageImage(sd->stage, bd->u.simage, Store, shaderRegister);
3683 case QRhiShaderResourceBinding::ImageLoadStore:
3685 const int shaderRegister = mapBinding(bd->binding, sd).first;
3686 if (shaderRegister >= 0 && storageImage)
3687 storageImage(sd->stage, bd->u.simage, LoadStore, shaderRegister);
3690 case QRhiShaderResourceBinding::BufferLoad:
3692 const int shaderRegister = mapBinding(bd->binding, sd).first;
3693 if (shaderRegister >= 0 && storageBuffer)
3694 storageBuffer(sd->stage, bd->u.sbuf, Load, shaderRegister);
3697 case QRhiShaderResourceBinding::BufferStore:
3699 const int shaderRegister = mapBinding(bd->binding, sd).first;
3700 if (shaderRegister >= 0 && storageBuffer)
3701 storageBuffer(sd->stage, bd->u.sbuf, Store, shaderRegister);
3704 case QRhiShaderResourceBinding::BufferLoadStore:
3706 const int shaderRegister = mapBinding(bd->binding, sd).first;
3707 if (shaderRegister >= 0 && storageBuffer)
3708 storageBuffer(sd->stage, bd->u.sbuf, LoadStore, shaderRegister);
3716bool QD3D12SamplerManager::create(ID3D12Device *device)
3719 if (!shaderVisibleSamplerHeap.create(device,
3720 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
3721 MAX_SAMPLERS / QD3D12_FRAMES_IN_FLIGHT))
3723 qWarning(
"Could not create shader-visible SAMPLER heap");
3727 this->device = device;
3731void QD3D12SamplerManager::destroy()
3734 shaderVisibleSamplerHeap.destroy();
3739QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc)
3741 auto it = gpuMap.constFind({desc});
3742 if (it != gpuMap.cend())
3745 QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
3746 if (descriptor.isValid()) {
3747 device->CreateSampler(&desc, descriptor.cpuHandle);
3748 gpuMap.insert({desc}, descriptor);
3750 qWarning(
"Out of shader-visible SAMPLER descriptor heap space,"
3751 " this should not happen, maximum number of unique samplers is %u",
3752 shaderVisibleSamplerHeap.heap.capacity);
3758QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptors(
const QVarLengthArray<Q_D3D12_SAMPLER_DESC, 8> &descs)
3764 auto it = gpuArrayMap.constFind({ descs });
3765 if (it != gpuArrayMap.cend())
3768 const quint32 count = quint32(descs.count());
3769 QD3D12Descriptor startDescriptor = shaderVisibleSamplerHeap.heap.get(count);
3770 if (startDescriptor.isValid()) {
3771 for (quint32 i = 0; i < count; ++i) {
3772 device->CreateSampler(&descs[
int(i)].desc,
3773 shaderVisibleSamplerHeap.heap.incremented(startDescriptor, i).cpuHandle);
3775 gpuArrayMap.insert({ descs }, startDescriptor);
3782 qWarning(
"Out of shader-visible SAMPLER descriptor heap space when reserving"
3783 " %u consecutive descriptors for a sampler array, maximum number of"
3784 " sampler descriptors is %u",
3785 count, shaderVisibleSamplerHeap.heap.capacity);
3788 return startDescriptor;
3791void QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
3796bool QD3D12MipmapGenerator::ensureCreated()
3798 if (!pipelineHandle.isNull())
3804 if (!buildPipeline()) {
3805 createFailed =
true;
3812bool QD3D12MipmapGenerator::buildPipeline()
3814 qCDebug(QRHI_LOG_INFO,
"Building mipmap generator compute pipeline on first use");
3816 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3817 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3820 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3821 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3822 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3825 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3826 descriptorRanges[0].NumDescriptors = 1;
3827 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3828 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3829 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3830 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3831 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3834 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3835 descriptorRanges[1].NumDescriptors = 4;
3836 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3837 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3838 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3839 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3842 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3843 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3844 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3845 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3846 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3847 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3849 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3850 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3851 rsDesc.Desc_1_1.NumParameters = 3;
3852 rsDesc.Desc_1_1.pParameters = rootParams;
3853 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3854 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3856 ID3DBlob *signature =
nullptr;
3857 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3859 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3862 ID3D12RootSignature *rootSig =
nullptr;
3863 hr = rhiD->dev->CreateRootSignature(0,
3864 signature->GetBufferPointer(),
3865 signature->GetBufferSize(),
3866 __uuidof(ID3D12RootSignature),
3867 reinterpret_cast<
void **>(&rootSig));
3868 signature->Release();
3870 qWarning(
"Failed to create root signature: %s",
3871 qPrintable(QSystemError::windowsComString(hr)));
3875 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3877 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3878 psoDesc.pRootSignature = rootSig;
3879 psoDesc.CS.pShaderBytecode = g_csMipmap;
3880 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap);
3881 ID3D12PipelineState *pso =
nullptr;
3882 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3883 __uuidof(ID3D12PipelineState),
3884 reinterpret_cast<
void **>(&pso));
3886 qWarning(
"Failed to create compute pipeline state: %s",
3887 qPrintable(QSystemError::windowsComString(hr)));
3888 rhiD->rootSignaturePool.remove(rootSigHandle);
3893 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3898void QD3D12MipmapGenerator::destroy()
3905 rhiD->pipelinePool.remove(pipelineHandle);
3906 pipelineHandle = {};
3907 rhiD->rootSignaturePool.remove(rootSigHandle);
3909 createFailed =
false;
3912void QD3D12MipmapGenerator::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3914 if (!ensureCreated())
3917 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3920 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3923 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3927 const quint32 mipLevelCount = res->desc.MipLevels;
3928 if (mipLevelCount < 2)
3931 if (res->desc.SampleDesc.Count > 1) {
3932 qWarning(
"Cannot generate mipmaps for MSAA texture");
3936 const bool is1D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D;
3938 qWarning(
"Cannot generate mipmaps for 1D texture");
3942 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3943 const bool isCubeOrArray = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
3944 && res->desc.DepthOrArraySize > 1;
3945 const quint32 layerCount = isCubeOrArray ? res->desc.DepthOrArraySize : 1;
3948 qWarning(
"2D mipmap generator invoked for 3D texture, this should not happen");
3952 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3953 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3955 cbD->cmdList->SetPipelineState(pipeline->pso);
3956 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3958 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3961 quint32 srcMipLevel;
3962 quint32 numMipLevels;
3967 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount * layerCount);
3968 std::optional<QD3D12StagingArea> ownStagingArea;
3969 rhiD->recordSmallStagingAreaDemand(allocSize);
3970 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3971 ownStagingArea = QD3D12StagingArea();
3972 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3973 qWarning(
"Could not create staging area for mipmap generation");
3977 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3978 ? &ownStagingArea.value()
3979 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3981 bool gotNewHeap =
false;
3982 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3983 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3984 rhiD->currentFrameSlot,
3985 (1 + 4) * mipLevelCount * layerCount,
3988 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3992 rhiD->bindShaderVisibleHeaps(cbD);
3994 for (quint32 layer = 0; layer < layerCount; ++layer) {
3995 for (quint32 level = 0; level < mipLevelCount ;) {
3996 UINT subresource = calcSubresource(level, layer, res->desc.MipLevels);
3997 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3998 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3999 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
4001 quint32 levelPlusOneMipWidth = res->desc.Width >> (level + 1);
4002 quint32 levelPlusOneMipHeight = res->desc.Height >> (level + 1);
4003 const quint32 dw = levelPlusOneMipWidth == 1 ? levelPlusOneMipHeight : levelPlusOneMipWidth;
4004 const quint32 dh = levelPlusOneMipHeight == 1 ? levelPlusOneMipWidth : levelPlusOneMipHeight;
4006 const quint32 additionalMips = qCountTrailingZeroBits(dw | dh);
4007 const quint32 numGenMips = qMin(1u + qMin(3u, additionalMips), res->desc.MipLevels - level);
4008 levelPlusOneMipWidth = qMax(1u, levelPlusOneMipWidth);
4009 levelPlusOneMipHeight = qMax(1u, levelPlusOneMipHeight);
4011 CBufData cbufData = {
4014 1.0f /
float(levelPlusOneMipWidth),
4015 1.0f /
float(levelPlusOneMipHeight)
4018 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
4019 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
4020 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
4022 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4023 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4024 srvDesc.Format = res->desc.Format;
4025 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4026 if (isCubeOrArray) {
4027 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
4028 srvDesc.Texture2DArray.MipLevels = res->desc.MipLevels;
4029 srvDesc.Texture2DArray.FirstArraySlice = layer;
4030 srvDesc.Texture2DArray.ArraySize = 1;
4032 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
4033 srvDesc.Texture2D.MipLevels = res->desc.MipLevels;
4035 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4036 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
4038 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(4);
4039 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
4041 for (quint32 uavIdx = 0; uavIdx < 4; ++uavIdx) {
4042 const quint32 uavMipLevel = qMin(level + 1u + uavIdx, res->desc.MipLevels - 1u);
4043 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
4044 uavDesc.Format = res->desc.Format;
4045 if (isCubeOrArray) {
4046 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
4047 uavDesc.Texture2DArray.MipSlice = uavMipLevel;
4048 uavDesc.Texture2DArray.FirstArraySlice = layer;
4049 uavDesc.Texture2DArray.ArraySize = 1;
4051 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
4052 uavDesc.Texture2D.MipSlice = uavMipLevel;
4054 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
4055 uavCpuHandle.ptr += descriptorByteSize;
4057 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
4059 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, 1);
4061 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
4062 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4063 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
4064 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4066 level += numGenMips;
4070 if (ownStagingArea.has_value())
4071 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
4074void QD3D12MipmapGenerator3D::create(QRhiD3D12 *rhiD)
4079bool QD3D12MipmapGenerator3D::ensureCreated()
4081 if (!pipelineHandle.isNull())
4087 if (!buildPipeline()) {
4088 createFailed =
true;
4095bool QD3D12MipmapGenerator3D::buildPipeline()
4097 qCDebug(QRHI_LOG_INFO,
"Building 3D texture mipmap generator compute pipeline on first use");
4099 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
4100 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
4103 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
4104 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4105 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
4108 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
4109 descriptorRanges[0].NumDescriptors = 1;
4110 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
4111 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
4112 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4113 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
4114 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
4117 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
4118 descriptorRanges[1].NumDescriptors = 1;
4119 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
4120 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4121 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
4122 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
4125 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
4126 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
4127 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4128 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4129 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4130 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4132 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
4133 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
4134 rsDesc.Desc_1_1.NumParameters = 3;
4135 rsDesc.Desc_1_1.pParameters = rootParams;
4136 rsDesc.Desc_1_1.NumStaticSamplers = 1;
4137 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
4139 ID3DBlob *signature =
nullptr;
4140 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
4142 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
4145 ID3D12RootSignature *rootSig =
nullptr;
4146 hr = rhiD->dev->CreateRootSignature(0,
4147 signature->GetBufferPointer(),
4148 signature->GetBufferSize(),
4149 __uuidof(ID3D12RootSignature),
4150 reinterpret_cast<
void **>(&rootSig));
4151 signature->Release();
4153 qWarning(
"Failed to create root signature: %s",
4154 qPrintable(QSystemError::windowsComString(hr)));
4158 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
4160 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
4161 psoDesc.pRootSignature = rootSig;
4162 psoDesc.CS.pShaderBytecode = g_csMipmap3D;
4163 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap3D);
4164 ID3D12PipelineState *pso =
nullptr;
4165 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
4166 __uuidof(ID3D12PipelineState),
4167 reinterpret_cast<
void **>(&pso));
4169 qWarning(
"Failed to create compute pipeline state: %s",
4170 qPrintable(QSystemError::windowsComString(hr)));
4171 rhiD->rootSignaturePool.remove(rootSigHandle);
4176 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
4181void QD3D12MipmapGenerator3D::destroy()
4186 rhiD->pipelinePool.remove(pipelineHandle);
4187 pipelineHandle = {};
4188 rhiD->rootSignaturePool.remove(rootSigHandle);
4190 createFailed =
false;
4193void QD3D12MipmapGenerator3D::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
4195 if (!ensureCreated())
4198 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
4201 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
4204 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
4208 const quint32 mipLevelCount = res->desc.MipLevels;
4209 if (mipLevelCount < 2)
4212 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
4214 qWarning(
"3D mipmap generator invoked for non-3D texture, this should not happen");
4218 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4219 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
4221 cbD->cmdList->SetPipelineState(pipeline->pso);
4222 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
4224 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
4230 quint32 srcMipLevel;
4233 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount);
4234 std::optional<QD3D12StagingArea> ownStagingArea;
4235 rhiD->recordSmallStagingAreaDemand(allocSize);
4236 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
4237 ownStagingArea = QD3D12StagingArea();
4238 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
4239 qWarning(
"Could not create staging area for mipmap generation");
4243 QD3D12StagingArea *workArea = ownStagingArea.has_value()
4244 ? &ownStagingArea.value()
4245 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
4247 bool gotNewHeap =
false;
4248 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
4249 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
4250 rhiD->currentFrameSlot,
4251 (1 + 1) * mipLevelCount,
4254 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
4258 rhiD->bindShaderVisibleHeaps(cbD);
4260 for (quint32 level = 0; level < mipLevelCount; ++level) {
4261 UINT subresource = calcSubresource(level, 0u, res->desc.MipLevels);
4262 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4263 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
4264 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
4266 quint32 levelPlusOneMipWidth = qMax<quint32>(1, res->desc.Width >> (level + 1));
4267 quint32 levelPlusOneMipHeight = qMax<quint32>(1, res->desc.Height >> (level + 1));
4268 quint32 levelPlusOneMipDepth = qMax<quint32>(1, res->desc.DepthOrArraySize >> (level + 1));
4270 CBufData cbufData = {
4271 1.0f /
float(levelPlusOneMipWidth),
4272 1.0f /
float(levelPlusOneMipHeight),
4273 1.0f /
float(levelPlusOneMipDepth),
4277 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
4278 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
4279 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
4281 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4282 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4283 srvDesc.Format = res->desc.Format;
4284 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4285 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4286 srvDesc.Texture3D.MipLevels = res->desc.MipLevels;
4288 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4289 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
4291 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4292 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
4293 const quint32 uavMipLevel = qMin(level + 1u, res->desc.MipLevels - 1u);
4294 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
4295 uavDesc.Format = res->desc.Format;
4296 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
4297 uavDesc.Texture3D.MipSlice = uavMipLevel;
4298 uavDesc.Texture3D.WSize = UINT(-1);
4299 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
4300 uavCpuHandle.ptr += descriptorByteSize;
4301 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
4303 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, levelPlusOneMipDepth);
4305 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
4306 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4307 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
4308 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4311 if (ownStagingArea.has_value())
4312 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
4315bool QD3D12MemoryAllocator::create(ID3D12Device *device, IDXGIAdapter1 *adapter)
4317 this->device = device;
4324 static bool disableMA = qEnvironmentVariableIntValue(
"QT_D3D_NO_SUBALLOC");
4328 DXGI_ADAPTER_DESC1 desc;
4329 adapter->GetDesc1(&desc);
4330 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
4333 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
4334 allocatorDesc.pDevice = device;
4335 allocatorDesc.pAdapter = adapter;
4338 allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED;
4339 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
4341 qWarning(
"Failed to initialize D3D12 Memory Allocator: %s",
4342 qPrintable(QSystemError::windowsComString(hr)));
4348void QD3D12MemoryAllocator::destroy()
4351 allocator->Release();
4352 allocator =
nullptr;
4356HRESULT QD3D12MemoryAllocator::createResource(D3D12_HEAP_TYPE heapType,
4357 const D3D12_RESOURCE_DESC *resourceDesc,
4358 D3D12_RESOURCE_STATES initialState,
4359 const D3D12_CLEAR_VALUE *optimizedClearValue,
4360 D3D12MA::Allocation **maybeAllocation,
4361 REFIID riidResource,
4365 D3D12MA::ALLOCATION_DESC allocDesc = {};
4366 allocDesc.HeapType = heapType;
4367 return allocator->CreateResource(&allocDesc,
4370 optimizedClearValue,
4375 *maybeAllocation =
nullptr;
4376 D3D12_HEAP_PROPERTIES heapProps = {};
4377 heapProps.Type = heapType;
4378 return device->CreateCommittedResource(&heapProps,
4379 D3D12_HEAP_FLAG_NONE,
4382 optimizedClearValue,
4388void QD3D12MemoryAllocator::getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget)
4391 allocator->GetBudget(localBudget, nonLocalBudget);
4394 *nonLocalBudget = {};
4398void QRhiD3D12::waitGpu()
4400 fullFenceCounter += 1u;
4401 if (SUCCEEDED(cmdQueue->Signal(fullFence, fullFenceCounter))) {
4402 if (SUCCEEDED(fullFence->SetEventOnCompletion(fullFenceCounter, fullFenceEvent)))
4403 WaitForSingleObject(fullFenceEvent, INFINITE);
4407DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleDesc(
int sampleCount, DXGI_FORMAT format)
const
4409 DXGI_SAMPLE_DESC desc;
4413 const int s = effectiveSampleCount(sampleCount);
4416 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
4417 msaaInfo.Format = format;
4418 msaaInfo.SampleCount = UINT(s);
4419 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo,
sizeof(msaaInfo)))) {
4420 if (msaaInfo.NumQualityLevels > 0) {
4421 desc.Count = UINT(s);
4422 desc.Quality = msaaInfo.NumQualityLevels - 1;
4424 qWarning(
"No quality levels for multisampling with sample count %d", s);
4432bool QRhiD3D12::startCommandListForCurrentFrameSlot(D3D12GraphicsCommandList **cmdList)
4434 ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
4436 HRESULT hr = dev->CreateCommandList(0,
4437 D3D12_COMMAND_LIST_TYPE_DIRECT,
4440 __uuidof(D3D12GraphicsCommandList),
4441 reinterpret_cast<
void **>(cmdList));
4443 qWarning(
"Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
4447 HRESULT hr = (*cmdList)->Reset(cmdAlloc,
nullptr);
4449 qWarning(
"Failed to reset command list: %s", qPrintable(QSystemError::windowsComString(hr)));
4456static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
4459 case DXGI_FORMAT_R8G8B8A8_UNORM:
4460 return QRhiTexture::RGBA8;
4461 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
4463 (*flags) |= QRhiTexture::sRGB;
4464 return QRhiTexture::RGBA8;
4465 case DXGI_FORMAT_B8G8R8A8_UNORM:
4466 return QRhiTexture::BGRA8;
4467 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
4469 (*flags) |= QRhiTexture::sRGB;
4470 return QRhiTexture::BGRA8;
4471 case DXGI_FORMAT_R16G16B16A16_FLOAT:
4472 return QRhiTexture::RGBA16F;
4473 case DXGI_FORMAT_R32G32B32A32_FLOAT:
4474 return QRhiTexture::RGBA32F;
4475 case DXGI_FORMAT_R10G10B10A2_UNORM:
4476 return QRhiTexture::RGB10A2;
4478 qWarning(
"DXGI_FORMAT %d cannot be read back", format);
4481 return QRhiTexture::UnknownFormat;
4484static inline bool isDepthTextureFormat(QRhiTexture::Format format)
4487 case QRhiTexture::Format::D16:
4488 case QRhiTexture::Format::D24:
4489 case QRhiTexture::Format::D24S8:
4490 case QRhiTexture::Format::D32F:
4491 case QRhiTexture::Format::D32FS8:
4498void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
4500 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
4502 for (
int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
4503 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
4504 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
4505 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4506 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4507 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4508 if (u.offset == 0 && u.data.size() == bufD->m_size)
4509 bufD->pendingHostWrites[i].clear();
4510 bufD->pendingHostWrites[i].append({ u.offset, u.data });
4512 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
4513 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4514 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4515 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
4523 QD3D12StagingArea::Allocation stagingAlloc;
4524 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(bufD->m_size, 1);
4525 recordSmallStagingAreaDemand(allocSize);
4526 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
4527 stagingAlloc = smallStagingAreas[currentFrameSlot].get(bufD->m_size);
4529 std::optional<QD3D12StagingArea> ownStagingArea;
4530 if (!stagingAlloc.isValid()) {
4531 ownStagingArea = QD3D12StagingArea();
4532 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
4534 stagingAlloc = ownStagingArea->get(allocSize);
4535 if (!stagingAlloc.isValid()) {
4536 ownStagingArea->destroy();
4541 memcpy(stagingAlloc.p + u.offset, u.data.constData(), u.data.size());
4543 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
4544 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4546 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
4547 cbD->cmdList->CopyBufferRegion(res->resource,
4549 stagingAlloc.buffer,
4550 stagingAlloc.bufferOffset + u.offset,
4554 if (ownStagingArea.has_value())
4555 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4556 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
4557 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4558 if (bufD->m_type == QRhiBuffer::Dynamic) {
4559 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
4560 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[currentFrameSlot])) {
4561 Q_ASSERT(res->cpuMapPtr);
4562 u.result->data.resize(u.readSize);
4563 memcpy(u.result->data.data(),
reinterpret_cast<
char *>(res->cpuMapPtr) + u.offset, u.readSize);
4565 if (u.result->completed)
4566 u.result->completed();
4568 QD3D12Readback readback;
4569 readback.frameSlot = currentFrameSlot;
4570 readback.result = u.result;
4571 readback.byteSize = u.readSize;
4572 const quint32 allocSize = aligned(u.readSize, QD3D12StagingArea::ALIGNMENT);
4573 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
4574 if (u.result->completed)
4575 u.result->completed();
4578 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(u.readSize);
4579 if (!stagingAlloc.isValid()) {
4580 readback.staging.destroy();
4581 if (u.result->completed)
4582 u.result->completed();
4585 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4586 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
4587 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4588 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
4589 cbD->cmdList->CopyBufferRegion(stagingAlloc.buffer, 0, res->resource, u.offset, u.readSize);
4590 activeReadbacks.append(readback);
4592 readback.staging.destroy();
4593 if (u.result->completed)
4594 u.result->completed();
4597 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Copy) {
4598 QD3D12Buffer *dstD = QRHI_RES(QD3D12Buffer, u.buf);
4599 QD3D12Buffer *srcD = QRHI_RES(QD3D12Buffer, u.src);
4600 Q_ASSERT(dstD->m_type != QRhiBuffer::Dynamic && srcD->m_type != QRhiBuffer::Dynamic);
4602 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handles[0]);
4603 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handles[0]);
4604 if (!dstRes || !srcRes)
4607 barrierGen.addTransitionBarrier(srcD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
4608 barrierGen.addTransitionBarrier(dstD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
4609 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4611 cbD->cmdList->CopyBufferRegion(dstRes->resource, u.offset,
4612 srcRes->resource, u.srcOffset,
4614 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Clear) {
4615 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4616 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4618 QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0]);
4622 bool gotNewHeap =
false;
4623 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
4624 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
4625 currentFrameSlot, 1, &gotNewHeap))
4630 bindShaderVisibleHeaps(cbD);
4632 const QD3D12Descriptor cpuDesc = cbvSrvUavPool.allocate(1);
4633 if (!cpuDesc.isValid())
4635 const QD3D12Descriptor gpuDesc = shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].get(1);
4638 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
4639 uavDesc.Format = DXGI_FORMAT_R32_UINT;
4640 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
4641 uavDesc.Buffer.FirstElement = u.offset / 4u;
4642 uavDesc.Buffer.NumElements = u.readSize / 4u;
4643 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, cpuDesc.cpuHandle);
4644 dev->CopyDescriptorsSimple(1, gpuDesc.cpuHandle, cpuDesc.cpuHandle,
4645 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
4647 if (res->state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS && res->uavUsage)
4648 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
4649 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4650 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4652 const UINT values[4] = { u.fillValue32(), u.fillValue32(), u.fillValue32(), u.fillValue32() };
4653 cbD->cmdList->ClearUnorderedAccessViewUint(gpuDesc.gpuHandle, cpuDesc.cpuHandle,
4654 res->resource, values, 0,
nullptr);
4656 res->uavUsage = QD3D12Resource::UavUsageWrite;
4658 releaseQueue.deferredReleaseViews(&cbvSrvUavPool, cpuDesc, 1);
4662 for (
int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
4663 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
4664 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
4665 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4666 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4667 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
4670 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4671 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4672 for (
const auto &subres : u.subresDesc) {
4673 const int layer = subres.layer;
4674 const int level = subres.level;
4675 const QRhiTextureSubresourceUploadDescription &subresDesc(subres.desc);
4676 D3D12_SUBRESOURCE_FOOTPRINT footprint = {};
4677 footprint.Format = res->desc.Format;
4678 footprint.Depth = 1;
4679 quint32 totalBytes = 0;
4681 QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
4682 : subresDesc.sourceSize();
4683 const QPoint srcPos = subresDesc.sourceTopLeft();
4684 QPoint dstPos = subresDesc.destinationTopLeft();
4686 if (subresDesc.image().isNull()
4687 && !subresDesc.data().isEmpty()
4688 && !isCompressedFormat(texD->m_format))
4690 subresSize = clampedSubResourceUploadSize(subresSize, dstPos, level, texD->m_pixelSize);
4691 quint32 bytesPerPixel = 0;
4692 textureFormatInfo(texD->m_format, subresSize,
nullptr,
nullptr, &bytesPerPixel);
4693 subresSize = clampedSubResourceUploadSizeForSourceData(subresSize,
4694 subresDesc.dataStride(),
4696 subresDesc.data().size());
4697 if (subresSize.isEmpty())
4701 if (!subresDesc.image().isNull()) {
4702 const QImage img = subresDesc.image();
4703 const int bpl = img.bytesPerLine();
4704 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4705 totalBytes = footprint.RowPitch * img.height();
4706 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
4709 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
4710 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4711 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
4712 totalBytes = footprint.RowPitch * rowCount;
4713 }
else if (!subresDesc.data().isEmpty()) {
4715 if (subresDesc.dataStride())
4716 bpl = subresDesc.dataStride();
4718 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4719 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4720 totalBytes = footprint.RowPitch * subresSize.height();
4722 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4726 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(totalBytes, 1);
4727 QD3D12StagingArea::Allocation stagingAlloc;
4728 recordSmallStagingAreaDemand(allocSize);
4729 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
4730 stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
4732 std::optional<QD3D12StagingArea> ownStagingArea;
4733 if (!stagingAlloc.isValid()) {
4734 ownStagingArea = QD3D12StagingArea();
4735 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
4737 stagingAlloc = ownStagingArea->get(allocSize);
4738 if (!stagingAlloc.isValid()) {
4739 ownStagingArea->destroy();
4744 D3D12_TEXTURE_COPY_LOCATION dst;
4745 dst.pResource = res->resource;
4746 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4747 dst.SubresourceIndex = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
4748 D3D12_TEXTURE_COPY_LOCATION src;
4749 src.pResource = stagingAlloc.buffer;
4750 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4751 src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
4755 if (!subresDesc.image().isNull()) {
4756 const QImage img = subresDesc.image();
4757 const int bpc = qMax(1, img.depth() / 8);
4758 const int bpl = img.bytesPerLine();
4760 QSize size = subresDesc.sourceSize().isEmpty() ? img.size() : subresDesc.sourceSize();
4761 size.setWidth(qMin(size.width(), img.width() - srcPos.x()));
4762 size.setHeight(qMin(size.height(), img.height() - srcPos.y()));
4763 size = clampedSubResourceUploadSize(size, dstPos, level, texD->m_pixelSize);
4765 footprint.Width = size.width();
4766 footprint.Height = size.height();
4770 srcBox.right = UINT(size.width());
4771 srcBox.bottom = UINT(size.height());
4775 const uchar *imgPtr = img.constBits();
4776 const quint32 lineBytes = size.width() * bpc;
4777 for (
int y = 0, h = size.height(); y < h; ++y) {
4778 memcpy(stagingAlloc.p + y * footprint.RowPitch,
4779 imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
4782 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
4785 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
4787 dstPos.setX(aligned(dstPos.x(), blockDim.width()));
4788 dstPos.setY(aligned(dstPos.y(), blockDim.height()));
4793 srcBox.right = aligned(subresSize.width(), blockDim.width());
4794 srcBox.bottom = aligned(subresSize.height(), blockDim.height());
4799 footprint.Width = aligned(subresSize.width(), blockDim.width());
4800 footprint.Height = aligned(subresSize.height(), blockDim.height());
4802 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4803 const QByteArray imgData = subresDesc.data();
4804 const char *imgPtr = imgData.constData();
4805 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
4806 for (
int y = 0; y < rowCount; ++y) {
4807 const quint64 srcOffset = quint64(y) * bpl;
4808 if (srcOffset >= quint64(imgData.size()))
4810 const quint32 n = quint32(qMin(quint64(copyBytes),
4811 quint64(imgData.size()) - srcOffset));
4812 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + srcOffset, n);
4814 }
else if (!subresDesc.data().isEmpty()) {
4817 srcBox.right = subresSize.width();
4818 srcBox.bottom = subresSize.height();
4822 footprint.Width = subresSize.width();
4823 footprint.Height = subresSize.height();
4826 if (subresDesc.dataStride())
4827 bpl = subresDesc.dataStride();
4829 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4831 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4832 const QByteArray data = subresDesc.data();
4833 const char *imgPtr = data.constData();
4834 for (
int y = 0, h = subresSize.height(); y < h; ++y) {
4839 const quint64 srcOffset = quint64(y) * bpl;
4840 if (srcOffset >= quint64(data.size()))
4842 const quint32 n = quint32(qMin(quint64(copyBytes),
4843 quint64(data.size()) - srcOffset));
4844 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + srcOffset, n);
4848 src.PlacedFootprint.Footprint = footprint;
4850 cbD->cmdList->CopyTextureRegion(&dst,
4853 is3D ? UINT(layer) : 0u,
4857 if (ownStagingArea.has_value())
4858 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4860 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
4861 Q_ASSERT(u.src && u.dst);
4862 QD3D12Texture *srcD = QRHI_RES(QD3D12Texture, u.src);
4863 QD3D12Texture *dstD = QRHI_RES(QD3D12Texture, u.dst);
4864 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4865 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4866 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
4867 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
4868 if (!srcRes || !dstRes)
4871 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4872 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4873 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4875 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
4876 srcIs3D ? 0u : UINT(u.desc.sourceLayer()),
4877 srcD->mipLevelCount);
4878 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
4879 dstIs3D ? 0u : UINT(u.desc.destinationLayer()),
4880 dstD->mipLevelCount);
4881 const QPoint dp = u.desc.destinationTopLeft();
4882 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4883 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4884 const QPoint sp = u.desc.sourceTopLeft();
4887 srcBox.left = UINT(sp.x());
4888 srcBox.top = UINT(sp.y());
4889 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
4891 srcBox.right = srcBox.left + UINT(copySize.width());
4892 srcBox.bottom = srcBox.top + UINT(copySize.height());
4893 srcBox.back = srcBox.front + 1;
4895 D3D12_TEXTURE_COPY_LOCATION src;
4896 src.pResource = srcRes->resource;
4897 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4898 src.SubresourceIndex = srcSubresource;
4899 D3D12_TEXTURE_COPY_LOCATION dst;
4900 dst.pResource = dstRes->resource;
4901 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4902 dst.SubresourceIndex = dstSubresource;
4904 cbD->cmdList->CopyTextureRegion(&dst,
4907 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
4910 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
4911 QD3D12Readback readback;
4912 readback.frameSlot = currentFrameSlot;
4913 readback.result = u.result;
4915 QD3D12ObjectHandle srcHandle;
4918 if (u.rb.texture()) {
4919 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.rb.texture());
4920 if (texD->sampleDesc.Count > 1) {
4921 qWarning(
"Multisample texture cannot be read back");
4924 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4925 const QRect levelRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4926 readback.format = texD->m_format;
4927 rect = u.rb.rect().isValid() ? u.rb.rect() : levelRect;
4928 if (isDepthTextureFormat(readback.format)) {
4933 rect = rect.intersected(levelRect);
4934 readback.cropOrigin = rect.topLeft();
4936 srcHandle = texD->handle;
4938 Q_ASSERT(currentSwapChain);
4939 if (u.rb.rect().isValid())
4942 rect = QRect({0, 0}, currentSwapChain->pixelSize);
4943 readback.format = swapchainReadbackTextureFormat(currentSwapChain->colorFormat,
nullptr);
4944 if (readback.format == QRhiTexture::UnknownFormat)
4946 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
4948 readback.pixelSize = rect.size();
4950 textureFormatInfo(readback.format,
4952 &readback.bytesPerLine,
4954 &readback.bytesPerPixel);
4956 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
4967 const bool combinedDepthStencil = u.rb.texture() && isStencilSupportingFormat(readback.format);
4968 const bool depthTexture = u.rb.texture() && isDepthTextureFormat(readback.format);
4970 const UINT subresource = calcSubresource(UINT(u.rb.level()),
4971 is3D ? 0u : UINT(u.rb.layer()),
4972 srcRes->desc.MipLevels);
4973 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
4976 UINT64 totalBytes = 0;
4977 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
4978 &layout,
nullptr,
nullptr, &totalBytes);
4979 readback.stagingRowPitch = layout.Footprint.RowPitch;
4981 UINT stencilSubresource = 0;
4982 D3D12_PLACED_SUBRESOURCE_FOOTPRINT stencilLayout;
4983 UINT64 stencilTotalBytes = 0;
4984 if (combinedDepthStencil) {
4985 stencilSubresource = subresource
4986 + srcRes->desc.MipLevels * UINT(srcRes->desc.DepthOrArraySize);
4987 dev->GetCopyableFootprints(&srcRes->desc, stencilSubresource, 1, 0,
4988 &stencilLayout,
nullptr,
nullptr, &stencilTotalBytes);
4989 readback.stencilStagingRowPitch = stencilLayout.Footprint.RowPitch;
4992 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT)
4993 + (combinedDepthStencil ? aligned<quint32>(stencilTotalBytes, QD3D12StagingArea::ALIGNMENT) : 0);
4994 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
4995 if (u.result->completed)
4996 u.result->completed();
4999 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
5000 QD3D12StagingArea::Allocation stencilStagingAlloc;
5001 if (combinedDepthStencil)
5002 stencilStagingAlloc = readback.staging.get(stencilTotalBytes);
5003 if (!stagingAlloc.isValid() || (combinedDepthStencil && !stencilStagingAlloc.isValid())) {
5004 readback.staging.destroy();
5005 if (u.result->completed)
5006 u.result->completed();
5009 Q_ASSERT(stagingAlloc.bufferOffset == 0);
5010 readback.stencilStagingOffset = stencilStagingAlloc.bufferOffset;
5012 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
5013 barrierGen.enqueueBufferedTransitionBarriers(cbD);
5015 D3D12_TEXTURE_COPY_LOCATION dst;
5016 dst.pResource = stagingAlloc.buffer;
5017 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
5018 dst.PlacedFootprint.Offset = 0;
5019 dst.PlacedFootprint.Footprint = layout.Footprint;
5021 D3D12_TEXTURE_COPY_LOCATION src;
5022 src.pResource = srcRes->resource;
5023 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
5024 src.SubresourceIndex = subresource;
5026 D3D12_BOX srcBox = {};
5027 srcBox.left = UINT(rect.left());
5028 srcBox.top = UINT(rect.top());
5029 srcBox.front = is3D ? UINT(u.rb.layer()) : 0u;
5031 srcBox.right = srcBox.left + UINT(rect.width());
5032 srcBox.bottom = srcBox.top + UINT(rect.height());
5033 srcBox.back = srcBox.front + 1;
5036 const D3D12_BOX *srcBoxPtr = depthTexture ?
nullptr : &srcBox;
5038 cbD->cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, srcBoxPtr);
5040 if (combinedDepthStencil) {
5041 D3D12_TEXTURE_COPY_LOCATION stencilDst;
5042 stencilDst.pResource = stencilStagingAlloc.buffer;
5043 stencilDst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
5044 stencilDst.PlacedFootprint.Offset = stencilStagingAlloc.bufferOffset;
5045 stencilDst.PlacedFootprint.Footprint = stencilLayout.Footprint;
5047 D3D12_TEXTURE_COPY_LOCATION stencilSrc;
5048 stencilSrc.pResource = srcRes->resource;
5049 stencilSrc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
5050 stencilSrc.SubresourceIndex = stencilSubresource;
5052 cbD->cmdList->CopyTextureRegion(&stencilDst, 0, 0, 0, &stencilSrc, srcBoxPtr);
5055 activeReadbacks.append(readback);
5056 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
5057 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
5058 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
5064 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
5065 if (res && texD->mipLevelCount >= 2
5066 && (res->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET))
5068 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
5069 const UINT layerCount = is3D ? 1u : UINT(res->desc.DepthOrArraySize);
5070 QBitArray &initialized(texD->subresourceInitialized);
5071 QVarLengthArray<UINT, 16> subresourcesToDiscard;
5072 for (UINT layer = 0; layer < layerCount; ++layer) {
5073 for (UINT level = 1; level < texD->mipLevelCount; ++level) {
5074 const UINT subresource = calcSubresource(level, layer, texD->mipLevelCount);
5075 if (
int(subresource) >= initialized.size())
5076 initialized.resize(
int(subresource) + 1);
5077 if (!initialized.testBit(
int(subresource))) {
5078 initialized.setBit(
int(subresource));
5079 subresourcesToDiscard.append(subresource);
5083 if (!subresourcesToDiscard.isEmpty()) {
5085 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
5086 barrierGen.enqueueBufferedTransitionBarriers(cbD);
5087 for (UINT subresource : subresourcesToDiscard) {
5088 D3D12_DISCARD_REGION region = {};
5089 region.FirstSubresource = subresource;
5090 region.NumSubresources = 1;
5091 cbD->cmdList->DiscardResource(res->resource, ®ion);
5096 if (texD->flags().testFlag(QRhiTexture::ThreeDimensional))
5097 mipmapGen3D.generate(cbD, texD->handle);
5099 mipmapGen.generate(cbD, texD->handle);
5106void QRhiD3D12::finishActiveReadbacks(
bool forced)
5108 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
5110 for (
int i = activeReadbacks.size() - 1; i >= 0; --i) {
5111 QD3D12Readback &readback(activeReadbacks[i]);
5112 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
5113 readback.result->format = readback.format;
5114 readback.result->pixelSize = readback.pixelSize;
5115 readback.result->data.resize(
int(readback.byteSize));
5117 if (readback.format != QRhiTexture::UnknownFormat) {
5118 if (isStencilSupportingFormat(readback.format)) {
5130 const quint8 *depthBase = readback.staging.mem.p
5131 + readback.cropOrigin.y() * readback.stagingRowPitch
5132 + readback.cropOrigin.x() * 4;
5133 const quint8 *stencilBase = readback.staging.mem.p + readback.stencilStagingOffset
5134 + readback.cropOrigin.y() * readback.stencilStagingRowPitch
5135 + readback.cropOrigin.x();
5136 char *dst = readback.result->data.data();
5137 const int w = readback.pixelSize.width();
5138 const int h = readback.pixelSize.height();
5139 if (readback.format == QRhiTexture::D32FS8) {
5142 for (
int y = 0; y < h; ++y) {
5143 const quint8 *depthRow = depthBase + y * readback.stagingRowPitch;
5144 const quint8 *stencilRow = stencilBase + y * readback.stencilStagingRowPitch;
5145 for (
int x = 0; x < w; ++x) {
5146 const quint32 stencilWord = stencilRow[x];
5147 char *dstPixel = dst + (y * w + x) * 8;
5148 memcpy(dstPixel, depthRow + x * 4,
sizeof(quint32));
5149 memcpy(dstPixel + 4, &stencilWord,
sizeof(quint32));
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) {
5163 memcpy(&depthWord, depthRow + x * 4,
sizeof(quint32));
5164 const quint32 combined = ((depthWord & 0x00FFFFFFu) << 8) | stencilRow[x];
5165 memcpy(dst + (y * w + x) * 4, &combined,
sizeof(quint32));
5170 quint8 *dstPtr =
reinterpret_cast<quint8 *>(readback.result->data.data());
5171 const quint8 *srcPtr = readback.staging.mem.p
5172 + readback.cropOrigin.y() * readback.stagingRowPitch
5173 + readback.cropOrigin.x() * readback.bytesPerPixel;
5174 const quint32 lineSize = qMin(readback.bytesPerLine, readback.stagingRowPitch);
5175 for (
int y = 0, h = readback.pixelSize.height(); y < h; ++y)
5176 memcpy(dstPtr + y * readback.bytesPerLine, srcPtr + y * readback.stagingRowPitch, lineSize);
5177 if (readback.format == QRhiTexture::D24) {
5181 char *p = readback.result->data.data();
5182 for (qsizetype px = 0, count = readback.result->data.size() / 4; px < count; ++px)
5183 qToUnaligned((qFromUnaligned<quint32>(p + px * 4) & 0x00FFFFFFu) << 8, p + px * 4);
5187 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
5190 readback.staging.destroy();
5192 if (readback.result->completed)
5193 completedCallbacks.append(readback.result->completed);
5195 activeReadbacks.remove(i);
5199 for (
auto f : completedCallbacks)
5203bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
5204 D3D12_DESCRIPTOR_HEAP_TYPE type,
5206 quint32 neededDescriptorCount,
5214 if (h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
5215 const quint32 newPerFrameSize = qMax(h->perFrameHeapSlice[frameSlot].capacity * 2,
5216 neededDescriptorCount);
5217 QD3D12ShaderVisibleDescriptorHeap newHeap;
5218 if (!newHeap.create(dev, type, newPerFrameSize)) {
5219 qWarning(
"Could not create new shader-visible descriptor heap");
5222 h->destroyWithDeferredRelease(&releaseQueue);
5229void QRhiD3D12::resetAndResizeSmallStagingArea(
int frameSlot)
5231 QD3D12StagingArea &area(smallStagingAreas[frameSlot]);
5237 const quint32 needed = smallStagingAreaBytesNeeded[frameSlot];
5238 smallStagingAreaBytesNeeded[frameSlot] = 0;
5240 quint32 newCapacity = 0;
5241 if (needed > area.capacity) {
5244 smallStagingAreaLowDemandFrames[frameSlot] = 0;
5245 newCapacity = qMin(qNextPowerOfTwo(needed), SMALL_STAGING_AREA_BYTES_PER_FRAME_MAX);
5246 }
else if (needed <= area.capacity / 4 && area.capacity > SMALL_STAGING_AREA_BYTES_PER_FRAME_START) {
5247 if (++smallStagingAreaLowDemandFrames[frameSlot] >= SMALL_STAGING_AREA_LOW_DEMAND_FRAMES) {
5248 smallStagingAreaLowDemandFrames[frameSlot] = 0;
5249 newCapacity = qMax(area.capacity / 2, SMALL_STAGING_AREA_BYTES_PER_FRAME_START);
5252 smallStagingAreaLowDemandFrames[frameSlot] = 0;
5255 if (newCapacity && newCapacity != area.capacity) {
5256 QD3D12StagingArea newArea;
5257 if (newArea.create(
this, aligned(newCapacity, QD3D12StagingArea::ALIGNMENT), D3D12_HEAP_TYPE_UPLOAD)) {
5258 area.destroyWithDeferredRelease(&releaseQueue);
5260 QString decoratedName = QLatin1String(
"Small staging area buffer/");
5261 decoratedName += QString::number(frameSlot);
5262 area.mem.buffer->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
5271void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
5273 ID3D12DescriptorHeap *heaps[] = {
5274 shaderVisibleCbvSrvUavHeap.heap.heap,
5275 samplerMgr.shaderVisibleSamplerHeap.heap.heap
5277 cbD->cmdList->SetDescriptorHeaps(2, heaps);
5280QD3D12Buffer::QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
5281 : QRhiBuffer(rhi, type, usage, size)
5285QD3D12Buffer::~QD3D12Buffer()
5290void QD3D12Buffer::destroy()
5292 if (handles[0].isNull())
5295 QRHI_RES_RHI(QRhiD3D12);
5304 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
5306 rhiD->releaseQueue.deferredReleaseResource(handles[i]);
5308 pendingHostWrites[i].clear();
5312 rhiD->unregisterResource(
this);
5315bool QD3D12Buffer::create()
5317 if (!handles[0].isNull())
5320 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
5321 qWarning(
"UniformBuffer must always be Dynamic");
5325 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
5326 qWarning(
"StorageBuffer cannot be combined with Dynamic");
5330 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
5331 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
5333 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
5334 if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
5335 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5337 QRHI_RES_RHI(QRhiD3D12);
5339 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
5340 if (i == 0 || m_type == Dynamic) {
5341 D3D12_RESOURCE_DESC resourceDesc = {};
5342 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
5343 resourceDesc.Width = roundedSize;
5344 resourceDesc.Height = 1;
5345 resourceDesc.DepthOrArraySize = 1;
5346 resourceDesc.MipLevels = 1;
5347 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
5348 resourceDesc.SampleDesc = { 1, 0 };
5349 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
5350 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
5351 ID3D12Resource *resource =
nullptr;
5352 D3D12MA::Allocation *allocation =
nullptr;
5354 D3D12_HEAP_TYPE heapType = m_type == Dynamic
5355 ? D3D12_HEAP_TYPE_UPLOAD
5356 : D3D12_HEAP_TYPE_DEFAULT;
5357 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
5358 ? D3D12_RESOURCE_STATE_GENERIC_READ
5359 : D3D12_RESOURCE_STATE_COMMON;
5360 hr = rhiD->vma.createResource(heapType,
5366 reinterpret_cast<
void **>(&resource));
5369 if (!m_objectName.isEmpty()) {
5370 QString decoratedName = QString::fromUtf8(m_objectName);
5371 if (m_type == Dynamic) {
5372 decoratedName += QLatin1Char(
'/');
5373 decoratedName += QString::number(i);
5375 resource->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
5377 void *cpuMemPtr =
nullptr;
5378 if (m_type == Dynamic) {
5380 hr = resource->Map(0,
nullptr, &cpuMemPtr);
5382 qWarning(
"Map() failed to dynamic buffer");
5383 resource->Release();
5385 allocation->Release();
5389 handles[i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
5397 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
5398 qPrintable(QSystemError::windowsComString(hr)),
5401 int(rhiD->vma.isUsingD3D12MA()));
5406 rhiD->registerResource(
this);
5410QRhiBuffer::NativeBuffer QD3D12Buffer::nativeBuffer()
5413 Q_ASSERT(
sizeof(b.objects) /
sizeof(b.objects[0]) >= size_t(QD3D12_FRAMES_IN_FLIGHT));
5414 QRHI_RES_RHI(QRhiD3D12);
5415 if (m_type == Dynamic) {
5416 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
5417 executeHostWritesForFrameSlot(i);
5418 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[i]))
5419 b.objects[i] = res->resource;
5421 b.objects[i] =
nullptr;
5423 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
5426 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[0]))
5427 b.objects[0] = res->resource;
5429 b.objects[0] =
nullptr;
5434char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
5442 Q_ASSERT(m_type == Dynamic);
5443 QRHI_RES_RHI(QRhiD3D12);
5444 Q_ASSERT(rhiD->inFrame);
5445 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
5446 return static_cast<
char *>(res->cpuMapPtr);
5451void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
5456void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
5458 if (pendingHostWrites[frameSlot].isEmpty())
5461 Q_ASSERT(m_type == QRhiBuffer::Dynamic);
5462 QRHI_RES_RHI(QRhiD3D12);
5463 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
5464 Q_ASSERT(res->cpuMapPtr);
5465 for (
const QD3D12Buffer::HostWrite &u : std::as_const(pendingHostWrites[frameSlot]))
5466 memcpy(
static_cast<
char *>(res->cpuMapPtr) + u.offset, u.data.constData(), u.data.size());
5468 pendingHostWrites[frameSlot].clear();
5471static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
5473 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
5475 case QRhiTexture::RGBA8:
5476 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
5477 case QRhiTexture::BGRA8:
5478 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
5479 case QRhiTexture::R8:
5480 return DXGI_FORMAT_R8_UNORM;
5481 case QRhiTexture::R8SI:
5482 return DXGI_FORMAT_R8_SINT;
5483 case QRhiTexture::R8UI:
5484 return DXGI_FORMAT_R8_UINT;
5485 case QRhiTexture::RG8:
5486 return DXGI_FORMAT_R8G8_UNORM;
5487 case QRhiTexture::R16:
5488 return DXGI_FORMAT_R16_UNORM;
5489 case QRhiTexture::RG16:
5490 return DXGI_FORMAT_R16G16_UNORM;
5491 case QRhiTexture::RED_OR_ALPHA8:
5492 return DXGI_FORMAT_R8_UNORM;
5494 case QRhiTexture::RGBA16F:
5495 return DXGI_FORMAT_R16G16B16A16_FLOAT;
5496 case QRhiTexture::RGBA32F:
5497 return DXGI_FORMAT_R32G32B32A32_FLOAT;
5498 case QRhiTexture::R16F:
5499 return DXGI_FORMAT_R16_FLOAT;
5500 case QRhiTexture::R32F:
5501 return DXGI_FORMAT_R32_FLOAT;
5503 case QRhiTexture::RGB10A2:
5504 return DXGI_FORMAT_R10G10B10A2_UNORM;
5506 case QRhiTexture::R32SI:
5507 return DXGI_FORMAT_R32_SINT;
5508 case QRhiTexture::R32UI:
5509 return DXGI_FORMAT_R32_UINT;
5510 case QRhiTexture::RG32SI:
5511 return DXGI_FORMAT_R32G32_SINT;
5512 case QRhiTexture::RG32UI:
5513 return DXGI_FORMAT_R32G32_UINT;
5514 case QRhiTexture::RGBA32SI:
5515 return DXGI_FORMAT_R32G32B32A32_SINT;
5516 case QRhiTexture::RGBA32UI:
5517 return DXGI_FORMAT_R32G32B32A32_UINT;
5519 case QRhiTexture::D16:
5520 return DXGI_FORMAT_R16_TYPELESS;
5521 case QRhiTexture::D24:
5522 return DXGI_FORMAT_R24G8_TYPELESS;
5523 case QRhiTexture::D24S8:
5524 return DXGI_FORMAT_R24G8_TYPELESS;
5525 case QRhiTexture::D32F:
5526 return DXGI_FORMAT_R32_TYPELESS;
5527 case QRhiTexture::Format::D32FS8:
5528 return DXGI_FORMAT_R32G8X24_TYPELESS;
5530 case QRhiTexture::BC1:
5531 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
5532 case QRhiTexture::BC2:
5533 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
5534 case QRhiTexture::BC3:
5535 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
5536 case QRhiTexture::BC4:
5537 return DXGI_FORMAT_BC4_UNORM;
5538 case QRhiTexture::BC5:
5539 return DXGI_FORMAT_BC5_UNORM;
5540 case QRhiTexture::BC6H:
5541 return DXGI_FORMAT_BC6H_UF16;
5542 case QRhiTexture::BC7:
5543 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
5545 case QRhiTexture::ETC2_RGB8:
5546 case QRhiTexture::ETC2_RGB8A1:
5547 case QRhiTexture::ETC2_RGBA8:
5548 qWarning(
"QRhiD3D12 does not support ETC2 textures");
5549 return DXGI_FORMAT_R8G8B8A8_UNORM;
5551 case QRhiTexture::ASTC_4x4:
5552 case QRhiTexture::ASTC_5x4:
5553 case QRhiTexture::ASTC_5x5:
5554 case QRhiTexture::ASTC_6x5:
5555 case QRhiTexture::ASTC_6x6:
5556 case QRhiTexture::ASTC_8x5:
5557 case QRhiTexture::ASTC_8x6:
5558 case QRhiTexture::ASTC_8x8:
5559 case QRhiTexture::ASTC_10x5:
5560 case QRhiTexture::ASTC_10x6:
5561 case QRhiTexture::ASTC_10x8:
5562 case QRhiTexture::ASTC_10x10:
5563 case QRhiTexture::ASTC_12x10:
5564 case QRhiTexture::ASTC_12x12:
5565 qWarning(
"QRhiD3D12 does not support ASTC textures");
5566 return DXGI_FORMAT_R8G8B8A8_UNORM;
5571 return DXGI_FORMAT_R8G8B8A8_UNORM;
5574QD3D12RenderBuffer::QD3D12RenderBuffer(QRhiImplementation *rhi,
5576 const QSize &pixelSize,
5579 QRhiTexture::Format backingFormatHint)
5580 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
5584QD3D12RenderBuffer::~QD3D12RenderBuffer()
5589void QD3D12RenderBuffer::destroy()
5591 if (handle.isNull())
5594 QRHI_RES_RHI(QRhiD3D12);
5597 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->rtvPool, rtv, 1);
5598 else if (dsv.isValid())
5599 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->dsvPool, dsv, 1);
5607 rhiD->unregisterResource(
this);
5610bool QD3D12RenderBuffer::create()
5612 if (!handle.isNull())
5615 if (m_pixelSize.isEmpty())
5618 QRHI_RES_RHI(QRhiD3D12);
5621 case QRhiRenderBuffer::Color:
5623 dxgiFormat = toD3DTextureFormat(backingFormat(), {});
5624 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5625 D3D12_RESOURCE_DESC resourceDesc = {};
5626 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
5627 resourceDesc.Width = UINT64(m_pixelSize.width());
5628 resourceDesc.Height = UINT(m_pixelSize.height());
5629 resourceDesc.DepthOrArraySize = 1;
5630 resourceDesc.MipLevels = 1;
5631 resourceDesc.Format = dxgiFormat;
5632 resourceDesc.SampleDesc = sampleDesc;
5633 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5634 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
5635 D3D12_CLEAR_VALUE clearValue = {};
5636 clearValue.Format = dxgiFormat;
5638 ID3D12Resource *resource =
nullptr;
5639 D3D12MA::Allocation *allocation =
nullptr;
5640 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5642 D3D12_RESOURCE_STATE_RENDER_TARGET,
5645 __uuidof(ID3D12Resource),
5646 reinterpret_cast<
void **>(&resource));
5648 qWarning(
"Failed to create color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
5651 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
5652 rtv = rhiD->rtvPool.allocate(1);
5655 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5656 rtvDesc.Format = dxgiFormat;
5657 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
5658 : D3D12_RTV_DIMENSION_TEXTURE2D;
5659 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
5662 case QRhiRenderBuffer::DepthStencil:
5664 dxgiFormat = DS_FORMAT;
5665 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5666 D3D12_RESOURCE_DESC resourceDesc = {};
5667 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
5668 resourceDesc.Width = UINT64(m_pixelSize.width());
5669 resourceDesc.Height = UINT(m_pixelSize.height());
5670 resourceDesc.DepthOrArraySize = 1;
5671 resourceDesc.MipLevels = 1;
5672 resourceDesc.Format = dxgiFormat;
5673 resourceDesc.SampleDesc = sampleDesc;
5674 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5675 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
5676 if (m_flags.testFlag(UsedWithSwapChainOnly))
5677 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
5678 D3D12_CLEAR_VALUE clearValue = {};
5679 clearValue.Format = dxgiFormat;
5680 clearValue.DepthStencil.Depth = 1.0f;
5681 clearValue.DepthStencil.Stencil = 0;
5682 ID3D12Resource *resource =
nullptr;
5683 D3D12MA::Allocation *allocation =
nullptr;
5684 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5686 D3D12_RESOURCE_STATE_DEPTH_WRITE,
5689 __uuidof(ID3D12Resource),
5690 reinterpret_cast<
void **>(&resource));
5692 qWarning(
"Failed to create depth-stencil buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
5695 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE, allocation);
5696 dsv = rhiD->dsvPool.allocate(1);
5699 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5700 dsvDesc.Format = dxgiFormat;
5701 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
5702 : D3D12_DSV_DIMENSION_TEXTURE2D;
5703 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
5708 if (!m_objectName.isEmpty()) {
5709 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
5710 const QString name = QString::fromUtf8(m_objectName);
5711 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
5716 rhiD->registerResource(
this);
5720QRhiTexture::Format QD3D12RenderBuffer::backingFormat()
const
5722 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
5723 return m_backingFormatHint;
5725 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
5728QD3D12Texture::QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
5729 int arraySize,
int sampleCount, Flags flags)
5730 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
5734QD3D12Texture::~QD3D12Texture()
5739void QD3D12Texture::destroy()
5741 if (handle.isNull())
5744 QRHI_RES_RHI(QRhiD3D12);
5746 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->cbvSrvUavPool, srv, 1);
5750 subresourceInitialized.clear();
5753 rhiD->unregisterResource(
this);
5756static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
5759 case QRhiTexture::Format::D16:
5760 return DXGI_FORMAT_R16_FLOAT;
5761 case QRhiTexture::Format::D24:
5762 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
5763 case QRhiTexture::Format::D24S8:
5764 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
5765 case QRhiTexture::Format::D32F:
5766 return DXGI_FORMAT_R32_FLOAT;
5767 case QRhiTexture::Format::D32FS8:
5768 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
5772 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
5775static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
5779 case QRhiTexture::Format::D16:
5780 return DXGI_FORMAT_D16_UNORM;
5781 case QRhiTexture::Format::D24:
5782 return DXGI_FORMAT_D24_UNORM_S8_UINT;
5783 case QRhiTexture::Format::D24S8:
5784 return DXGI_FORMAT_D24_UNORM_S8_UINT;
5785 case QRhiTexture::Format::D32F:
5786 return DXGI_FORMAT_D32_FLOAT;
5787 case QRhiTexture::Format::D32FS8:
5788 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
5792 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
5795bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
5797 if (!handle.isNull())
5800 QRHI_RES_RHI(QRhiD3D12);
5801 if (!rhiD->isTextureFormatSupported(m_format, m_flags))
5804 const bool isDepth = isDepthTextureFormat(m_format);
5805 const bool isCube = m_flags.testFlag(CubeMap);
5806 const bool is3D = m_flags.testFlag(ThreeDimensional);
5807 const bool isArray = m_flags.testFlag(TextureArray);
5808 const bool hasMipMaps = m_flags.testFlag(MipMapped);
5809 const bool is1D = m_flags.testFlag(OneDimensional);
5811 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
5812 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
5814 dxgiFormat = toD3DTextureFormat(m_format, m_flags);
5816 srvFormat = toD3DDepthTextureSRVFormat(m_format);
5817 rtFormat = toD3DDepthTextureDSVFormat(m_format);
5819 srvFormat = dxgiFormat;
5820 rtFormat = dxgiFormat;
5822 if (m_writeViewFormat.format != UnknownFormat) {
5824 rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
5826 rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
5828 if (m_readViewFormat.format != UnknownFormat) {
5830 srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
5832 srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
5835 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
5836 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5837 if (sampleDesc.Count > 1) {
5839 qWarning(
"Cubemap texture cannot be multisample");
5843 qWarning(
"3D texture cannot be multisample");
5847 qWarning(
"Multisample texture cannot have mipmaps");
5851 if (isDepth && hasMipMaps) {
5852 qWarning(
"Depth texture cannot have mipmaps");
5855 if (isCube && is3D) {
5856 qWarning(
"Texture cannot be both cube and 3D");
5859 if (isArray && is3D) {
5860 qWarning(
"Texture cannot be both array and 3D");
5863 if (isCube && is1D) {
5864 qWarning(
"Texture cannot be both cube and 1D");
5868 qWarning(
"Texture cannot be both 1D and 3D");
5871 if (m_depth > 1 && !is3D) {
5872 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
5875 if (m_arraySize > 0 && !isArray) {
5876 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
5879 if (m_arraySize < 1 && isArray) {
5880 qWarning(
"Texture is an array but array size is %d", m_arraySize);
5884 if (!rhiD->textureFormatInfo(m_format, size,
nullptr,
nullptr,
nullptr))
5888 *adjustedSize = size;
5893bool QD3D12Texture::finishCreate()
5895 QRHI_RES_RHI(QRhiD3D12);
5896 const bool isCube = m_flags.testFlag(CubeMap);
5897 const bool is3D = m_flags.testFlag(ThreeDimensional);
5898 const bool isArray = m_flags.testFlag(TextureArray);
5899 const bool is1D = m_flags.testFlag(OneDimensional);
5901 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
5902 srvDesc.Format = srvFormat;
5903 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
5906 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
5907 srvDesc.TextureCube.MipLevels = mipLevelCount;
5911 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
5912 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
5913 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5914 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
5915 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
5917 srvDesc.Texture1DArray.FirstArraySlice = 0;
5918 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
5921 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
5922 srvDesc.Texture1D.MipLevels = mipLevelCount;
5924 }
else if (isArray) {
5925 if (sampleDesc.Count > 1) {
5926 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
5927 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5928 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
5929 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
5931 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
5932 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
5935 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
5936 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
5937 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5938 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
5939 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
5941 srvDesc.Texture2DArray.FirstArraySlice = 0;
5942 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
5946 if (sampleDesc.Count > 1) {
5947 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
5949 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
5950 srvDesc.Texture3D.MipLevels = mipLevelCount;
5952 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
5953 srvDesc.Texture2D.MipLevels = mipLevelCount;
5958 srv = rhiD->cbvSrvUavPool.allocate(1);
5962 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
5963 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
5964 if (!m_objectName.isEmpty()) {
5965 const QString name = QString::fromUtf8(m_objectName);
5966 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
5976bool QD3D12Texture::create()
5979 if (!prepareCreate(&size))
5982 const bool isDepth = isDepthTextureFormat(m_format);
5983 const bool isCube = m_flags.testFlag(CubeMap);
5984 const bool is3D = m_flags.testFlag(ThreeDimensional);
5985 const bool isArray = m_flags.testFlag(TextureArray);
5986 const bool is1D = m_flags.testFlag(OneDimensional);
5988 QRHI_RES_RHI(QRhiD3D12);
5990 bool needsOptimizedClearValueSpecified =
false;
5991 UINT resourceFlags = 0;
5992 if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
5994 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
5996 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
5997 needsOptimizedClearValueSpecified =
true;
5999 if (m_flags.testFlag(UsedWithGenerateMips)) {
6001 qWarning(
"Depth texture cannot have mipmaps generated");
6004 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
6006 if (m_flags.testFlag(UsedWithLoadStore))
6007 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
6009 D3D12_RESOURCE_DESC resourceDesc = {};
6010 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
6011 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
6012 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
6013 resourceDesc.Width = UINT64(size.width());
6014 resourceDesc.Height = UINT(size.height());
6015 resourceDesc.DepthOrArraySize = isCube ? 6
6016 : (isArray ? UINT(qMax(0, m_arraySize))
6017 : (is3D ? qMax(1, m_depth)
6019 resourceDesc.MipLevels = mipLevelCount;
6020 resourceDesc.Format = dxgiFormat;
6021 resourceDesc.SampleDesc = sampleDesc;
6022 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
6023 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
6024 D3D12_CLEAR_VALUE clearValue = {};
6025 clearValue.Format = dxgiFormat;
6027 clearValue.Format = toD3DDepthTextureDSVFormat(m_format);
6028 clearValue.DepthStencil.Depth = 1.0f;
6029 clearValue.DepthStencil.Stencil = 0;
6031 ID3D12Resource *resource =
nullptr;
6032 D3D12MA::Allocation *allocation =
nullptr;
6033 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
6035 D3D12_RESOURCE_STATE_COMMON,
6036 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
6038 __uuidof(ID3D12Resource),
6039 reinterpret_cast<
void **>(&resource));
6041 qWarning(
"Failed to create texture: '%s'"
6042 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
6043 qPrintable(QSystemError::windowsComString(hr)),
6044 int(resourceDesc.Dimension),
6045 uint(resourceDesc.Width),
6046 uint(resourceDesc.Height),
6047 uint(resourceDesc.DepthOrArraySize),
6048 uint(resourceDesc.MipLevels),
6049 int(resourceDesc.Format),
6050 int(resourceDesc.SampleDesc.Count));
6051 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
6052 rhiD->deviceLost =
true;
6056 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON, allocation);
6058 if (!finishCreate())
6061 rhiD->registerResource(
this);
6065bool QD3D12Texture::createFrom(QRhiTexture::NativeTexture src)
6070 if (!prepareCreate())
6073 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *>(src.object);
6074 D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(src.layout);
6076 QRHI_RES_RHI(QRhiD3D12);
6077 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource, state);
6079 if (!finishCreate())
6082 rhiD->registerResource(
this);
6086QRhiTexture::NativeTexture QD3D12Texture::nativeTexture()
6088 QRHI_RES_RHI(QRhiD3D12);
6089 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
6090 return { quint64(res->resource),
int(res->state) };
6095void QD3D12Texture::setNativeLayout(
int layout)
6097 QRHI_RES_RHI(QRhiD3D12);
6098 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
6099 res->state = D3D12_RESOURCE_STATES(layout);
6102QD3D12Sampler::QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
6103 AddressMode u, AddressMode v, AddressMode w)
6104 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
6108QD3D12Sampler::~QD3D12Sampler()
6113void QD3D12Sampler::destroy()
6115 shaderVisibleDescriptor = {};
6117 QRHI_RES_RHI(QRhiD3D12);
6119 rhiD->unregisterResource(
this);
6122static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
6124 if (minFilter == QRhiSampler::Nearest) {
6125 if (magFilter == QRhiSampler::Nearest) {
6126 if (mipFilter == QRhiSampler::Linear)
6127 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
6129 return D3D12_FILTER_MIN_MAG_MIP_POINT;
6131 if (mipFilter == QRhiSampler::Linear)
6132 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
6134 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
6137 if (magFilter == QRhiSampler::Nearest) {
6138 if (mipFilter == QRhiSampler::Linear)
6139 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
6141 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
6143 if (mipFilter == QRhiSampler::Linear)
6144 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
6146 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
6149 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
6152static inline D3D12_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
6155 case QRhiSampler::Repeat:
6156 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
6157 case QRhiSampler::ClampToEdge:
6158 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
6159 case QRhiSampler::Mirror:
6160 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
6162 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
6165static inline D3D12_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
6168 case QRhiSampler::Never:
6169 return D3D12_COMPARISON_FUNC_NEVER;
6170 case QRhiSampler::Less:
6171 return D3D12_COMPARISON_FUNC_LESS;
6172 case QRhiSampler::Equal:
6173 return D3D12_COMPARISON_FUNC_EQUAL;
6174 case QRhiSampler::LessOrEqual:
6175 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
6176 case QRhiSampler::Greater:
6177 return D3D12_COMPARISON_FUNC_GREATER;
6178 case QRhiSampler::NotEqual:
6179 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
6180 case QRhiSampler::GreaterOrEqual:
6181 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
6182 case QRhiSampler::Always:
6183 return D3D12_COMPARISON_FUNC_ALWAYS;
6185 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
6188bool QD3D12Sampler::create()
6191 desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
6192 if (m_compareOp != Never)
6193 desc.Filter = D3D12_FILTER(desc.Filter | 0x80);
6194 desc.AddressU = toD3DAddressMode(m_addressU);
6195 desc.AddressV = toD3DAddressMode(m_addressV);
6196 desc.AddressW = toD3DAddressMode(m_addressW);
6197 desc.MaxAnisotropy = 1.0f;
6198 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
6199 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
6203 shaderVisibleDescriptor = {};
6207 QRHI_RES_RHI(QRhiD3D12);
6208 rhiD->registerResource(
this,
false);
6212QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
6214 if (!shaderVisibleDescriptor.isValid()) {
6215 QRHI_RES_RHI(QRhiD3D12);
6216 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(desc);
6218 return shaderVisibleDescriptor;
6221QD3D12ShadingRateMap::QD3D12ShadingRateMap(QRhiImplementation *rhi)
6222 : QRhiShadingRateMap(rhi)
6226QD3D12ShadingRateMap::~QD3D12ShadingRateMap()
6231void QD3D12ShadingRateMap::destroy()
6233 if (handle.isNull())
6239bool QD3D12ShadingRateMap::createFrom(QRhiTexture *src)
6241 if (!handle.isNull())
6244 handle = QRHI_RES(QD3D12Texture, src)->handle;
6249QD3D12TextureRenderTarget::QD3D12TextureRenderTarget(QRhiImplementation *rhi,
6250 const QRhiTextureRenderTargetDescription &desc,
6252 : QRhiTextureRenderTarget(rhi, desc, flags),
6257QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
6262void QD3D12TextureRenderTarget::destroy()
6264 if (!rtv[0].isValid() && !dsv.isValid())
6267 QRHI_RES_RHI(QRhiD3D12);
6268 if (dsv.isValid()) {
6269 if (ownsDsv && rhiD)
6270 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
6274 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i) {
6275 if (rtv[i].isValid()) {
6276 if (ownsRtv[i] && rhiD)
6277 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[i], 1);
6283 rhiD->unregisterResource(
this);
6286QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDescriptor()
6290 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6292 rpD->colorAttachmentCount = 0;
6293 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it) {
6294 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
6295 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
6297 rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
6299 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
6300 rpD->colorAttachmentCount += 1;
6303 rpD->hasDepthStencil =
false;
6304 if (m_desc.depthStencilBuffer()) {
6305 rpD->hasDepthStencil =
true;
6306 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
6307 }
else if (m_desc.depthTexture()) {
6308 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
6309 rpD->hasDepthStencil =
true;
6310 rpD->dsFormat = toD3DDepthTextureDSVFormat(depthTexD->format());
6313 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
6315 rpD->updateSerializedFormat();
6317 QRHI_RES_RHI(QRhiD3D12);
6318 rhiD->registerResource(rpD);
6322bool QD3D12TextureRenderTarget::create()
6324 if (rtv[0].isValid() || dsv.isValid())
6327 QRHI_RES_RHI(QRhiD3D12);
6328 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
6329 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
6330 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
6331 d.colorAttCount = 0;
6334 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
6335 d.colorAttCount += 1;
6336 const QRhiColorAttachment &colorAtt(*it);
6337 QRhiTexture *texture = colorAtt.texture();
6338 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
6339 Q_ASSERT(texture || rb);
6341 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, texture);
6342 QD3D12Resource *res = rhiD->resourcePool.lookupRef(texD->handle);
6344 qWarning(
"Could not look up texture handle for render target");
6347 const bool isMultiView = it->multiViewCount() >= 2;
6348 UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
6349 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6350 rtvDesc.Format = texD->rtFormat;
6351 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
6352 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
6353 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
6354 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
6355 rtvDesc.Texture2DArray.ArraySize = layerCount;
6356 }
else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
6357 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
6358 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
6359 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
6360 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
6361 rtvDesc.Texture1DArray.ArraySize = layerCount;
6363 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
6364 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
6366 }
else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
6367 if (texD->sampleDesc.Count > 1) {
6368 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
6369 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
6370 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
6372 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
6373 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
6374 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
6375 rtvDesc.Texture2DArray.ArraySize = layerCount;
6377 }
else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
6378 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
6379 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
6380 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
6381 rtvDesc.Texture3D.WSize = layerCount;
6383 if (texD->sampleDesc.Count > 1) {
6384 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
6386 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
6387 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
6390 rtv[attIndex] = rhiD->rtvPool.allocate(1);
6391 if (!rtv[attIndex].isValid()) {
6392 qWarning(
"Failed to allocate RTV for texture render target");
6395 rhiD->dev->CreateRenderTargetView(res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
6396 ownsRtv[attIndex] =
true;
6397 if (attIndex == 0) {
6398 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
6399 d.sampleCount =
int(texD->sampleDesc.Count);
6402 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rb);
6403 ownsRtv[attIndex] =
false;
6404 rtv[attIndex] = rbD->rtv;
6405 if (attIndex == 0) {
6406 d.pixelSize = rbD->pixelSize();
6407 d.sampleCount =
int(rbD->sampleDesc.Count);
6414 if (hasDepthStencil) {
6415 if (m_desc.depthTexture()) {
6417 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
6418 QD3D12Resource *res = rhiD->resourcePool.lookupRef(depthTexD->handle);
6420 qWarning(
"Could not look up depth texture handle");
6423 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
6424 dsvDesc.Format = depthTexD->rtFormat;
6425 const bool isMultisample = depthTexD->sampleDesc.Count > 1;
6426 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
6427 if (isMultisample) {
6428 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
6429 if (m_desc.depthLayer() >= 0) {
6430 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_desc.depthLayer());
6431 dsvDesc.Texture2DMSArray.ArraySize = 1;
6432 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
6433 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
6434 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
6436 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
6437 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
6440 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
6441 if (m_desc.depthLayer() >= 0) {
6442 dsvDesc.Texture2DArray.FirstArraySlice = UINT(m_desc.depthLayer());
6443 dsvDesc.Texture2DArray.ArraySize = 1;
6444 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
6445 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
6446 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
6448 dsvDesc.Texture2DArray.FirstArraySlice = 0;
6449 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
6454 dsvDesc.ViewDimension = isMultisample ? D3D12_DSV_DIMENSION_TEXTURE2DMS
6455 : D3D12_DSV_DIMENSION_TEXTURE2D;
6457 dsv = rhiD->dsvPool.allocate(1);
6458 if (!dsv.isValid()) {
6459 qWarning(
"Failed to allocate DSV for texture render target");
6462 rhiD->dev->CreateDepthStencilView(res->resource, &dsvDesc, dsv.cpuHandle);
6463 if (d.colorAttCount == 0) {
6464 d.pixelSize = depthTexD->pixelSize();
6465 d.sampleCount =
int(depthTexD->sampleDesc.Count);
6469 QD3D12RenderBuffer *depthRbD = QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
6470 dsv = depthRbD->dsv;
6471 if (d.colorAttCount == 0) {
6472 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
6473 d.sampleCount =
int(depthRbD->sampleDesc.Count);
6481 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
6482 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i)
6483 d.rtv[i] = i < d.colorAttCount ? rtv[i].cpuHandle : nullDescHandle;
6484 d.dsv = dsv.cpuHandle;
6485 d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6487 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &d.currentResIdList);
6489 rhiD->registerResource(
this);
6493QSize QD3D12TextureRenderTarget::pixelSize()
const
6495 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc, d.currentResIdList))
6496 const_cast<QD3D12TextureRenderTarget *>(
this)->create();
6501float QD3D12TextureRenderTarget::devicePixelRatio()
const
6506int QD3D12TextureRenderTarget::sampleCount()
const
6508 return d.sampleCount;
6511QD3D12ShaderResourceBindings::QD3D12ShaderResourceBindings(QRhiImplementation *rhi)
6512 : QRhiShaderResourceBindings(rhi)
6516QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
6521void QD3D12ShaderResourceBindings::destroy()
6523 bindingCache.reset();
6524 bindingCacheValid =
false;
6525 boundResourceData.clear();
6527 QRHI_RES_RHI(QRhiD3D12);
6529 rhiD->unregisterResource(
this);
6532bool QD3D12ShaderResourceBindings::create()
6534 QRHI_RES_RHI(QRhiD3D12);
6535 if (!rhiD->sanityCheckShaderResourceBindings(
this))
6538 rhiD->updateLayoutDesc(
this);
6540 boundResourceData.resize(m_bindings.count());
6541 for (BoundResourceData &bd : boundResourceData)
6544 bindingCache.reset();
6545 bindingCacheValid =
false;
6547 hasDynamicOffset =
false;
6548 for (
const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
6549 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
6550 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
6551 hasDynamicOffset =
true;
6565 rhiD->registerResource(
this,
false);
6569void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
6573 Q_ASSERT(boundResourceData.count() == m_bindings.count());
6574 for (BoundResourceData &bd : boundResourceData)
6577 bindingCache.reset();
6578 bindingCacheValid =
false;
6588void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
6589 const QRhiShaderResourceBinding::Data::UniformBufferData &,
6593 D3D12_ROOT_PARAMETER1 rootParam = {};
6594 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
6595 rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
6596 rootParam.Descriptor.ShaderRegister = shaderRegister;
6597 rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
6598 visitorData.cbParams[s].append(rootParam);
6601void QD3D12ShaderResourceBindings::visitTextures(QD3D12Stage s,
6602 const QRhiShaderResourceBinding::TextureAndSampler *,
6604 int baseShaderRegister)
6609 D3D12_DESCRIPTOR_RANGE1 range = {};
6610 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
6611 range.NumDescriptors = UINT(count);
6612 range.BaseShaderRegister = baseShaderRegister;
6613 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[s];
6614 visitorData.currentSrvRangeOffset[s] += UINT(count);
6615 visitorData.srvRanges[s].append(range);
6616 if (visitorData.srvRanges[s].count() == 1) {
6617 visitorData.srvTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6618 visitorData.srvTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6622void QD3D12ShaderResourceBindings::visitSamplers(QD3D12Stage s,
6623 const QRhiShaderResourceBinding::TextureAndSampler *,
6625 int baseShaderRegister)
6633 int &rangeStoreIdx(visitorData.samplerRangeHeads[s]);
6634 if (rangeStoreIdx == 16) {
6635 qWarning(
"Sampler binding count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi", s);
6638 D3D12_DESCRIPTOR_RANGE1 range = {};
6639 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
6640 range.NumDescriptors = UINT(count);
6641 range.BaseShaderRegister = baseShaderRegister;
6642 visitorData.samplerRanges[s][rangeStoreIdx] = range;
6643 D3D12_ROOT_PARAMETER1 param = {};
6644 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6645 param.ShaderVisibility = qd3d12_stageToVisibility(s);
6646 param.DescriptorTable.NumDescriptorRanges = 1;
6647 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[s][rangeStoreIdx];
6649 visitorData.samplerTables[s].append(param);
6652void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage s,
6653 const QRhiShaderResourceBinding::Data::StorageBufferData &,
6654 QD3D12ShaderResourceVisitor::StorageOp,
6657 D3D12_DESCRIPTOR_RANGE1 range = {};
6658 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
6659 range.NumDescriptors = 1;
6660 range.BaseShaderRegister = shaderRegister;
6661 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
6662 visitorData.currentUavRangeOffset[s] += 1;
6663 visitorData.uavRanges[s].append(range);
6664 if (visitorData.uavRanges[s].count() == 1) {
6665 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6666 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6670void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage s,
6671 const QRhiShaderResourceBinding::Data::StorageImageData &,
6672 QD3D12ShaderResourceVisitor::StorageOp,
6675 D3D12_DESCRIPTOR_RANGE1 range = {};
6676 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
6677 range.NumDescriptors = 1;
6678 range.BaseShaderRegister = shaderRegister;
6679 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
6680 visitorData.currentUavRangeOffset[s] += 1;
6681 visitorData.uavRanges[s].append(range);
6682 if (visitorData.uavRanges[s].count() == 1) {
6683 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6684 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6688static void qd3d12_setPushConstantInfo(QD3D12ShaderStageData *sd,
const QShader &shader,
const QShaderKey &key)
6690 const QList<QShaderDescription::PushConstantBlock> blocks = shader.description().pushConstantBlocks();
6691 if (blocks.isEmpty())
6693 sd->pushConstantRegister = shader.nativeShaderInfo(key).extraBufferBindings.value(
6694 QShaderPrivate::HlslPushConstantBufferBinding, -1);
6695 sd->pushConstantSize = quint32((blocks.first().size + 3) & ~3);
6698QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
6701 QRHI_RES_RHI(QRhiD3D12);
6715 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
6719 using namespace std::placeholders;
6720 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
6721 visitor.textures = std::bind(&QD3D12ShaderResourceBindings::visitTextures,
this, _1, _2, _3, _4);
6722 visitor.samplers = std::bind(&QD3D12ShaderResourceBindings::visitSamplers,
this, _1, _2, _3, _4);
6723 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
6724 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
6748 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> rootParams;
6749 for (
int s = 0; s < 6; ++s) {
6750 if (!visitorData.cbParams[s].isEmpty())
6751 rootParams.append(visitorData.cbParams[s].constData(), visitorData.cbParams[s].count());
6753 for (
int s = 0; s < 6; ++s) {
6754 if (!visitorData.srvRanges[s].isEmpty()) {
6755 visitorData.srvTables[s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[s].count();
6756 visitorData.srvTables[s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[s].constData();
6757 rootParams.append(visitorData.srvTables[s]);
6760 for (
int s = 0; s < 6; ++s) {
6761 if (!visitorData.samplerTables[s].isEmpty())
6762 rootParams.append(visitorData.samplerTables[s].constData(), visitorData.samplerTables[s].count());
6764 for (
int s = 0; s < 6; ++s) {
6765 if (!visitorData.uavRanges[s].isEmpty()) {
6766 visitorData.uavTables[s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[s].count();
6767 visitorData.uavTables[s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[s].constData();
6768 rootParams.append(visitorData.uavTables[s]);
6774 pushConstantRootParamIndex = -1;
6775 UINT pushConstantReg = 0;
6776 quint32 pushConstantSize = 0;
6777 int pushConstantStages = 0;
6778 D3D12_SHADER_VISIBILITY pushConstantVis = D3D12_SHADER_VISIBILITY_ALL;
6779 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
6780 const QD3D12ShaderStageData &sd(stageData[stageIdx]);
6781 if (!sd.valid || !sd.pushConstantSize || sd.pushConstantRegister < 0)
6783 pushConstantReg = UINT(sd.pushConstantRegister);
6784 pushConstantSize = qMax(pushConstantSize, sd.pushConstantSize);
6785 pushConstantVis = qd3d12_stageToVisibility(sd.stage);
6786 ++pushConstantStages;
6788 if (pushConstantSize) {
6792 D3D12_ROOT_PARAMETER1 param = {};
6793 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
6794 param.ShaderVisibility = pushConstantStages > 1 ? D3D12_SHADER_VISIBILITY_ALL : pushConstantVis;
6795 param.Constants.ShaderRegister = pushConstantReg;
6796 param.Constants.Num32BitValues = pushConstantSize / 4;
6797 pushConstantRootParamIndex = rootParams.count();
6798 rootParams.append(param);
6801 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
6802 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
6803 if (!rootParams.isEmpty()) {
6804 rsDesc.Desc_1_1.NumParameters = rootParams.count();
6805 rsDesc.Desc_1_1.pParameters = rootParams.constData();
6809 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
6810 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
6811 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
6813 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
6815 ID3DBlob *signature =
nullptr;
6816 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
6818 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
6821 ID3D12RootSignature *rootSig =
nullptr;
6822 hr = rhiD->dev->CreateRootSignature(0,
6823 signature->GetBufferPointer(),
6824 signature->GetBufferSize(),
6825 __uuidof(ID3D12RootSignature),
6826 reinterpret_cast<
void **>(&rootSig));
6827 signature->Release();
6829 qWarning(
"Failed to create root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
6833 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
6845static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
6847 const int smMajor = version / 10;
6848 const int smMinor = version % 10;
6849 target[0] = stage[0];
6850 target[1] = stage[1];
6852 target[3] =
'0' + smMajor;
6854 target[5] =
'0' + smMinor;
6858enum class HlslCompileFlag
6860 WithDebugInfo = 0x01
6863static QByteArray legacyCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
6865 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
6867 qWarning(
"Unable to resolve function D3DCompile()");
6868 return QByteArray();
6871 ID3DBlob *bytecode =
nullptr;
6872 ID3DBlob *errors =
nullptr;
6873 UINT d3dCompileFlags = 0;
6874 if (flags &
int(HlslCompileFlag::WithDebugInfo))
6875 d3dCompileFlags |= D3DCOMPILE_DEBUG;
6877 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
6878 nullptr,
nullptr,
nullptr,
6879 hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
6880 if (FAILED(hr) || !bytecode) {
6881 qWarning(
"HLSL shader compilation failed: 0x%x", uint(hr));
6883 *error = QString::fromUtf8(
static_cast<
const char *>(errors->GetBufferPointer()),
6884 int(errors->GetBufferSize()));
6887 return QByteArray();
6891 result.resize(
int(bytecode->GetBufferSize()));
6892 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
6893 bytecode->Release();
6897#ifdef QRHI_D3D12_HAS_DXC
6900#define DXC_CP_UTF8 65001
6903#ifndef DXC_ARG_DEBUG
6904#define DXC_ARG_DEBUG L"-Zi"
6907static QByteArray dxcCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
6909 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
6910 IDxcCompiler *compiler = dxc.first;
6912 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
6913 "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
6914 return QByteArray();
6916 IDxcLibrary *library = dxc.second;
6918 return QByteArray();
6920 IDxcBlobEncoding *sourceBlob =
nullptr;
6921 HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
6922 UINT32(hlslSource.shader().size()),
6926 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
6928 qPrintable(QSystemError::windowsComString(hr)));
6929 return QByteArray();
6932 const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
6933 const QString targetStr = QString::fromLatin1(target);
6935 QVarLengthArray<LPCWSTR, 4> argPtrs;
6937 if (flags &
int(HlslCompileFlag::WithDebugInfo)) {
6938 debugArg = QString::fromUtf16(
reinterpret_cast<
const char16_t *>(DXC_ARG_DEBUG));
6939 argPtrs.append(
reinterpret_cast<LPCWSTR>(debugArg.utf16()));
6942 IDxcOperationResult *result =
nullptr;
6943 hr = compiler->Compile(sourceBlob,
6945 reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
6946 reinterpret_cast<LPCWSTR>(targetStr.utf16()),
6947 argPtrs.data(), argPtrs.count(),
6951 sourceBlob->Release();
6953 result->GetStatus(&hr);
6955 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
6957 qPrintable(QSystemError::windowsComString(hr)));
6959 IDxcBlobEncoding *errorsBlob =
nullptr;
6960 if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
6962 *error = QString::fromUtf8(
static_cast<
const char *>(errorsBlob->GetBufferPointer()),
6963 int(errorsBlob->GetBufferSize()));
6964 errorsBlob->Release();
6968 return QByteArray();
6971 IDxcBlob *bytecode =
nullptr;
6972 if FAILED(result->GetResult(&bytecode)) {
6973 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
6975 qPrintable(QSystemError::windowsComString(hr)));
6976 return QByteArray();
6980 ba.resize(
int(bytecode->GetBufferSize()));
6981 memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
6982 bytecode->Release();
6988static QByteArray compileHlslShaderSource(
const QShader &shader,
6989 QShader::Variant shaderVariant,
6992 QShaderKey *usedShaderKey)
6995 const int shaderModelMax = 67;
6996 for (
int sm = shaderModelMax; sm >= 50; --sm) {
6997 for (QShader::Source type : { QShader::DxilShader, QShader::DxbcShader }) {
6998 QShaderKey key = { type, sm, shaderVariant };
6999 QShaderCode intermediateBytecodeShader = shader.shader(key);
7000 if (!intermediateBytecodeShader.shader().isEmpty()) {
7002 *usedShaderKey = key;
7003 return intermediateBytecodeShader.shader();
7008 QShaderCode hlslSource;
7010 for (
int sm = shaderModelMax; sm >= 50; --sm) {
7011 key = { QShader::HlslShader, sm, shaderVariant };
7012 hlslSource = shader.shader(key);
7013 if (!hlslSource.shader().isEmpty())
7017 if (hlslSource.shader().isEmpty()) {
7018 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" << shader;
7019 return QByteArray();
7023 *usedShaderKey = key;
7026 switch (shader.stage()) {
7027 case QShader::VertexStage:
7028 makeHlslTargetString(target,
"vs", key.sourceVersion().version());
7030 case QShader::TessellationControlStage:
7031 makeHlslTargetString(target,
"hs", key.sourceVersion().version());
7033 case QShader::TessellationEvaluationStage:
7034 makeHlslTargetString(target,
"ds", key.sourceVersion().version());
7036 case QShader::GeometryStage:
7037 makeHlslTargetString(target,
"gs", key.sourceVersion().version());
7039 case QShader::FragmentStage:
7040 makeHlslTargetString(target,
"ps", key.sourceVersion().version());
7042 case QShader::ComputeStage:
7043 makeHlslTargetString(target,
"cs", key.sourceVersion().version());
7046 qWarning(
"compileHlslShaderSource: Unknown stage (%d)",
int(shader.stage()));
7047 return QByteArray();
7050 if (key.sourceVersion().version() >= 60) {
7051#ifdef QRHI_D3D12_HAS_DXC
7052 return dxcCompile(hlslSource, target, flags, error);
7054 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
7055 "but the Qt build has no support for DXC. "
7056 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
7060 return legacyCompile(hlslSource, target, flags, error);
7063static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
7066 if (c.testFlag(QRhiGraphicsPipeline::R))
7067 f |= D3D12_COLOR_WRITE_ENABLE_RED;
7068 if (c.testFlag(QRhiGraphicsPipeline::G))
7069 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
7070 if (c.testFlag(QRhiGraphicsPipeline::B))
7071 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
7072 if (c.testFlag(QRhiGraphicsPipeline::A))
7073 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
7077static inline D3D12_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f,
bool rgb)
7086 case QRhiGraphicsPipeline::Zero:
7087 return D3D12_BLEND_ZERO;
7088 case QRhiGraphicsPipeline::One:
7089 return D3D12_BLEND_ONE;
7090 case QRhiGraphicsPipeline::SrcColor:
7091 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
7092 case QRhiGraphicsPipeline::OneMinusSrcColor:
7093 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
7094 case QRhiGraphicsPipeline::DstColor:
7095 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
7096 case QRhiGraphicsPipeline::OneMinusDstColor:
7097 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
7098 case QRhiGraphicsPipeline::SrcAlpha:
7099 return D3D12_BLEND_SRC_ALPHA;
7100 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
7101 return D3D12_BLEND_INV_SRC_ALPHA;
7102 case QRhiGraphicsPipeline::DstAlpha:
7103 return D3D12_BLEND_DEST_ALPHA;
7104 case QRhiGraphicsPipeline::OneMinusDstAlpha:
7105 return D3D12_BLEND_INV_DEST_ALPHA;
7106 case QRhiGraphicsPipeline::ConstantColor:
7107 case QRhiGraphicsPipeline::ConstantAlpha:
7108 return D3D12_BLEND_BLEND_FACTOR;
7109 case QRhiGraphicsPipeline::OneMinusConstantColor:
7110 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
7111 return D3D12_BLEND_INV_BLEND_FACTOR;
7112 case QRhiGraphicsPipeline::SrcAlphaSaturate:
7113 return D3D12_BLEND_SRC_ALPHA_SAT;
7114 case QRhiGraphicsPipeline::Src1Color:
7115 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
7116 case QRhiGraphicsPipeline::OneMinusSrc1Color:
7117 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
7118 case QRhiGraphicsPipeline::Src1Alpha:
7119 return D3D12_BLEND_SRC1_ALPHA;
7120 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
7121 return D3D12_BLEND_INV_SRC1_ALPHA;
7123 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
7126static inline D3D12_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
7129 case QRhiGraphicsPipeline::Add:
7130 return D3D12_BLEND_OP_ADD;
7131 case QRhiGraphicsPipeline::Subtract:
7132 return D3D12_BLEND_OP_SUBTRACT;
7133 case QRhiGraphicsPipeline::ReverseSubtract:
7134 return D3D12_BLEND_OP_REV_SUBTRACT;
7135 case QRhiGraphicsPipeline::Min:
7136 return D3D12_BLEND_OP_MIN;
7137 case QRhiGraphicsPipeline::Max:
7138 return D3D12_BLEND_OP_MAX;
7140 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
7143static inline D3D12_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
7146 case QRhiGraphicsPipeline::None:
7147 return D3D12_CULL_MODE_NONE;
7148 case QRhiGraphicsPipeline::Front:
7149 return D3D12_CULL_MODE_FRONT;
7150 case QRhiGraphicsPipeline::Back:
7151 return D3D12_CULL_MODE_BACK;
7153 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
7156static inline D3D12_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
7159 case QRhiGraphicsPipeline::Fill:
7160 return D3D12_FILL_MODE_SOLID;
7161 case QRhiGraphicsPipeline::Line:
7162 return D3D12_FILL_MODE_WIREFRAME;
7164 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
7167static inline D3D12_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
7170 case QRhiGraphicsPipeline::Never:
7171 return D3D12_COMPARISON_FUNC_NEVER;
7172 case QRhiGraphicsPipeline::Less:
7173 return D3D12_COMPARISON_FUNC_LESS;
7174 case QRhiGraphicsPipeline::Equal:
7175 return D3D12_COMPARISON_FUNC_EQUAL;
7176 case QRhiGraphicsPipeline::LessOrEqual:
7177 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
7178 case QRhiGraphicsPipeline::Greater:
7179 return D3D12_COMPARISON_FUNC_GREATER;
7180 case QRhiGraphicsPipeline::NotEqual:
7181 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
7182 case QRhiGraphicsPipeline::GreaterOrEqual:
7183 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
7184 case QRhiGraphicsPipeline::Always:
7185 return D3D12_COMPARISON_FUNC_ALWAYS;
7187 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
7190static inline D3D12_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
7193 case QRhiGraphicsPipeline::StencilZero:
7194 return D3D12_STENCIL_OP_ZERO;
7195 case QRhiGraphicsPipeline::Keep:
7196 return D3D12_STENCIL_OP_KEEP;
7197 case QRhiGraphicsPipeline::Replace:
7198 return D3D12_STENCIL_OP_REPLACE;
7199 case QRhiGraphicsPipeline::IncrementAndClamp:
7200 return D3D12_STENCIL_OP_INCR_SAT;
7201 case QRhiGraphicsPipeline::DecrementAndClamp:
7202 return D3D12_STENCIL_OP_DECR_SAT;
7203 case QRhiGraphicsPipeline::Invert:
7204 return D3D12_STENCIL_OP_INVERT;
7205 case QRhiGraphicsPipeline::IncrementAndWrap:
7206 return D3D12_STENCIL_OP_INCR;
7207 case QRhiGraphicsPipeline::DecrementAndWrap:
7208 return D3D12_STENCIL_OP_DECR;
7210 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
7213static inline D3D12_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t,
int patchControlPointCount)
7216 case QRhiGraphicsPipeline::Triangles:
7217 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
7218 case QRhiGraphicsPipeline::TriangleStrip:
7219 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
7220 case QRhiGraphicsPipeline::TriangleFan:
7221 qWarning(
"Triangle fans are not supported with D3D");
7222 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
7223 case QRhiGraphicsPipeline::Lines:
7224 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
7225 case QRhiGraphicsPipeline::LineStrip:
7226 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
7227 case QRhiGraphicsPipeline::Points:
7228 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
7229 case QRhiGraphicsPipeline::Patches:
7230 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
7231 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
7233 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
7236static inline D3D12_PRIMITIVE_TOPOLOGY_TYPE toD3DTopologyType(QRhiGraphicsPipeline::Topology t)
7239 case QRhiGraphicsPipeline::Triangles:
7240 case QRhiGraphicsPipeline::TriangleStrip:
7241 case QRhiGraphicsPipeline::TriangleFan:
7242 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
7243 case QRhiGraphicsPipeline::Lines:
7244 case QRhiGraphicsPipeline::LineStrip:
7245 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
7246 case QRhiGraphicsPipeline::Points:
7247 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
7248 case QRhiGraphicsPipeline::Patches:
7249 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
7251 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
7254static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
7257 case QRhiVertexInputAttribute::Float4:
7258 return DXGI_FORMAT_R32G32B32A32_FLOAT;
7259 case QRhiVertexInputAttribute::Float3:
7260 return DXGI_FORMAT_R32G32B32_FLOAT;
7261 case QRhiVertexInputAttribute::Float2:
7262 return DXGI_FORMAT_R32G32_FLOAT;
7263 case QRhiVertexInputAttribute::Float:
7264 return DXGI_FORMAT_R32_FLOAT;
7265 case QRhiVertexInputAttribute::UNormByte4:
7266 return DXGI_FORMAT_R8G8B8A8_UNORM;
7267 case QRhiVertexInputAttribute::UNormByte2:
7268 return DXGI_FORMAT_R8G8_UNORM;
7269 case QRhiVertexInputAttribute::UNormByte:
7270 return DXGI_FORMAT_R8_UNORM;
7271 case QRhiVertexInputAttribute::UInt4:
7272 return DXGI_FORMAT_R32G32B32A32_UINT;
7273 case QRhiVertexInputAttribute::UInt3:
7274 return DXGI_FORMAT_R32G32B32_UINT;
7275 case QRhiVertexInputAttribute::UInt2:
7276 return DXGI_FORMAT_R32G32_UINT;
7277 case QRhiVertexInputAttribute::UInt:
7278 return DXGI_FORMAT_R32_UINT;
7279 case QRhiVertexInputAttribute::SInt4:
7280 return DXGI_FORMAT_R32G32B32A32_SINT;
7281 case QRhiVertexInputAttribute::SInt3:
7282 return DXGI_FORMAT_R32G32B32_SINT;
7283 case QRhiVertexInputAttribute::SInt2:
7284 return DXGI_FORMAT_R32G32_SINT;
7285 case QRhiVertexInputAttribute::SInt:
7286 return DXGI_FORMAT_R32_SINT;
7287 case QRhiVertexInputAttribute::Half4:
7289 case QRhiVertexInputAttribute::Half3:
7290 return DXGI_FORMAT_R16G16B16A16_FLOAT;
7291 case QRhiVertexInputAttribute::Half2:
7292 return DXGI_FORMAT_R16G16_FLOAT;
7293 case QRhiVertexInputAttribute::Half:
7294 return DXGI_FORMAT_R16_FLOAT;
7295 case QRhiVertexInputAttribute::UShort4:
7297 case QRhiVertexInputAttribute::UShort3:
7298 return DXGI_FORMAT_R16G16B16A16_UINT;
7299 case QRhiVertexInputAttribute::UShort2:
7300 return DXGI_FORMAT_R16G16_UINT;
7301 case QRhiVertexInputAttribute::UShort:
7302 return DXGI_FORMAT_R16_UINT;
7303 case QRhiVertexInputAttribute::SShort4:
7305 case QRhiVertexInputAttribute::SShort3:
7306 return DXGI_FORMAT_R16G16B16A16_SINT;
7307 case QRhiVertexInputAttribute::SShort2:
7308 return DXGI_FORMAT_R16G16_SINT;
7309 case QRhiVertexInputAttribute::SShort:
7310 return DXGI_FORMAT_R16_SINT;
7312 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
7315QD3D12GraphicsPipeline::QD3D12GraphicsPipeline(QRhiImplementation *rhi)
7316 : QRhiGraphicsPipeline(rhi)
7320QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
7325void QD3D12GraphicsPipeline::destroy()
7327 if (handle.isNull())
7330 QRHI_RES_RHI(QRhiD3D12);
7332 rhiD->releaseQueue.deferredReleasePipeline(handle);
7333 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
7340 rhiD->unregisterResource(
this);
7343bool QD3D12GraphicsPipeline::create()
7345 if (!handle.isNull())
7348 QRHI_RES_RHI(QRhiD3D12);
7349 if (!rhiD->sanityCheckGraphicsPipeline(
this))
7352 rhiD->pipelineCreationStart();
7354 QByteArray shaderBytecode[5];
7355 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
7356 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
7357 stageData[d3dStage].valid =
true;
7358 stageData[d3dStage].stage = d3dStage;
7359 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
7360 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
7361 shaderBytecode[d3dStage] = cacheIt->bytecode;
7362 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
7363 stageData[d3dStage].pushConstantRegister = cacheIt->pushConstantRegister;
7364 stageData[d3dStage].pushConstantSize = cacheIt->pushConstantSize;
7367 QShaderKey shaderKey;
7368 int compileFlags = 0;
7369 if (m_flags.testFlag(CompileShadersWithDebugInfo))
7370 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
7371 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
7372 shaderStage.shaderVariant(),
7376 if (bytecode.isEmpty()) {
7377 qWarning(
"HLSL graphics shader compilation failed: %s", qPrintable(error));
7381 shaderBytecode[d3dStage] = bytecode;
7382 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
7383 qd3d12_setPushConstantInfo(&stageData[d3dStage], shaderStage.shader(), shaderKey);
7384 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
7385 { bytecode, stageData[d3dStage].nativeResourceBindingMap,
7386 stageData[d3dStage].pushConstantRegister,
7387 stageData[d3dStage].pushConstantSize });
7391 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
7393 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
7394 pushConstantRootParamIndex = srbD->pushConstantRootParamIndex;
7395 if (rootSigHandle.isNull()) {
7396 qWarning(
"Failed to create root signature");
7400 ID3D12RootSignature *rootSig =
nullptr;
7401 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
7402 rootSig = rs->rootSig;
7404 qWarning(
"Cannot create graphics pipeline state without root signature");
7408 QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7409 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
7410 if (rpD->colorAttachmentCount > 0) {
7411 format = DXGI_FORMAT(rpD->colorFormat[0]);
7412 }
else if (rpD->hasDepthStencil) {
7413 format = DXGI_FORMAT(rpD->dsFormat);
7415 qWarning(
"Cannot create graphics pipeline state without color or depthStencil format");
7418 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
7421 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
7422 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
7423 QD3D12PipelineStateSubObject<D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE> primitiveRestartValue;
7424 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
7425 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
7426 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
7427 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
7428 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
7429 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
7430 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
7431 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
7432 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
7433 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
7434 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
7435 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
7436 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
7437 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
7440 stream.rootSig.object = rootSig;
7442 QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
7443 QByteArrayList matrixSliceSemantics;
7444 if (!shaderBytecode[VS].isEmpty()) {
7445 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
7448 D3D12_INPUT_ELEMENT_DESC desc = {};
7453 const int matrixSlice = it->matrixSlice();
7454 if (matrixSlice < 0) {
7455 desc.SemanticName =
"TEXCOORD";
7456 desc.SemanticIndex = UINT(it->location());
7460 std::snprintf(sem.data(), sem.size(),
"TEXCOORD%d_", it->location() - matrixSlice);
7461 matrixSliceSemantics.append(sem);
7462 desc.SemanticName = matrixSliceSemantics.last().constData();
7463 desc.SemanticIndex = UINT(matrixSlice);
7465 desc.Format = toD3DAttributeFormat(it->format());
7466 desc.InputSlot = UINT(it->binding());
7467 desc.AlignedByteOffset = it->offset();
7468 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
7469 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
7470 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
7471 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
7473 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
7475 inputDescs.append(desc);
7479 stream.inputLayout.object.NumElements = inputDescs.count();
7480 stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ?
nullptr : inputDescs.constData();
7482 stream.primitiveRestartValue.object = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
7484 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
7485 topology = toD3DTopology(m_topology, m_patchControlPointCount);
7487 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
7488 const int d3dStage = qd3d12_stage(shaderStage.type());
7491 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7492 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7495 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7496 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7499 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7500 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7503 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7504 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7507 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7508 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7516 stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
7517 stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
7518 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
7519 stream.rasterizerState.object.DepthBias = m_depthBias;
7520 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
7521 stream.rasterizerState.object.DepthClipEnable = m_depthClamp ? FALSE : TRUE;
7522 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
7524 stream.depthStencilState.object.DepthEnable = m_depthTest;
7525 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
7526 stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
7527 stream.depthStencilState.object.StencilEnable = m_stencilTest;
7528 if (m_stencilTest) {
7529 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
7530 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
7531 stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
7532 stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
7533 stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
7534 stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
7535 stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
7536 stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
7537 stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
7538 stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
7541 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
7542 for (
int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
7543 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
7544 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
7545 blend.BlendEnable = b.enable;
7546 blend.SrcBlend = toD3DBlendFactor(b.srcColor,
true);
7547 blend.DestBlend = toD3DBlendFactor(b.dstColor,
true);
7548 blend.BlendOp = toD3DBlendOp(b.opColor);
7549 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha,
false);
7550 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha,
false);
7551 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
7552 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
7553 stream.blendState.object.RenderTarget[i] = blend;
7555 if (m_targetBlends.isEmpty()) {
7556 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
7557 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
7558 stream.blendState.object.RenderTarget[0] = blend;
7561 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
7562 for (
int i = 0; i < rpD->colorAttachmentCount; ++i)
7563 stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
7565 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
7567 stream.sampleDesc.object = sampleDesc;
7569 stream.sampleMask.object = 0xFFFFFFFF;
7571 viewInstanceMask = 0;
7572 const bool isMultiView = m_multiViewCount >= 2;
7573 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
7574 QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
7576 for (
int i = 0; i < m_multiViewCount; ++i) {
7577 viewInstanceMask |= (1 << i);
7578 viewInstanceLocations.append({ 0, UINT(i) });
7580 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
7583 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
7585 QCryptographicHash keyHash(QCryptographicHash::Sha1);
7586 for (
const QByteArray &bytecode : shaderBytecode)
7587 addToKey(&keyHash, bytecode);
7588 for (
const D3D12_INPUT_ELEMENT_DESC &desc : inputDescs) {
7589 keyHash.addData(QByteArrayView(desc.SemanticName));
7590 addToKey(&keyHash, desc.SemanticIndex);
7591 addToKey(&keyHash, desc.Format);
7592 addToKey(&keyHash, desc.InputSlot);
7593 addToKey(&keyHash, desc.AlignedByteOffset);
7594 addToKey(&keyHash, desc.InputSlotClass);
7595 addToKey(&keyHash, desc.InstanceDataStepRate);
7597 addToKey(&keyHash, stream.primitiveRestartValue.object);
7598 addToKey(&keyHash, stream.primitiveTopology.object);
7599 addToKey(&keyHash, stream.rasterizerState.object);
7600 addToKey(&keyHash, stream.depthStencilState.object);
7601 addToKey(&keyHash, stream.blendState.object);
7602 addToKey(&keyHash, stream.rtFormats.object);
7603 addToKey(&keyHash, stream.dsFormat.object);
7604 addToKey(&keyHash, stream.sampleDesc.object);
7605 addToKey(&keyHash, stream.sampleMask.object);
7606 addToKey(&keyHash, stream.viewInstancingDesc.object.ViewInstanceCount);
7607 addToKey(&keyHash, stream.viewInstancingDesc.object.Flags);
7608 addToKey(&keyHash, viewInstanceLocations.constData(),
7609 viewInstanceLocations.count() *
sizeof(D3D12_VIEW_INSTANCE_LOCATION));
7612 addToKey(&keyHash, srbD->serializedLayoutDescription());
7614 ID3D12PipelineState *pso = rhiD->loadOrCreatePipelineState(&streamDesc, keyHash.result().toHex(),
"graphics");
7616 rhiD->rootSignaturePool.remove(rootSigHandle);
7621 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
7623 rhiD->pipelineCreationEnd();
7625 rhiD->registerResource(
this);
7629QD3D12ComputePipeline::QD3D12ComputePipeline(QRhiImplementation *rhi)
7630 : QRhiComputePipeline(rhi)
7634QD3D12ComputePipeline::~QD3D12ComputePipeline()
7639void QD3D12ComputePipeline::destroy()
7641 if (handle.isNull())
7644 QRHI_RES_RHI(QRhiD3D12);
7646 rhiD->releaseQueue.deferredReleasePipeline(handle);
7647 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
7654 rhiD->unregisterResource(
this);
7657bool QD3D12ComputePipeline::create()
7659 if (!handle.isNull())
7662 QRHI_RES_RHI(QRhiD3D12);
7663 rhiD->pipelineCreationStart();
7665 stageData.valid =
true;
7666 stageData.stage = CS;
7668 QByteArray shaderBytecode;
7669 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(m_shaderStage);
7670 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
7671 shaderBytecode = cacheIt->bytecode;
7672 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
7673 stageData.pushConstantRegister = cacheIt->pushConstantRegister;
7674 stageData.pushConstantSize = cacheIt->pushConstantSize;
7677 QShaderKey shaderKey;
7678 int compileFlags = 0;
7679 if (m_flags.testFlag(CompileShadersWithDebugInfo))
7680 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
7681 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
7682 m_shaderStage.shaderVariant(),
7686 if (bytecode.isEmpty()) {
7687 qWarning(
"HLSL compute shader compilation failed: %s", qPrintable(error));
7691 shaderBytecode = bytecode;
7692 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
7693 qd3d12_setPushConstantInfo(&stageData, m_shaderStage.shader(), shaderKey);
7694 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
7695 stageData.nativeResourceBindingMap,
7696 stageData.pushConstantRegister,
7697 stageData.pushConstantSize });
7700 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
7702 rootSigHandle = srbD->createRootSignature(&stageData, 1);
7703 pushConstantRootParamIndex = srbD->pushConstantRootParamIndex;
7704 if (rootSigHandle.isNull()) {
7705 qWarning(
"Failed to create root signature");
7709 ID3D12RootSignature *rootSig =
nullptr;
7710 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
7711 rootSig = rs->rootSig;
7713 qWarning(
"Cannot create compute pipeline state without root signature");
7718 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
7719 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
7721 stream.rootSig.object = rootSig;
7722 stream.CS.object.pShaderBytecode = shaderBytecode.constData();
7723 stream.CS.object.BytecodeLength = shaderBytecode.size();
7724 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
7726 QCryptographicHash keyHash(QCryptographicHash::Sha1);
7727 addToKey(&keyHash, shaderBytecode);
7728 addToKey(&keyHash, srbD->serializedLayoutDescription());
7730 ID3D12PipelineState *pso = rhiD->loadOrCreatePipelineState(&streamDesc, keyHash.result().toHex(),
"compute");
7732 rhiD->rootSignaturePool.remove(rootSigHandle);
7737 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
7739 rhiD->pipelineCreationEnd();
7741 rhiD->registerResource(
this);
7748QD3D12RenderPassDescriptor::QD3D12RenderPassDescriptor(QRhiImplementation *rhi)
7749 : QRhiRenderPassDescriptor(rhi)
7751 serializedFormatData.reserve(16);
7754QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
7759void QD3D12RenderPassDescriptor::destroy()
7761 QRHI_RES_RHI(QRhiD3D12);
7763 rhiD->unregisterResource(
this);
7766bool QD3D12RenderPassDescriptor::isCompatible(
const QRhiRenderPassDescriptor *other)
const
7771 const QD3D12RenderPassDescriptor *o = QRHI_RES(
const QD3D12RenderPassDescriptor, other);
7773 if (colorAttachmentCount != o->colorAttachmentCount)
7776 if (hasDepthStencil != o->hasDepthStencil)
7779 for (
int i = 0; i < colorAttachmentCount; ++i) {
7780 if (colorFormat[i] != o->colorFormat[i])
7784 if (hasDepthStencil) {
7785 if (dsFormat != o->dsFormat)
7789 if (hasShadingRateMap != o->hasShadingRateMap)
7795void QD3D12RenderPassDescriptor::updateSerializedFormat()
7797 serializedFormatData.clear();
7798 auto p = std::back_inserter(serializedFormatData);
7800 *p++ = colorAttachmentCount;
7801 *p++ = hasDepthStencil;
7802 for (
int i = 0; i < colorAttachmentCount; ++i)
7803 *p++ = colorFormat[i];
7804 *p++ = hasDepthStencil ? dsFormat : 0;
7807QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor()
const
7809 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
7810 rpD->colorAttachmentCount = colorAttachmentCount;
7811 rpD->hasDepthStencil = hasDepthStencil;
7812 memcpy(rpD->colorFormat, colorFormat,
sizeof(colorFormat));
7813 rpD->dsFormat = dsFormat;
7814 rpD->hasShadingRateMap = hasShadingRateMap;
7816 rpD->updateSerializedFormat();
7818 QRHI_RES_RHI(QRhiD3D12);
7819 rhiD->registerResource(rpD);
7823QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat()
const
7825 return serializedFormatData;
7828QD3D12CommandBuffer::QD3D12CommandBuffer(QRhiImplementation *rhi)
7829 : QRhiCommandBuffer(rhi)
7834QD3D12CommandBuffer::~QD3D12CommandBuffer()
7839void QD3D12CommandBuffer::destroy()
7844const QRhiNativeHandles *QD3D12CommandBuffer::nativeHandles()
7846 nativeHandlesStruct.commandList = cmdList;
7847 return &nativeHandlesStruct;
7850QD3D12SwapChainRenderTarget::QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
7851 : QRhiSwapChainRenderTarget(rhi, swapchain),
7856QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
7861void QD3D12SwapChainRenderTarget::destroy()
7866QSize QD3D12SwapChainRenderTarget::pixelSize()
const
7871float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
7876int QD3D12SwapChainRenderTarget::sampleCount()
const
7878 return d.sampleCount;
7881QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
7882 : QRhiSwapChain(rhi),
7883 rtWrapper(rhi,
this),
7884 rtWrapperRight(rhi,
this),
7889QD3D12SwapChain::~QD3D12SwapChain()
7894void QD3D12SwapChain::destroy()
7901 swapChain->Release();
7902 swapChain =
nullptr;
7903 sourceSwapChain1->Release();
7904 sourceSwapChain1 =
nullptr;
7906 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7907 FrameResources &fr(frameRes[i]);
7909 fr.fence->Release();
7911 CloseHandle(fr.fenceEvent);
7913 fr.cmdList->Release();
7918 dcompVisual->Release();
7919 dcompVisual =
nullptr;
7923 dcompTarget->Release();
7924 dcompTarget =
nullptr;
7927 if (frameLatencyWaitableObject) {
7928 CloseHandle(frameLatencyWaitableObject);
7929 frameLatencyWaitableObject =
nullptr;
7932 QDxgiVSyncService::instance()->unregisterWindow(window);
7934 QRHI_RES_RHI(QRhiD3D12);
7936 rhiD->swapchains.remove(
this);
7937 rhiD->unregisterResource(
this);
7941void QD3D12SwapChain::releaseBuffers()
7943 QRHI_RES_RHI(QRhiD3D12);
7945 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7946 rhiD->resourcePool.remove(colorBuffers[i]);
7947 rhiD->rtvPool.release(rtvs[i], 1);
7949 rhiD->rtvPool.release(rtvsRight[i], 1);
7951 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7952 if (!msaaBuffers[i].isNull())
7953 rhiD->resourcePool.remove(msaaBuffers[i]);
7954 if (msaaRtvs[i].isValid())
7955 rhiD->rtvPool.release(msaaRtvs[i], 1);
7959void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
7961 FrameResources &fr(frameRes[frameSlot]);
7962 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
7963 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
7964 WaitForSingleObject(fr.fenceEvent, INFINITE);
7968void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
7970 QRHI_RES_RHI(QRhiD3D12);
7971 FrameResources &fr(frameRes[currentFrameSlot]);
7972 fr.fenceCounter += 1u;
7973 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
7976QRhiCommandBuffer *QD3D12SwapChain::currentFrameCommandBuffer()
7981QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
7986QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
7988 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
7991QSize QD3D12SwapChain::surfacePixelSize()
7994 return m_window->size() * m_window->devicePixelRatio();
7997bool QD3D12SwapChain::isFormatSupported(Format f)
8003 qWarning(
"Attempted to call isFormatSupported() without a window set");
8007 QRHI_RES_RHI(QRhiD3D12);
8008 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window))
8009 return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
8014QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
8016 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
8019 QRHI_RES_RHI(QRhiD3D12);
8020 info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window);
8025QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
8030 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
8031 rpD->colorAttachmentCount = 1;
8032 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
8033 rpD->colorFormat[0] =
int(srgbAdjustedColorFormat);
8034 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
8036 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
8038 rpD->updateSerializedFormat();
8040 QRHI_RES_RHI(QRhiD3D12);
8041 rhiD->registerResource(rpD);
8045bool QRhiD3D12::ensureDirectCompositionDevice()
8050 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
8051 dcompDevice = QRhiD3D::createDirectCompositionDevice();
8052 return dcompDevice ?
true :
false;
8055static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
8056static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
8058void QD3D12SwapChain::chooseFormats()
8060 colorFormat = DEFAULT_FORMAT;
8061 srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
8062 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
8063 QRHI_RES_RHI(QRhiD3D12);
8064 if (m_format != SDR) {
8065 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) {
8068 case HDRExtendedSrgbLinear:
8069 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
8070 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
8071 srgbAdjustedColorFormat = colorFormat;
8074 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
8075 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
8076 srgbAdjustedColorFormat = colorFormat;
8085 qWarning(
"The output associated with the window is not HDR capable "
8086 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
8089 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
8092bool QD3D12SwapChain::createOrResize()
8098 const bool needsRegistration = !window || window != m_window;
8101 if (window && window != m_window)
8105 m_currentPixelSize = surfacePixelSize();
8106 pixelSize = m_currentPixelSize;
8108 if (pixelSize.isEmpty())
8111 HWND hwnd =
reinterpret_cast<HWND>(window->winId());
8113 QRHI_RES_RHI(QRhiD3D12);
8114 stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
8116 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
8117 if (rhiD->ensureDirectCompositionDevice()) {
8119 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
false, &dcompTarget);
8121 qWarning(
"Failed to create Direct Composition target for the window: %s",
8122 qPrintable(QSystemError::windowsComString(hr)));
8125 if (dcompTarget && !dcompVisual) {
8126 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
8128 qWarning(
"Failed to create DirectComposition visual: %s",
8129 qPrintable(QSystemError::windowsComString(hr)));
8134 if (window->requestedFormat().alphaBufferSize() <= 0)
8135 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
8136 "This may lead to problems.");
8139 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
8141 if (swapInterval == 0 && rhiD->supportsAllowTearing)
8142 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
8146 const bool useFrameLatencyWaitableObject = rhiD->maxFrameLatency != 0
8147 && swapInterval != 0
8148 && rhiD->driverInfoStruct.deviceType != QRhiDriverInfo::CpuDevice;
8149 if (useFrameLatencyWaitableObject)
8150 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
8155 DXGI_SWAP_CHAIN_DESC1 desc = {};
8156 desc.Width = UINT(pixelSize.width());
8157 desc.Height = UINT(pixelSize.height());
8158 desc.Format = colorFormat;
8159 desc.SampleDesc.Count = 1;
8160 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
8161 desc.BufferCount = BUFFER_COUNT;
8162 desc.Flags = swapChainFlags;
8163 desc.Scaling = DXGI_SCALING_NONE;
8164 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
8165 desc.Stereo = stereo;
8171 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
8176 desc.Scaling = DXGI_SCALING_STRETCH;
8180 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
8182 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
8187 if (FAILED(hr) && m_format != SDR) {
8188 colorFormat = DEFAULT_FORMAT;
8189 desc.Format = DEFAULT_FORMAT;
8191 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
8193 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
8196 if (SUCCEEDED(hr)) {
8197 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<
void **>(&swapChain)))) {
8198 qWarning(
"IDXGISwapChain3 not available");
8201 if (m_format != SDR) {
8202 hr = swapChain->SetColorSpace1(hdrColorSpace);
8204 qWarning(
"Failed to set color space on swapchain: %s",
8205 qPrintable(QSystemError::windowsComString(hr)));
8208 if (useFrameLatencyWaitableObject) {
8209 swapChain->SetMaximumFrameLatency(rhiD->maxFrameLatency);
8210 frameLatencyWaitableObject = swapChain->GetFrameLatencyWaitableObject();
8213 hr = dcompVisual->SetContent(swapChain);
8214 if (SUCCEEDED(hr)) {
8215 hr = dcompTarget->SetRoot(dcompVisual);
8217 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
8218 qPrintable(QSystemError::windowsComString(hr)));
8221 qWarning(
"Failed to set content for Direct Composition visual: %s",
8222 qPrintable(QSystemError::windowsComString(hr)));
8226 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
8229 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
8230 qWarning(
"Device loss detected during swapchain creation");
8231 rhiD->deviceLost =
true;
8233 }
else if (FAILED(hr)) {
8234 qWarning(
"Failed to create D3D12 swapchain: %s"
8235 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
8236 qPrintable(QSystemError::windowsComString(hr)),
8237 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
8238 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
8242 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
8243 hr = rhiD->dev->CreateFence(0,
8244 D3D12_FENCE_FLAG_NONE,
8245 __uuidof(ID3D12Fence),
8246 reinterpret_cast<
void **>(&frameRes[i].fence));
8248 qWarning(
"Failed to create fence for swapchain: %s",
8249 qPrintable(QSystemError::windowsComString(hr)));
8252 frameRes[i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
8254 frameRes[i].fenceCounter = 0;
8258 hr = swapChain->ResizeBuffers(BUFFER_COUNT,
8259 UINT(pixelSize.width()),
8260 UINT(pixelSize.height()),
8263 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
8264 qWarning(
"Device loss detected in ResizeBuffers()");
8265 rhiD->deviceLost =
true;
8267 }
else if (FAILED(hr)) {
8268 qWarning(
"Failed to resize D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
8273 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
8274 ID3D12Resource *colorBuffer;
8275 hr = swapChain->GetBuffer(i, __uuidof(ID3D12Resource),
reinterpret_cast<
void **>(&colorBuffer));
8277 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
8278 i, qPrintable(QSystemError::windowsComString(hr)));
8281 colorBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
8282 rtvs[i] = rhiD->rtvPool.allocate(1);
8283 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
8284 rtvDesc.Format = srgbAdjustedColorFormat;
8285 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
8286 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
8289 rtvsRight[i] = rhiD->rtvPool.allocate(1);
8290 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
8291 rtvDesc.Format = srgbAdjustedColorFormat;
8292 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
8293 rtvDesc.Texture2DArray.ArraySize = 1;
8294 rtvDesc.Texture2DArray.FirstArraySlice = 1;
8295 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
8299 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
8300 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
8301 m_depthStencil->sampleCount(), m_sampleCount);
8303 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
8304 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
8305 m_depthStencil->setPixelSize(pixelSize);
8306 if (!m_depthStencil->create())
8307 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
8308 pixelSize.width(), pixelSize.height());
8310 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
8311 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
8312 pixelSize.width(), pixelSize.height());
8316 ds = m_depthStencil ? QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
8318 if (sampleDesc.Count > 1) {
8319 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
8320 D3D12_RESOURCE_DESC resourceDesc = {};
8321 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
8322 resourceDesc.Width = UINT64(pixelSize.width());
8323 resourceDesc.Height = UINT(pixelSize.height());
8324 resourceDesc.DepthOrArraySize = 1;
8325 resourceDesc.MipLevels = 1;
8326 resourceDesc.Format = srgbAdjustedColorFormat;
8327 resourceDesc.SampleDesc = sampleDesc;
8328 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
8329 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
8330 D3D12_CLEAR_VALUE clearValue = {};
8331 clearValue.Format = colorFormat;
8332 ID3D12Resource *resource =
nullptr;
8333 D3D12MA::Allocation *allocation =
nullptr;
8334 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
8336 D3D12_RESOURCE_STATE_RENDER_TARGET,
8339 __uuidof(ID3D12Resource),
8340 reinterpret_cast<
void **>(&resource));
8342 qWarning(
"Failed to create MSAA color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
8345 msaaBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
8346 msaaRtvs[i] = rhiD->rtvPool.allocate(1);
8347 if (!msaaRtvs[i].isValid())
8349 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
8350 rtvDesc.Format = srgbAdjustedColorFormat;
8351 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
8352 : D3D12_RTV_DIMENSION_TEXTURE2D;
8353 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[i].cpuHandle);
8357 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
8358 currentFrameSlot = 0;
8359 lastFrameLatencyWaitSlot = -1;
8361 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
8362 QD3D12SwapChainRenderTarget *rtD = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
8363 rtD->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
8364 rtD->d.pixelSize = pixelSize;
8365 rtD->d.dpr =
float(window->devicePixelRatio());
8366 rtD->d.sampleCount =
int(sampleDesc.Count);
8367 rtD->d.colorAttCount = 1;
8368 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
8370 rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
8371 QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
8372 rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
8373 rtDr->d.pixelSize = pixelSize;
8374 rtDr->d.dpr =
float(window->devicePixelRatio());
8375 rtDr->d.sampleCount =
int(sampleDesc.Count);
8376 rtDr->d.colorAttCount = 1;
8377 rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
8379 QDxgiVSyncService::instance()->registerWindow(window);
8381 if (needsRegistration || !rhiD->swapchains.contains(
this))
8382 rhiD->swapchains.insert(
this);
8384 rhiD->registerResource(
this);