8#include <QtCore/private/qsystemerror_p.h>
9#include <QtCore/qcryptographichash.h>
19#define QRHI_D3D12_HAS_OLD_PIX
22#ifdef __ID3D12Device2_INTERFACE_DEFINED__
27
28
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
72
73
74
75
76
77
78
79
80
83
84
85
86
87
88
89
90
91
92
93
94
97
98
99
100
101
102
105
106
107
108
109
110
111
112
113
114
115
118
119
120
121
122
123
126
127
128
129
130
131
134
135
136
137
138
139
140
143
144
145
146
147
148
149
150
151
152
153
154
155
156
159
160
163static const D3D_FEATURE_LEVEL MIN_FEATURE_LEVEL = D3D_FEATURE_LEVEL_11_0;
165QRhiD3D12::QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importParams)
167 debugLayer = params->enableDebugLayer;
169 if (importParams->dev) {
170 ID3D12Device *d3d12Device =
reinterpret_cast<ID3D12Device *>(importParams->dev);
171 if (SUCCEEDED(d3d12Device->QueryInterface(__uuidof(ID3D12Device2),
reinterpret_cast<
void **>(&dev)))) {
173 d3d12Device->Release();
174 importedDevice =
true;
176 qWarning(
"ID3D12Device2 not supported, cannot import device");
179 if (importParams->commandQueue) {
180 cmdQueue =
reinterpret_cast<ID3D12CommandQueue *>(importParams->commandQueue);
181 importedCommandQueue =
true;
183 minimumFeatureLevel = D3D_FEATURE_LEVEL(importParams->minimumFeatureLevel);
184 adapterLuid.LowPart = importParams->adapterLuidLow;
185 adapterLuid.HighPart = importParams->adapterLuidHigh;
190inline Int aligned(Int v, Int byteAlign)
192 return (v + byteAlign - 1) & ~(byteAlign - 1);
195static inline UINT calcSubresource(UINT mipSlice, UINT arraySlice, UINT mipLevels)
197 return mipSlice + arraySlice * mipLevels;
200static inline QD3D12RenderTargetData *rtData(QRhiRenderTarget *rt)
202 switch (rt->resourceType()) {
203 case QRhiResource::SwapChainRenderTarget:
204 return &QRHI_RES(QD3D12SwapChainRenderTarget, rt)->d;
205 case QRhiResource::TextureRenderTarget:
206 return &QRHI_RES(QD3D12TextureRenderTarget, rt)->d;
211 Q_UNREACHABLE_RETURN(
nullptr);
214#ifdef QRHI_D3D12_INFOQUEUE1_AVAILABLE
215static void __stdcall qd3d12_message_callback(D3D12_MESSAGE_CATEGORY category,
216 D3D12_MESSAGE_SEVERITY severity,
226 if (severity == D3D12_MESSAGE_SEVERITY_INFO)
228 if (id == D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE
229 || id == D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE
230 || id == D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE)
237 qDebug(
"D3D12: %s", description);
241bool QRhiD3D12::create(QRhi::Flags flags)
245 UINT factoryFlags = 0;
247 factoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
248 HRESULT hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
252 qCDebug(QRHI_LOG_INFO,
"Debug layer was requested but is not available. "
253 "Attempting to create DXGIFactory2 without it.");
254 factoryFlags &= ~DXGI_CREATE_FACTORY_DEBUG;
255 hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
260 qWarning(
"CreateDXGIFactory2() failed to create DXGI factory: %s",
261 qPrintable(QSystemError::windowsComString(hr)));
266 if (qEnvironmentVariableIsSet(
"QT_D3D_MAX_FRAME_LATENCY"))
267 maxFrameLatency = UINT(qMax(0, qEnvironmentVariableIntValue(
"QT_D3D_MAX_FRAME_LATENCY")));
268 if (maxFrameLatency != 0)
269 qCDebug(QRHI_LOG_INFO,
"Using frame latency waitable object with max frame latency %u", maxFrameLatency);
271 supportsAllowTearing =
false;
272 IDXGIFactory5 *factory5 =
nullptr;
273 if (SUCCEEDED(dxgiFactory->QueryInterface(__uuidof(IDXGIFactory5),
reinterpret_cast<
void **>(&factory5)))) {
274 BOOL allowTearing =
false;
275 if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing,
sizeof(allowTearing))))
276 supportsAllowTearing = allowTearing;
281 ID3D12Debug1 *debug =
nullptr;
282 if (SUCCEEDED(D3D12GetDebugInterface(__uuidof(ID3D12Debug1),
reinterpret_cast<
void **>(&debug)))) {
283 qCDebug(QRHI_LOG_INFO,
"Enabling D3D12 debug layer");
284 debug->EnableDebugLayer();
289 activeAdapter =
nullptr;
291 if (!importedDevice) {
292 IDXGIAdapter1 *adapter;
293 int requestedAdapterIndex = -1;
294 if (qEnvironmentVariableIsSet(
"QT_D3D_ADAPTER_INDEX"))
295 requestedAdapterIndex = qEnvironmentVariableIntValue(
"QT_D3D_ADAPTER_INDEX");
297 if (requestedRhiAdapter)
298 adapterLuid =
static_cast<QD3D12Adapter *>(requestedRhiAdapter)->luid;
301 if (requestedAdapterIndex < 0 && (adapterLuid.LowPart || adapterLuid.HighPart)) {
302 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
303 DXGI_ADAPTER_DESC1 desc;
304 adapter->GetDesc1(&desc);
306 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
307 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
309 requestedAdapterIndex = adapterIndex;
315 if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
316 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
317 DXGI_ADAPTER_DESC1 desc;
318 adapter->GetDesc1(&desc);
320 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
321 requestedAdapterIndex = adapterIndex;
327 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
328 DXGI_ADAPTER_DESC1 desc;
329 adapter->GetDesc1(&desc);
330 const QString name = QString::fromUtf16(
reinterpret_cast<
char16_t *>(desc.Description));
331 qCDebug(QRHI_LOG_INFO,
"Adapter %d: '%s' (vendor 0x%X device 0x%X flags 0x%X)",
337 if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
338 activeAdapter = adapter;
339 adapterLuid = desc.AdapterLuid;
340 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
341 qCDebug(QRHI_LOG_INFO,
" using this adapter");
346 if (!activeAdapter) {
347 qWarning(
"No adapter");
351 if (minimumFeatureLevel == 0)
352 minimumFeatureLevel = MIN_FEATURE_LEVEL;
354 hr = D3D12CreateDevice(activeAdapter,
356 __uuidof(ID3D12Device2),
357 reinterpret_cast<
void **>(&dev));
359 qWarning(
"Failed to create D3D12 device: %s", qPrintable(QSystemError::windowsComString(hr)));
365 adapterLuid = dev->GetAdapterLuid();
366 IDXGIAdapter1 *adapter;
367 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
368 DXGI_ADAPTER_DESC1 desc;
369 adapter->GetDesc1(&desc);
370 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
371 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
373 activeAdapter = adapter;
374 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
380 if (!activeAdapter) {
381 qWarning(
"No adapter");
384 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
387 QDxgiVSyncService::instance()->refAdapter(adapterLuid);
390 ID3D12InfoQueue *infoQueue;
391 if (SUCCEEDED(dev->QueryInterface(__uuidof(ID3D12InfoQueue),
reinterpret_cast<
void **>(&infoQueue)))) {
392 if (qEnvironmentVariableIntValue(
"QT_D3D_DEBUG_BREAK")) {
393 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION,
true);
394 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR,
true);
395 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING,
true);
397 D3D12_INFO_QUEUE_FILTER filter = {};
398 D3D12_MESSAGE_ID suppressedMessages[3] = {
400 D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
402 D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
404 D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE
406 filter.DenyList.NumIDs = 3;
407 filter.DenyList.pIDList = suppressedMessages;
410 D3D12_MESSAGE_SEVERITY infoSev = D3D12_MESSAGE_SEVERITY_INFO;
411 filter.DenyList.NumSeverities = 1;
412 filter.DenyList.pSeverityList = &infoSev;
413 infoQueue->PushStorageFilter(&filter);
414#ifdef QRHI_D3D12_INFOQUEUE1_AVAILABLE
419 if (SUCCEEDED(infoQueue->QueryInterface(__uuidof(ID3D12InfoQueue1),
reinterpret_cast<
void **>(&infoQueue1)))) {
424 if (SUCCEEDED(infoQueue1->RegisterMessageCallback(qd3d12_message_callback,
425 D3D12_MESSAGE_CALLBACK_IGNORE_FILTERS,
427 &infoQueueCallbackCookie)))
431 infoQueue1->SetMuteDebugOutput(
true);
433 infoQueue1->Release();
434 infoQueue1 =
nullptr;
438 infoQueue->Release();
442 if (!importedCommandQueue) {
443 D3D12_COMMAND_QUEUE_DESC queueDesc = {};
444 queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
445 queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
446 hr = dev->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue),
reinterpret_cast<
void **>(&cmdQueue));
448 qWarning(
"Failed to create command queue: %s", qPrintable(QSystemError::windowsComString(hr)));
453 hr = dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence),
reinterpret_cast<
void **>(&fullFence));
455 qWarning(
"Failed to create fence: %s", qPrintable(QSystemError::windowsComString(hr)));
458 fullFenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
459 fullFenceCounter = 0;
461 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
462 hr = dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
463 __uuidof(ID3D12CommandAllocator),
464 reinterpret_cast<
void **>(&cmdAllocators[i]));
466 qWarning(
"Failed to create command allocator: %s", qPrintable(QSystemError::windowsComString(hr)));
471 if (!vma.create(dev, activeAdapter)) {
472 qWarning(
"Failed to initialize graphics memory suballocator");
476 if (!rtvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
"main RTV pool")) {
477 qWarning(
"Could not create RTV pool");
481 if (!dsvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
"main DSV pool")) {
482 qWarning(
"Could not create DSV pool");
486 if (!cbvSrvUavPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
"main CBV-SRV-UAV pool")) {
487 qWarning(
"Could not create CBV-SRV-UAV pool");
491 resourcePool.create(
"main resource pool");
492 pipelinePool.create(
"main pipeline pool");
493 rootSignaturePool.create(
"main root signature pool");
494 releaseQueue.create(&resourcePool, &pipelinePool, &rootSignaturePool);
495 barrierGen.create(&resourcePool);
497 if (!samplerMgr.create(dev)) {
498 qWarning(
"Could not create sampler pool and shader-visible sampler heap");
502 mipmapGen.create(
this);
503 mipmapGen3D.create(
this);
505 const qint32 smallStagingSize = aligned(SMALL_STAGING_AREA_BYTES_PER_FRAME_START, QD3D12StagingArea::ALIGNMENT);
506 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
507 if (!smallStagingAreas[i].create(
this, smallStagingSize, D3D12_HEAP_TYPE_UPLOAD)) {
508 qWarning(
"Could not create host-visible staging area");
511 QString decoratedName = QLatin1String(
"Small staging area buffer/");
512 decoratedName += QString::number(i);
513 smallStagingAreas[i].mem.buffer->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
516 if (!shaderVisibleCbvSrvUavHeap.create(dev,
517 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
518 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE))
520 qWarning(
"Could not create first shader-visible CBV/SRV/UAV heap");
524 if (flags.testFlag(QRhi::EnableTimestamps)) {
525 static bool wantsStablePowerState = qEnvironmentVariableIntValue(
"QT_D3D_STABLE_POWER_STATE");
541 if (wantsStablePowerState)
542 dev->SetStablePowerState(TRUE);
544 hr = cmdQueue->GetTimestampFrequency(×tampTicksPerSecond);
546 qWarning(
"Failed to query timestamp frequency: %s",
547 qPrintable(QSystemError::windowsComString(hr)));
550 if (!timestampQueryHeap.create(dev, QD3D12_FRAMES_IN_FLIGHT * 2, D3D12_QUERY_HEAP_TYPE_TIMESTAMP)) {
551 qWarning(
"Failed to create timestamp query pool");
554 const quint32 readbackBufSize = QD3D12_FRAMES_IN_FLIGHT * 2 *
sizeof(quint64);
555 if (!timestampReadbackArea.create(
this, readbackBufSize, D3D12_HEAP_TYPE_READBACK)) {
556 qWarning(
"Failed to create timestamp readback buffer");
559 timestampReadbackArea.mem.buffer->SetName(L"Timestamp readback buffer");
560 memset(timestampReadbackArea.mem.p, 0, readbackBufSize);
564 D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
565 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3,
sizeof(options3)))) {
566 caps.multiView = options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
568 caps.textureViewFormat = options3.CastingFullyTypedFormatSupported;
571#ifdef QRHI_D3D12_CL5_AVAILABLE
572 D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {};
573 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6,
sizeof(options6)))) {
574 caps.vrs = options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED;
575 caps.vrsMap = options6.VariableShadingRateTier == D3D12_VARIABLE_SHADING_RATE_TIER_2;
576 caps.vrsAdditionalRates = options6.AdditionalShadingRatesSupported;
577 shadingRateImageTileSize = options6.ShadingRateImageTileSize;
582 caps.vrsAdditionalRates =
false;
586 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
587 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
589 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
590 sigDesc.ByteStride =
sizeof(D3D12_DRAW_ARGUMENTS);
591 sigDesc.NumArgumentDescs = 1;
592 sigDesc.pArgumentDescs = &arg;
594 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&drawCommandSignature));
596 qWarning(
"Failed to create draw command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
602 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
603 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
605 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
606 sigDesc.ByteStride =
sizeof(D3D12_DRAW_INDEXED_ARGUMENTS);
607 sigDesc.NumArgumentDescs = 1;
608 sigDesc.pArgumentDescs = &arg;
610 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&drawIndexedCommandSignature));
612 qWarning(
"Failed to create draw indexed command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
618 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
619 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH;
621 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
622 sigDesc.ByteStride =
sizeof(D3D12_DISPATCH_ARGUMENTS);
623 sigDesc.NumArgumentDescs = 1;
624 sigDesc.pArgumentDescs = &arg;
626 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&dispatchCommandSignature));
628 qWarning(
"Failed to create dispatch command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
634 offscreenActive =
false;
636 nativeHandlesStruct.dev = dev;
637 nativeHandlesStruct.minimumFeatureLevel = minimumFeatureLevel;
638 nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
639 nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
640 nativeHandlesStruct.commandQueue = cmdQueue;
645void QRhiD3D12::destroy()
647 if (!deviceLost && fullFence && fullFenceEvent)
650 releaseQueue.releaseAll();
652 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
653 if (offscreenCb[i]) {
654 if (offscreenCb[i]->cmdList)
655 offscreenCb[i]->cmdList->Release();
656 delete offscreenCb[i];
657 offscreenCb[i] =
nullptr;
661 timestampQueryHeap.destroy();
662 timestampReadbackArea.destroy();
664 shaderVisibleCbvSrvUavHeap.destroy();
666 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i)
667 smallStagingAreas[i].destroy();
670 mipmapGen3D.destroy();
671 samplerMgr.destroy();
672 resourcePool.destroy();
673 pipelinePool.destroy();
674 rootSignaturePool.destroy();
677 cbvSrvUavPool.destroy();
679 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
680 if (cmdAllocators[i]) {
681 cmdAllocators[i]->Release();
682 cmdAllocators[i] =
nullptr;
686 if (fullFenceEvent) {
687 CloseHandle(fullFenceEvent);
688 fullFenceEvent =
nullptr;
692 fullFence->Release();
696 if (!importedCommandQueue) {
705#ifdef QRHI_D3D12_INFOQUEUE1_AVAILABLE
707 infoQueue1->UnregisterMessageCallback(infoQueueCallbackCookie);
708 infoQueue1->Release();
709 infoQueue1 =
nullptr;
710 infoQueueCallbackCookie = 0;
714 if (!importedDevice) {
722 dcompDevice->Release();
723 dcompDevice =
nullptr;
727 activeAdapter->Release();
728 activeAdapter =
nullptr;
732 dxgiFactory->Release();
733 dxgiFactory =
nullptr;
736 QDxgiVSyncService::instance()->derefAdapter(adapterLuid);
739 importedDevice =
false;
740 importedCommandQueue =
false;
742 if (drawCommandSignature) {
743 drawCommandSignature->Release();
744 drawCommandSignature =
nullptr;
747 if (drawIndexedCommandSignature) {
748 drawIndexedCommandSignature->Release();
749 drawIndexedCommandSignature =
nullptr;
752 if (dispatchCommandSignature) {
753 dispatchCommandSignature->Release();
754 dispatchCommandSignature =
nullptr;
757 for (ID3D12CommandSignature *sig : std::as_const(drawCommandSignaturesByStride))
759 drawCommandSignaturesByStride.clear();
761 for (ID3D12CommandSignature *sig : std::as_const(drawIndexedCommandSignaturesByStride))
763 drawIndexedCommandSignaturesByStride.clear();
765 destroyPipelineLibrary();
768QRhi::AdapterList QRhiD3D12::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
770 LUID requestedLuid = {};
772 QRhiD3D12NativeHandles *h =
static_cast<QRhiD3D12NativeHandles *>(nativeHandles);
773 const LUID adapterLuid = { h->adapterLuidLow, h->adapterLuidHigh };
774 if (adapterLuid.LowPart || adapterLuid.HighPart)
775 requestedLuid = adapterLuid;
778 IDXGIFactory2 *dxgi =
nullptr;
779 if (FAILED(CreateDXGIFactory2(0, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgi))))
782 QRhi::AdapterList list;
783 IDXGIAdapter1 *adapter;
784 for (
int adapterIndex = 0; dxgi->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
785 DXGI_ADAPTER_DESC1 desc;
786 adapter->GetDesc1(&desc);
788 if (requestedLuid.LowPart || requestedLuid.HighPart) {
789 if (desc.AdapterLuid.LowPart != requestedLuid.LowPart
790 || desc.AdapterLuid.HighPart != requestedLuid.HighPart)
795 QD3D12Adapter *a =
new QD3D12Adapter;
796 a->luid = desc.AdapterLuid;
797 QRhiD3D::fillDriverInfo(&a->adapterInfo, desc);
805QRhiDriverInfo QD3D12Adapter::info()
const
810QList<
int> QRhiD3D12::supportedSampleCounts()
const
812 return { 1, 2, 4, 8 };
815QList<QSize> QRhiD3D12::supportedShadingRates(
int sampleCount)
const
818 switch (sampleCount) {
821 if (caps.vrsAdditionalRates) {
822 sizes.append(QSize(4, 4));
823 sizes.append(QSize(4, 2));
824 sizes.append(QSize(2, 4));
826 sizes.append(QSize(2, 2));
827 sizes.append(QSize(2, 1));
828 sizes.append(QSize(1, 2));
831 if (caps.vrsAdditionalRates)
832 sizes.append(QSize(2, 4));
833 sizes.append(QSize(2, 2));
834 sizes.append(QSize(2, 1));
835 sizes.append(QSize(1, 2));
838 sizes.append(QSize(2, 2));
839 sizes.append(QSize(2, 1));
840 sizes.append(QSize(1, 2));
845 sizes.append(QSize(1, 1));
849QRhiSwapChain *QRhiD3D12::createSwapChain()
851 return new QD3D12SwapChain(
this);
854QRhiBuffer *QRhiD3D12::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
856 return new QD3D12Buffer(
this, type, usage, size);
859int QRhiD3D12::ubufAlignment()
const
861 return D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
864bool QRhiD3D12::isYUpInFramebuffer()
const
869bool QRhiD3D12::isYUpInNDC()
const
874bool QRhiD3D12::isClipDepthZeroToOne()
const
879QMatrix4x4 QRhiD3D12::clipSpaceCorrMatrix()
const
884 static constexpr QMatrix4x4 m(1.0f, 0.0f, 0.0f, 0.0f,
885 0.0f, 1.0f, 0.0f, 0.0f,
886 0.0f, 0.0f, 0.5f, 0.5f,
887 0.0f, 0.0f, 0.0f, 1.0f);
891bool QRhiD3D12::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags)
const
895 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ASTC_12x12)
901bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature)
const
904 case QRhi::MultisampleTexture:
906 case QRhi::MultisampleRenderBuffer:
908 case QRhi::DebugMarkers:
909#ifdef QRHI_D3D12_HAS_OLD_PIX
914 case QRhi::Timestamps:
916 case QRhi::Instancing:
918 case QRhi::CustomInstanceStepRate:
920 case QRhi::PrimitiveRestart:
922 case QRhi::NonDynamicUniformBuffers:
924 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
926 case QRhi::NPOTTextureRepeat:
928 case QRhi::RedOrAlpha8IsRed:
930 case QRhi::ElementIndexUint:
934 case QRhi::WideLines:
936 case QRhi::VertexShaderPointSize:
938 case QRhi::BaseVertex:
940 case QRhi::BaseInstance:
942 case QRhi::TriangleFanTopology:
944 case QRhi::ReadBackNonUniformBuffer:
946 case QRhi::ReadBackNonBaseMipLevel:
948 case QRhi::TexelFetch:
950 case QRhi::RenderToNonBaseMipLevel:
952 case QRhi::IntAttributes:
954 case QRhi::ScreenSpaceDerivatives:
956 case QRhi::ReadBackAnyTextureFormat:
958 case QRhi::PipelineCacheDataLoadSave:
959#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
964 case QRhi::ImageDataStride:
966 case QRhi::RenderBufferImport:
968 case QRhi::ThreeDimensionalTextures:
970 case QRhi::RenderTo3DTextureSlice:
972 case QRhi::TextureArrays:
974 case QRhi::Tessellation:
976 case QRhi::GeometryShader:
978 case QRhi::TextureArrayRange:
980 case QRhi::NonFillPolygonMode:
982 case QRhi::OneDimensionalTextures:
984 case QRhi::OneDimensionalTextureMipmaps:
986 case QRhi::HalfAttributes:
988 case QRhi::RenderToOneDimensionalTexture:
990 case QRhi::ThreeDimensionalTextureMipmaps:
992 case QRhi::MultiView:
993 return caps.multiView;
994 case QRhi::TextureViewFormat:
995 return caps.textureViewFormat;
996 case QRhi::ResolveDepthStencil:
1000 case QRhi::VariableRateShading:
1002 case QRhi::VariableRateShadingMap:
1003 case QRhi::VariableRateShadingMapWithTexture:
1005 case QRhi::PerRenderTargetBlending:
1006 case QRhi::SampleVariables:
1008 case QRhi::InstanceIndexIncludesBaseInstance:
1010 case QRhi::DepthClamp:
1012 case QRhi::DrawIndirect:
1013 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
1014 case QRhi::DrawIndirectMulti:
1015 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
1016 case QRhi::ShaderDrawParameters:
1018 case QRhi::DispatchIndirect:
1019 return dispatchCommandSignature !=
nullptr;
1020 case QRhi::PushConstants:
1022 case QRhi::DrawIndirectCount:
1024 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
1025 case QRhi::BufferToBufferCopy:
1027 case QRhi::StaticBuffersOnGpuTimeline:
1033int QRhiD3D12::resourceLimit(QRhi::ResourceLimit limit)
const
1036 case QRhi::TextureSizeMin:
1038 case QRhi::TextureSizeMax:
1040 case QRhi::MaxColorAttachments:
1042 case QRhi::FramesInFlight:
1043 return QD3D12_FRAMES_IN_FLIGHT;
1044 case QRhi::MaxAsyncReadbackFrames:
1045 return QD3D12_FRAMES_IN_FLIGHT;
1046 case QRhi::MaxThreadGroupsPerDimension:
1048 case QRhi::MaxThreadsPerThreadGroup:
1050 case QRhi::MaxThreadGroupX:
1052 case QRhi::MaxThreadGroupY:
1054 case QRhi::MaxThreadGroupZ:
1056 case QRhi::TextureArraySizeMax:
1058 case QRhi::MaxUniformBufferRange:
1060 case QRhi::MaxVertexInputs:
1062 case QRhi::MaxVertexOutputs:
1064 case QRhi::MaxPushConstantsSize:
1066 case QRhi::MaxVertexStorageBuffers:
1067 case QRhi::MaxFragmentStorageBuffers:
1069 case QRhi::ShadingRateImageTileSize:
1070 return shadingRateImageTileSize;
1075const QRhiNativeHandles *QRhiD3D12::nativeHandles()
1077 return &nativeHandlesStruct;
1080QRhiDriverInfo QRhiD3D12::driverInfo()
const
1082 return driverInfoStruct;
1085QRhiStats QRhiD3D12::statistics()
1088 result.totalPipelineCreationTime = totalPipelineCreationTime();
1090 D3D12MA::Budget budgets[2];
1091 vma.getBudget(&budgets[0], &budgets[1]);
1092 for (
int i = 0; i < 2; ++i) {
1093 const D3D12MA::Statistics &stats(budgets[i].Stats);
1094 result.blockCount += stats.BlockCount;
1095 result.allocCount += stats.AllocationCount;
1096 result.usedBytes += stats.AllocationBytes;
1097 result.unusedBytes += stats.BlockBytes - stats.AllocationBytes;
1098 result.totalUsageBytes += budgets[i].UsageBytes;
1104bool QRhiD3D12::makeThreadLocalNativeContextCurrent()
1110void QRhiD3D12::setQueueSubmitParams(QRhiNativeHandles *)
1115void QRhiD3D12::releaseCachedResources()
1117 shaderBytecodeCache.data.clear();
1126static inline void addToKey(QCryptographicHash *h,
const void *p, size_t size)
1128 h->addData(QByteArrayView(
static_cast<
const char *>(p), qsizetype(size)));
1132static inline void addToKey(QCryptographicHash *h,
const T &v)
1134 addToKey(h, &v,
sizeof(T));
1137static inline void addToKey(QCryptographicHash *h,
const QByteArray &b)
1139 const quint32 size = quint32(b.size());
1144static inline void addToKey(QCryptographicHash *h,
const QVector<quint32> &v)
1146 const quint32 count = quint32(v.count());
1148 addToKey(h, v.constData(), v.count() *
sizeof(quint32));
1151bool QRhiD3D12::createPipelineLibrary(
const QByteArray &blob)
1153#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1154 destroyPipelineLibrary();
1156 pipelineLibraryBlob = blob;
1157 HRESULT hr = dev->CreatePipelineLibrary(pipelineLibraryBlob.isEmpty() ?
nullptr
1158 : pipelineLibraryBlob.constData(),
1159 SIZE_T(pipelineLibraryBlob.size()),
1160 __uuidof(ID3D12PipelineLibrary1),
1161 reinterpret_cast<
void **>(&pipelineLibrary));
1167 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline library: %s",
1168 qPrintable(QSystemError::windowsComString(hr)));
1169 pipelineLibrary =
nullptr;
1170 pipelineLibraryBlob.clear();
1180bool QRhiD3D12::ensurePipelineLibrary()
1182#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1183 if (pipelineLibrary)
1185 if (!rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
1187 return createPipelineLibrary(QByteArray());
1193void QRhiD3D12::destroyPipelineLibrary()
1195#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1196 if (pipelineLibrary) {
1197 pipelineLibrary->Release();
1198 pipelineLibrary =
nullptr;
1200 pipelineLibraryBlob.clear();
1201 pipelineLibraryNames.clear();
1205ID3D12PipelineState *QRhiD3D12::loadOrCreatePipelineState(
const D3D12_PIPELINE_STATE_STREAM_DESC *streamDesc,
1206 const QByteArray &cacheKey,
1209 ID3D12PipelineState *pso =
nullptr;
1211#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1212 QVarLengthArray<
wchar_t, 64> name;
1213 if (ensurePipelineLibrary() && !cacheKey.isEmpty()) {
1214 name.resize(cacheKey.size() + 1);
1215 for (qsizetype i = 0; i < cacheKey.size(); ++i)
1216 name[i] =
wchar_t(cacheKey.at(i));
1217 name[cacheKey.size()] = 0;
1218 HRESULT hr = pipelineLibrary->LoadPipeline(name.constData(),
1220 __uuidof(ID3D12PipelineState),
1221 reinterpret_cast<
void **>(&pso));
1227 HRESULT hr = dev->CreatePipelineState(streamDesc,
1228 __uuidof(ID3D12PipelineState),
1229 reinterpret_cast<
void **>(&pso));
1231 qWarning(
"Failed to create %s pipeline state: %s",
1232 what, qPrintable(QSystemError::windowsComString(hr)));
1236#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1237 if (pipelineLibrary && !name.isEmpty() && !pipelineLibraryNames.contains(cacheKey)) {
1238 if (SUCCEEDED(pipelineLibrary->StorePipeline(name.constData(), pso)))
1239 pipelineLibraryNames.insert(cacheKey);
1246struct QD3D12PipelineCacheDataHeader
1254 quint64 adapterLuid;
1257QByteArray QRhiD3D12::pipelineCacheData()
1259 static_assert(
sizeof(QD3D12PipelineCacheDataHeader) == 32);
1262#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1263 if (!pipelineLibrary || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
1266 const SIZE_T dataSize = pipelineLibrary->GetSerializedSize();
1270 const size_t headerSize =
sizeof(QD3D12PipelineCacheDataHeader);
1271 data.resize(qsizetype(headerSize + dataSize));
1272 HRESULT hr = pipelineLibrary->Serialize(data.data() + headerSize, dataSize);
1274 qCDebug(QRHI_LOG_INFO,
"Failed to serialize pipeline library: %s",
1275 qPrintable(QSystemError::windowsComString(hr)));
1276 return QByteArray();
1279 QD3D12PipelineCacheDataHeader header = {};
1280 header.rhiId = pipelineCacheRhiId();
1281 header.arch = quint32(
sizeof(
void *));
1282 header.dataSize = quint32(dataSize);
1283 header.vendorId = quint32(driverInfoStruct.vendorId);
1284 header.deviceId = quint32(driverInfoStruct.deviceId);
1285 header.adapterLuid = (quint64(quint32(adapterLuid.HighPart)) << 32) | quint64(adapterLuid.LowPart);
1286 memcpy(data.data(), &header, headerSize);
1291void QRhiD3D12::setPipelineCacheData(
const QByteArray &data)
1293#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1297 const size_t headerSize =
sizeof(QD3D12PipelineCacheDataHeader);
1298 if (data.size() < qsizetype(headerSize)) {
1299 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
1302 QD3D12PipelineCacheDataHeader header;
1303 memcpy(&header, data.constData(), headerSize);
1305 const quint32 rhiId = pipelineCacheRhiId();
1306 if (header.rhiId != rhiId) {
1307 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
1308 rhiId, header.rhiId);
1311 const quint32 arch = quint32(
sizeof(
void *));
1312 if (header.arch != arch) {
1313 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
1317 if (header.vendorId != quint32(driverInfoStruct.vendorId)) {
1318 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorId does not match (%u, %u)",
1319 quint32(driverInfoStruct.vendorId), header.vendorId);
1322 if (header.deviceId != quint32(driverInfoStruct.deviceId)) {
1323 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceId does not match (%u, %u)",
1324 quint32(driverInfoStruct.deviceId), header.deviceId);
1327 const quint64 luid = (quint64(quint32(adapterLuid.HighPart)) << 32) | quint64(adapterLuid.LowPart);
1328 if (header.adapterLuid != luid) {
1329 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: adapter LUID does not match");
1332 if (quint64(data.size()) < quint64(headerSize) + header.dataSize) {
1333 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
1340 if (createPipelineLibrary(data.mid(qsizetype(headerSize)))) {
1341 qCDebug(QRHI_LOG_INFO,
"Created pipeline library with initial data of %u bytes",
1349bool QRhiD3D12::isDeviceLost()
const
1354QRhiRenderBuffer *QRhiD3D12::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
1355 int sampleCount, QRhiRenderBuffer::Flags flags,
1356 QRhiTexture::Format backingFormatHint)
1358 return new QD3D12RenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
1361QRhiTexture *QRhiD3D12::createTexture(QRhiTexture::Format format,
1362 const QSize &pixelSize,
int depth,
int arraySize,
1363 int sampleCount, QRhiTexture::Flags flags)
1365 return new QD3D12Texture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
1368QRhiSampler *QRhiD3D12::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
1369 QRhiSampler::Filter mipmapMode,
1370 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
1372 return new QD3D12Sampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
1375QRhiTextureRenderTarget *QRhiD3D12::createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
1376 QRhiTextureRenderTarget::Flags flags)
1378 return new QD3D12TextureRenderTarget(
this, desc, flags);
1381QRhiShadingRateMap *QRhiD3D12::createShadingRateMap()
1383 return new QD3D12ShadingRateMap(
this);
1386QRhiGraphicsPipeline *QRhiD3D12::createGraphicsPipeline()
1388 return new QD3D12GraphicsPipeline(
this);
1391QRhiComputePipeline *QRhiD3D12::createComputePipeline()
1393 return new QD3D12ComputePipeline(
this);
1396QRhiShaderResourceBindings *QRhiD3D12::createShaderResourceBindings()
1398 return new QD3D12ShaderResourceBindings(
this);
1401void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
1403 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1404 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1405 QD3D12GraphicsPipeline *psD = QRHI_RES(QD3D12GraphicsPipeline, ps);
1406 const bool pipelineChanged = cbD->currentGraphicsPipeline != psD || cbD->currentPipelineGeneration != psD->generation;
1408 if (pipelineChanged) {
1409 cbD->currentGraphicsPipeline = psD;
1410 cbD->currentComputePipeline =
nullptr;
1411 cbD->currentPipelineGeneration = psD->generation;
1413 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
1414 Q_ASSERT(pipeline->type == QD3D12Pipeline::Graphics);
1415 cbD->cmdList->SetPipelineState(pipeline->pso);
1416 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
1417 cbD->cmdList->SetGraphicsRootSignature(rs->rootSig);
1420 cbD->cmdList->IASetPrimitiveTopology(psD->topology);
1422 if (psD->viewInstanceMask)
1423 cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
1425 if (cbD->hasCustomScissorSet && !psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor))
1426 setDefaultScissor(cbD);
1430void QD3D12ShaderResourceBindings::cacheUniformBuffer(QD3D12Stage s,
1431 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
1438 bindingCache.cbufs[s].append({ QRHI_RES(QD3D12Buffer, d.buf), d.offset, binding });
1441void QD3D12ShaderResourceBindings::cacheTextures(QD3D12Stage s,
1442 const QRhiShaderResourceBinding::TextureAndSampler *d,
1446 for (
int i = 0; i < count; ++i) {
1447 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d[i].tex);
1448 bindingCache.srvs[s].append(texD->srv.cpuHandle);
1452void QD3D12ShaderResourceBindings::cacheSamplers(QD3D12Stage s,
1453 const QRhiShaderResourceBinding::TextureAndSampler *d,
1458 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, d[0].sampler);
1459 bindingCache.samplers[s].append(samplerD->lookupOrCreateShaderVisibleDescriptor().gpuHandle);
1467 QRHI_RES_RHI(QRhiD3D12);
1468 QVarLengthArray<Q_D3D12_SAMPLER_DESC, 8> descs;
1469 for (
int i = 0; i < count; ++i)
1470 descs.append({ QRHI_RES(QD3D12Sampler, d[i].sampler)->desc });
1471 bindingCache.samplers[s].append(rhiD->samplerMgr.getShaderVisibleDescriptors(descs).gpuHandle);
1474void QD3D12ShaderResourceBindings::cacheStorageBuffer(QD3D12Stage s,
1475 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
1476 QD3D12ShaderResourceVisitor::StorageOp,
1479 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1481 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1482 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1483 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
1484 uavDesc.Buffer.FirstElement = d.offset / 4;
1485 uavDesc.Buffer.NumElements = aligned(bufD->m_size - d.offset, 4u) / 4;
1486 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
1487 bindingCache.uavs[s].append({ bufD->handles[0], uavDesc });
1490void QD3D12ShaderResourceBindings::cacheStorageImage(QD3D12Stage s,
1491 const QRhiShaderResourceBinding::Data::StorageImageData &d,
1492 QD3D12ShaderResourceVisitor::StorageOp,
1495 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1496 const bool isCube = texD->m_flags.testFlag(QRhiTexture::CubeMap);
1497 const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
1498 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1499 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1500 uavDesc.Format = texD->rtFormat;
1502 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1503 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1504 uavDesc.Texture2DArray.FirstArraySlice = 0;
1505 uavDesc.Texture2DArray.ArraySize = 6;
1506 }
else if (isArray) {
1507 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1508 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1509 uavDesc.Texture2DArray.FirstArraySlice = 0;
1510 uavDesc.Texture2DArray.ArraySize = UINT(qMax(0, texD->m_arraySize));
1512 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1513 uavDesc.Texture3D.MipSlice = UINT(d.level);
1514 uavDesc.Texture3D.WSize = UINT(-1);
1516 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
1517 uavDesc.Texture2D.MipSlice = UINT(d.level);
1519 bindingCache.uavs[s].append({ texD->handle, uavDesc });
1522void QD3D12ShaderResourceBindings::rebuildBindingCache(
const QD3D12ShaderStageData *stageData,
1525 bindingCache.reset();
1527 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
1529 using namespace std::placeholders;
1530 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::cacheUniformBuffer,
this, _1, _2, _3, _4);
1531 visitor.textures = std::bind(&QD3D12ShaderResourceBindings::cacheTextures,
this, _1, _2, _3, _4);
1532 visitor.samplers = std::bind(&QD3D12ShaderResourceBindings::cacheSamplers,
this, _1, _2, _3, _4);
1533 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::cacheStorageBuffer,
this, _1, _2, _3, _4);
1534 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::cacheStorageImage,
this, _1, _2, _3, _4);
1539 for (
int s = 0; s < 6; ++s) {
1540 bindingCache.srvUavCount += bindingCache.srvs[s].count();
1541 bindingCache.srvUavCount += bindingCache.uavs[s].count();
1544 bindingCacheValid =
true;
1545 bindingCacheGeneration = generation;
1548void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
1549 int dynamicOffsetCount,
1550 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1552 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1553 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
1554 QD3D12GraphicsPipeline *gfxPsD = QRHI_RES(QD3D12GraphicsPipeline, cbD->currentGraphicsPipeline);
1555 QD3D12ComputePipeline *compPsD = QRHI_RES(QD3D12ComputePipeline, cbD->currentComputePipeline);
1559 srb = gfxPsD->m_shaderResourceBindings;
1561 srb = compPsD->m_shaderResourceBindings;
1564 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, srb);
1566 bool pipelineChanged =
false;
1568 pipelineChanged = srbD->lastUsedGraphicsPipeline != gfxPsD
1569 || srbD->lastUsedPipelineGeneration != gfxPsD->generation;
1570 srbD->lastUsedGraphicsPipeline = gfxPsD;
1571 srbD->lastUsedComputePipeline =
nullptr;
1572 srbD->lastUsedPipelineGeneration = gfxPsD->generation;
1574 pipelineChanged = srbD->lastUsedComputePipeline != compPsD
1575 || srbD->lastUsedPipelineGeneration != compPsD->generation;
1576 srbD->lastUsedGraphicsPipeline =
nullptr;
1577 srbD->lastUsedComputePipeline = compPsD;
1578 srbD->lastUsedPipelineGeneration = compPsD->generation;
1581 bool srbUpdate =
false;
1583 for (
int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
1584 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings[i]);
1585 QD3D12ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
1587 case QRhiShaderResourceBinding::UniformBuffer:
1589 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.ubuf.buf);
1590 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
1591 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1592 sanityCheckResourceOwnership(bufD);
1593 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1594 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
1596 bd.ubuf.id = bufD->m_id;
1597 bd.ubuf.generation = bufD->generation;
1601 case QRhiShaderResourceBinding::SampledTexture:
1602 case QRhiShaderResourceBinding::Texture:
1603 case QRhiShaderResourceBinding::Sampler:
1605 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
1606 if (bd.stex.count != data->count) {
1607 bd.stex.count = data->count;
1610 for (
int elem = 0; elem < data->count; ++elem) {
1611 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, data->texSamplers[elem].tex);
1612 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, data->texSamplers[elem].sampler);
1616 Q_ASSERT(texD || samplerD);
1617 sanityCheckResourceOwnership(texD);
1618 sanityCheckResourceOwnership(samplerD);
1619 const quint64 texId = texD ? texD->m_id : 0;
1620 const uint texGen = texD ? texD->generation : 0;
1621 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
1622 const uint samplerGen = samplerD ? samplerD->generation : 0;
1623 if (texId != bd.stex.d[elem].texId || texGen != bd.stex.d[elem].texGeneration
1624 || samplerId != bd.stex.d[elem].samplerId
1625 || samplerGen != bd.stex.d[elem].samplerGeneration)
1628 bd.stex.d[elem].texId = texId;
1629 bd.stex.d[elem].texGeneration = texGen;
1630 bd.stex.d[elem].samplerId = samplerId;
1631 bd.stex.d[elem].samplerGeneration = samplerGen;
1635 if (b->stage == QRhiShaderResourceBinding::FragmentStage) {
1636 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1637 }
else if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
1638 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1640 state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1642 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATES(state));
1647 case QRhiShaderResourceBinding::ImageLoad:
1648 case QRhiShaderResourceBinding::ImageStore:
1649 case QRhiShaderResourceBinding::ImageLoadStore:
1651 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, b->u.simage.tex);
1652 sanityCheckResourceOwnership(texD);
1653 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
1655 bd.simage.id = texD->m_id;
1656 bd.simage.generation = texD->generation;
1658 if (QD3D12Resource *res = resourcePool.lookupRef(texD->handle)) {
1659 if (res->uavUsage) {
1660 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1662 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1664 if (b->type == QRhiShaderResourceBinding::ImageStore
1665 || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1668 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1673 if (b->type == QRhiShaderResourceBinding::ImageLoad || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1674 res->uavUsage |= QD3D12Resource::UavUsageRead;
1675 if (b->type == QRhiShaderResourceBinding::ImageStore || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1676 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1677 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1681 case QRhiShaderResourceBinding::BufferLoad:
1682 case QRhiShaderResourceBinding::BufferStore:
1683 case QRhiShaderResourceBinding::BufferLoadStore:
1685 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.sbuf.buf);
1686 sanityCheckResourceOwnership(bufD);
1687 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
1688 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1689 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
1691 bd.sbuf.id = bufD->m_id;
1692 bd.sbuf.generation = bufD->generation;
1694 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
1695 if (res->uavUsage) {
1696 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1698 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1700 if (b->type == QRhiShaderResourceBinding::BufferStore
1701 || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1704 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1709 if (b->type == QRhiShaderResourceBinding::BufferLoad || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1710 res->uavUsage |= QD3D12Resource::UavUsageRead;
1711 if (b->type == QRhiShaderResourceBinding::BufferStore || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1712 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1713 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1720 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1721 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1729 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1735 if (pipelineChanged || srbUpdate || !srbD->bindingCacheValid
1736 || srbD->bindingCacheGeneration != srbD->generation)
1738 const QD3D12ShaderStageData *stageData = gfxPsD ? gfxPsD->stageData.data() : &compPsD->stageData;
1739 srbD->rebuildBindingCache(stageData, gfxPsD ? 5 : 1);
1742 if (pipelineChanged || srbChanged || srbRebuilt || srbUpdate || srbD->hasDynamicOffset) {
1747 const QD3D12ShaderResourceBindings::BindingCache &cache(srbD->bindingCache);
1749 bool gotNewHeap =
false;
1750 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
1751 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1759 qCDebug(QRHI_LOG_INFO,
"Created new shader-visible CBV/SRV/UAV descriptor heap,"
1760 " per-frame slice size is now %u,"
1761 " if this happens frequently then that's not great.",
1762 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[0].capacity);
1763 bindShaderVisibleHeaps(cbD);
1766 int rootParamIndex = 0;
1767 for (
int s = 0; s < 6; ++s) {
1768 for (
const QD3D12ShaderResourceBindings::BindingCache::CBuf &cbuf : cache.cbufs[s]) {
1769 if (QD3D12Resource *res = resourcePool.lookupRef(cbuf.buf->handles[currentFrameSlot])) {
1770 quint32 offset = cbuf.offset;
1771 if (srbD->hasDynamicOffset) {
1772 for (
int i = 0; i < dynamicOffsetCount; ++i) {
1773 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1774 if (dynOfs.first == cbuf.binding) {
1775 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1776 offset += dynOfs.second;
1780 const D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = res->resource->GetGPUVirtualAddress() + offset;
1782 cbD->cmdList->SetGraphicsRootConstantBufferView(rootParamIndex, gpuAddr);
1784 cbD->cmdList->SetComputeRootConstantBufferView(rootParamIndex, gpuAddr);
1786 rootParamIndex += 1;
1789 for (
int s = 0; s < 6; ++s) {
1790 if (!cache.srvs[s].isEmpty()) {
1791 QD3D12DescriptorHeap &gpuSrvHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1792 const UINT count = UINT(cache.srvs[s].count());
1793 const QD3D12Descriptor startDesc = gpuSrvHeap.get(count);
1796 dev->CopyDescriptors(1, &startDesc.cpuHandle, &count,
1797 count, cache.srvs[s].constData(),
nullptr,
1798 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1801 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1803 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1805 rootParamIndex += 1;
1808 for (
int s = 0; s < 6; ++s) {
1811 for (D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor : cache.samplers[s]) {
1813 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerDescriptor);
1815 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, samplerDescriptor);
1817 rootParamIndex += 1;
1820 for (
int s = 0; s < 6; ++s) {
1821 if (!cache.uavs[s].isEmpty()) {
1822 QD3D12DescriptorHeap &gpuUavHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1823 const int count = cache.uavs[s].count();
1824 const QD3D12Descriptor startDesc = gpuUavHeap.get(count);
1825 for (
int i = 0; i < count; ++i) {
1826 const QD3D12ShaderResourceBindings::BindingCache::Uav &uav(cache.uavs[s][i]);
1827 if (QD3D12Resource *res = resourcePool.lookupRef(uav.handle)) {
1828 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uav.desc,
1829 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1831 dev->CreateUnorderedAccessView(
nullptr,
nullptr,
nullptr,
1832 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1837 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1839 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1841 rootParamIndex += 1;
1846 cbD->currentGraphicsSrb = srb;
1847 cbD->currentComputeSrb =
nullptr;
1849 cbD->currentGraphicsSrb =
nullptr;
1850 cbD->currentComputeSrb = srb;
1852 cbD->currentSrbGeneration = srbD->generation;
1856void QRhiD3D12::setVertexInput(QRhiCommandBuffer *cb,
1857 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1858 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1860 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1861 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1863 bool needsBindVBuf =
false;
1864 for (
int i = 0; i < bindingCount; ++i) {
1865 const int inputSlot = startBinding + i;
1866 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1867 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1868 const bool isDynamic = bufD->m_type == QRhiBuffer::Dynamic;
1870 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1872 if (cbD->currentVertexBuffers[inputSlot] != bufD->handles[isDynamic ? currentFrameSlot : 0]
1873 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1875 needsBindVBuf =
true;
1876 cbD->currentVertexBuffers[inputSlot] = bufD->handles[isDynamic ? currentFrameSlot : 0];
1877 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1881 if (needsBindVBuf) {
1882 QVarLengthArray<D3D12_VERTEX_BUFFER_VIEW, 4> vbv;
1883 vbv.reserve(bindingCount);
1885 QD3D12GraphicsPipeline *psD = cbD->currentGraphicsPipeline;
1886 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1887 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1889 for (
int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1890 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1891 const QD3D12ObjectHandle handle = bufD->handles[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
1892 const quint32 offset = bindings[i].second;
1893 const quint32 stride = inputLayout.bindingAt(i)->stride();
1895 if (bufD->m_type != QRhiBuffer::Dynamic) {
1896 barrierGen.addTransitionBarrier(handle, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
1897 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1900 if (QD3D12Resource *res = resourcePool.lookupRef(handle)) {
1902 res->resource->GetGPUVirtualAddress() + offset,
1903 UINT(res->desc.Width - offset),
1909 cbD->cmdList->IASetVertexBuffers(UINT(startBinding), vbv.count(), vbv.constData());
1913 QD3D12Buffer *ibufD = QRHI_RES(QD3D12Buffer, indexBuf);
1914 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1915 const bool isDynamic = ibufD->m_type == QRhiBuffer::Dynamic;
1917 ibufD->executeHostWritesForFrameSlot(currentFrameSlot);
1919 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1920 : DXGI_FORMAT_R32_UINT;
1921 if (cbD->currentIndexBuffer != ibufD->handles[isDynamic ? currentFrameSlot : 0]
1922 || cbD->currentIndexOffset != indexOffset
1923 || cbD->currentIndexFormat != dxgiFormat)
1925 cbD->currentIndexBuffer = ibufD->handles[isDynamic ? currentFrameSlot : 0];
1926 cbD->currentIndexOffset = indexOffset;
1927 cbD->currentIndexFormat = dxgiFormat;
1929 if (ibufD->m_type != QRhiBuffer::Dynamic) {
1930 barrierGen.addTransitionBarrier(cbD->currentIndexBuffer, D3D12_RESOURCE_STATE_INDEX_BUFFER);
1931 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1934 if (QD3D12Resource *res = resourcePool.lookupRef(cbD->currentIndexBuffer)) {
1935 const D3D12_INDEX_BUFFER_VIEW ibv = {
1936 res->resource->GetGPUVirtualAddress() + indexOffset,
1937 UINT(res->desc.Width - indexOffset),
1940 cbD->cmdList->IASetIndexBuffer(&ibv);
1946void QRhiD3D12::setDefaultScissor(QD3D12CommandBuffer *cbD)
1948 cbD->hasCustomScissorSet =
false;
1950 const QSize outputSize = cbD->currentTarget->pixelSize();
1951 std::array<
float, 4> vp = cbD->currentViewport.viewport();
1952 float x = 0, y = 0, w = 0, h = 0;
1954 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
1957 w = outputSize.width();
1958 h = outputSize.height();
1961 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, vp, &x, &y, &w, &h);
1970 cbD->cmdList->RSSetScissorRects(1, &r);
1973void QRhiD3D12::setViewport(QRhiCommandBuffer *cb,
const QRhiViewport &viewport)
1975 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1976 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1977 Q_ASSERT(cbD->currentTarget);
1978 const QSize outputSize = cbD->currentTarget->pixelSize();
1982 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1990 v.MinDepth = viewport.minDepth();
1991 v.MaxDepth = viewport.maxDepth();
1992 cbD->cmdList->RSSetViewports(1, &v);
1994 cbD->currentViewport = viewport;
1995 if (cbD->currentGraphicsPipeline
1996 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
1998 setDefaultScissor(cbD);
2002void QRhiD3D12::setScissor(QRhiCommandBuffer *cb,
const QRhiScissor &scissor)
2004 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2005 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2006 Q_ASSERT(cbD->currentTarget);
2007 const QSize outputSize = cbD->currentTarget->pixelSize();
2011 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
2020 cbD->cmdList->RSSetScissorRects(1, &r);
2022 cbD->hasCustomScissorSet =
true;
2025void QRhiD3D12::setBlendConstants(QRhiCommandBuffer *cb,
const QColor &c)
2027 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2028 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2029 float v[4] = { c.redF(), c.greenF(), c.blueF(), c.alphaF() };
2030 cbD->cmdList->OMSetBlendFactor(v);
2033void QRhiD3D12::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
2035 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2036 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2037 cbD->cmdList->OMSetStencilRef(refValue);
2040void QRhiD3D12::setPushConstants(QRhiCommandBuffer *cb, quint32 offset, quint32 size,
const void *data)
2042 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2043 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
2045 const bool compute = cbD->recordingPass == QD3D12CommandBuffer::ComputePass;
2046 const int index = compute ? (cbD->currentComputePipeline ? cbD->currentComputePipeline->pushConstantRootParamIndex : -1)
2047 : (cbD->currentGraphicsPipeline ? cbD->currentGraphicsPipeline->pushConstantRootParamIndex : -1);
2049 qWarning(
"No pipeline with a push constant block is active; setPushConstants ignored");
2054 cbD->cmdList->SetComputeRoot32BitConstants(UINT(index), size / 4, data, offset / 4);
2056 cbD->cmdList->SetGraphicsRoot32BitConstants(UINT(index), size / 4, data, offset / 4);
2059static inline D3D12_SHADING_RATE toD3DShadingRate(
const QSize &coarsePixelSize)
2061 if (coarsePixelSize == QSize(1, 2))
2062 return D3D12_SHADING_RATE_1X2;
2063 if (coarsePixelSize == QSize(2, 1))
2064 return D3D12_SHADING_RATE_2X1;
2065 if (coarsePixelSize == QSize(2, 2))
2066 return D3D12_SHADING_RATE_2X2;
2067 if (coarsePixelSize == QSize(2, 4))
2068 return D3D12_SHADING_RATE_2X4;
2069 if (coarsePixelSize == QSize(4, 2))
2070 return D3D12_SHADING_RATE_4X2;
2071 if (coarsePixelSize == QSize(4, 4))
2072 return D3D12_SHADING_RATE_4X4;
2073 return D3D12_SHADING_RATE_1X1;
2076void QRhiD3D12::setShadingRate(QRhiCommandBuffer *cb,
const QSize &coarsePixelSize)
2078 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2079 cbD->hasShadingRateSet =
false;
2081#ifdef QRHI_D3D12_CL5_AVAILABLE
2085 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2086 const D3D12_SHADING_RATE_COMBINER combiners[] = { D3D12_SHADING_RATE_COMBINER_MAX, D3D12_SHADING_RATE_COMBINER_MAX };
2087 cbD->cmdList->RSSetShadingRate(toD3DShadingRate(coarsePixelSize), combiners);
2088 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
2089 cbD->hasShadingRateSet =
true;
2092 Q_UNUSED(coarsePixelSize);
2093 qWarning(
"Attempted to set ShadingRate without building Qt against a sufficiently new Windows SDK and d3d12.h. This cannot work.");
2097void QRhiD3D12::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
2098 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
2100 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2101 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2102 cbD->cmdList->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
2105void QRhiD3D12::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
2106 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
2108 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2109 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2110 cbD->cmdList->DrawIndexedInstanced(indexCount, instanceCount,
2111 firstIndex, vertexOffset,
2115void QRhiD3D12::drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
2116 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
2118 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2119 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2121 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2122 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2123 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
2125 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2127 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2128 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2130 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
2133 ID3D12Resource *indirectBufferRes = indirectRes->resource;
2135 const bool canUseMulti = (stride ==
sizeof(QRhiIndirectDrawCommand) && drawCommandSignature);
2137 if (canUseMulti && drawCount > 1) {
2138 cbD->cmdList->ExecuteIndirect(drawCommandSignature, drawCount,
2139 indirectBufferRes, indirectBufferOffset,
2142 UINT offset = indirectBufferOffset;
2143 for (quint32 i = 0; i < drawCount; ++i) {
2144 cbD->cmdList->ExecuteIndirect(drawCommandSignature, 1,
2145 indirectBufferRes, offset,
2152void QRhiD3D12::drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
2153 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
2155 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2156 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2158 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2159 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2160 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
2162 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2164 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2165 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2167 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
2170 ID3D12Resource *indirectBufferRes = indirectRes->resource;
2172 const bool canUseMulti = (stride ==
sizeof(QRhiIndexedIndirectDrawCommand) && drawIndexedCommandSignature);
2174 if (canUseMulti && drawCount > 1) {
2175 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, drawCount,
2176 indirectBufferRes, indirectBufferOffset,
2179 UINT offset = indirectBufferOffset;
2180 for (quint32 i = 0; i < drawCount; ++i) {
2181 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, 1,
2182 indirectBufferRes, offset,
2189void QRhiD3D12::debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name)
2194 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2195#ifdef QRHI_D3D12_HAS_OLD_PIX
2196 PIXBeginEvent(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(name).utf16()));
2203void QRhiD3D12::debugMarkEnd(QRhiCommandBuffer *cb)
2208 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2209#ifdef QRHI_D3D12_HAS_OLD_PIX
2210 PIXEndEvent(cbD->cmdList);
2216void QRhiD3D12::debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg)
2221 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2222#ifdef QRHI_D3D12_HAS_OLD_PIX
2223 PIXSetMarker(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(msg).utf16()));
2230const QRhiNativeHandles *QRhiD3D12::nativeHandles(QRhiCommandBuffer *cb)
2232 return QRHI_RES(QD3D12CommandBuffer, cb)->nativeHandles();
2235void QRhiD3D12::beginExternal(QRhiCommandBuffer *cb)
2240void QRhiD3D12::endExternal(QRhiCommandBuffer *cb)
2242 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2243 cbD->resetPerPassState();
2244 bindShaderVisibleHeaps(cbD);
2245 if (cbD->currentTarget) {
2246 QD3D12RenderTargetData *rtD = rtData(cbD->currentTarget);
2247 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2250 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2254double QRhiD3D12::lastCompletedGpuTime(QRhiCommandBuffer *cb)
2256 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2257 return cbD->lastGpuTime;
2260static void calculateGpuTime(QD3D12CommandBuffer *cbD,
2261 int timestampPairStartIndex,
2262 const quint8 *readbackBufPtr,
2263 quint64 timestampTicksPerSecond)
2265 const size_t byteOffset = timestampPairStartIndex *
sizeof(quint64);
2266 const quint64 *p =
reinterpret_cast<
const quint64 *>(readbackBufPtr + byteOffset);
2267 const quint64 startTime = *p++;
2268 const quint64 endTime = *p;
2269 if (startTime < endTime) {
2270 const quint64 ticks = endTime - startTime;
2271 const double timeSec = ticks /
double(timestampTicksPerSecond);
2272 cbD->lastGpuTime = timeSec;
2276QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
2286 return QRhi::FrameOpDeviceLost;
2288 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
2289 currentSwapChain = swapChainD;
2290 currentFrameSlot = swapChainD->currentFrameSlot;
2291 QD3D12SwapChain::FrameResources &fr(swapChainD->frameRes[currentFrameSlot]);
2304 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2305 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2307 if (swapChainD->frameLatencyWaitableObject) {
2309 if (swapChainD->lastFrameLatencyWaitSlot != currentFrameSlot) {
2310 WaitForSingleObjectEx(swapChainD->frameLatencyWaitableObject, 1000,
true);
2311 swapChainD->lastFrameLatencyWaitSlot = currentFrameSlot;
2315 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2317 qWarning(
"Failed to reset command allocator: %s",
2318 qPrintable(QSystemError::windowsComString(hr)));
2319 return QRhi::FrameOpError;
2322 if (!startCommandListForCurrentFrameSlot(&fr.cmdList))
2323 return QRhi::FrameOpError;
2325 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
2326 cbD->cmdList = fr.cmdList;
2328 swapChainD->rtWrapper.d.rtv[0] = swapChainD->sampleDesc.Count > 1
2329 ? swapChainD->msaaRtvs[currentFrameSlot].cpuHandle
2330 : swapChainD->rtvs[swapChainD->currentBackBufferIndex].cpuHandle;
2332 swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
2333 : D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
2335 if (swapChainD->stereo) {
2336 swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
2337 ? swapChainD->msaaRtvs[currentFrameSlot].cpuHandle
2338 : swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
2340 swapChainD->rtWrapperRight.d.dsv =
2341 swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
2348 releaseQueue.executeDeferredReleases(currentFrameSlot);
2354 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2357 resetAndResizeSmallStagingArea(currentFrameSlot);
2359 bindShaderVisibleHeaps(cbD);
2361 finishActiveReadbacks();
2363 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2366 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2367 calculateGpuTime(cbD,
2368 timestampPairStartIndex,
2369 timestampReadbackArea.mem.p,
2370 timestampTicksPerSecond);
2372 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2373 D3D12_QUERY_TYPE_TIMESTAMP,
2374 timestampPairStartIndex);
2377 QDxgiVSyncService::instance()->beginFrame(adapterLuid);
2379 return QRhi::FrameOpSuccess;
2382QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
2384 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
2385 Q_ASSERT(currentSwapChain == swapChainD);
2386 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
2388 QD3D12ObjectHandle backBufferResourceHandle = swapChainD->colorBuffers[swapChainD->currentBackBufferIndex];
2389 if (swapChainD->sampleDesc.Count > 1) {
2390 QD3D12ObjectHandle msaaBackBufferResourceHandle = swapChainD->msaaBuffers[currentFrameSlot];
2391 barrierGen.addTransitionBarrier(msaaBackBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2392 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2393 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2394 const QD3D12Resource *src = resourcePool.lookupRef(msaaBackBufferResourceHandle);
2395 const QD3D12Resource *dst = resourcePool.lookupRef(backBufferResourceHandle);
2397 cbD->cmdList->ResolveSubresource(dst->resource, 0, src->resource, 0, swapChainD->colorFormat);
2400 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
2401 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2403 if (timestampQueryHeap.isValid()) {
2404 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2405 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2406 D3D12_QUERY_TYPE_TIMESTAMP,
2407 timestampPairStartIndex + 1);
2408 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2409 D3D12_QUERY_TYPE_TIMESTAMP,
2410 timestampPairStartIndex,
2412 timestampReadbackArea.mem.buffer,
2413 timestampPairStartIndex *
sizeof(quint64));
2416 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2417 HRESULT hr = cmdList->Close();
2419 qWarning(
"Failed to close command list: %s",
2420 qPrintable(QSystemError::windowsComString(hr)));
2421 return QRhi::FrameOpError;
2424 ID3D12CommandList *execList[] = { cmdList };
2425 cmdQueue->ExecuteCommandLists(1, execList);
2427 if (!flags.testFlag(QRhi::SkipPresent)) {
2428 UINT presentFlags = 0;
2429 if (swapChainD->swapInterval == 0
2430 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
2432 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
2434 if (!swapChainD->swapChain) {
2435 qWarning(
"Failed to present, no swapchain");
2436 return QRhi::FrameOpError;
2438 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
2439 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
2440 qWarning(
"Device loss detected in Present()");
2442 return QRhi::FrameOpDeviceLost;
2443 }
else if (FAILED(hr)) {
2444 qWarning(
"Failed to present: %s", qPrintable(QSystemError::windowsComString(hr)));
2445 return QRhi::FrameOpError;
2448 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
2449 dcompDevice->Commit();
2452 swapChainD->addCommandCompletionSignalForCurrentFrameSlot();
2459 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2461 if (!flags.testFlag(QRhi::SkipPresent)) {
2465 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2466 swapChainD->currentBackBufferIndex = swapChainD->swapChain->GetCurrentBackBufferIndex();
2469 currentSwapChain =
nullptr;
2470 return QRhi::FrameOpSuccess;
2473QRhi::FrameOpResult QRhiD3D12::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
2486 currentFrameSlot = (currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2488 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2489 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2491 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2493 qWarning(
"Failed to reset command allocator: %s",
2494 qPrintable(QSystemError::windowsComString(hr)));
2495 return QRhi::FrameOpError;
2498 if (!offscreenCb[currentFrameSlot])
2499 offscreenCb[currentFrameSlot] =
new QD3D12CommandBuffer(
this);
2500 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2501 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2502 return QRhi::FrameOpError;
2504 releaseQueue.executeDeferredReleases(currentFrameSlot);
2506 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2507 resetAndResizeSmallStagingArea(currentFrameSlot);
2509 bindShaderVisibleHeaps(cbD);
2511 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2512 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2513 D3D12_QUERY_TYPE_TIMESTAMP,
2514 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT);
2517 offscreenActive =
true;
2520 return QRhi::FrameOpSuccess;
2523QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
2526 Q_ASSERT(offscreenActive);
2527 offscreenActive =
false;
2529 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2530 if (timestampQueryHeap.isValid()) {
2531 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2532 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2533 D3D12_QUERY_TYPE_TIMESTAMP,
2534 timestampPairStartIndex + 1);
2535 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2536 D3D12_QUERY_TYPE_TIMESTAMP,
2537 timestampPairStartIndex,
2539 timestampReadbackArea.mem.buffer,
2540 timestampPairStartIndex *
sizeof(quint64));
2543 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2544 HRESULT hr = cmdList->Close();
2546 qWarning(
"Failed to close command list: %s",
2547 qPrintable(QSystemError::windowsComString(hr)));
2548 return QRhi::FrameOpError;
2551 ID3D12CommandList *execList[] = { cmdList };
2552 cmdQueue->ExecuteCommandLists(1, execList);
2554 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2561 finishActiveReadbacks(
true);
2564 if (timestampQueryHeap.isValid()) {
2565 calculateGpuTime(cbD,
2566 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT,
2567 timestampReadbackArea.mem.p,
2568 timestampTicksPerSecond);
2571 return QRhi::FrameOpSuccess;
2574QRhi::FrameOpResult QRhiD3D12::finish()
2576 QD3D12CommandBuffer *cbD =
nullptr;
2578 if (offscreenActive) {
2579 Q_ASSERT(!currentSwapChain);
2580 cbD = offscreenCb[currentFrameSlot];
2582 Q_ASSERT(currentSwapChain);
2583 cbD = ¤tSwapChain->cbWrapper;
2586 return QRhi::FrameOpError;
2588 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2590 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2591 HRESULT hr = cmdList->Close();
2593 qWarning(
"Failed to close command list: %s",
2594 qPrintable(QSystemError::windowsComString(hr)));
2595 return QRhi::FrameOpError;
2598 ID3D12CommandList *execList[] = { cmdList };
2599 cmdQueue->ExecuteCommandLists(1, execList);
2601 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2608 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2610 qWarning(
"Failed to reset command allocator: %s",
2611 qPrintable(QSystemError::windowsComString(hr)));
2612 return QRhi::FrameOpError;
2615 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2616 return QRhi::FrameOpError;
2620 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2621 smallStagingAreas[currentFrameSlot].head = 0;
2623 bindShaderVisibleHeaps(cbD);
2626 releaseQueue.releaseAll();
2627 finishActiveReadbacks(
true);
2629 return QRhi::FrameOpSuccess;
2632void QRhiD3D12::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2634 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2635 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2636 enqueueResourceUpdates(cbD, resourceUpdates);
2639void QRhiD3D12::beginPass(QRhiCommandBuffer *cb,
2640 QRhiRenderTarget *rt,
2641 const QColor &colorClearValue,
2642 const QRhiDepthStencilClearValue &depthStencilClearValue,
2643 QRhiResourceUpdateBatch *resourceUpdates,
2644 QRhiCommandBuffer::BeginPassFlags)
2646 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2647 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2649 if (resourceUpdates)
2650 enqueueResourceUpdates(cbD, resourceUpdates);
2652 QD3D12RenderTargetData *rtD = rtData(rt);
2653 bool wantsColorClear =
true;
2654 bool wantsDsClear =
true;
2655 if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) {
2656 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, rt);
2657 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2658 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2659 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2662 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); it != itEnd; ++it) {
2663 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
2664 QD3D12Texture *resolveTexD = QRHI_RES(QD3D12Texture, it->resolveTexture());
2665 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
2667 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2669 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2671 barrierGen.addTransitionBarrier(resolveTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2673 if (rtTex->m_desc.depthStencilBuffer()) {
2674 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rtTex->m_desc.depthStencilBuffer());
2675 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
2676 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2677 }
else if (rtTex->m_desc.depthTexture()) {
2678 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, rtTex->m_desc.depthTexture());
2679 barrierGen.addTransitionBarrier(depthTexD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2681 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2683 Q_ASSERT(currentSwapChain);
2684 barrierGen.addTransitionBarrier(currentSwapChain->sampleDesc.Count > 1
2685 ? currentSwapChain->msaaBuffers[currentFrameSlot]
2686 : currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex],
2687 D3D12_RESOURCE_STATE_RENDER_TARGET);
2688 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2691 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2694 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2696 if (rtD->colorAttCount && wantsColorClear) {
2697 float clearColor[4] = {
2698 colorClearValue.redF(),
2699 colorClearValue.greenF(),
2700 colorClearValue.blueF(),
2701 colorClearValue.alphaF()
2703 for (
int i = 0; i < rtD->colorAttCount; ++i)
2704 cbD->cmdList->ClearRenderTargetView(rtD->rtv[i], clearColor, 0,
nullptr);
2706 if (rtD->dsAttCount && wantsDsClear) {
2707 cbD->cmdList->ClearDepthStencilView(rtD->dsv,
2708 D3D12_CLEAR_FLAGS(D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL),
2709 depthStencilClearValue.depthClearValue(),
2710 UINT8(depthStencilClearValue.stencilClearValue()),
2715 cbD->recordingPass = QD3D12CommandBuffer::RenderPass;
2716 cbD->currentTarget = rt;
2718 bool hasShadingRateMapSet =
false;
2719#ifdef QRHI_D3D12_CL5_AVAILABLE
2720 if (rtD->rp->hasShadingRateMap) {
2721 cbD->setShadingRate(QSize(1, 1));
2722 QD3D12ShadingRateMap *rateMapD = rt->resourceType() == QRhiRenderTarget::TextureRenderTarget
2723 ? QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12TextureRenderTarget, rt)->m_desc.shadingRateMap())
2724 : QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12SwapChainRenderTarget, rt)->swapChain()->shadingRateMap());
2725 if (QD3D12Resource *res = resourcePool.lookupRef(rateMapD->handle)) {
2726 barrierGen.addTransitionBarrier(rateMapD->handle, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
2727 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2728 cbD->cmdList->RSSetShadingRateImage(res->resource);
2729 hasShadingRateMapSet =
true;
2731 }
else if (cbD->hasShadingRateMapSet) {
2732 cbD->cmdList->RSSetShadingRateImage(
nullptr);
2733 cbD->setShadingRate(QSize(1, 1));
2734 }
else if (cbD->hasShadingRateSet) {
2735 cbD->setShadingRate(QSize(1, 1));
2739 cbD->resetPerPassState();
2742 cbD->hasShadingRateMapSet = hasShadingRateMapSet;
2745void QRhiD3D12::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2747 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2748 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2750 if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
2751 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, cbD->currentTarget);
2752 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2755 const QRhiColorAttachment &colorAtt(*it);
2756 if (!colorAtt.resolveTexture())
2759 QD3D12Texture *dstTexD = QRHI_RES(QD3D12Texture, colorAtt.resolveTexture());
2760 QD3D12Resource *dstRes = resourcePool.lookupRef(dstTexD->handle);
2764 QD3D12Texture *srcTexD = QRHI_RES(QD3D12Texture, colorAtt.texture());
2765 QD3D12RenderBuffer *srcRbD = QRHI_RES(QD3D12RenderBuffer, colorAtt.renderBuffer());
2766 Q_ASSERT(srcTexD || srcRbD);
2767 QD3D12Resource *srcRes = resourcePool.lookupRef(srcTexD ? srcTexD->handle : srcRbD->handle);
2772 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2773 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2774 int(srcTexD->dxgiFormat),
int(dstTexD->dxgiFormat));
2777 if (srcTexD->sampleDesc.Count <= 1) {
2778 qWarning(
"Cannot resolve a non-multisample texture");
2781 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2782 qWarning(
"Resolve source and destination sizes do not match");
2786 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2787 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2788 int(srcRbD->dxgiFormat),
int(dstTexD->dxgiFormat));
2791 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2792 qWarning(
"Resolve source and destination sizes do not match");
2803 const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
2804 QBitArray &initialized(dstTexD->subresourceInitialized);
2805 QVarLengthArray<UINT, 4> dstSubresources;
2806 QVarLengthArray<UINT, 4> subresourcesToDiscard;
2807 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2808 const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
2809 UINT(colorAtt.resolveLayer()) + resolveIdx,
2810 dstTexD->mipLevelCount);
2811 dstSubresources.append(dstSubresource);
2812 if (
int(dstSubresource) >= initialized.size())
2813 initialized.resize(
int(dstSubresource) + 1);
2814 if (!initialized.testBit(
int(dstSubresource))) {
2815 initialized.setBit(
int(dstSubresource));
2816 subresourcesToDiscard.append(dstSubresource);
2820 barrierGen.addTransitionBarrier(srcTexD ? srcTexD->handle : srcRbD->handle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2823 if (!subresourcesToDiscard.isEmpty()) {
2824 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2825 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2826 for (UINT dstSubresource : subresourcesToDiscard) {
2827 D3D12_DISCARD_REGION region = {};
2828 region.FirstSubresource = dstSubresource;
2829 region.NumSubresources = 1;
2830 cbD->cmdList->DiscardResource(dstRes->resource, ®ion);
2834 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2835 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2837 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2838 const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
2839 cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresources[resolveIdx],
2840 srcRes->resource, srcSubresource,
2841 dstTexD->dxgiFormat);
2844 if (rtTex->m_desc.depthResolveTexture())
2845 qWarning(
"Resolving multisample depth-stencil buffers is not supported with D3D");
2848 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2849 cbD->currentTarget =
nullptr;
2851 if (resourceUpdates)
2852 enqueueResourceUpdates(cbD, resourceUpdates);
2855void QRhiD3D12::beginComputePass(QRhiCommandBuffer *cb,
2856 QRhiResourceUpdateBatch *resourceUpdates,
2857 QRhiCommandBuffer::BeginPassFlags)
2859 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2860 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2862 if (resourceUpdates)
2863 enqueueResourceUpdates(cbD, resourceUpdates);
2865 cbD->recordingPass = QD3D12CommandBuffer::ComputePass;
2867 cbD->resetPerPassState();
2870void QRhiD3D12::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2872 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2873 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2875 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2877 if (resourceUpdates)
2878 enqueueResourceUpdates(cbD, resourceUpdates);
2881void QRhiD3D12::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
2883 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2884 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2885 QD3D12ComputePipeline *psD = QRHI_RES(QD3D12ComputePipeline, ps);
2886 const bool pipelineChanged = cbD->currentComputePipeline != psD || cbD->currentPipelineGeneration != psD->generation;
2888 if (pipelineChanged) {
2889 cbD->currentGraphicsPipeline =
nullptr;
2890 cbD->currentComputePipeline = psD;
2891 cbD->currentPipelineGeneration = psD->generation;
2893 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
2894 Q_ASSERT(pipeline->type == QD3D12Pipeline::Compute);
2895 cbD->cmdList->SetPipelineState(pipeline->pso);
2896 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
2897 cbD->cmdList->SetComputeRootSignature(rs->rootSig);
2902void QRhiD3D12::dispatch(QRhiCommandBuffer *cb,
int x,
int y,
int z)
2904 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2905 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2906 cbD->cmdList->Dispatch(UINT(x), UINT(y), UINT(z));
2912ID3D12CommandSignature *QRhiD3D12::indirectDrawCommandSignature(
bool indexed, quint32 stride)
2914 const quint32 canonicalStride = indexed ?
sizeof(QRhiIndexedIndirectDrawCommand)
2915 :
sizeof(QRhiIndirectDrawCommand);
2916 if (stride == canonicalStride)
2917 return indexed ? drawIndexedCommandSignature : drawCommandSignature;
2919 QHash<quint32, ID3D12CommandSignature *> &cache(indexed ? drawIndexedCommandSignaturesByStride
2920 : drawCommandSignaturesByStride);
2921 auto it = cache.constFind(stride);
2922 if (it != cache.constEnd())
2925 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
2926 arg.Type = indexed ? D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED : D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
2928 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
2929 sigDesc.ByteStride = stride;
2930 sigDesc.NumArgumentDescs = 1;
2931 sigDesc.pArgumentDescs = &arg;
2933 ID3D12CommandSignature *sig =
nullptr;
2934 HRESULT hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&sig));
2936 qWarning(
"Failed to create indirect draw command signature with stride %u: %s",
2937 stride, qPrintable(QSystemError::windowsComString(hr)));
2941 cache.insert(stride, sig);
2945void QRhiD3D12::drawIndirectCount(QRhiCommandBuffer *cb,
2946 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
2947 QRhiBuffer *countBuffer, quint32 countBufferOffset,
2948 quint32 maxDrawCount, quint32 stride)
2950 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2951 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2953 ID3D12CommandSignature *sig = indirectDrawCommandSignature(
false, stride);
2957 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2958 const bool indirectIsDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2959 const QD3D12ObjectHandle indirectHandle = indirectBufferD->handles[indirectIsDynamic ? currentFrameSlot : 0];
2960 if (indirectIsDynamic)
2961 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2963 barrierGen.addTransitionBarrier(indirectHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2965 QD3D12Buffer *countBufferD = QRHI_RES(QD3D12Buffer, countBuffer);
2966 const bool countIsDynamic = countBufferD->m_type == QRhiBuffer::Dynamic;
2967 const QD3D12ObjectHandle countHandle = countBufferD->handles[countIsDynamic ? currentFrameSlot : 0];
2969 countBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2971 barrierGen.addTransitionBarrier(countHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2973 if (!indirectIsDynamic || !countIsDynamic)
2974 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2976 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectHandle);
2977 QD3D12Resource *countRes = resourcePool.lookupRef(countHandle);
2978 if (!indirectRes || !countRes)
2981 cbD->cmdList->ExecuteIndirect(sig, maxDrawCount,
2982 indirectRes->resource, indirectBufferOffset,
2983 countRes->resource, countBufferOffset);
2986void QRhiD3D12::drawIndexedIndirectCount(QRhiCommandBuffer *cb,
2987 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
2988 QRhiBuffer *countBuffer, quint32 countBufferOffset,
2989 quint32 maxDrawCount, quint32 stride)
2991 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2992 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2994 ID3D12CommandSignature *sig = indirectDrawCommandSignature(
true, stride);
2998 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2999 const bool indirectIsDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
3000 const QD3D12ObjectHandle indirectHandle = indirectBufferD->handles[indirectIsDynamic ? currentFrameSlot : 0];
3001 if (indirectIsDynamic)
3002 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
3004 barrierGen.addTransitionBarrier(indirectHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
3006 QD3D12Buffer *countBufferD = QRHI_RES(QD3D12Buffer, countBuffer);
3007 const bool countIsDynamic = countBufferD->m_type == QRhiBuffer::Dynamic;
3008 const QD3D12ObjectHandle countHandle = countBufferD->handles[countIsDynamic ? currentFrameSlot : 0];
3010 countBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
3012 barrierGen.addTransitionBarrier(countHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
3014 if (!indirectIsDynamic || !countIsDynamic)
3015 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3017 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectHandle);
3018 QD3D12Resource *countRes = resourcePool.lookupRef(countHandle);
3019 if (!indirectRes || !countRes)
3022 cbD->cmdList->ExecuteIndirect(sig, maxDrawCount,
3023 indirectRes->resource, indirectBufferOffset,
3024 countRes->resource, countBufferOffset);
3027void QRhiD3D12::dispatchIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
3028 quint32 indirectBufferOffset)
3030 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
3031 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
3033 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
3034 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
3035 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
3037 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
3042 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
3043 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3045 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
3049 cbD->cmdList->ExecuteIndirect(dispatchCommandSignature, 1,
3050 indirectRes->resource, indirectBufferOffset,
3054bool QD3D12DescriptorHeap::create(ID3D12Device *device,
3055 quint32 descriptorCount,
3056 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
3057 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags)
3060 capacity = descriptorCount;
3061 this->heapType = heapType;
3062 this->heapFlags = heapFlags;
3064 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
3065 heapDesc.Type = heapType;
3066 heapDesc.NumDescriptors = capacity;
3067 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS(heapFlags);
3069 HRESULT hr = device->CreateDescriptorHeap(&heapDesc, __uuidof(ID3D12DescriptorHeap),
reinterpret_cast<
void **>(&heap));
3071 qWarning(
"Failed to create descriptor heap: %s", qPrintable(QSystemError::windowsComString(hr)));
3073 capacity = descriptorByteSize = 0;
3077 descriptorByteSize = device->GetDescriptorHandleIncrementSize(heapType);
3078 heapStart.cpuHandle = heap->GetCPUDescriptorHandleForHeapStart();
3079 if (heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
3080 heapStart.gpuHandle = heap->GetGPUDescriptorHandleForHeapStart();
3085void QD3D12DescriptorHeap::createWithExisting(
const QD3D12DescriptorHeap &other,
3086 quint32 offsetInDescriptors,
3087 quint32 descriptorCount)
3091 capacity = descriptorCount;
3092 heapType = other.heapType;
3093 heapFlags = other.heapFlags;
3094 descriptorByteSize = other.descriptorByteSize;
3095 heapStart = incremented(other.heapStart, offsetInDescriptors);
3098void QD3D12DescriptorHeap::destroy()
3107void QD3D12DescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3110 releaseQueue->deferredReleaseDescriptorHeap(heap);
3116QD3D12Descriptor QD3D12DescriptorHeap::get(quint32 count)
3118 Q_ASSERT(count > 0);
3119 if (head + count > capacity) {
3120 qWarning(
"Cannot get %u descriptors as that would exceed capacity %u", count, capacity);
3124 return at(head - count);
3127QD3D12Descriptor QD3D12DescriptorHeap::at(quint32 index)
const
3129 const quint32 startOffset = index * descriptorByteSize;
3130 QD3D12Descriptor result;
3131 result.cpuHandle.ptr = heapStart.cpuHandle.ptr + startOffset;
3132 if (heapStart.gpuHandle.ptr != 0)
3133 result.gpuHandle.ptr = heapStart.gpuHandle.ptr + startOffset;
3137bool QD3D12CpuDescriptorPool::create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName)
3139 QD3D12DescriptorHeap firstHeap;
3140 if (!firstHeap.create(device, DESCRIPTORS_PER_HEAP, heapType, D3D12_DESCRIPTOR_HEAP_FLAG_NONE))
3142 heaps.append(HeapWithMap::init(firstHeap, DESCRIPTORS_PER_HEAP));
3143 descriptorByteSize = heaps[0].heap.descriptorByteSize;
3144 this->device = device;
3145 this->debugName = debugName;
3149void QD3D12CpuDescriptorPool::destroy()
3153 static bool leakCheck =
true;
3156 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
3159 for (
const HeapWithMap &heap : std::as_const(heaps)) {
3160 const int leakedDescriptorCount = heap.map.count(
true);
3161 if (leakedDescriptorCount > 0) {
3162 qWarning(
"QD3D12CpuDescriptorPool::destroy(): "
3163 "Heap %p for descriptor pool %p '%s' has %d unreleased descriptors",
3164 &heap.heap,
this, debugName, leakedDescriptorCount);
3168 for (HeapWithMap &heap : heaps)
3169 heap.heap.destroy();
3173QD3D12Descriptor QD3D12CpuDescriptorPool::allocate(quint32 count)
3175 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
3177 HeapWithMap &last(heaps.last());
3178 if (last.heap.head + count <= last.heap.capacity) {
3179 quint32 firstIndex = last.heap.head;
3180 for (quint32 i = 0; i < count; ++i)
3181 last.map.setBit(firstIndex + i);
3182 return last.heap.get(count);
3185 for (HeapWithMap &heap : heaps) {
3186 quint32 freeCount = 0;
3187 for (quint32 i = 0; i < DESCRIPTORS_PER_HEAP; ++i) {
3188 if (heap.map.testBit(i)) {
3192 if (freeCount == count) {
3193 const quint32 firstIndex = i - (freeCount - 1);
3194 for (quint32 j = 0; j < count; ++j)
3195 heap.map.setBit(firstIndex + j);
3199 if (firstIndex + count > heap.heap.head)
3200 heap.heap.head = firstIndex + count;
3201 return heap.heap.at(firstIndex);
3207 QD3D12DescriptorHeap newHeap;
3208 if (!newHeap.create(device, DESCRIPTORS_PER_HEAP, last.heap.heapType, last.heap.heapFlags))
3211 heaps.append(HeapWithMap::init(newHeap, DESCRIPTORS_PER_HEAP));
3213 for (quint32 i = 0; i < count; ++i)
3214 heaps.last().map.setBit(i);
3216 return heaps.last().heap.get(count);
3219void QD3D12CpuDescriptorPool::release(
const QD3D12Descriptor &descriptor, quint32 count)
3221 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
3222 if (!descriptor.isValid())
3225 const SIZE_T addr = descriptor.cpuHandle.ptr;
3226 for (HeapWithMap &heap : heaps) {
3227 const SIZE_T begin = heap.heap.heapStart.cpuHandle.ptr;
3228 const SIZE_T end = begin + heap.heap.descriptorByteSize * heap.heap.capacity;
3229 if (addr >= begin && addr < end) {
3230 quint32 firstIndex = (addr - begin) / heap.heap.descriptorByteSize;
3231 for (quint32 i = 0; i < count; ++i)
3232 heap.map.setBit(firstIndex + i,
false);
3237 qWarning(
"QD3D12CpuDescriptorPool::release: Descriptor with address %llu is not in any heap",
3238 quint64(descriptor.cpuHandle.ptr));
3241bool QD3D12QueryHeap::create(ID3D12Device *device,
3243 D3D12_QUERY_HEAP_TYPE heapType)
3245 capacity = queryCount;
3247 D3D12_QUERY_HEAP_DESC heapDesc = {};
3248 heapDesc.Type = heapType;
3249 heapDesc.Count = capacity;
3251 HRESULT hr = device->CreateQueryHeap(&heapDesc, __uuidof(ID3D12QueryHeap),
reinterpret_cast<
void **>(&heap));
3253 qWarning(
"Failed to create query heap: %s", qPrintable(QSystemError::windowsComString(hr)));
3262void QD3D12QueryHeap::destroy()
3271bool QD3D12StagingArea::create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType)
3273 Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
3274 D3D12_RESOURCE_DESC resourceDesc = {};
3275 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
3276 resourceDesc.Width = capacity;
3277 resourceDesc.Height = 1;
3278 resourceDesc.DepthOrArraySize = 1;
3279 resourceDesc.MipLevels = 1;
3280 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
3281 resourceDesc.SampleDesc = { 1, 0 };
3282 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
3283 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
3284 UINT state = heapType == D3D12_HEAP_TYPE_UPLOAD ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
3285 HRESULT hr = rhi->vma.createResource(heapType,
3287 D3D12_RESOURCE_STATES(state),
3290 __uuidof(ID3D12Resource),
3291 reinterpret_cast<
void **>(&resource));
3293 qWarning(
"Failed to create buffer for staging area: %s",
3294 qPrintable(QSystemError::windowsComString(hr)));
3298 hr = resource->Map(0,
nullptr, &p);
3300 qWarning(
"Failed to map buffer for staging area: %s",
3301 qPrintable(QSystemError::windowsComString(hr)));
3306 mem.p =
static_cast<quint8 *>(p);
3307 mem.gpuAddr = resource->GetGPUVirtualAddress();
3308 mem.buffer = resource;
3309 mem.bufferOffset = 0;
3311 this->capacity = capacity;
3317void QD3D12StagingArea::destroy()
3320 resource->Release();
3324 allocation->Release();
3325 allocation =
nullptr;
3330void QD3D12StagingArea::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3333 releaseQueue->deferredReleaseResourceAndAllocation(resource, allocation);
3337QD3D12StagingArea::Allocation QD3D12StagingArea::get(quint32 byteSize)
3339 const quint32 allocSize = aligned(byteSize, ALIGNMENT);
3340 if (head + allocSize > capacity) {
3341 qWarning(
"Failed to allocate %u (%u) bytes from staging area of size %u with %u bytes left",
3342 allocSize, byteSize, capacity, remainingCapacity());
3345 const quint32 offset = head;
3349 mem.gpuAddr + offset,
3358void QD3D12ReleaseQueue::deferredReleaseResource(
const QD3D12ObjectHandle &handle)
3360 DeferredReleaseEntry e;
3365void QD3D12ReleaseQueue::deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
3366 QD3D12CpuDescriptorPool *pool,
3367 const QD3D12Descriptor &viewsStart,
3370 DeferredReleaseEntry e;
3371 e.type = DeferredReleaseEntry::Resource;
3373 e.poolForViews = pool;
3374 e.viewsStart = viewsStart;
3375 e.viewCount = viewCount;
3379void QD3D12ReleaseQueue::deferredReleasePipeline(
const QD3D12ObjectHandle &handle)
3381 DeferredReleaseEntry e;
3382 e.type = DeferredReleaseEntry::Pipeline;
3387void QD3D12ReleaseQueue::deferredReleaseRootSignature(
const QD3D12ObjectHandle &handle)
3389 DeferredReleaseEntry e;
3390 e.type = DeferredReleaseEntry::RootSignature;
3395void QD3D12ReleaseQueue::deferredReleaseCallback(std::function<
void(
void*)> callback,
void *userData)
3397 DeferredReleaseEntry e;
3398 e.type = DeferredReleaseEntry::Callback;
3399 e.callback = callback;
3400 e.callbackUserData = userData;
3404void QD3D12ReleaseQueue::deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
3405 D3D12MA::Allocation *allocation)
3407 DeferredReleaseEntry e;
3408 e.type = DeferredReleaseEntry::ResourceAndAllocation;
3409 e.resourceAndAllocation = { resource, allocation };
3413void QD3D12ReleaseQueue::deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap)
3415 DeferredReleaseEntry e;
3416 e.type = DeferredReleaseEntry::DescriptorHeap;
3417 e.descriptorHeap = heap;
3421void QD3D12ReleaseQueue::deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
3422 const QD3D12Descriptor &viewsStart,
3425 DeferredReleaseEntry e;
3426 e.type = DeferredReleaseEntry::Views;
3427 e.poolForViews = pool;
3428 e.viewsStart = viewsStart;
3429 e.viewCount = viewCount;
3433void QD3D12ReleaseQueue::activatePendingDeferredReleaseRequests(
int frameSlot)
3435 for (DeferredReleaseEntry &e : queue) {
3436 if (!e.frameSlotToBeReleasedIn.has_value())
3437 e.frameSlotToBeReleasedIn = frameSlot;
3441void QD3D12ReleaseQueue::executeDeferredReleases(
int frameSlot,
bool forced)
3443 qsizetype keepBegin = queue.size();
3444 for (qsizetype i = keepBegin - 1; i >= 0; --i) {
3445 const DeferredReleaseEntry &e(queue[i]);
3446 if (forced || (e.frameSlotToBeReleasedIn.has_value() && e.frameSlotToBeReleasedIn.value() == frameSlot)) {
3448 case DeferredReleaseEntry::Resource:
3449 resourcePool->remove(e.handle);
3450 if (e.poolForViews && e.viewsStart.isValid() && e.viewCount > 0)
3451 e.poolForViews->release(e.viewsStart, e.viewCount);
3453 case DeferredReleaseEntry::Pipeline:
3454 pipelinePool->remove(e.handle);
3456 case DeferredReleaseEntry::RootSignature:
3457 rootSignaturePool->remove(e.handle);
3459 case DeferredReleaseEntry::Callback:
3460 e.callback(e.callbackUserData);
3462 case DeferredReleaseEntry::ResourceAndAllocation:
3465 e.resourceAndAllocation.first->Release();
3466 if (e.resourceAndAllocation.second)
3467 e.resourceAndAllocation.second->Release();
3469 case DeferredReleaseEntry::DescriptorHeap:
3470 e.descriptorHeap->Release();
3472 case DeferredReleaseEntry::Views:
3473 e.poolForViews->release(e.viewsStart, e.viewCount);
3476 }
else if (--keepBegin != i) {
3477 queue[keepBegin] = std::move(queue[i]);
3481 queue.remove(0, keepBegin);
3484void QD3D12ReleaseQueue::releaseAll()
3486 executeDeferredReleases(0,
true);
3489void QD3D12ResourceBarrierGenerator::addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle,
3490 D3D12_RESOURCE_STATES stateAfter)
3492 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3493 if (stateAfter != res->state) {
3494 transitionResourceBarriers.append({ resourceHandle, res->state, stateAfter });
3495 res->state = stateAfter;
3500void QD3D12ResourceBarrierGenerator::enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD)
3502 QVarLengthArray<D3D12_RESOURCE_BARRIER, PREALLOC> barriers;
3503 for (
const TransitionResourceBarrier &trb : transitionResourceBarriers) {
3504 if (QD3D12Resource *res = resourcePool->lookupRef(trb.resourceHandle)) {
3505 D3D12_RESOURCE_BARRIER barrier = {};
3506 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
3507 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3508 barrier.Transition.pResource = res->resource;
3509 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
3510 barrier.Transition.StateBefore = trb.stateBefore;
3511 barrier.Transition.StateAfter = trb.stateAfter;
3512 barriers.append(barrier);
3515 transitionResourceBarriers.clear();
3516 if (!barriers.isEmpty())
3517 cbD->cmdList->ResourceBarrier(barriers.count(), barriers.constData());
3520void QD3D12ResourceBarrierGenerator::enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
3521 const QD3D12ObjectHandle &resourceHandle,
3523 D3D12_RESOURCE_STATES stateBefore,
3524 D3D12_RESOURCE_STATES stateAfter)
3526 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3527 D3D12_RESOURCE_BARRIER barrier = {};
3528 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
3529 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3530 barrier.Transition.pResource = res->resource;
3531 barrier.Transition.Subresource = subresource;
3532 barrier.Transition.StateBefore = stateBefore;
3533 barrier.Transition.StateAfter = stateAfter;
3534 cbD->cmdList->ResourceBarrier(1, &barrier);
3538void QD3D12ResourceBarrierGenerator::enqueueUavBarrier(QD3D12CommandBuffer *cbD,
3539 const QD3D12ObjectHandle &resourceHandle)
3541 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3542 D3D12_RESOURCE_BARRIER barrier = {};
3543 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
3544 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3545 barrier.UAV.pResource = res->resource;
3546 cbD->cmdList->ResourceBarrier(1, &barrier);
3550void QD3D12ShaderBytecodeCache::insertWithCapacityLimit(
const QRhiShaderStage &key,
const Shader &s)
3552 if (data.count() >= QRhiD3D12::MAX_SHADER_CACHE_ENTRIES)
3554 data.insert(key, s);
3557bool QD3D12ShaderVisibleDescriptorHeap::create(ID3D12Device *device,
3558 D3D12_DESCRIPTOR_HEAP_TYPE type,
3559 quint32 perFrameDescriptorCount)
3561 Q_ASSERT(type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
3563 quint32 size = perFrameDescriptorCount * QD3D12_FRAMES_IN_FLIGHT;
3566 const quint32 CBV_SRV_UAV_MAX = 1000000;
3567 const quint32 SAMPLER_MAX = 2048;
3568 if (type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
3569 size = qMin(size, CBV_SRV_UAV_MAX);
3570 else if (type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
3571 size = qMin(size, SAMPLER_MAX);
3573 if (!heap.create(device, size, type, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
3574 qWarning(
"Failed to create shader-visible descriptor heap of size %u", size);
3578 perFrameDescriptorCount = size / QD3D12_FRAMES_IN_FLIGHT;
3579 quint32 currentOffsetInDescriptors = 0;
3580 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3581 perFrameHeapSlice[i].createWithExisting(heap, currentOffsetInDescriptors, perFrameDescriptorCount);
3582 currentOffsetInDescriptors += perFrameDescriptorCount;
3588void QD3D12ShaderVisibleDescriptorHeap::destroy()
3593void QD3D12ShaderVisibleDescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3595 heap.destroyWithDeferredRelease(releaseQueue);
3598static inline std::pair<
int,
int> mapBinding(
int binding,
const QD3D12ShaderStageData *sd)
3600 const QShader::NativeResourceBindingMap &map(sd->nativeResourceBindingMap);
3601 if (map.isEmpty()) {
3609 if (sd->pushConstantRegister >= 0)
3611 return { binding, binding };
3614 auto it = map.constFind(binding);
3615 if (it != map.cend())
3624void QD3D12ShaderResourceVisitor::visit()
3626 for (
int bindingIdx = 0, bindingCount = srb->m_bindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
3627 const QRhiShaderResourceBinding &b(srb->m_bindings[bindingIdx]);
3628 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
3630 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
3631 const QD3D12ShaderStageData *sd = &stageData[stageIdx];
3635 if (!bd->stage.testFlag(qd3d12_stageToSrb(sd->stage)))
3639 case QRhiShaderResourceBinding::UniformBuffer:
3641 const int shaderRegister = mapBinding(bd->binding, sd).first;
3642 if (shaderRegister >= 0 && uniformBuffer)
3643 uniformBuffer(sd->stage, bd->u.ubuf, shaderRegister, bd->binding);
3646 case QRhiShaderResourceBinding::SampledTexture:
3648 Q_ASSERT(bd->u.stex.count > 0);
3649 const int textureBaseShaderRegister = mapBinding(bd->binding, sd).first;
3650 const int samplerBaseShaderRegister = mapBinding(bd->binding, sd).second;
3651 if (textureBaseShaderRegister >= 0 && textures)
3652 textures(sd->stage, bd->u.stex.texSamplers, bd->u.stex.count, textureBaseShaderRegister);
3653 if (samplerBaseShaderRegister >= 0 && samplers)
3654 samplers(sd->stage, bd->u.stex.texSamplers, bd->u.stex.count, samplerBaseShaderRegister);
3657 case QRhiShaderResourceBinding::Texture:
3659 Q_ASSERT(bd->u.stex.count > 0);
3660 const int baseShaderRegister = mapBinding(bd->binding, sd).first;
3661 if (baseShaderRegister >= 0 && textures)
3662 textures(sd->stage, bd->u.stex.texSamplers, bd->u.stex.count, baseShaderRegister);
3665 case QRhiShaderResourceBinding::Sampler:
3667 Q_ASSERT(bd->u.stex.count > 0);
3668 const int baseShaderRegister = mapBinding(bd->binding, sd).first;
3669 if (baseShaderRegister >= 0 && samplers)
3670 samplers(sd->stage, bd->u.stex.texSamplers, bd->u.stex.count, baseShaderRegister);
3673 case QRhiShaderResourceBinding::ImageLoad:
3675 const int shaderRegister = mapBinding(bd->binding, sd).first;
3676 if (shaderRegister >= 0 && storageImage)
3677 storageImage(sd->stage, bd->u.simage, Load, shaderRegister);
3680 case QRhiShaderResourceBinding::ImageStore:
3682 const int shaderRegister = mapBinding(bd->binding, sd).first;
3683 if (shaderRegister >= 0 && storageImage)
3684 storageImage(sd->stage, bd->u.simage, Store, shaderRegister);
3687 case QRhiShaderResourceBinding::ImageLoadStore:
3689 const int shaderRegister = mapBinding(bd->binding, sd).first;
3690 if (shaderRegister >= 0 && storageImage)
3691 storageImage(sd->stage, bd->u.simage, LoadStore, shaderRegister);
3694 case QRhiShaderResourceBinding::BufferLoad:
3696 const int shaderRegister = mapBinding(bd->binding, sd).first;
3697 if (shaderRegister >= 0 && storageBuffer)
3698 storageBuffer(sd->stage, bd->u.sbuf, Load, shaderRegister);
3701 case QRhiShaderResourceBinding::BufferStore:
3703 const int shaderRegister = mapBinding(bd->binding, sd).first;
3704 if (shaderRegister >= 0 && storageBuffer)
3705 storageBuffer(sd->stage, bd->u.sbuf, Store, shaderRegister);
3708 case QRhiShaderResourceBinding::BufferLoadStore:
3710 const int shaderRegister = mapBinding(bd->binding, sd).first;
3711 if (shaderRegister >= 0 && storageBuffer)
3712 storageBuffer(sd->stage, bd->u.sbuf, LoadStore, shaderRegister);
3720bool QD3D12SamplerManager::create(ID3D12Device *device)
3723 if (!shaderVisibleSamplerHeap.create(device,
3724 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
3725 MAX_SAMPLERS / QD3D12_FRAMES_IN_FLIGHT))
3727 qWarning(
"Could not create shader-visible SAMPLER heap");
3731 this->device = device;
3735void QD3D12SamplerManager::destroy()
3738 shaderVisibleSamplerHeap.destroy();
3743QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc)
3745 auto it = gpuMap.constFind({desc});
3746 if (it != gpuMap.cend())
3749 QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
3750 if (descriptor.isValid()) {
3751 device->CreateSampler(&desc, descriptor.cpuHandle);
3752 gpuMap.insert({desc}, descriptor);
3754 qWarning(
"Out of shader-visible SAMPLER descriptor heap space,"
3755 " this should not happen, maximum number of unique samplers is %u",
3756 shaderVisibleSamplerHeap.heap.capacity);
3762QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptors(
const QVarLengthArray<Q_D3D12_SAMPLER_DESC, 8> &descs)
3768 auto it = gpuArrayMap.constFind({ descs });
3769 if (it != gpuArrayMap.cend())
3772 const quint32 count = quint32(descs.count());
3773 QD3D12Descriptor startDescriptor = shaderVisibleSamplerHeap.heap.get(count);
3774 if (startDescriptor.isValid()) {
3775 for (quint32 i = 0; i < count; ++i) {
3776 device->CreateSampler(&descs[
int(i)].desc,
3777 shaderVisibleSamplerHeap.heap.incremented(startDescriptor, i).cpuHandle);
3779 gpuArrayMap.insert({ descs }, startDescriptor);
3786 qWarning(
"Out of shader-visible SAMPLER descriptor heap space when reserving"
3787 " %u consecutive descriptors for a sampler array, maximum number of"
3788 " sampler descriptors is %u",
3789 count, shaderVisibleSamplerHeap.heap.capacity);
3792 return startDescriptor;
3795void QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
3800bool QD3D12MipmapGenerator::ensureCreated()
3802 if (!pipelineHandle.isNull())
3808 if (!buildPipeline()) {
3809 createFailed =
true;
3816bool QD3D12MipmapGenerator::buildPipeline()
3818 qCDebug(QRHI_LOG_INFO,
"Building mipmap generator compute pipeline on first use");
3820 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3821 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3824 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3825 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3826 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3829 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3830 descriptorRanges[0].NumDescriptors = 1;
3831 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3832 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3833 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3834 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3835 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3838 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3839 descriptorRanges[1].NumDescriptors = 4;
3840 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3841 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3842 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3843 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3846 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3847 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3848 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3849 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3850 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3851 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3853 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3854 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3855 rsDesc.Desc_1_1.NumParameters = 3;
3856 rsDesc.Desc_1_1.pParameters = rootParams;
3857 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3858 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3860 ID3DBlob *signature =
nullptr;
3861 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3863 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3866 ID3D12RootSignature *rootSig =
nullptr;
3867 hr = rhiD->dev->CreateRootSignature(0,
3868 signature->GetBufferPointer(),
3869 signature->GetBufferSize(),
3870 __uuidof(ID3D12RootSignature),
3871 reinterpret_cast<
void **>(&rootSig));
3872 signature->Release();
3874 qWarning(
"Failed to create root signature: %s",
3875 qPrintable(QSystemError::windowsComString(hr)));
3879 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3881 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3882 psoDesc.pRootSignature = rootSig;
3883 psoDesc.CS.pShaderBytecode = g_csMipmap;
3884 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap);
3885 ID3D12PipelineState *pso =
nullptr;
3886 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3887 __uuidof(ID3D12PipelineState),
3888 reinterpret_cast<
void **>(&pso));
3890 qWarning(
"Failed to create compute pipeline state: %s",
3891 qPrintable(QSystemError::windowsComString(hr)));
3892 rhiD->rootSignaturePool.remove(rootSigHandle);
3897 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3902void QD3D12MipmapGenerator::destroy()
3909 rhiD->pipelinePool.remove(pipelineHandle);
3910 pipelineHandle = {};
3911 rhiD->rootSignaturePool.remove(rootSigHandle);
3913 createFailed =
false;
3916void QD3D12MipmapGenerator::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3918 if (!ensureCreated())
3921 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3924 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3927 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3931 const quint32 mipLevelCount = res->desc.MipLevels;
3932 if (mipLevelCount < 2)
3935 if (res->desc.SampleDesc.Count > 1) {
3936 qWarning(
"Cannot generate mipmaps for MSAA texture");
3940 const bool is1D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D;
3942 qWarning(
"Cannot generate mipmaps for 1D texture");
3946 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3947 const bool isCubeOrArray = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
3948 && res->desc.DepthOrArraySize > 1;
3949 const quint32 layerCount = isCubeOrArray ? res->desc.DepthOrArraySize : 1;
3952 qWarning(
"2D mipmap generator invoked for 3D texture, this should not happen");
3956 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3957 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3959 cbD->cmdList->SetPipelineState(pipeline->pso);
3960 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3962 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3965 quint32 srcMipLevel;
3966 quint32 numMipLevels;
3971 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount * layerCount);
3972 std::optional<QD3D12StagingArea> ownStagingArea;
3973 rhiD->recordSmallStagingAreaDemand(allocSize);
3974 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3975 ownStagingArea = QD3D12StagingArea();
3976 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3977 qWarning(
"Could not create staging area for mipmap generation");
3981 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3982 ? &ownStagingArea.value()
3983 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3985 bool gotNewHeap =
false;
3986 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3987 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3988 rhiD->currentFrameSlot,
3989 (1 + 4) * mipLevelCount * layerCount,
3992 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3996 rhiD->bindShaderVisibleHeaps(cbD);
3998 for (quint32 layer = 0; layer < layerCount; ++layer) {
3999 for (quint32 level = 0; level < mipLevelCount ;) {
4000 UINT subresource = calcSubresource(level, layer, res->desc.MipLevels);
4001 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4002 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
4003 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
4005 quint32 levelPlusOneMipWidth = res->desc.Width >> (level + 1);
4006 quint32 levelPlusOneMipHeight = res->desc.Height >> (level + 1);
4007 const quint32 dw = levelPlusOneMipWidth == 1 ? levelPlusOneMipHeight : levelPlusOneMipWidth;
4008 const quint32 dh = levelPlusOneMipHeight == 1 ? levelPlusOneMipWidth : levelPlusOneMipHeight;
4010 const quint32 additionalMips = qCountTrailingZeroBits(dw | dh);
4011 const quint32 numGenMips = qMin(1u + qMin(3u, additionalMips), res->desc.MipLevels - level);
4012 levelPlusOneMipWidth = qMax(1u, levelPlusOneMipWidth);
4013 levelPlusOneMipHeight = qMax(1u, levelPlusOneMipHeight);
4015 CBufData cbufData = {
4018 1.0f /
float(levelPlusOneMipWidth),
4019 1.0f /
float(levelPlusOneMipHeight)
4022 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
4023 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
4024 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
4026 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4027 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4028 srvDesc.Format = res->desc.Format;
4029 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4030 if (isCubeOrArray) {
4031 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
4032 srvDesc.Texture2DArray.MipLevels = res->desc.MipLevels;
4033 srvDesc.Texture2DArray.FirstArraySlice = layer;
4034 srvDesc.Texture2DArray.ArraySize = 1;
4036 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
4037 srvDesc.Texture2D.MipLevels = res->desc.MipLevels;
4039 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4040 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
4042 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(4);
4043 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
4045 for (quint32 uavIdx = 0; uavIdx < 4; ++uavIdx) {
4046 const quint32 uavMipLevel = qMin(level + 1u + uavIdx, res->desc.MipLevels - 1u);
4047 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
4048 uavDesc.Format = res->desc.Format;
4049 if (isCubeOrArray) {
4050 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
4051 uavDesc.Texture2DArray.MipSlice = uavMipLevel;
4052 uavDesc.Texture2DArray.FirstArraySlice = layer;
4053 uavDesc.Texture2DArray.ArraySize = 1;
4055 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
4056 uavDesc.Texture2D.MipSlice = uavMipLevel;
4058 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
4059 uavCpuHandle.ptr += descriptorByteSize;
4061 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
4063 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, 1);
4065 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
4066 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4067 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
4068 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4070 level += numGenMips;
4074 if (ownStagingArea.has_value())
4075 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
4078void QD3D12MipmapGenerator3D::create(QRhiD3D12 *rhiD)
4083bool QD3D12MipmapGenerator3D::ensureCreated()
4085 if (!pipelineHandle.isNull())
4091 if (!buildPipeline()) {
4092 createFailed =
true;
4099bool QD3D12MipmapGenerator3D::buildPipeline()
4101 qCDebug(QRHI_LOG_INFO,
"Building 3D texture mipmap generator compute pipeline on first use");
4103 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
4104 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
4107 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
4108 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4109 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
4112 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
4113 descriptorRanges[0].NumDescriptors = 1;
4114 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
4115 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
4116 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4117 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
4118 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
4121 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
4122 descriptorRanges[1].NumDescriptors = 1;
4123 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
4124 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4125 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
4126 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
4129 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
4130 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
4131 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4132 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4133 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4134 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4136 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
4137 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
4138 rsDesc.Desc_1_1.NumParameters = 3;
4139 rsDesc.Desc_1_1.pParameters = rootParams;
4140 rsDesc.Desc_1_1.NumStaticSamplers = 1;
4141 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
4143 ID3DBlob *signature =
nullptr;
4144 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
4146 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
4149 ID3D12RootSignature *rootSig =
nullptr;
4150 hr = rhiD->dev->CreateRootSignature(0,
4151 signature->GetBufferPointer(),
4152 signature->GetBufferSize(),
4153 __uuidof(ID3D12RootSignature),
4154 reinterpret_cast<
void **>(&rootSig));
4155 signature->Release();
4157 qWarning(
"Failed to create root signature: %s",
4158 qPrintable(QSystemError::windowsComString(hr)));
4162 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
4164 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
4165 psoDesc.pRootSignature = rootSig;
4166 psoDesc.CS.pShaderBytecode = g_csMipmap3D;
4167 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap3D);
4168 ID3D12PipelineState *pso =
nullptr;
4169 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
4170 __uuidof(ID3D12PipelineState),
4171 reinterpret_cast<
void **>(&pso));
4173 qWarning(
"Failed to create compute pipeline state: %s",
4174 qPrintable(QSystemError::windowsComString(hr)));
4175 rhiD->rootSignaturePool.remove(rootSigHandle);
4180 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
4185void QD3D12MipmapGenerator3D::destroy()
4190 rhiD->pipelinePool.remove(pipelineHandle);
4191 pipelineHandle = {};
4192 rhiD->rootSignaturePool.remove(rootSigHandle);
4194 createFailed =
false;
4197void QD3D12MipmapGenerator3D::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
4199 if (!ensureCreated())
4202 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
4205 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
4208 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
4212 const quint32 mipLevelCount = res->desc.MipLevels;
4213 if (mipLevelCount < 2)
4216 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
4218 qWarning(
"3D mipmap generator invoked for non-3D texture, this should not happen");
4222 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4223 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
4225 cbD->cmdList->SetPipelineState(pipeline->pso);
4226 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
4228 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
4234 quint32 srcMipLevel;
4237 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount);
4238 std::optional<QD3D12StagingArea> ownStagingArea;
4239 rhiD->recordSmallStagingAreaDemand(allocSize);
4240 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
4241 ownStagingArea = QD3D12StagingArea();
4242 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
4243 qWarning(
"Could not create staging area for mipmap generation");
4247 QD3D12StagingArea *workArea = ownStagingArea.has_value()
4248 ? &ownStagingArea.value()
4249 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
4251 bool gotNewHeap =
false;
4252 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
4253 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
4254 rhiD->currentFrameSlot,
4255 (1 + 1) * mipLevelCount,
4258 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
4262 rhiD->bindShaderVisibleHeaps(cbD);
4264 for (quint32 level = 0; level < mipLevelCount; ++level) {
4265 UINT subresource = calcSubresource(level, 0u, res->desc.MipLevels);
4266 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4267 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
4268 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
4270 quint32 levelPlusOneMipWidth = qMax<quint32>(1, res->desc.Width >> (level + 1));
4271 quint32 levelPlusOneMipHeight = qMax<quint32>(1, res->desc.Height >> (level + 1));
4272 quint32 levelPlusOneMipDepth = qMax<quint32>(1, res->desc.DepthOrArraySize >> (level + 1));
4274 CBufData cbufData = {
4275 1.0f /
float(levelPlusOneMipWidth),
4276 1.0f /
float(levelPlusOneMipHeight),
4277 1.0f /
float(levelPlusOneMipDepth),
4281 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
4282 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
4283 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
4285 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4286 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4287 srvDesc.Format = res->desc.Format;
4288 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4289 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4290 srvDesc.Texture3D.MipLevels = res->desc.MipLevels;
4292 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4293 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
4295 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4296 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
4297 const quint32 uavMipLevel = qMin(level + 1u, res->desc.MipLevels - 1u);
4298 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
4299 uavDesc.Format = res->desc.Format;
4300 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
4301 uavDesc.Texture3D.MipSlice = uavMipLevel;
4302 uavDesc.Texture3D.WSize = UINT(-1);
4303 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
4304 uavCpuHandle.ptr += descriptorByteSize;
4305 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
4307 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, levelPlusOneMipDepth);
4309 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
4310 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4311 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
4312 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4315 if (ownStagingArea.has_value())
4316 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
4319bool QD3D12MemoryAllocator::create(ID3D12Device *device, IDXGIAdapter1 *adapter)
4321 this->device = device;
4328 static bool disableMA = qEnvironmentVariableIntValue(
"QT_D3D_NO_SUBALLOC");
4332 DXGI_ADAPTER_DESC1 desc;
4333 adapter->GetDesc1(&desc);
4334 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
4337 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
4338 allocatorDesc.pDevice = device;
4339 allocatorDesc.pAdapter = adapter;
4342 allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED;
4343 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
4345 qWarning(
"Failed to initialize D3D12 Memory Allocator: %s",
4346 qPrintable(QSystemError::windowsComString(hr)));
4352void QD3D12MemoryAllocator::destroy()
4355 allocator->Release();
4356 allocator =
nullptr;
4360HRESULT QD3D12MemoryAllocator::createResource(D3D12_HEAP_TYPE heapType,
4361 const D3D12_RESOURCE_DESC *resourceDesc,
4362 D3D12_RESOURCE_STATES initialState,
4363 const D3D12_CLEAR_VALUE *optimizedClearValue,
4364 D3D12MA::Allocation **maybeAllocation,
4365 REFIID riidResource,
4369 D3D12MA::ALLOCATION_DESC allocDesc = {};
4370 allocDesc.HeapType = heapType;
4371 return allocator->CreateResource(&allocDesc,
4374 optimizedClearValue,
4379 *maybeAllocation =
nullptr;
4380 D3D12_HEAP_PROPERTIES heapProps = {};
4381 heapProps.Type = heapType;
4382 return device->CreateCommittedResource(&heapProps,
4383 D3D12_HEAP_FLAG_NONE,
4386 optimizedClearValue,
4392void QD3D12MemoryAllocator::getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget)
4395 allocator->GetBudget(localBudget, nonLocalBudget);
4398 *nonLocalBudget = {};
4402void QRhiD3D12::waitGpu()
4404 fullFenceCounter += 1u;
4405 if (SUCCEEDED(cmdQueue->Signal(fullFence, fullFenceCounter))) {
4406 if (SUCCEEDED(fullFence->SetEventOnCompletion(fullFenceCounter, fullFenceEvent)))
4407 WaitForSingleObject(fullFenceEvent, INFINITE);
4411DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleDesc(
int sampleCount, DXGI_FORMAT format)
const
4413 DXGI_SAMPLE_DESC desc;
4417 const int s = effectiveSampleCount(sampleCount);
4420 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
4421 msaaInfo.Format = format;
4422 msaaInfo.SampleCount = UINT(s);
4423 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo,
sizeof(msaaInfo)))) {
4424 if (msaaInfo.NumQualityLevels > 0) {
4425 desc.Count = UINT(s);
4426 desc.Quality = msaaInfo.NumQualityLevels - 1;
4428 qWarning(
"No quality levels for multisampling with sample count %d", s);
4436bool QRhiD3D12::startCommandListForCurrentFrameSlot(D3D12GraphicsCommandList **cmdList)
4438 ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
4440 HRESULT hr = dev->CreateCommandList(0,
4441 D3D12_COMMAND_LIST_TYPE_DIRECT,
4444 __uuidof(D3D12GraphicsCommandList),
4445 reinterpret_cast<
void **>(cmdList));
4447 qWarning(
"Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
4451 HRESULT hr = (*cmdList)->Reset(cmdAlloc,
nullptr);
4453 qWarning(
"Failed to reset command list: %s", qPrintable(QSystemError::windowsComString(hr)));
4460static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
4463 case DXGI_FORMAT_R8G8B8A8_UNORM:
4464 return QRhiTexture::RGBA8;
4465 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
4467 (*flags) |= QRhiTexture::sRGB;
4468 return QRhiTexture::RGBA8;
4469 case DXGI_FORMAT_B8G8R8A8_UNORM:
4470 return QRhiTexture::BGRA8;
4471 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
4473 (*flags) |= QRhiTexture::sRGB;
4474 return QRhiTexture::BGRA8;
4475 case DXGI_FORMAT_R16G16B16A16_FLOAT:
4476 return QRhiTexture::RGBA16F;
4477 case DXGI_FORMAT_R32G32B32A32_FLOAT:
4478 return QRhiTexture::RGBA32F;
4479 case DXGI_FORMAT_R10G10B10A2_UNORM:
4480 return QRhiTexture::RGB10A2;
4482 qWarning(
"DXGI_FORMAT %d cannot be read back", format);
4485 return QRhiTexture::UnknownFormat;
4488void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
4490 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
4492 for (
int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
4493 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
4494 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
4495 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4496 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4497 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4498 if (u.offset == 0 && u.data.size() == bufD->m_size)
4499 bufD->pendingHostWrites[i].clear();
4500 bufD->pendingHostWrites[i].append({ u.offset, u.data });
4502 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
4503 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4504 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4505 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
4513 QD3D12StagingArea::Allocation stagingAlloc;
4514 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(bufD->m_size, 1);
4515 recordSmallStagingAreaDemand(allocSize);
4516 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
4517 stagingAlloc = smallStagingAreas[currentFrameSlot].get(bufD->m_size);
4519 std::optional<QD3D12StagingArea> ownStagingArea;
4520 if (!stagingAlloc.isValid()) {
4521 ownStagingArea = QD3D12StagingArea();
4522 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
4524 stagingAlloc = ownStagingArea->get(allocSize);
4525 if (!stagingAlloc.isValid()) {
4526 ownStagingArea->destroy();
4531 memcpy(stagingAlloc.p + u.offset, u.data.constData(), u.data.size());
4533 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
4534 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4536 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
4537 cbD->cmdList->CopyBufferRegion(res->resource,
4539 stagingAlloc.buffer,
4540 stagingAlloc.bufferOffset + u.offset,
4544 if (ownStagingArea.has_value())
4545 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4546 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
4547 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4548 if (bufD->m_type == QRhiBuffer::Dynamic) {
4549 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
4550 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[currentFrameSlot])) {
4551 Q_ASSERT(res->cpuMapPtr);
4552 u.result->data.resize(u.readSize);
4553 memcpy(u.result->data.data(),
reinterpret_cast<
char *>(res->cpuMapPtr) + u.offset, u.readSize);
4555 if (u.result->completed)
4556 u.result->completed();
4558 QD3D12Readback readback;
4559 readback.frameSlot = currentFrameSlot;
4560 readback.result = u.result;
4561 readback.byteSize = u.readSize;
4562 const quint32 allocSize = aligned(u.readSize, QD3D12StagingArea::ALIGNMENT);
4563 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
4564 if (u.result->completed)
4565 u.result->completed();
4568 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(u.readSize);
4569 if (!stagingAlloc.isValid()) {
4570 readback.staging.destroy();
4571 if (u.result->completed)
4572 u.result->completed();
4575 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4576 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
4577 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4578 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
4579 cbD->cmdList->CopyBufferRegion(stagingAlloc.buffer, 0, res->resource, u.offset, u.readSize);
4580 activeReadbacks.append(readback);
4582 readback.staging.destroy();
4583 if (u.result->completed)
4584 u.result->completed();
4587 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Copy) {
4588 QD3D12Buffer *dstD = QRHI_RES(QD3D12Buffer, u.buf);
4589 QD3D12Buffer *srcD = QRHI_RES(QD3D12Buffer, u.src);
4590 Q_ASSERT(dstD->m_type != QRhiBuffer::Dynamic && srcD->m_type != QRhiBuffer::Dynamic);
4592 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handles[0]);
4593 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handles[0]);
4594 if (!dstRes || !srcRes)
4597 barrierGen.addTransitionBarrier(srcD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
4598 barrierGen.addTransitionBarrier(dstD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
4599 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4601 cbD->cmdList->CopyBufferRegion(dstRes->resource, u.offset,
4602 srcRes->resource, u.srcOffset,
4607 for (
int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
4608 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
4609 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
4610 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4611 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4612 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
4615 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4616 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4617 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4618 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4619 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level])) {
4620 D3D12_SUBRESOURCE_FOOTPRINT footprint = {};
4621 footprint.Format = res->desc.Format;
4622 footprint.Depth = 1;
4623 quint32 totalBytes = 0;
4625 QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
4626 : subresDesc.sourceSize();
4627 const QPoint srcPos = subresDesc.sourceTopLeft();
4628 QPoint dstPos = subresDesc.destinationTopLeft();
4630 if (subresDesc.image().isNull()
4631 && !subresDesc.data().isEmpty()
4632 && !isCompressedFormat(texD->m_format))
4634 subresSize = clampedSubResourceUploadSize(subresSize, dstPos, level, texD->m_pixelSize);
4635 quint32 bytesPerPixel = 0;
4636 textureFormatInfo(texD->m_format, subresSize,
nullptr,
nullptr, &bytesPerPixel);
4637 subresSize = clampedSubResourceUploadSizeForSourceData(subresSize,
4638 subresDesc.dataStride(),
4640 subresDesc.data().size());
4641 if (subresSize.isEmpty())
4645 if (!subresDesc.image().isNull()) {
4646 const QImage img = subresDesc.image();
4647 const int bpl = img.bytesPerLine();
4648 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4649 totalBytes = footprint.RowPitch * img.height();
4650 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
4653 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
4654 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4655 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
4656 totalBytes = footprint.RowPitch * rowCount;
4657 }
else if (!subresDesc.data().isEmpty()) {
4659 if (subresDesc.dataStride())
4660 bpl = subresDesc.dataStride();
4662 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4663 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4664 totalBytes = footprint.RowPitch * subresSize.height();
4666 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4670 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(totalBytes, 1);
4671 QD3D12StagingArea::Allocation stagingAlloc;
4672 recordSmallStagingAreaDemand(allocSize);
4673 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
4674 stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
4676 std::optional<QD3D12StagingArea> ownStagingArea;
4677 if (!stagingAlloc.isValid()) {
4678 ownStagingArea = QD3D12StagingArea();
4679 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
4681 stagingAlloc = ownStagingArea->get(allocSize);
4682 if (!stagingAlloc.isValid()) {
4683 ownStagingArea->destroy();
4688 D3D12_TEXTURE_COPY_LOCATION dst;
4689 dst.pResource = res->resource;
4690 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4691 dst.SubresourceIndex = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
4692 D3D12_TEXTURE_COPY_LOCATION src;
4693 src.pResource = stagingAlloc.buffer;
4694 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4695 src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
4699 if (!subresDesc.image().isNull()) {
4700 const QImage img = subresDesc.image();
4701 const int bpc = qMax(1, img.depth() / 8);
4702 const int bpl = img.bytesPerLine();
4704 QSize size = subresDesc.sourceSize().isEmpty() ? img.size() : subresDesc.sourceSize();
4705 size.setWidth(qMin(size.width(), img.width() - srcPos.x()));
4706 size.setHeight(qMin(size.height(), img.height() - srcPos.y()));
4707 size = clampedSubResourceUploadSize(size, dstPos, level, texD->m_pixelSize);
4709 footprint.Width = size.width();
4710 footprint.Height = size.height();
4714 srcBox.right = UINT(size.width());
4715 srcBox.bottom = UINT(size.height());
4719 const uchar *imgPtr = img.constBits();
4720 const quint32 lineBytes = size.width() * bpc;
4721 for (
int y = 0, h = size.height(); y < h; ++y) {
4722 memcpy(stagingAlloc.p + y * footprint.RowPitch,
4723 imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
4726 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
4729 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
4731 dstPos.setX(aligned(dstPos.x(), blockDim.width()));
4732 dstPos.setY(aligned(dstPos.y(), blockDim.height()));
4737 srcBox.right = aligned(subresSize.width(), blockDim.width());
4738 srcBox.bottom = aligned(subresSize.height(), blockDim.height());
4743 footprint.Width = aligned(subresSize.width(), blockDim.width());
4744 footprint.Height = aligned(subresSize.height(), blockDim.height());
4746 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4747 const QByteArray imgData = subresDesc.data();
4748 const char *imgPtr = imgData.constData();
4749 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
4750 for (
int y = 0; y < rowCount; ++y) {
4751 const quint64 srcOffset = quint64(y) * bpl;
4752 if (srcOffset >= quint64(imgData.size()))
4754 const quint32 n = quint32(qMin(quint64(copyBytes),
4755 quint64(imgData.size()) - srcOffset));
4756 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + srcOffset, n);
4758 }
else if (!subresDesc.data().isEmpty()) {
4761 srcBox.right = subresSize.width();
4762 srcBox.bottom = subresSize.height();
4766 footprint.Width = subresSize.width();
4767 footprint.Height = subresSize.height();
4770 if (subresDesc.dataStride())
4771 bpl = subresDesc.dataStride();
4773 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4775 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4776 const QByteArray data = subresDesc.data();
4777 const char *imgPtr = data.constData();
4778 for (
int y = 0, h = subresSize.height(); y < h; ++y) {
4783 const quint64 srcOffset = quint64(y) * bpl;
4784 if (srcOffset >= quint64(data.size()))
4786 const quint32 n = quint32(qMin(quint64(copyBytes),
4787 quint64(data.size()) - srcOffset));
4788 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + srcOffset, n);
4792 src.PlacedFootprint.Footprint = footprint;
4794 cbD->cmdList->CopyTextureRegion(&dst,
4797 is3D ? UINT(layer) : 0u,
4801 if (ownStagingArea.has_value())
4802 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4806 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
4807 Q_ASSERT(u.src && u.dst);
4808 QD3D12Texture *srcD = QRHI_RES(QD3D12Texture, u.src);
4809 QD3D12Texture *dstD = QRHI_RES(QD3D12Texture, u.dst);
4810 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4811 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4812 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
4813 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
4814 if (!srcRes || !dstRes)
4817 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4818 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4819 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4821 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
4822 srcIs3D ? 0u : UINT(u.desc.sourceLayer()),
4823 srcD->mipLevelCount);
4824 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
4825 dstIs3D ? 0u : UINT(u.desc.destinationLayer()),
4826 dstD->mipLevelCount);
4827 const QPoint dp = u.desc.destinationTopLeft();
4828 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4829 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4830 const QPoint sp = u.desc.sourceTopLeft();
4833 srcBox.left = UINT(sp.x());
4834 srcBox.top = UINT(sp.y());
4835 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
4837 srcBox.right = srcBox.left + UINT(copySize.width());
4838 srcBox.bottom = srcBox.top + UINT(copySize.height());
4839 srcBox.back = srcBox.front + 1;
4841 D3D12_TEXTURE_COPY_LOCATION src;
4842 src.pResource = srcRes->resource;
4843 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4844 src.SubresourceIndex = srcSubresource;
4845 D3D12_TEXTURE_COPY_LOCATION dst;
4846 dst.pResource = dstRes->resource;
4847 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4848 dst.SubresourceIndex = dstSubresource;
4850 cbD->cmdList->CopyTextureRegion(&dst,
4853 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
4856 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
4857 QD3D12Readback readback;
4858 readback.frameSlot = currentFrameSlot;
4859 readback.result = u.result;
4861 QD3D12ObjectHandle srcHandle;
4864 if (u.rb.texture()) {
4865 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.rb.texture());
4866 if (texD->sampleDesc.Count > 1) {
4867 qWarning(
"Multisample texture cannot be read back");
4870 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4871 if (u.rb.rect().isValid())
4874 rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4875 readback.format = texD->m_format;
4876 srcHandle = texD->handle;
4878 Q_ASSERT(currentSwapChain);
4879 if (u.rb.rect().isValid())
4882 rect = QRect({0, 0}, currentSwapChain->pixelSize);
4883 readback.format = swapchainReadbackTextureFormat(currentSwapChain->colorFormat,
nullptr);
4884 if (readback.format == QRhiTexture::UnknownFormat)
4886 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
4888 readback.pixelSize = rect.size();
4890 textureFormatInfo(readback.format,
4892 &readback.bytesPerLine,
4896 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
4900 const UINT subresource = calcSubresource(UINT(u.rb.level()),
4901 is3D ? 0u : UINT(u.rb.layer()),
4902 srcRes->desc.MipLevels);
4903 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
4906 UINT64 totalBytes = 0;
4907 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
4908 &layout,
nullptr,
nullptr, &totalBytes);
4909 readback.stagingRowPitch = layout.Footprint.RowPitch;
4911 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT);
4912 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
4913 if (u.result->completed)
4914 u.result->completed();
4917 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
4918 if (!stagingAlloc.isValid()) {
4919 readback.staging.destroy();
4920 if (u.result->completed)
4921 u.result->completed();
4924 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4926 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4927 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4929 D3D12_TEXTURE_COPY_LOCATION dst;
4930 dst.pResource = stagingAlloc.buffer;
4931 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4932 dst.PlacedFootprint.Offset = 0;
4933 dst.PlacedFootprint.Footprint = layout.Footprint;
4935 D3D12_TEXTURE_COPY_LOCATION src;
4936 src.pResource = srcRes->resource;
4937 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4938 src.SubresourceIndex = subresource;
4940 D3D12_BOX srcBox = {};
4941 srcBox.left = UINT(rect.left());
4942 srcBox.top = UINT(rect.top());
4943 srcBox.front = is3D ? UINT(u.rb.layer()) : 0u;
4945 srcBox.right = srcBox.left + UINT(rect.width());
4946 srcBox.bottom = srcBox.top + UINT(rect.height());
4947 srcBox.back = srcBox.front + 1;
4949 cbD->cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &srcBox);
4950 activeReadbacks.append(readback);
4951 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
4952 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4953 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
4959 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
4960 if (res && texD->mipLevelCount >= 2
4961 && (res->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET))
4963 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
4964 const UINT layerCount = is3D ? 1u : UINT(res->desc.DepthOrArraySize);
4965 QBitArray &initialized(texD->subresourceInitialized);
4966 QVarLengthArray<UINT, 16> subresourcesToDiscard;
4967 for (UINT layer = 0; layer < layerCount; ++layer) {
4968 for (UINT level = 1; level < texD->mipLevelCount; ++level) {
4969 const UINT subresource = calcSubresource(level, layer, texD->mipLevelCount);
4970 if (
int(subresource) >= initialized.size())
4971 initialized.resize(
int(subresource) + 1);
4972 if (!initialized.testBit(
int(subresource))) {
4973 initialized.setBit(
int(subresource));
4974 subresourcesToDiscard.append(subresource);
4978 if (!subresourcesToDiscard.isEmpty()) {
4980 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
4981 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4982 for (UINT subresource : subresourcesToDiscard) {
4983 D3D12_DISCARD_REGION region = {};
4984 region.FirstSubresource = subresource;
4985 region.NumSubresources = 1;
4986 cbD->cmdList->DiscardResource(res->resource, ®ion);
4991 if (texD->flags().testFlag(QRhiTexture::ThreeDimensional))
4992 mipmapGen3D.generate(cbD, texD->handle);
4994 mipmapGen.generate(cbD, texD->handle);
5001void QRhiD3D12::finishActiveReadbacks(
bool forced)
5003 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
5005 for (
int i = activeReadbacks.size() - 1; i >= 0; --i) {
5006 QD3D12Readback &readback(activeReadbacks[i]);
5007 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
5008 readback.result->format = readback.format;
5009 readback.result->pixelSize = readback.pixelSize;
5010 readback.result->data.resize(
int(readback.byteSize));
5012 if (readback.format != QRhiTexture::UnknownFormat) {
5013 quint8 *dstPtr =
reinterpret_cast<quint8 *>(readback.result->data.data());
5014 const quint8 *srcPtr = readback.staging.mem.p;
5015 const quint32 lineSize = qMin(readback.bytesPerLine, readback.stagingRowPitch);
5016 for (
int y = 0, h = readback.pixelSize.height(); y < h; ++y)
5017 memcpy(dstPtr + y * readback.bytesPerLine, srcPtr + y * readback.stagingRowPitch, lineSize);
5019 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
5022 readback.staging.destroy();
5024 if (readback.result->completed)
5025 completedCallbacks.append(readback.result->completed);
5027 activeReadbacks.remove(i);
5031 for (
auto f : completedCallbacks)
5035bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
5036 D3D12_DESCRIPTOR_HEAP_TYPE type,
5038 quint32 neededDescriptorCount,
5046 if (h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
5047 const quint32 newPerFrameSize = qMax(h->perFrameHeapSlice[frameSlot].capacity * 2,
5048 neededDescriptorCount);
5049 QD3D12ShaderVisibleDescriptorHeap newHeap;
5050 if (!newHeap.create(dev, type, newPerFrameSize)) {
5051 qWarning(
"Could not create new shader-visible descriptor heap");
5054 h->destroyWithDeferredRelease(&releaseQueue);
5061void QRhiD3D12::resetAndResizeSmallStagingArea(
int frameSlot)
5063 QD3D12StagingArea &area(smallStagingAreas[frameSlot]);
5069 const quint32 needed = smallStagingAreaBytesNeeded[frameSlot];
5070 smallStagingAreaBytesNeeded[frameSlot] = 0;
5072 quint32 newCapacity = 0;
5073 if (needed > area.capacity) {
5076 smallStagingAreaLowDemandFrames[frameSlot] = 0;
5077 newCapacity = qMin(qNextPowerOfTwo(needed), SMALL_STAGING_AREA_BYTES_PER_FRAME_MAX);
5078 }
else if (needed <= area.capacity / 4 && area.capacity > SMALL_STAGING_AREA_BYTES_PER_FRAME_START) {
5079 if (++smallStagingAreaLowDemandFrames[frameSlot] >= SMALL_STAGING_AREA_LOW_DEMAND_FRAMES) {
5080 smallStagingAreaLowDemandFrames[frameSlot] = 0;
5081 newCapacity = qMax(area.capacity / 2, SMALL_STAGING_AREA_BYTES_PER_FRAME_START);
5084 smallStagingAreaLowDemandFrames[frameSlot] = 0;
5087 if (newCapacity && newCapacity != area.capacity) {
5088 QD3D12StagingArea newArea;
5089 if (newArea.create(
this, aligned(newCapacity, QD3D12StagingArea::ALIGNMENT), D3D12_HEAP_TYPE_UPLOAD)) {
5090 area.destroyWithDeferredRelease(&releaseQueue);
5092 QString decoratedName = QLatin1String(
"Small staging area buffer/");
5093 decoratedName += QString::number(frameSlot);
5094 area.mem.buffer->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
5103void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
5105 ID3D12DescriptorHeap *heaps[] = {
5106 shaderVisibleCbvSrvUavHeap.heap.heap,
5107 samplerMgr.shaderVisibleSamplerHeap.heap.heap
5109 cbD->cmdList->SetDescriptorHeaps(2, heaps);
5112QD3D12Buffer::QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
5113 : QRhiBuffer(rhi, type, usage, size)
5117QD3D12Buffer::~QD3D12Buffer()
5122void QD3D12Buffer::destroy()
5124 if (handles[0].isNull())
5127 QRHI_RES_RHI(QRhiD3D12);
5136 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
5138 rhiD->releaseQueue.deferredReleaseResource(handles[i]);
5140 pendingHostWrites[i].clear();
5144 rhiD->unregisterResource(
this);
5147bool QD3D12Buffer::create()
5149 if (!handles[0].isNull())
5152 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
5153 qWarning(
"UniformBuffer must always be Dynamic");
5157 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
5158 qWarning(
"StorageBuffer cannot be combined with Dynamic");
5162 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
5163 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
5165 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
5166 if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
5167 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5169 QRHI_RES_RHI(QRhiD3D12);
5171 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
5172 if (i == 0 || m_type == Dynamic) {
5173 D3D12_RESOURCE_DESC resourceDesc = {};
5174 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
5175 resourceDesc.Width = roundedSize;
5176 resourceDesc.Height = 1;
5177 resourceDesc.DepthOrArraySize = 1;
5178 resourceDesc.MipLevels = 1;
5179 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
5180 resourceDesc.SampleDesc = { 1, 0 };
5181 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
5182 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
5183 ID3D12Resource *resource =
nullptr;
5184 D3D12MA::Allocation *allocation =
nullptr;
5186 D3D12_HEAP_TYPE heapType = m_type == Dynamic
5187 ? D3D12_HEAP_TYPE_UPLOAD
5188 : D3D12_HEAP_TYPE_DEFAULT;
5189 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
5190 ? D3D12_RESOURCE_STATE_GENERIC_READ
5191 : D3D12_RESOURCE_STATE_COMMON;
5192 hr = rhiD->vma.createResource(heapType,
5198 reinterpret_cast<
void **>(&resource));
5201 if (!m_objectName.isEmpty()) {
5202 QString decoratedName = QString::fromUtf8(m_objectName);
5203 if (m_type == Dynamic) {
5204 decoratedName += QLatin1Char(
'/');
5205 decoratedName += QString::number(i);
5207 resource->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
5209 void *cpuMemPtr =
nullptr;
5210 if (m_type == Dynamic) {
5212 hr = resource->Map(0,
nullptr, &cpuMemPtr);
5214 qWarning(
"Map() failed to dynamic buffer");
5215 resource->Release();
5217 allocation->Release();
5221 handles[i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
5229 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
5230 qPrintable(QSystemError::windowsComString(hr)),
5233 int(rhiD->vma.isUsingD3D12MA()));
5238 rhiD->registerResource(
this);
5242QRhiBuffer::NativeBuffer QD3D12Buffer::nativeBuffer()
5245 Q_ASSERT(
sizeof(b.objects) /
sizeof(b.objects[0]) >= size_t(QD3D12_FRAMES_IN_FLIGHT));
5246 QRHI_RES_RHI(QRhiD3D12);
5247 if (m_type == Dynamic) {
5248 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
5249 executeHostWritesForFrameSlot(i);
5250 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[i]))
5251 b.objects[i] = res->resource;
5253 b.objects[i] =
nullptr;
5255 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
5258 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[0]))
5259 b.objects[0] = res->resource;
5261 b.objects[0] =
nullptr;
5266char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
5274 Q_ASSERT(m_type == Dynamic);
5275 QRHI_RES_RHI(QRhiD3D12);
5276 Q_ASSERT(rhiD->inFrame);
5277 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
5278 return static_cast<
char *>(res->cpuMapPtr);
5283void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
5288void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
5290 if (pendingHostWrites[frameSlot].isEmpty())
5293 Q_ASSERT(m_type == QRhiBuffer::Dynamic);
5294 QRHI_RES_RHI(QRhiD3D12);
5295 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
5296 Q_ASSERT(res->cpuMapPtr);
5297 for (
const QD3D12Buffer::HostWrite &u : std::as_const(pendingHostWrites[frameSlot]))
5298 memcpy(
static_cast<
char *>(res->cpuMapPtr) + u.offset, u.data.constData(), u.data.size());
5300 pendingHostWrites[frameSlot].clear();
5303static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
5305 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
5307 case QRhiTexture::RGBA8:
5308 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
5309 case QRhiTexture::BGRA8:
5310 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
5311 case QRhiTexture::R8:
5312 return DXGI_FORMAT_R8_UNORM;
5313 case QRhiTexture::R8SI:
5314 return DXGI_FORMAT_R8_SINT;
5315 case QRhiTexture::R8UI:
5316 return DXGI_FORMAT_R8_UINT;
5317 case QRhiTexture::RG8:
5318 return DXGI_FORMAT_R8G8_UNORM;
5319 case QRhiTexture::R16:
5320 return DXGI_FORMAT_R16_UNORM;
5321 case QRhiTexture::RG16:
5322 return DXGI_FORMAT_R16G16_UNORM;
5323 case QRhiTexture::RED_OR_ALPHA8:
5324 return DXGI_FORMAT_R8_UNORM;
5326 case QRhiTexture::RGBA16F:
5327 return DXGI_FORMAT_R16G16B16A16_FLOAT;
5328 case QRhiTexture::RGBA32F:
5329 return DXGI_FORMAT_R32G32B32A32_FLOAT;
5330 case QRhiTexture::R16F:
5331 return DXGI_FORMAT_R16_FLOAT;
5332 case QRhiTexture::R32F:
5333 return DXGI_FORMAT_R32_FLOAT;
5335 case QRhiTexture::RGB10A2:
5336 return DXGI_FORMAT_R10G10B10A2_UNORM;
5338 case QRhiTexture::R32SI:
5339 return DXGI_FORMAT_R32_SINT;
5340 case QRhiTexture::R32UI:
5341 return DXGI_FORMAT_R32_UINT;
5342 case QRhiTexture::RG32SI:
5343 return DXGI_FORMAT_R32G32_SINT;
5344 case QRhiTexture::RG32UI:
5345 return DXGI_FORMAT_R32G32_UINT;
5346 case QRhiTexture::RGBA32SI:
5347 return DXGI_FORMAT_R32G32B32A32_SINT;
5348 case QRhiTexture::RGBA32UI:
5349 return DXGI_FORMAT_R32G32B32A32_UINT;
5351 case QRhiTexture::D16:
5352 return DXGI_FORMAT_R16_TYPELESS;
5353 case QRhiTexture::D24:
5354 return DXGI_FORMAT_R24G8_TYPELESS;
5355 case QRhiTexture::D24S8:
5356 return DXGI_FORMAT_R24G8_TYPELESS;
5357 case QRhiTexture::D32F:
5358 return DXGI_FORMAT_R32_TYPELESS;
5359 case QRhiTexture::Format::D32FS8:
5360 return DXGI_FORMAT_R32G8X24_TYPELESS;
5362 case QRhiTexture::BC1:
5363 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
5364 case QRhiTexture::BC2:
5365 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
5366 case QRhiTexture::BC3:
5367 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
5368 case QRhiTexture::BC4:
5369 return DXGI_FORMAT_BC4_UNORM;
5370 case QRhiTexture::BC5:
5371 return DXGI_FORMAT_BC5_UNORM;
5372 case QRhiTexture::BC6H:
5373 return DXGI_FORMAT_BC6H_UF16;
5374 case QRhiTexture::BC7:
5375 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
5377 case QRhiTexture::ETC2_RGB8:
5378 case QRhiTexture::ETC2_RGB8A1:
5379 case QRhiTexture::ETC2_RGBA8:
5380 qWarning(
"QRhiD3D12 does not support ETC2 textures");
5381 return DXGI_FORMAT_R8G8B8A8_UNORM;
5383 case QRhiTexture::ASTC_4x4:
5384 case QRhiTexture::ASTC_5x4:
5385 case QRhiTexture::ASTC_5x5:
5386 case QRhiTexture::ASTC_6x5:
5387 case QRhiTexture::ASTC_6x6:
5388 case QRhiTexture::ASTC_8x5:
5389 case QRhiTexture::ASTC_8x6:
5390 case QRhiTexture::ASTC_8x8:
5391 case QRhiTexture::ASTC_10x5:
5392 case QRhiTexture::ASTC_10x6:
5393 case QRhiTexture::ASTC_10x8:
5394 case QRhiTexture::ASTC_10x10:
5395 case QRhiTexture::ASTC_12x10:
5396 case QRhiTexture::ASTC_12x12:
5397 qWarning(
"QRhiD3D12 does not support ASTC textures");
5398 return DXGI_FORMAT_R8G8B8A8_UNORM;
5403 return DXGI_FORMAT_R8G8B8A8_UNORM;
5406QD3D12RenderBuffer::QD3D12RenderBuffer(QRhiImplementation *rhi,
5408 const QSize &pixelSize,
5411 QRhiTexture::Format backingFormatHint)
5412 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
5416QD3D12RenderBuffer::~QD3D12RenderBuffer()
5421void QD3D12RenderBuffer::destroy()
5423 if (handle.isNull())
5426 QRHI_RES_RHI(QRhiD3D12);
5429 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->rtvPool, rtv, 1);
5430 else if (dsv.isValid())
5431 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->dsvPool, dsv, 1);
5439 rhiD->unregisterResource(
this);
5442bool QD3D12RenderBuffer::create()
5444 if (!handle.isNull())
5447 if (m_pixelSize.isEmpty())
5450 QRHI_RES_RHI(QRhiD3D12);
5453 case QRhiRenderBuffer::Color:
5455 dxgiFormat = toD3DTextureFormat(backingFormat(), {});
5456 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5457 D3D12_RESOURCE_DESC resourceDesc = {};
5458 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
5459 resourceDesc.Width = UINT64(m_pixelSize.width());
5460 resourceDesc.Height = UINT(m_pixelSize.height());
5461 resourceDesc.DepthOrArraySize = 1;
5462 resourceDesc.MipLevels = 1;
5463 resourceDesc.Format = dxgiFormat;
5464 resourceDesc.SampleDesc = sampleDesc;
5465 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5466 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
5467 D3D12_CLEAR_VALUE clearValue = {};
5468 clearValue.Format = dxgiFormat;
5470 ID3D12Resource *resource =
nullptr;
5471 D3D12MA::Allocation *allocation =
nullptr;
5472 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5474 D3D12_RESOURCE_STATE_RENDER_TARGET,
5477 __uuidof(ID3D12Resource),
5478 reinterpret_cast<
void **>(&resource));
5480 qWarning(
"Failed to create color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
5483 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
5484 rtv = rhiD->rtvPool.allocate(1);
5487 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5488 rtvDesc.Format = dxgiFormat;
5489 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
5490 : D3D12_RTV_DIMENSION_TEXTURE2D;
5491 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
5494 case QRhiRenderBuffer::DepthStencil:
5496 dxgiFormat = DS_FORMAT;
5497 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5498 D3D12_RESOURCE_DESC resourceDesc = {};
5499 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
5500 resourceDesc.Width = UINT64(m_pixelSize.width());
5501 resourceDesc.Height = UINT(m_pixelSize.height());
5502 resourceDesc.DepthOrArraySize = 1;
5503 resourceDesc.MipLevels = 1;
5504 resourceDesc.Format = dxgiFormat;
5505 resourceDesc.SampleDesc = sampleDesc;
5506 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5507 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
5508 if (m_flags.testFlag(UsedWithSwapChainOnly))
5509 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
5510 D3D12_CLEAR_VALUE clearValue = {};
5511 clearValue.Format = dxgiFormat;
5512 clearValue.DepthStencil.Depth = 1.0f;
5513 clearValue.DepthStencil.Stencil = 0;
5514 ID3D12Resource *resource =
nullptr;
5515 D3D12MA::Allocation *allocation =
nullptr;
5516 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5518 D3D12_RESOURCE_STATE_DEPTH_WRITE,
5521 __uuidof(ID3D12Resource),
5522 reinterpret_cast<
void **>(&resource));
5524 qWarning(
"Failed to create depth-stencil buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
5527 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE, allocation);
5528 dsv = rhiD->dsvPool.allocate(1);
5531 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5532 dsvDesc.Format = dxgiFormat;
5533 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
5534 : D3D12_DSV_DIMENSION_TEXTURE2D;
5535 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
5540 if (!m_objectName.isEmpty()) {
5541 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
5542 const QString name = QString::fromUtf8(m_objectName);
5543 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
5548 rhiD->registerResource(
this);
5552QRhiTexture::Format QD3D12RenderBuffer::backingFormat()
const
5554 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
5555 return m_backingFormatHint;
5557 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
5560QD3D12Texture::QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
5561 int arraySize,
int sampleCount, Flags flags)
5562 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
5566QD3D12Texture::~QD3D12Texture()
5571void QD3D12Texture::destroy()
5573 if (handle.isNull())
5576 QRHI_RES_RHI(QRhiD3D12);
5578 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->cbvSrvUavPool, srv, 1);
5582 subresourceInitialized.clear();
5585 rhiD->unregisterResource(
this);
5588static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
5591 case QRhiTexture::Format::D16:
5592 return DXGI_FORMAT_R16_FLOAT;
5593 case QRhiTexture::Format::D24:
5594 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
5595 case QRhiTexture::Format::D24S8:
5596 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
5597 case QRhiTexture::Format::D32F:
5598 return DXGI_FORMAT_R32_FLOAT;
5599 case QRhiTexture::Format::D32FS8:
5600 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
5604 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
5607static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
5611 case QRhiTexture::Format::D16:
5612 return DXGI_FORMAT_D16_UNORM;
5613 case QRhiTexture::Format::D24:
5614 return DXGI_FORMAT_D24_UNORM_S8_UINT;
5615 case QRhiTexture::Format::D24S8:
5616 return DXGI_FORMAT_D24_UNORM_S8_UINT;
5617 case QRhiTexture::Format::D32F:
5618 return DXGI_FORMAT_D32_FLOAT;
5619 case QRhiTexture::Format::D32FS8:
5620 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
5624 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
5627static inline bool isDepthTextureFormat(QRhiTexture::Format format)
5630 case QRhiTexture::Format::D16:
5631 case QRhiTexture::Format::D24:
5632 case QRhiTexture::Format::D24S8:
5633 case QRhiTexture::Format::D32F:
5634 case QRhiTexture::Format::D32FS8:
5641bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
5643 if (!handle.isNull())
5646 QRHI_RES_RHI(QRhiD3D12);
5647 if (!rhiD->isTextureFormatSupported(m_format, m_flags))
5650 const bool isDepth = isDepthTextureFormat(m_format);
5651 const bool isCube = m_flags.testFlag(CubeMap);
5652 const bool is3D = m_flags.testFlag(ThreeDimensional);
5653 const bool isArray = m_flags.testFlag(TextureArray);
5654 const bool hasMipMaps = m_flags.testFlag(MipMapped);
5655 const bool is1D = m_flags.testFlag(OneDimensional);
5657 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
5658 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
5660 dxgiFormat = toD3DTextureFormat(m_format, m_flags);
5662 srvFormat = toD3DDepthTextureSRVFormat(m_format);
5663 rtFormat = toD3DDepthTextureDSVFormat(m_format);
5665 srvFormat = dxgiFormat;
5666 rtFormat = dxgiFormat;
5668 if (m_writeViewFormat.format != UnknownFormat) {
5670 rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
5672 rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
5674 if (m_readViewFormat.format != UnknownFormat) {
5676 srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
5678 srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
5681 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
5682 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5683 if (sampleDesc.Count > 1) {
5685 qWarning(
"Cubemap texture cannot be multisample");
5689 qWarning(
"3D texture cannot be multisample");
5693 qWarning(
"Multisample texture cannot have mipmaps");
5697 if (isDepth && hasMipMaps) {
5698 qWarning(
"Depth texture cannot have mipmaps");
5701 if (isCube && is3D) {
5702 qWarning(
"Texture cannot be both cube and 3D");
5705 if (isArray && is3D) {
5706 qWarning(
"Texture cannot be both array and 3D");
5709 if (isCube && is1D) {
5710 qWarning(
"Texture cannot be both cube and 1D");
5714 qWarning(
"Texture cannot be both 1D and 3D");
5717 if (m_depth > 1 && !is3D) {
5718 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
5721 if (m_arraySize > 0 && !isArray) {
5722 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
5725 if (m_arraySize < 1 && isArray) {
5726 qWarning(
"Texture is an array but array size is %d", m_arraySize);
5730 if (!rhiD->textureFormatInfo(m_format, size,
nullptr,
nullptr,
nullptr))
5734 *adjustedSize = size;
5739bool QD3D12Texture::finishCreate()
5741 QRHI_RES_RHI(QRhiD3D12);
5742 const bool isCube = m_flags.testFlag(CubeMap);
5743 const bool is3D = m_flags.testFlag(ThreeDimensional);
5744 const bool isArray = m_flags.testFlag(TextureArray);
5745 const bool is1D = m_flags.testFlag(OneDimensional);
5747 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
5748 srvDesc.Format = srvFormat;
5749 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
5752 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
5753 srvDesc.TextureCube.MipLevels = mipLevelCount;
5757 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
5758 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
5759 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5760 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
5761 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
5763 srvDesc.Texture1DArray.FirstArraySlice = 0;
5764 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
5767 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
5768 srvDesc.Texture1D.MipLevels = mipLevelCount;
5770 }
else if (isArray) {
5771 if (sampleDesc.Count > 1) {
5772 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
5773 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5774 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
5775 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
5777 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
5778 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
5781 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
5782 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
5783 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5784 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
5785 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
5787 srvDesc.Texture2DArray.FirstArraySlice = 0;
5788 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
5792 if (sampleDesc.Count > 1) {
5793 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
5795 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
5796 srvDesc.Texture3D.MipLevels = mipLevelCount;
5798 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
5799 srvDesc.Texture2D.MipLevels = mipLevelCount;
5804 srv = rhiD->cbvSrvUavPool.allocate(1);
5808 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
5809 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
5810 if (!m_objectName.isEmpty()) {
5811 const QString name = QString::fromUtf8(m_objectName);
5812 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
5822bool QD3D12Texture::create()
5825 if (!prepareCreate(&size))
5828 const bool isDepth = isDepthTextureFormat(m_format);
5829 const bool isCube = m_flags.testFlag(CubeMap);
5830 const bool is3D = m_flags.testFlag(ThreeDimensional);
5831 const bool isArray = m_flags.testFlag(TextureArray);
5832 const bool is1D = m_flags.testFlag(OneDimensional);
5834 QRHI_RES_RHI(QRhiD3D12);
5836 bool needsOptimizedClearValueSpecified =
false;
5837 UINT resourceFlags = 0;
5838 if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
5840 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
5842 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
5843 needsOptimizedClearValueSpecified =
true;
5845 if (m_flags.testFlag(UsedWithGenerateMips)) {
5847 qWarning(
"Depth texture cannot have mipmaps generated");
5850 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5852 if (m_flags.testFlag(UsedWithLoadStore))
5853 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5855 D3D12_RESOURCE_DESC resourceDesc = {};
5856 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
5857 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
5858 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
5859 resourceDesc.Width = UINT64(size.width());
5860 resourceDesc.Height = UINT(size.height());
5861 resourceDesc.DepthOrArraySize = isCube ? 6
5862 : (isArray ? UINT(qMax(0, m_arraySize))
5863 : (is3D ? qMax(1, m_depth)
5865 resourceDesc.MipLevels = mipLevelCount;
5866 resourceDesc.Format = dxgiFormat;
5867 resourceDesc.SampleDesc = sampleDesc;
5868 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5869 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
5870 D3D12_CLEAR_VALUE clearValue = {};
5871 clearValue.Format = dxgiFormat;
5873 clearValue.Format = toD3DDepthTextureDSVFormat(m_format);
5874 clearValue.DepthStencil.Depth = 1.0f;
5875 clearValue.DepthStencil.Stencil = 0;
5877 ID3D12Resource *resource =
nullptr;
5878 D3D12MA::Allocation *allocation =
nullptr;
5879 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5881 D3D12_RESOURCE_STATE_COMMON,
5882 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
5884 __uuidof(ID3D12Resource),
5885 reinterpret_cast<
void **>(&resource));
5887 qWarning(
"Failed to create texture: '%s'"
5888 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
5889 qPrintable(QSystemError::windowsComString(hr)),
5890 int(resourceDesc.Dimension),
5891 uint(resourceDesc.Width),
5892 uint(resourceDesc.Height),
5893 uint(resourceDesc.DepthOrArraySize),
5894 uint(resourceDesc.MipLevels),
5895 int(resourceDesc.Format),
5896 int(resourceDesc.SampleDesc.Count));
5897 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
5898 rhiD->deviceLost =
true;
5902 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON, allocation);
5904 if (!finishCreate())
5907 rhiD->registerResource(
this);
5911bool QD3D12Texture::createFrom(QRhiTexture::NativeTexture src)
5916 if (!prepareCreate())
5919 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *>(src.object);
5920 D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(src.layout);
5922 QRHI_RES_RHI(QRhiD3D12);
5923 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource, state);
5925 if (!finishCreate())
5928 rhiD->registerResource(
this);
5932QRhiTexture::NativeTexture QD3D12Texture::nativeTexture()
5934 QRHI_RES_RHI(QRhiD3D12);
5935 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
5936 return { quint64(res->resource),
int(res->state) };
5941void QD3D12Texture::setNativeLayout(
int layout)
5943 QRHI_RES_RHI(QRhiD3D12);
5944 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
5945 res->state = D3D12_RESOURCE_STATES(layout);
5948QD3D12Sampler::QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
5949 AddressMode u, AddressMode v, AddressMode w)
5950 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
5954QD3D12Sampler::~QD3D12Sampler()
5959void QD3D12Sampler::destroy()
5961 shaderVisibleDescriptor = {};
5963 QRHI_RES_RHI(QRhiD3D12);
5965 rhiD->unregisterResource(
this);
5968static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
5970 if (minFilter == QRhiSampler::Nearest) {
5971 if (magFilter == QRhiSampler::Nearest) {
5972 if (mipFilter == QRhiSampler::Linear)
5973 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
5975 return D3D12_FILTER_MIN_MAG_MIP_POINT;
5977 if (mipFilter == QRhiSampler::Linear)
5978 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
5980 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
5983 if (magFilter == QRhiSampler::Nearest) {
5984 if (mipFilter == QRhiSampler::Linear)
5985 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
5987 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
5989 if (mipFilter == QRhiSampler::Linear)
5990 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
5992 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
5995 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
5998static inline D3D12_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
6001 case QRhiSampler::Repeat:
6002 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
6003 case QRhiSampler::ClampToEdge:
6004 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
6005 case QRhiSampler::Mirror:
6006 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
6008 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
6011static inline D3D12_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
6014 case QRhiSampler::Never:
6015 return D3D12_COMPARISON_FUNC_NEVER;
6016 case QRhiSampler::Less:
6017 return D3D12_COMPARISON_FUNC_LESS;
6018 case QRhiSampler::Equal:
6019 return D3D12_COMPARISON_FUNC_EQUAL;
6020 case QRhiSampler::LessOrEqual:
6021 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
6022 case QRhiSampler::Greater:
6023 return D3D12_COMPARISON_FUNC_GREATER;
6024 case QRhiSampler::NotEqual:
6025 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
6026 case QRhiSampler::GreaterOrEqual:
6027 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
6028 case QRhiSampler::Always:
6029 return D3D12_COMPARISON_FUNC_ALWAYS;
6031 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
6034bool QD3D12Sampler::create()
6037 desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
6038 if (m_compareOp != Never)
6039 desc.Filter = D3D12_FILTER(desc.Filter | 0x80);
6040 desc.AddressU = toD3DAddressMode(m_addressU);
6041 desc.AddressV = toD3DAddressMode(m_addressV);
6042 desc.AddressW = toD3DAddressMode(m_addressW);
6043 desc.MaxAnisotropy = 1.0f;
6044 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
6045 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
6049 shaderVisibleDescriptor = {};
6053 QRHI_RES_RHI(QRhiD3D12);
6054 rhiD->registerResource(
this,
false);
6058QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
6060 if (!shaderVisibleDescriptor.isValid()) {
6061 QRHI_RES_RHI(QRhiD3D12);
6062 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(desc);
6064 return shaderVisibleDescriptor;
6067QD3D12ShadingRateMap::QD3D12ShadingRateMap(QRhiImplementation *rhi)
6068 : QRhiShadingRateMap(rhi)
6072QD3D12ShadingRateMap::~QD3D12ShadingRateMap()
6077void QD3D12ShadingRateMap::destroy()
6079 if (handle.isNull())
6085bool QD3D12ShadingRateMap::createFrom(QRhiTexture *src)
6087 if (!handle.isNull())
6090 handle = QRHI_RES(QD3D12Texture, src)->handle;
6095QD3D12TextureRenderTarget::QD3D12TextureRenderTarget(QRhiImplementation *rhi,
6096 const QRhiTextureRenderTargetDescription &desc,
6098 : QRhiTextureRenderTarget(rhi, desc, flags),
6103QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
6108void QD3D12TextureRenderTarget::destroy()
6110 if (!rtv[0].isValid() && !dsv.isValid())
6113 QRHI_RES_RHI(QRhiD3D12);
6114 if (dsv.isValid()) {
6115 if (ownsDsv && rhiD)
6116 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
6120 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i) {
6121 if (rtv[i].isValid()) {
6122 if (ownsRtv[i] && rhiD)
6123 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[i], 1);
6129 rhiD->unregisterResource(
this);
6132QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDescriptor()
6136 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6138 rpD->colorAttachmentCount = 0;
6139 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it) {
6140 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
6141 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
6143 rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
6145 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
6146 rpD->colorAttachmentCount += 1;
6149 rpD->hasDepthStencil =
false;
6150 if (m_desc.depthStencilBuffer()) {
6151 rpD->hasDepthStencil =
true;
6152 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
6153 }
else if (m_desc.depthTexture()) {
6154 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
6155 rpD->hasDepthStencil =
true;
6156 rpD->dsFormat = toD3DDepthTextureDSVFormat(depthTexD->format());
6159 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
6161 rpD->updateSerializedFormat();
6163 QRHI_RES_RHI(QRhiD3D12);
6164 rhiD->registerResource(rpD);
6168bool QD3D12TextureRenderTarget::create()
6170 if (rtv[0].isValid() || dsv.isValid())
6173 QRHI_RES_RHI(QRhiD3D12);
6174 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
6175 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
6176 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
6177 d.colorAttCount = 0;
6180 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
6181 d.colorAttCount += 1;
6182 const QRhiColorAttachment &colorAtt(*it);
6183 QRhiTexture *texture = colorAtt.texture();
6184 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
6185 Q_ASSERT(texture || rb);
6187 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, texture);
6188 QD3D12Resource *res = rhiD->resourcePool.lookupRef(texD->handle);
6190 qWarning(
"Could not look up texture handle for render target");
6193 const bool isMultiView = it->multiViewCount() >= 2;
6194 UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
6195 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6196 rtvDesc.Format = texD->rtFormat;
6197 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
6198 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
6199 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
6200 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
6201 rtvDesc.Texture2DArray.ArraySize = layerCount;
6202 }
else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
6203 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
6204 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
6205 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
6206 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
6207 rtvDesc.Texture1DArray.ArraySize = layerCount;
6209 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
6210 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
6212 }
else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
6213 if (texD->sampleDesc.Count > 1) {
6214 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
6215 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
6216 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
6218 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
6219 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
6220 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
6221 rtvDesc.Texture2DArray.ArraySize = layerCount;
6223 }
else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
6224 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
6225 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
6226 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
6227 rtvDesc.Texture3D.WSize = layerCount;
6229 if (texD->sampleDesc.Count > 1) {
6230 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
6232 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
6233 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
6236 rtv[attIndex] = rhiD->rtvPool.allocate(1);
6237 if (!rtv[attIndex].isValid()) {
6238 qWarning(
"Failed to allocate RTV for texture render target");
6241 rhiD->dev->CreateRenderTargetView(res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
6242 ownsRtv[attIndex] =
true;
6243 if (attIndex == 0) {
6244 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
6245 d.sampleCount =
int(texD->sampleDesc.Count);
6248 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rb);
6249 ownsRtv[attIndex] =
false;
6250 rtv[attIndex] = rbD->rtv;
6251 if (attIndex == 0) {
6252 d.pixelSize = rbD->pixelSize();
6253 d.sampleCount =
int(rbD->sampleDesc.Count);
6260 if (hasDepthStencil) {
6261 if (m_desc.depthTexture()) {
6263 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
6264 QD3D12Resource *res = rhiD->resourcePool.lookupRef(depthTexD->handle);
6266 qWarning(
"Could not look up depth texture handle");
6269 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
6270 dsvDesc.Format = depthTexD->rtFormat;
6271 const bool isMultisample = depthTexD->sampleDesc.Count > 1;
6272 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
6273 if (isMultisample) {
6274 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
6275 if (m_desc.depthLayer() >= 0) {
6276 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_desc.depthLayer());
6277 dsvDesc.Texture2DMSArray.ArraySize = 1;
6278 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
6279 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
6280 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
6282 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
6283 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
6286 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
6287 if (m_desc.depthLayer() >= 0) {
6288 dsvDesc.Texture2DArray.FirstArraySlice = UINT(m_desc.depthLayer());
6289 dsvDesc.Texture2DArray.ArraySize = 1;
6290 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
6291 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
6292 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
6294 dsvDesc.Texture2DArray.FirstArraySlice = 0;
6295 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
6300 dsvDesc.ViewDimension = isMultisample ? D3D12_DSV_DIMENSION_TEXTURE2DMS
6301 : D3D12_DSV_DIMENSION_TEXTURE2D;
6303 dsv = rhiD->dsvPool.allocate(1);
6304 if (!dsv.isValid()) {
6305 qWarning(
"Failed to allocate DSV for texture render target");
6308 rhiD->dev->CreateDepthStencilView(res->resource, &dsvDesc, dsv.cpuHandle);
6309 if (d.colorAttCount == 0) {
6310 d.pixelSize = depthTexD->pixelSize();
6311 d.sampleCount =
int(depthTexD->sampleDesc.Count);
6315 QD3D12RenderBuffer *depthRbD = QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
6316 dsv = depthRbD->dsv;
6317 if (d.colorAttCount == 0) {
6318 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
6319 d.sampleCount =
int(depthRbD->sampleDesc.Count);
6327 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
6328 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i)
6329 d.rtv[i] = i < d.colorAttCount ? rtv[i].cpuHandle : nullDescHandle;
6330 d.dsv = dsv.cpuHandle;
6331 d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6333 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &d.currentResIdList);
6335 rhiD->registerResource(
this);
6339QSize QD3D12TextureRenderTarget::pixelSize()
const
6341 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc, d.currentResIdList))
6342 const_cast<QD3D12TextureRenderTarget *>(
this)->create();
6347float QD3D12TextureRenderTarget::devicePixelRatio()
const
6352int QD3D12TextureRenderTarget::sampleCount()
const
6354 return d.sampleCount;
6357QD3D12ShaderResourceBindings::QD3D12ShaderResourceBindings(QRhiImplementation *rhi)
6358 : QRhiShaderResourceBindings(rhi)
6362QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
6367void QD3D12ShaderResourceBindings::destroy()
6369 bindingCache.reset();
6370 bindingCacheValid =
false;
6371 boundResourceData.clear();
6373 QRHI_RES_RHI(QRhiD3D12);
6375 rhiD->unregisterResource(
this);
6378bool QD3D12ShaderResourceBindings::create()
6380 QRHI_RES_RHI(QRhiD3D12);
6381 if (!rhiD->sanityCheckShaderResourceBindings(
this))
6384 rhiD->updateLayoutDesc(
this);
6386 boundResourceData.resize(m_bindings.count());
6387 for (BoundResourceData &bd : boundResourceData)
6388 memset(&bd, 0,
sizeof(BoundResourceData));
6390 bindingCache.reset();
6391 bindingCacheValid =
false;
6393 hasDynamicOffset =
false;
6394 for (
const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
6395 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
6396 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
6397 hasDynamicOffset =
true;
6411 rhiD->registerResource(
this,
false);
6415void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
6419 Q_ASSERT(boundResourceData.count() == m_bindings.count());
6420 for (BoundResourceData &bd : boundResourceData)
6421 memset(&bd, 0,
sizeof(BoundResourceData));
6423 bindingCache.reset();
6424 bindingCacheValid =
false;
6434void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
6435 const QRhiShaderResourceBinding::Data::UniformBufferData &,
6439 D3D12_ROOT_PARAMETER1 rootParam = {};
6440 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
6441 rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
6442 rootParam.Descriptor.ShaderRegister = shaderRegister;
6443 rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
6444 visitorData.cbParams[s].append(rootParam);
6447void QD3D12ShaderResourceBindings::visitTextures(QD3D12Stage s,
6448 const QRhiShaderResourceBinding::TextureAndSampler *,
6450 int baseShaderRegister)
6455 D3D12_DESCRIPTOR_RANGE1 range = {};
6456 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
6457 range.NumDescriptors = UINT(count);
6458 range.BaseShaderRegister = baseShaderRegister;
6459 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[s];
6460 visitorData.currentSrvRangeOffset[s] += UINT(count);
6461 visitorData.srvRanges[s].append(range);
6462 if (visitorData.srvRanges[s].count() == 1) {
6463 visitorData.srvTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6464 visitorData.srvTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6468void QD3D12ShaderResourceBindings::visitSamplers(QD3D12Stage s,
6469 const QRhiShaderResourceBinding::TextureAndSampler *,
6471 int baseShaderRegister)
6479 int &rangeStoreIdx(visitorData.samplerRangeHeads[s]);
6480 if (rangeStoreIdx == 16) {
6481 qWarning(
"Sampler binding count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi", s);
6484 D3D12_DESCRIPTOR_RANGE1 range = {};
6485 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
6486 range.NumDescriptors = UINT(count);
6487 range.BaseShaderRegister = baseShaderRegister;
6488 visitorData.samplerRanges[s][rangeStoreIdx] = range;
6489 D3D12_ROOT_PARAMETER1 param = {};
6490 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6491 param.ShaderVisibility = qd3d12_stageToVisibility(s);
6492 param.DescriptorTable.NumDescriptorRanges = 1;
6493 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[s][rangeStoreIdx];
6495 visitorData.samplerTables[s].append(param);
6498void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage s,
6499 const QRhiShaderResourceBinding::Data::StorageBufferData &,
6500 QD3D12ShaderResourceVisitor::StorageOp,
6503 D3D12_DESCRIPTOR_RANGE1 range = {};
6504 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
6505 range.NumDescriptors = 1;
6506 range.BaseShaderRegister = shaderRegister;
6507 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
6508 visitorData.currentUavRangeOffset[s] += 1;
6509 visitorData.uavRanges[s].append(range);
6510 if (visitorData.uavRanges[s].count() == 1) {
6511 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6512 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6516void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage s,
6517 const QRhiShaderResourceBinding::Data::StorageImageData &,
6518 QD3D12ShaderResourceVisitor::StorageOp,
6521 D3D12_DESCRIPTOR_RANGE1 range = {};
6522 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
6523 range.NumDescriptors = 1;
6524 range.BaseShaderRegister = shaderRegister;
6525 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
6526 visitorData.currentUavRangeOffset[s] += 1;
6527 visitorData.uavRanges[s].append(range);
6528 if (visitorData.uavRanges[s].count() == 1) {
6529 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6530 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6534static void qd3d12_setPushConstantInfo(QD3D12ShaderStageData *sd,
const QShader &shader,
const QShaderKey &key)
6536 const QList<QShaderDescription::PushConstantBlock> blocks = shader.description().pushConstantBlocks();
6537 if (blocks.isEmpty())
6539 sd->pushConstantRegister = shader.nativeShaderInfo(key).extraBufferBindings.value(
6540 QShaderPrivate::HlslPushConstantBufferBinding, -1);
6541 sd->pushConstantSize = quint32((blocks.first().size + 3) & ~3);
6544QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
6547 QRHI_RES_RHI(QRhiD3D12);
6561 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
6565 using namespace std::placeholders;
6566 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
6567 visitor.textures = std::bind(&QD3D12ShaderResourceBindings::visitTextures,
this, _1, _2, _3, _4);
6568 visitor.samplers = std::bind(&QD3D12ShaderResourceBindings::visitSamplers,
this, _1, _2, _3, _4);
6569 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
6570 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
6594 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> rootParams;
6595 for (
int s = 0; s < 6; ++s) {
6596 if (!visitorData.cbParams[s].isEmpty())
6597 rootParams.append(visitorData.cbParams[s].constData(), visitorData.cbParams[s].count());
6599 for (
int s = 0; s < 6; ++s) {
6600 if (!visitorData.srvRanges[s].isEmpty()) {
6601 visitorData.srvTables[s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[s].count();
6602 visitorData.srvTables[s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[s].constData();
6603 rootParams.append(visitorData.srvTables[s]);
6606 for (
int s = 0; s < 6; ++s) {
6607 if (!visitorData.samplerTables[s].isEmpty())
6608 rootParams.append(visitorData.samplerTables[s].constData(), visitorData.samplerTables[s].count());
6610 for (
int s = 0; s < 6; ++s) {
6611 if (!visitorData.uavRanges[s].isEmpty()) {
6612 visitorData.uavTables[s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[s].count();
6613 visitorData.uavTables[s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[s].constData();
6614 rootParams.append(visitorData.uavTables[s]);
6620 pushConstantRootParamIndex = -1;
6621 UINT pushConstantReg = 0;
6622 quint32 pushConstantSize = 0;
6623 int pushConstantStages = 0;
6624 D3D12_SHADER_VISIBILITY pushConstantVis = D3D12_SHADER_VISIBILITY_ALL;
6625 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
6626 const QD3D12ShaderStageData &sd(stageData[stageIdx]);
6627 if (!sd.valid || !sd.pushConstantSize || sd.pushConstantRegister < 0)
6629 pushConstantReg = UINT(sd.pushConstantRegister);
6630 pushConstantSize = qMax(pushConstantSize, sd.pushConstantSize);
6631 pushConstantVis = qd3d12_stageToVisibility(sd.stage);
6632 ++pushConstantStages;
6634 if (pushConstantSize) {
6638 D3D12_ROOT_PARAMETER1 param = {};
6639 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
6640 param.ShaderVisibility = pushConstantStages > 1 ? D3D12_SHADER_VISIBILITY_ALL : pushConstantVis;
6641 param.Constants.ShaderRegister = pushConstantReg;
6642 param.Constants.Num32BitValues = pushConstantSize / 4;
6643 pushConstantRootParamIndex = rootParams.count();
6644 rootParams.append(param);
6647 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
6648 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
6649 if (!rootParams.isEmpty()) {
6650 rsDesc.Desc_1_1.NumParameters = rootParams.count();
6651 rsDesc.Desc_1_1.pParameters = rootParams.constData();
6655 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
6656 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
6657 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
6659 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
6661 ID3DBlob *signature =
nullptr;
6662 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
6664 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
6667 ID3D12RootSignature *rootSig =
nullptr;
6668 hr = rhiD->dev->CreateRootSignature(0,
6669 signature->GetBufferPointer(),
6670 signature->GetBufferSize(),
6671 __uuidof(ID3D12RootSignature),
6672 reinterpret_cast<
void **>(&rootSig));
6673 signature->Release();
6675 qWarning(
"Failed to create root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
6679 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
6691static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
6693 const int smMajor = version / 10;
6694 const int smMinor = version % 10;
6695 target[0] = stage[0];
6696 target[1] = stage[1];
6698 target[3] =
'0' + smMajor;
6700 target[5] =
'0' + smMinor;
6704enum class HlslCompileFlag
6706 WithDebugInfo = 0x01
6709static QByteArray legacyCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
6711 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
6713 qWarning(
"Unable to resolve function D3DCompile()");
6714 return QByteArray();
6717 ID3DBlob *bytecode =
nullptr;
6718 ID3DBlob *errors =
nullptr;
6719 UINT d3dCompileFlags = 0;
6720 if (flags &
int(HlslCompileFlag::WithDebugInfo))
6721 d3dCompileFlags |= D3DCOMPILE_DEBUG;
6723 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
6724 nullptr,
nullptr,
nullptr,
6725 hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
6726 if (FAILED(hr) || !bytecode) {
6727 qWarning(
"HLSL shader compilation failed: 0x%x", uint(hr));
6729 *error = QString::fromUtf8(
static_cast<
const char *>(errors->GetBufferPointer()),
6730 int(errors->GetBufferSize()));
6733 return QByteArray();
6737 result.resize(
int(bytecode->GetBufferSize()));
6738 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
6739 bytecode->Release();
6743#ifdef QRHI_D3D12_HAS_DXC
6746#define DXC_CP_UTF8 65001
6749#ifndef DXC_ARG_DEBUG
6750#define DXC_ARG_DEBUG L"-Zi"
6753static QByteArray dxcCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
6755 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
6756 IDxcCompiler *compiler = dxc.first;
6758 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
6759 "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
6760 return QByteArray();
6762 IDxcLibrary *library = dxc.second;
6764 return QByteArray();
6766 IDxcBlobEncoding *sourceBlob =
nullptr;
6767 HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
6768 UINT32(hlslSource.shader().size()),
6772 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
6774 qPrintable(QSystemError::windowsComString(hr)));
6775 return QByteArray();
6778 const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
6779 const QString targetStr = QString::fromLatin1(target);
6781 QVarLengthArray<LPCWSTR, 4> argPtrs;
6783 if (flags &
int(HlslCompileFlag::WithDebugInfo)) {
6784 debugArg = QString::fromUtf16(
reinterpret_cast<
const char16_t *>(DXC_ARG_DEBUG));
6785 argPtrs.append(
reinterpret_cast<LPCWSTR>(debugArg.utf16()));
6788 IDxcOperationResult *result =
nullptr;
6789 hr = compiler->Compile(sourceBlob,
6791 reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
6792 reinterpret_cast<LPCWSTR>(targetStr.utf16()),
6793 argPtrs.data(), argPtrs.count(),
6797 sourceBlob->Release();
6799 result->GetStatus(&hr);
6801 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
6803 qPrintable(QSystemError::windowsComString(hr)));
6805 IDxcBlobEncoding *errorsBlob =
nullptr;
6806 if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
6808 *error = QString::fromUtf8(
static_cast<
const char *>(errorsBlob->GetBufferPointer()),
6809 int(errorsBlob->GetBufferSize()));
6810 errorsBlob->Release();
6814 return QByteArray();
6817 IDxcBlob *bytecode =
nullptr;
6818 if FAILED(result->GetResult(&bytecode)) {
6819 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
6821 qPrintable(QSystemError::windowsComString(hr)));
6822 return QByteArray();
6826 ba.resize(
int(bytecode->GetBufferSize()));
6827 memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
6828 bytecode->Release();
6834static QByteArray compileHlslShaderSource(
const QShader &shader,
6835 QShader::Variant shaderVariant,
6838 QShaderKey *usedShaderKey)
6841 const int shaderModelMax = 67;
6842 for (
int sm = shaderModelMax; sm >= 50; --sm) {
6843 for (QShader::Source type : { QShader::DxilShader, QShader::DxbcShader }) {
6844 QShaderKey key = { type, sm, shaderVariant };
6845 QShaderCode intermediateBytecodeShader = shader.shader(key);
6846 if (!intermediateBytecodeShader.shader().isEmpty()) {
6848 *usedShaderKey = key;
6849 return intermediateBytecodeShader.shader();
6854 QShaderCode hlslSource;
6856 for (
int sm = shaderModelMax; sm >= 50; --sm) {
6857 key = { QShader::HlslShader, sm, shaderVariant };
6858 hlslSource = shader.shader(key);
6859 if (!hlslSource.shader().isEmpty())
6863 if (hlslSource.shader().isEmpty()) {
6864 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" << shader;
6865 return QByteArray();
6869 *usedShaderKey = key;
6872 switch (shader.stage()) {
6873 case QShader::VertexStage:
6874 makeHlslTargetString(target,
"vs", key.sourceVersion().version());
6876 case QShader::TessellationControlStage:
6877 makeHlslTargetString(target,
"hs", key.sourceVersion().version());
6879 case QShader::TessellationEvaluationStage:
6880 makeHlslTargetString(target,
"ds", key.sourceVersion().version());
6882 case QShader::GeometryStage:
6883 makeHlslTargetString(target,
"gs", key.sourceVersion().version());
6885 case QShader::FragmentStage:
6886 makeHlslTargetString(target,
"ps", key.sourceVersion().version());
6888 case QShader::ComputeStage:
6889 makeHlslTargetString(target,
"cs", key.sourceVersion().version());
6892 qWarning(
"compileHlslShaderSource: Unknown stage (%d)",
int(shader.stage()));
6893 return QByteArray();
6896 if (key.sourceVersion().version() >= 60) {
6897#ifdef QRHI_D3D12_HAS_DXC
6898 return dxcCompile(hlslSource, target, flags, error);
6900 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
6901 "but the Qt build has no support for DXC. "
6902 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
6906 return legacyCompile(hlslSource, target, flags, error);
6909static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
6912 if (c.testFlag(QRhiGraphicsPipeline::R))
6913 f |= D3D12_COLOR_WRITE_ENABLE_RED;
6914 if (c.testFlag(QRhiGraphicsPipeline::G))
6915 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
6916 if (c.testFlag(QRhiGraphicsPipeline::B))
6917 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
6918 if (c.testFlag(QRhiGraphicsPipeline::A))
6919 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
6923static inline D3D12_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f,
bool rgb)
6932 case QRhiGraphicsPipeline::Zero:
6933 return D3D12_BLEND_ZERO;
6934 case QRhiGraphicsPipeline::One:
6935 return D3D12_BLEND_ONE;
6936 case QRhiGraphicsPipeline::SrcColor:
6937 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
6938 case QRhiGraphicsPipeline::OneMinusSrcColor:
6939 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
6940 case QRhiGraphicsPipeline::DstColor:
6941 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
6942 case QRhiGraphicsPipeline::OneMinusDstColor:
6943 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
6944 case QRhiGraphicsPipeline::SrcAlpha:
6945 return D3D12_BLEND_SRC_ALPHA;
6946 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6947 return D3D12_BLEND_INV_SRC_ALPHA;
6948 case QRhiGraphicsPipeline::DstAlpha:
6949 return D3D12_BLEND_DEST_ALPHA;
6950 case QRhiGraphicsPipeline::OneMinusDstAlpha:
6951 return D3D12_BLEND_INV_DEST_ALPHA;
6952 case QRhiGraphicsPipeline::ConstantColor:
6953 case QRhiGraphicsPipeline::ConstantAlpha:
6954 return D3D12_BLEND_BLEND_FACTOR;
6955 case QRhiGraphicsPipeline::OneMinusConstantColor:
6956 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
6957 return D3D12_BLEND_INV_BLEND_FACTOR;
6958 case QRhiGraphicsPipeline::SrcAlphaSaturate:
6959 return D3D12_BLEND_SRC_ALPHA_SAT;
6960 case QRhiGraphicsPipeline::Src1Color:
6961 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
6962 case QRhiGraphicsPipeline::OneMinusSrc1Color:
6963 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
6964 case QRhiGraphicsPipeline::Src1Alpha:
6965 return D3D12_BLEND_SRC1_ALPHA;
6966 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
6967 return D3D12_BLEND_INV_SRC1_ALPHA;
6969 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
6972static inline D3D12_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
6975 case QRhiGraphicsPipeline::Add:
6976 return D3D12_BLEND_OP_ADD;
6977 case QRhiGraphicsPipeline::Subtract:
6978 return D3D12_BLEND_OP_SUBTRACT;
6979 case QRhiGraphicsPipeline::ReverseSubtract:
6980 return D3D12_BLEND_OP_REV_SUBTRACT;
6981 case QRhiGraphicsPipeline::Min:
6982 return D3D12_BLEND_OP_MIN;
6983 case QRhiGraphicsPipeline::Max:
6984 return D3D12_BLEND_OP_MAX;
6986 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
6989static inline D3D12_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
6992 case QRhiGraphicsPipeline::None:
6993 return D3D12_CULL_MODE_NONE;
6994 case QRhiGraphicsPipeline::Front:
6995 return D3D12_CULL_MODE_FRONT;
6996 case QRhiGraphicsPipeline::Back:
6997 return D3D12_CULL_MODE_BACK;
6999 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
7002static inline D3D12_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
7005 case QRhiGraphicsPipeline::Fill:
7006 return D3D12_FILL_MODE_SOLID;
7007 case QRhiGraphicsPipeline::Line:
7008 return D3D12_FILL_MODE_WIREFRAME;
7010 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
7013static inline D3D12_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
7016 case QRhiGraphicsPipeline::Never:
7017 return D3D12_COMPARISON_FUNC_NEVER;
7018 case QRhiGraphicsPipeline::Less:
7019 return D3D12_COMPARISON_FUNC_LESS;
7020 case QRhiGraphicsPipeline::Equal:
7021 return D3D12_COMPARISON_FUNC_EQUAL;
7022 case QRhiGraphicsPipeline::LessOrEqual:
7023 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
7024 case QRhiGraphicsPipeline::Greater:
7025 return D3D12_COMPARISON_FUNC_GREATER;
7026 case QRhiGraphicsPipeline::NotEqual:
7027 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
7028 case QRhiGraphicsPipeline::GreaterOrEqual:
7029 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
7030 case QRhiGraphicsPipeline::Always:
7031 return D3D12_COMPARISON_FUNC_ALWAYS;
7033 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
7036static inline D3D12_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
7039 case QRhiGraphicsPipeline::StencilZero:
7040 return D3D12_STENCIL_OP_ZERO;
7041 case QRhiGraphicsPipeline::Keep:
7042 return D3D12_STENCIL_OP_KEEP;
7043 case QRhiGraphicsPipeline::Replace:
7044 return D3D12_STENCIL_OP_REPLACE;
7045 case QRhiGraphicsPipeline::IncrementAndClamp:
7046 return D3D12_STENCIL_OP_INCR_SAT;
7047 case QRhiGraphicsPipeline::DecrementAndClamp:
7048 return D3D12_STENCIL_OP_DECR_SAT;
7049 case QRhiGraphicsPipeline::Invert:
7050 return D3D12_STENCIL_OP_INVERT;
7051 case QRhiGraphicsPipeline::IncrementAndWrap:
7052 return D3D12_STENCIL_OP_INCR;
7053 case QRhiGraphicsPipeline::DecrementAndWrap:
7054 return D3D12_STENCIL_OP_DECR;
7056 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
7059static inline D3D12_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t,
int patchControlPointCount)
7062 case QRhiGraphicsPipeline::Triangles:
7063 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
7064 case QRhiGraphicsPipeline::TriangleStrip:
7065 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
7066 case QRhiGraphicsPipeline::TriangleFan:
7067 qWarning(
"Triangle fans are not supported with D3D");
7068 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
7069 case QRhiGraphicsPipeline::Lines:
7070 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
7071 case QRhiGraphicsPipeline::LineStrip:
7072 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
7073 case QRhiGraphicsPipeline::Points:
7074 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
7075 case QRhiGraphicsPipeline::Patches:
7076 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
7077 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
7079 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
7082static inline D3D12_PRIMITIVE_TOPOLOGY_TYPE toD3DTopologyType(QRhiGraphicsPipeline::Topology t)
7085 case QRhiGraphicsPipeline::Triangles:
7086 case QRhiGraphicsPipeline::TriangleStrip:
7087 case QRhiGraphicsPipeline::TriangleFan:
7088 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
7089 case QRhiGraphicsPipeline::Lines:
7090 case QRhiGraphicsPipeline::LineStrip:
7091 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
7092 case QRhiGraphicsPipeline::Points:
7093 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
7094 case QRhiGraphicsPipeline::Patches:
7095 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
7097 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
7100static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
7103 case QRhiVertexInputAttribute::Float4:
7104 return DXGI_FORMAT_R32G32B32A32_FLOAT;
7105 case QRhiVertexInputAttribute::Float3:
7106 return DXGI_FORMAT_R32G32B32_FLOAT;
7107 case QRhiVertexInputAttribute::Float2:
7108 return DXGI_FORMAT_R32G32_FLOAT;
7109 case QRhiVertexInputAttribute::Float:
7110 return DXGI_FORMAT_R32_FLOAT;
7111 case QRhiVertexInputAttribute::UNormByte4:
7112 return DXGI_FORMAT_R8G8B8A8_UNORM;
7113 case QRhiVertexInputAttribute::UNormByte2:
7114 return DXGI_FORMAT_R8G8_UNORM;
7115 case QRhiVertexInputAttribute::UNormByte:
7116 return DXGI_FORMAT_R8_UNORM;
7117 case QRhiVertexInputAttribute::UInt4:
7118 return DXGI_FORMAT_R32G32B32A32_UINT;
7119 case QRhiVertexInputAttribute::UInt3:
7120 return DXGI_FORMAT_R32G32B32_UINT;
7121 case QRhiVertexInputAttribute::UInt2:
7122 return DXGI_FORMAT_R32G32_UINT;
7123 case QRhiVertexInputAttribute::UInt:
7124 return DXGI_FORMAT_R32_UINT;
7125 case QRhiVertexInputAttribute::SInt4:
7126 return DXGI_FORMAT_R32G32B32A32_SINT;
7127 case QRhiVertexInputAttribute::SInt3:
7128 return DXGI_FORMAT_R32G32B32_SINT;
7129 case QRhiVertexInputAttribute::SInt2:
7130 return DXGI_FORMAT_R32G32_SINT;
7131 case QRhiVertexInputAttribute::SInt:
7132 return DXGI_FORMAT_R32_SINT;
7133 case QRhiVertexInputAttribute::Half4:
7135 case QRhiVertexInputAttribute::Half3:
7136 return DXGI_FORMAT_R16G16B16A16_FLOAT;
7137 case QRhiVertexInputAttribute::Half2:
7138 return DXGI_FORMAT_R16G16_FLOAT;
7139 case QRhiVertexInputAttribute::Half:
7140 return DXGI_FORMAT_R16_FLOAT;
7141 case QRhiVertexInputAttribute::UShort4:
7143 case QRhiVertexInputAttribute::UShort3:
7144 return DXGI_FORMAT_R16G16B16A16_UINT;
7145 case QRhiVertexInputAttribute::UShort2:
7146 return DXGI_FORMAT_R16G16_UINT;
7147 case QRhiVertexInputAttribute::UShort:
7148 return DXGI_FORMAT_R16_UINT;
7149 case QRhiVertexInputAttribute::SShort4:
7151 case QRhiVertexInputAttribute::SShort3:
7152 return DXGI_FORMAT_R16G16B16A16_SINT;
7153 case QRhiVertexInputAttribute::SShort2:
7154 return DXGI_FORMAT_R16G16_SINT;
7155 case QRhiVertexInputAttribute::SShort:
7156 return DXGI_FORMAT_R16_SINT;
7158 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
7161QD3D12GraphicsPipeline::QD3D12GraphicsPipeline(QRhiImplementation *rhi)
7162 : QRhiGraphicsPipeline(rhi)
7166QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
7171void QD3D12GraphicsPipeline::destroy()
7173 if (handle.isNull())
7176 QRHI_RES_RHI(QRhiD3D12);
7178 rhiD->releaseQueue.deferredReleasePipeline(handle);
7179 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
7186 rhiD->unregisterResource(
this);
7189bool QD3D12GraphicsPipeline::create()
7191 if (!handle.isNull())
7194 QRHI_RES_RHI(QRhiD3D12);
7195 if (!rhiD->sanityCheckGraphicsPipeline(
this))
7198 rhiD->pipelineCreationStart();
7200 QByteArray shaderBytecode[5];
7201 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
7202 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
7203 stageData[d3dStage].valid =
true;
7204 stageData[d3dStage].stage = d3dStage;
7205 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
7206 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
7207 shaderBytecode[d3dStage] = cacheIt->bytecode;
7208 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
7209 stageData[d3dStage].pushConstantRegister = cacheIt->pushConstantRegister;
7210 stageData[d3dStage].pushConstantSize = cacheIt->pushConstantSize;
7213 QShaderKey shaderKey;
7214 int compileFlags = 0;
7215 if (m_flags.testFlag(CompileShadersWithDebugInfo))
7216 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
7217 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
7218 shaderStage.shaderVariant(),
7222 if (bytecode.isEmpty()) {
7223 qWarning(
"HLSL graphics shader compilation failed: %s", qPrintable(error));
7227 shaderBytecode[d3dStage] = bytecode;
7228 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
7229 qd3d12_setPushConstantInfo(&stageData[d3dStage], shaderStage.shader(), shaderKey);
7230 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
7231 { bytecode, stageData[d3dStage].nativeResourceBindingMap,
7232 stageData[d3dStage].pushConstantRegister,
7233 stageData[d3dStage].pushConstantSize });
7237 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
7239 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
7240 pushConstantRootParamIndex = srbD->pushConstantRootParamIndex;
7241 if (rootSigHandle.isNull()) {
7242 qWarning(
"Failed to create root signature");
7246 ID3D12RootSignature *rootSig =
nullptr;
7247 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
7248 rootSig = rs->rootSig;
7250 qWarning(
"Cannot create graphics pipeline state without root signature");
7254 QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7255 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
7256 if (rpD->colorAttachmentCount > 0) {
7257 format = DXGI_FORMAT(rpD->colorFormat[0]);
7258 }
else if (rpD->hasDepthStencil) {
7259 format = DXGI_FORMAT(rpD->dsFormat);
7261 qWarning(
"Cannot create graphics pipeline state without color or depthStencil format");
7264 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
7267 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
7268 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
7269 QD3D12PipelineStateSubObject<D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE> primitiveRestartValue;
7270 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
7271 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
7272 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
7273 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
7274 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
7275 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
7276 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
7277 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
7278 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
7279 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
7280 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
7281 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
7282 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
7283 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
7286 stream.rootSig.object = rootSig;
7288 QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
7289 QByteArrayList matrixSliceSemantics;
7290 if (!shaderBytecode[VS].isEmpty()) {
7291 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
7294 D3D12_INPUT_ELEMENT_DESC desc = {};
7299 const int matrixSlice = it->matrixSlice();
7300 if (matrixSlice < 0) {
7301 desc.SemanticName =
"TEXCOORD";
7302 desc.SemanticIndex = UINT(it->location());
7306 std::snprintf(sem.data(), sem.size(),
"TEXCOORD%d_", it->location() - matrixSlice);
7307 matrixSliceSemantics.append(sem);
7308 desc.SemanticName = matrixSliceSemantics.last().constData();
7309 desc.SemanticIndex = UINT(matrixSlice);
7311 desc.Format = toD3DAttributeFormat(it->format());
7312 desc.InputSlot = UINT(it->binding());
7313 desc.AlignedByteOffset = it->offset();
7314 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
7315 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
7316 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
7317 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
7319 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
7321 inputDescs.append(desc);
7325 stream.inputLayout.object.NumElements = inputDescs.count();
7326 stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ?
nullptr : inputDescs.constData();
7328 stream.primitiveRestartValue.object = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
7330 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
7331 topology = toD3DTopology(m_topology, m_patchControlPointCount);
7333 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
7334 const int d3dStage = qd3d12_stage(shaderStage.type());
7337 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7338 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7341 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7342 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7345 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7346 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7349 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7350 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7353 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7354 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7362 stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
7363 stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
7364 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
7365 stream.rasterizerState.object.DepthBias = m_depthBias;
7366 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
7367 stream.rasterizerState.object.DepthClipEnable = m_depthClamp ? FALSE : TRUE;
7368 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
7370 stream.depthStencilState.object.DepthEnable = m_depthTest;
7371 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
7372 stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
7373 stream.depthStencilState.object.StencilEnable = m_stencilTest;
7374 if (m_stencilTest) {
7375 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
7376 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
7377 stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
7378 stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
7379 stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
7380 stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
7381 stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
7382 stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
7383 stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
7384 stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
7387 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
7388 for (
int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
7389 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
7390 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
7391 blend.BlendEnable = b.enable;
7392 blend.SrcBlend = toD3DBlendFactor(b.srcColor,
true);
7393 blend.DestBlend = toD3DBlendFactor(b.dstColor,
true);
7394 blend.BlendOp = toD3DBlendOp(b.opColor);
7395 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha,
false);
7396 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha,
false);
7397 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
7398 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
7399 stream.blendState.object.RenderTarget[i] = blend;
7401 if (m_targetBlends.isEmpty()) {
7402 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
7403 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
7404 stream.blendState.object.RenderTarget[0] = blend;
7407 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
7408 for (
int i = 0; i < rpD->colorAttachmentCount; ++i)
7409 stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
7411 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
7413 stream.sampleDesc.object = sampleDesc;
7415 stream.sampleMask.object = 0xFFFFFFFF;
7417 viewInstanceMask = 0;
7418 const bool isMultiView = m_multiViewCount >= 2;
7419 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
7420 QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
7422 for (
int i = 0; i < m_multiViewCount; ++i) {
7423 viewInstanceMask |= (1 << i);
7424 viewInstanceLocations.append({ 0, UINT(i) });
7426 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
7429 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
7431 QCryptographicHash keyHash(QCryptographicHash::Sha1);
7432 for (
const QByteArray &bytecode : shaderBytecode)
7433 addToKey(&keyHash, bytecode);
7434 for (
const D3D12_INPUT_ELEMENT_DESC &desc : inputDescs) {
7435 keyHash.addData(QByteArrayView(desc.SemanticName));
7436 addToKey(&keyHash, desc.SemanticIndex);
7437 addToKey(&keyHash, desc.Format);
7438 addToKey(&keyHash, desc.InputSlot);
7439 addToKey(&keyHash, desc.AlignedByteOffset);
7440 addToKey(&keyHash, desc.InputSlotClass);
7441 addToKey(&keyHash, desc.InstanceDataStepRate);
7443 addToKey(&keyHash, stream.primitiveRestartValue.object);
7444 addToKey(&keyHash, stream.primitiveTopology.object);
7445 addToKey(&keyHash, stream.rasterizerState.object);
7446 addToKey(&keyHash, stream.depthStencilState.object);
7447 addToKey(&keyHash, stream.blendState.object);
7448 addToKey(&keyHash, stream.rtFormats.object);
7449 addToKey(&keyHash, stream.dsFormat.object);
7450 addToKey(&keyHash, stream.sampleDesc.object);
7451 addToKey(&keyHash, stream.sampleMask.object);
7452 addToKey(&keyHash, stream.viewInstancingDesc.object.ViewInstanceCount);
7453 addToKey(&keyHash, stream.viewInstancingDesc.object.Flags);
7454 addToKey(&keyHash, viewInstanceLocations.constData(),
7455 viewInstanceLocations.count() *
sizeof(D3D12_VIEW_INSTANCE_LOCATION));
7458 addToKey(&keyHash, srbD->serializedLayoutDescription());
7460 ID3D12PipelineState *pso = rhiD->loadOrCreatePipelineState(&streamDesc, keyHash.result().toHex(),
"graphics");
7462 rhiD->rootSignaturePool.remove(rootSigHandle);
7467 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
7469 rhiD->pipelineCreationEnd();
7471 rhiD->registerResource(
this);
7475QD3D12ComputePipeline::QD3D12ComputePipeline(QRhiImplementation *rhi)
7476 : QRhiComputePipeline(rhi)
7480QD3D12ComputePipeline::~QD3D12ComputePipeline()
7485void QD3D12ComputePipeline::destroy()
7487 if (handle.isNull())
7490 QRHI_RES_RHI(QRhiD3D12);
7492 rhiD->releaseQueue.deferredReleasePipeline(handle);
7493 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
7500 rhiD->unregisterResource(
this);
7503bool QD3D12ComputePipeline::create()
7505 if (!handle.isNull())
7508 QRHI_RES_RHI(QRhiD3D12);
7509 rhiD->pipelineCreationStart();
7511 stageData.valid =
true;
7512 stageData.stage = CS;
7514 QByteArray shaderBytecode;
7515 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(m_shaderStage);
7516 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
7517 shaderBytecode = cacheIt->bytecode;
7518 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
7519 stageData.pushConstantRegister = cacheIt->pushConstantRegister;
7520 stageData.pushConstantSize = cacheIt->pushConstantSize;
7523 QShaderKey shaderKey;
7524 int compileFlags = 0;
7525 if (m_flags.testFlag(CompileShadersWithDebugInfo))
7526 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
7527 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
7528 m_shaderStage.shaderVariant(),
7532 if (bytecode.isEmpty()) {
7533 qWarning(
"HLSL compute shader compilation failed: %s", qPrintable(error));
7537 shaderBytecode = bytecode;
7538 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
7539 qd3d12_setPushConstantInfo(&stageData, m_shaderStage.shader(), shaderKey);
7540 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
7541 stageData.nativeResourceBindingMap,
7542 stageData.pushConstantRegister,
7543 stageData.pushConstantSize });
7546 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
7548 rootSigHandle = srbD->createRootSignature(&stageData, 1);
7549 pushConstantRootParamIndex = srbD->pushConstantRootParamIndex;
7550 if (rootSigHandle.isNull()) {
7551 qWarning(
"Failed to create root signature");
7555 ID3D12RootSignature *rootSig =
nullptr;
7556 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
7557 rootSig = rs->rootSig;
7559 qWarning(
"Cannot create compute pipeline state without root signature");
7564 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
7565 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
7567 stream.rootSig.object = rootSig;
7568 stream.CS.object.pShaderBytecode = shaderBytecode.constData();
7569 stream.CS.object.BytecodeLength = shaderBytecode.size();
7570 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
7572 QCryptographicHash keyHash(QCryptographicHash::Sha1);
7573 addToKey(&keyHash, shaderBytecode);
7574 addToKey(&keyHash, srbD->serializedLayoutDescription());
7576 ID3D12PipelineState *pso = rhiD->loadOrCreatePipelineState(&streamDesc, keyHash.result().toHex(),
"compute");
7578 rhiD->rootSignaturePool.remove(rootSigHandle);
7583 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
7585 rhiD->pipelineCreationEnd();
7587 rhiD->registerResource(
this);
7594QD3D12RenderPassDescriptor::QD3D12RenderPassDescriptor(QRhiImplementation *rhi)
7595 : QRhiRenderPassDescriptor(rhi)
7597 serializedFormatData.reserve(16);
7600QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
7605void QD3D12RenderPassDescriptor::destroy()
7607 QRHI_RES_RHI(QRhiD3D12);
7609 rhiD->unregisterResource(
this);
7612bool QD3D12RenderPassDescriptor::isCompatible(
const QRhiRenderPassDescriptor *other)
const
7617 const QD3D12RenderPassDescriptor *o = QRHI_RES(
const QD3D12RenderPassDescriptor, other);
7619 if (colorAttachmentCount != o->colorAttachmentCount)
7622 if (hasDepthStencil != o->hasDepthStencil)
7625 for (
int i = 0; i < colorAttachmentCount; ++i) {
7626 if (colorFormat[i] != o->colorFormat[i])
7630 if (hasDepthStencil) {
7631 if (dsFormat != o->dsFormat)
7635 if (hasShadingRateMap != o->hasShadingRateMap)
7641void QD3D12RenderPassDescriptor::updateSerializedFormat()
7643 serializedFormatData.clear();
7644 auto p = std::back_inserter(serializedFormatData);
7646 *p++ = colorAttachmentCount;
7647 *p++ = hasDepthStencil;
7648 for (
int i = 0; i < colorAttachmentCount; ++i)
7649 *p++ = colorFormat[i];
7650 *p++ = hasDepthStencil ? dsFormat : 0;
7653QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor()
const
7655 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
7656 rpD->colorAttachmentCount = colorAttachmentCount;
7657 rpD->hasDepthStencil = hasDepthStencil;
7658 memcpy(rpD->colorFormat, colorFormat,
sizeof(colorFormat));
7659 rpD->dsFormat = dsFormat;
7660 rpD->hasShadingRateMap = hasShadingRateMap;
7662 rpD->updateSerializedFormat();
7664 QRHI_RES_RHI(QRhiD3D12);
7665 rhiD->registerResource(rpD);
7669QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat()
const
7671 return serializedFormatData;
7674QD3D12CommandBuffer::QD3D12CommandBuffer(QRhiImplementation *rhi)
7675 : QRhiCommandBuffer(rhi)
7680QD3D12CommandBuffer::~QD3D12CommandBuffer()
7685void QD3D12CommandBuffer::destroy()
7690const QRhiNativeHandles *QD3D12CommandBuffer::nativeHandles()
7692 nativeHandlesStruct.commandList = cmdList;
7693 return &nativeHandlesStruct;
7696QD3D12SwapChainRenderTarget::QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
7697 : QRhiSwapChainRenderTarget(rhi, swapchain),
7702QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
7707void QD3D12SwapChainRenderTarget::destroy()
7712QSize QD3D12SwapChainRenderTarget::pixelSize()
const
7717float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
7722int QD3D12SwapChainRenderTarget::sampleCount()
const
7724 return d.sampleCount;
7727QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
7728 : QRhiSwapChain(rhi),
7729 rtWrapper(rhi,
this),
7730 rtWrapperRight(rhi,
this),
7735QD3D12SwapChain::~QD3D12SwapChain()
7740void QD3D12SwapChain::destroy()
7747 swapChain->Release();
7748 swapChain =
nullptr;
7749 sourceSwapChain1->Release();
7750 sourceSwapChain1 =
nullptr;
7752 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7753 FrameResources &fr(frameRes[i]);
7755 fr.fence->Release();
7757 CloseHandle(fr.fenceEvent);
7759 fr.cmdList->Release();
7764 dcompVisual->Release();
7765 dcompVisual =
nullptr;
7769 dcompTarget->Release();
7770 dcompTarget =
nullptr;
7773 if (frameLatencyWaitableObject) {
7774 CloseHandle(frameLatencyWaitableObject);
7775 frameLatencyWaitableObject =
nullptr;
7778 QDxgiVSyncService::instance()->unregisterWindow(window);
7780 QRHI_RES_RHI(QRhiD3D12);
7782 rhiD->swapchains.remove(
this);
7783 rhiD->unregisterResource(
this);
7787void QD3D12SwapChain::releaseBuffers()
7789 QRHI_RES_RHI(QRhiD3D12);
7791 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7792 rhiD->resourcePool.remove(colorBuffers[i]);
7793 rhiD->rtvPool.release(rtvs[i], 1);
7795 rhiD->rtvPool.release(rtvsRight[i], 1);
7797 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7798 if (!msaaBuffers[i].isNull())
7799 rhiD->resourcePool.remove(msaaBuffers[i]);
7800 if (msaaRtvs[i].isValid())
7801 rhiD->rtvPool.release(msaaRtvs[i], 1);
7805void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
7807 FrameResources &fr(frameRes[frameSlot]);
7808 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
7809 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
7810 WaitForSingleObject(fr.fenceEvent, INFINITE);
7814void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
7816 QRHI_RES_RHI(QRhiD3D12);
7817 FrameResources &fr(frameRes[currentFrameSlot]);
7818 fr.fenceCounter += 1u;
7819 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
7822QRhiCommandBuffer *QD3D12SwapChain::currentFrameCommandBuffer()
7827QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
7832QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
7834 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
7837QSize QD3D12SwapChain::surfacePixelSize()
7840 return m_window->size() * m_window->devicePixelRatio();
7843bool QD3D12SwapChain::isFormatSupported(Format f)
7849 qWarning(
"Attempted to call isFormatSupported() without a window set");
7853 QRHI_RES_RHI(QRhiD3D12);
7854 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window))
7855 return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
7860QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
7862 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
7865 QRHI_RES_RHI(QRhiD3D12);
7866 info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window);
7871QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
7876 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
7877 rpD->colorAttachmentCount = 1;
7878 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
7879 rpD->colorFormat[0] =
int(srgbAdjustedColorFormat);
7880 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
7882 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
7884 rpD->updateSerializedFormat();
7886 QRHI_RES_RHI(QRhiD3D12);
7887 rhiD->registerResource(rpD);
7891bool QRhiD3D12::ensureDirectCompositionDevice()
7896 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
7897 dcompDevice = QRhiD3D::createDirectCompositionDevice();
7898 return dcompDevice ?
true :
false;
7901static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
7902static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
7904void QD3D12SwapChain::chooseFormats()
7906 colorFormat = DEFAULT_FORMAT;
7907 srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
7908 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
7909 QRHI_RES_RHI(QRhiD3D12);
7910 if (m_format != SDR) {
7911 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) {
7914 case HDRExtendedSrgbLinear:
7915 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
7916 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
7917 srgbAdjustedColorFormat = colorFormat;
7920 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
7921 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
7922 srgbAdjustedColorFormat = colorFormat;
7931 qWarning(
"The output associated with the window is not HDR capable "
7932 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
7935 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
7938bool QD3D12SwapChain::createOrResize()
7944 const bool needsRegistration = !window || window != m_window;
7947 if (window && window != m_window)
7951 m_currentPixelSize = surfacePixelSize();
7952 pixelSize = m_currentPixelSize;
7954 if (pixelSize.isEmpty())
7957 HWND hwnd =
reinterpret_cast<HWND>(window->winId());
7959 QRHI_RES_RHI(QRhiD3D12);
7960 stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
7962 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
7963 if (rhiD->ensureDirectCompositionDevice()) {
7965 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
false, &dcompTarget);
7967 qWarning(
"Failed to create Direct Composition target for the window: %s",
7968 qPrintable(QSystemError::windowsComString(hr)));
7971 if (dcompTarget && !dcompVisual) {
7972 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
7974 qWarning(
"Failed to create DirectComposition visual: %s",
7975 qPrintable(QSystemError::windowsComString(hr)));
7980 if (window->requestedFormat().alphaBufferSize() <= 0)
7981 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
7982 "This may lead to problems.");
7985 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
7987 if (swapInterval == 0 && rhiD->supportsAllowTearing)
7988 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
7992 const bool useFrameLatencyWaitableObject = rhiD->maxFrameLatency != 0
7993 && swapInterval != 0
7994 && rhiD->driverInfoStruct.deviceType != QRhiDriverInfo::CpuDevice;
7995 if (useFrameLatencyWaitableObject)
7996 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
8001 DXGI_SWAP_CHAIN_DESC1 desc = {};
8002 desc.Width = UINT(pixelSize.width());
8003 desc.Height = UINT(pixelSize.height());
8004 desc.Format = colorFormat;
8005 desc.SampleDesc.Count = 1;
8006 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
8007 desc.BufferCount = BUFFER_COUNT;
8008 desc.Flags = swapChainFlags;
8009 desc.Scaling = DXGI_SCALING_NONE;
8010 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
8011 desc.Stereo = stereo;
8017 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
8022 desc.Scaling = DXGI_SCALING_STRETCH;
8026 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
8028 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
8033 if (FAILED(hr) && m_format != SDR) {
8034 colorFormat = DEFAULT_FORMAT;
8035 desc.Format = DEFAULT_FORMAT;
8037 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
8039 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
8042 if (SUCCEEDED(hr)) {
8043 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<
void **>(&swapChain)))) {
8044 qWarning(
"IDXGISwapChain3 not available");
8047 if (m_format != SDR) {
8048 hr = swapChain->SetColorSpace1(hdrColorSpace);
8050 qWarning(
"Failed to set color space on swapchain: %s",
8051 qPrintable(QSystemError::windowsComString(hr)));
8054 if (useFrameLatencyWaitableObject) {
8055 swapChain->SetMaximumFrameLatency(rhiD->maxFrameLatency);
8056 frameLatencyWaitableObject = swapChain->GetFrameLatencyWaitableObject();
8059 hr = dcompVisual->SetContent(swapChain);
8060 if (SUCCEEDED(hr)) {
8061 hr = dcompTarget->SetRoot(dcompVisual);
8063 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
8064 qPrintable(QSystemError::windowsComString(hr)));
8067 qWarning(
"Failed to set content for Direct Composition visual: %s",
8068 qPrintable(QSystemError::windowsComString(hr)));
8072 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
8075 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
8076 qWarning(
"Device loss detected during swapchain creation");
8077 rhiD->deviceLost =
true;
8079 }
else if (FAILED(hr)) {
8080 qWarning(
"Failed to create D3D12 swapchain: %s"
8081 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
8082 qPrintable(QSystemError::windowsComString(hr)),
8083 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
8084 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
8088 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
8089 hr = rhiD->dev->CreateFence(0,
8090 D3D12_FENCE_FLAG_NONE,
8091 __uuidof(ID3D12Fence),
8092 reinterpret_cast<
void **>(&frameRes[i].fence));
8094 qWarning(
"Failed to create fence for swapchain: %s",
8095 qPrintable(QSystemError::windowsComString(hr)));
8098 frameRes[i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
8100 frameRes[i].fenceCounter = 0;
8104 hr = swapChain->ResizeBuffers(BUFFER_COUNT,
8105 UINT(pixelSize.width()),
8106 UINT(pixelSize.height()),
8109 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
8110 qWarning(
"Device loss detected in ResizeBuffers()");
8111 rhiD->deviceLost =
true;
8113 }
else if (FAILED(hr)) {
8114 qWarning(
"Failed to resize D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
8119 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
8120 ID3D12Resource *colorBuffer;
8121 hr = swapChain->GetBuffer(i, __uuidof(ID3D12Resource),
reinterpret_cast<
void **>(&colorBuffer));
8123 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
8124 i, qPrintable(QSystemError::windowsComString(hr)));
8127 colorBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
8128 rtvs[i] = rhiD->rtvPool.allocate(1);
8129 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
8130 rtvDesc.Format = srgbAdjustedColorFormat;
8131 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
8132 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
8135 rtvsRight[i] = rhiD->rtvPool.allocate(1);
8136 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
8137 rtvDesc.Format = srgbAdjustedColorFormat;
8138 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
8139 rtvDesc.Texture2DArray.ArraySize = 1;
8140 rtvDesc.Texture2DArray.FirstArraySlice = 1;
8141 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
8145 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
8146 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
8147 m_depthStencil->sampleCount(), m_sampleCount);
8149 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
8150 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
8151 m_depthStencil->setPixelSize(pixelSize);
8152 if (!m_depthStencil->create())
8153 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
8154 pixelSize.width(), pixelSize.height());
8156 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
8157 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
8158 pixelSize.width(), pixelSize.height());
8162 ds = m_depthStencil ? QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
8164 if (sampleDesc.Count > 1) {
8165 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
8166 D3D12_RESOURCE_DESC resourceDesc = {};
8167 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
8168 resourceDesc.Width = UINT64(pixelSize.width());
8169 resourceDesc.Height = UINT(pixelSize.height());
8170 resourceDesc.DepthOrArraySize = 1;
8171 resourceDesc.MipLevels = 1;
8172 resourceDesc.Format = srgbAdjustedColorFormat;
8173 resourceDesc.SampleDesc = sampleDesc;
8174 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
8175 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
8176 D3D12_CLEAR_VALUE clearValue = {};
8177 clearValue.Format = colorFormat;
8178 ID3D12Resource *resource =
nullptr;
8179 D3D12MA::Allocation *allocation =
nullptr;
8180 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
8182 D3D12_RESOURCE_STATE_RENDER_TARGET,
8185 __uuidof(ID3D12Resource),
8186 reinterpret_cast<
void **>(&resource));
8188 qWarning(
"Failed to create MSAA color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
8191 msaaBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
8192 msaaRtvs[i] = rhiD->rtvPool.allocate(1);
8193 if (!msaaRtvs[i].isValid())
8195 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
8196 rtvDesc.Format = srgbAdjustedColorFormat;
8197 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
8198 : D3D12_RTV_DIMENSION_TEXTURE2D;
8199 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[i].cpuHandle);
8203 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
8204 currentFrameSlot = 0;
8205 lastFrameLatencyWaitSlot = -1;
8207 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
8208 QD3D12SwapChainRenderTarget *rtD = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
8209 rtD->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
8210 rtD->d.pixelSize = pixelSize;
8211 rtD->d.dpr =
float(window->devicePixelRatio());
8212 rtD->d.sampleCount =
int(sampleDesc.Count);
8213 rtD->d.colorAttCount = 1;
8214 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
8216 rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
8217 QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
8218 rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
8219 rtDr->d.pixelSize = pixelSize;
8220 rtDr->d.dpr =
float(window->devicePixelRatio());
8221 rtDr->d.sampleCount =
int(sampleDesc.Count);
8222 rtDr->d.colorAttCount = 1;
8223 rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
8225 QDxgiVSyncService::instance()->registerWindow(window);
8227 if (needsRegistration || !rhiD->swapchains.contains(
this))
8228 rhiD->swapchains.insert(
this);
8230 rhiD->registerResource(
this);