7#include <QtCore/private/qsystemerror_p.h>
8#include <QtCore/qcryptographichash.h>
16#define QRHI_D3D12_HAS_OLD_PIX
19#ifdef __ID3D12Device2_INTERFACE_DEFINED__
24
25
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
69
70
71
72
73
74
75
76
77
80
81
82
83
84
85
86
87
88
89
90
91
94
95
96
97
98
99
102
103
104
105
106
107
108
109
110
111
112
115
116
117
118
119
120
123
124
125
126
127
128
131
132
133
134
135
136
137
140
141
142
143
144
145
146
147
148
149
150
151
152
153
156
157
160static const D3D_FEATURE_LEVEL MIN_FEATURE_LEVEL = D3D_FEATURE_LEVEL_11_0;
162QRhiD3D12::QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importParams)
164 debugLayer = params->enableDebugLayer;
166 if (importParams->dev) {
167 ID3D12Device *d3d12Device =
reinterpret_cast<ID3D12Device *>(importParams->dev);
168 if (SUCCEEDED(d3d12Device->QueryInterface(__uuidof(ID3D12Device2),
reinterpret_cast<
void **>(&dev)))) {
170 d3d12Device->Release();
171 importedDevice =
true;
173 qWarning(
"ID3D12Device2 not supported, cannot import device");
176 if (importParams->commandQueue) {
177 cmdQueue =
reinterpret_cast<ID3D12CommandQueue *>(importParams->commandQueue);
178 importedCommandQueue =
true;
180 minimumFeatureLevel = D3D_FEATURE_LEVEL(importParams->minimumFeatureLevel);
181 adapterLuid.LowPart = importParams->adapterLuidLow;
182 adapterLuid.HighPart = importParams->adapterLuidHigh;
187inline Int aligned(Int v, Int byteAlign)
189 return (v + byteAlign - 1) & ~(byteAlign - 1);
192static inline UINT calcSubresource(UINT mipSlice, UINT arraySlice, UINT mipLevels)
194 return mipSlice + arraySlice * mipLevels;
197static inline QD3D12RenderTargetData *rtData(QRhiRenderTarget *rt)
199 switch (rt->resourceType()) {
200 case QRhiResource::SwapChainRenderTarget:
201 return &QRHI_RES(QD3D12SwapChainRenderTarget, rt)->d;
202 case QRhiResource::TextureRenderTarget:
203 return &QRHI_RES(QD3D12TextureRenderTarget, rt)->d;
208 Q_UNREACHABLE_RETURN(
nullptr);
211#ifdef QRHI_D3D12_INFOQUEUE1_AVAILABLE
212static void __stdcall qd3d12_message_callback(D3D12_MESSAGE_CATEGORY category,
213 D3D12_MESSAGE_SEVERITY severity,
223 if (severity == D3D12_MESSAGE_SEVERITY_INFO)
225 if (id == D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE
226 || id == D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE
227 || id == D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE)
234 qDebug(
"D3D12: %s", description);
238bool QRhiD3D12::create(QRhi::Flags flags)
242 UINT factoryFlags = 0;
244 factoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
245 HRESULT hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
249 qCDebug(QRHI_LOG_INFO,
"Debug layer was requested but is not available. "
250 "Attempting to create DXGIFactory2 without it.");
251 factoryFlags &= ~DXGI_CREATE_FACTORY_DEBUG;
252 hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
257 qWarning(
"CreateDXGIFactory2() failed to create DXGI factory: %s",
258 qPrintable(QSystemError::windowsComString(hr)));
263 if (qEnvironmentVariableIsSet(
"QT_D3D_MAX_FRAME_LATENCY"))
264 maxFrameLatency = UINT(qMax(0, qEnvironmentVariableIntValue(
"QT_D3D_MAX_FRAME_LATENCY")));
265 if (maxFrameLatency != 0)
266 qCDebug(QRHI_LOG_INFO,
"Using frame latency waitable object with max frame latency %u", maxFrameLatency);
268 supportsAllowTearing =
false;
269 IDXGIFactory5 *factory5 =
nullptr;
270 if (SUCCEEDED(dxgiFactory->QueryInterface(__uuidof(IDXGIFactory5),
reinterpret_cast<
void **>(&factory5)))) {
271 BOOL allowTearing =
false;
272 if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing,
sizeof(allowTearing))))
273 supportsAllowTearing = allowTearing;
278 ID3D12Debug1 *debug =
nullptr;
279 if (SUCCEEDED(D3D12GetDebugInterface(__uuidof(ID3D12Debug1),
reinterpret_cast<
void **>(&debug)))) {
280 qCDebug(QRHI_LOG_INFO,
"Enabling D3D12 debug layer");
281 debug->EnableDebugLayer();
286 activeAdapter =
nullptr;
288 if (!importedDevice) {
289 IDXGIAdapter1 *adapter;
290 int requestedAdapterIndex = -1;
291 if (qEnvironmentVariableIsSet(
"QT_D3D_ADAPTER_INDEX"))
292 requestedAdapterIndex = qEnvironmentVariableIntValue(
"QT_D3D_ADAPTER_INDEX");
294 if (requestedRhiAdapter)
295 adapterLuid =
static_cast<QD3D12Adapter *>(requestedRhiAdapter)->luid;
298 if (requestedAdapterIndex < 0 && (adapterLuid.LowPart || adapterLuid.HighPart)) {
299 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
300 DXGI_ADAPTER_DESC1 desc;
301 adapter->GetDesc1(&desc);
303 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
304 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
306 requestedAdapterIndex = adapterIndex;
312 if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
313 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
314 DXGI_ADAPTER_DESC1 desc;
315 adapter->GetDesc1(&desc);
317 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
318 requestedAdapterIndex = adapterIndex;
324 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
325 DXGI_ADAPTER_DESC1 desc;
326 adapter->GetDesc1(&desc);
327 const QString name = QString::fromUtf16(
reinterpret_cast<
char16_t *>(desc.Description));
328 qCDebug(QRHI_LOG_INFO,
"Adapter %d: '%s' (vendor 0x%X device 0x%X flags 0x%X)",
334 if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
335 activeAdapter = adapter;
336 adapterLuid = desc.AdapterLuid;
337 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
338 qCDebug(QRHI_LOG_INFO,
" using this adapter");
343 if (!activeAdapter) {
344 qWarning(
"No adapter");
348 if (minimumFeatureLevel == 0)
349 minimumFeatureLevel = MIN_FEATURE_LEVEL;
351 hr = D3D12CreateDevice(activeAdapter,
353 __uuidof(ID3D12Device2),
354 reinterpret_cast<
void **>(&dev));
356 qWarning(
"Failed to create D3D12 device: %s", qPrintable(QSystemError::windowsComString(hr)));
362 adapterLuid = dev->GetAdapterLuid();
363 IDXGIAdapter1 *adapter;
364 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
365 DXGI_ADAPTER_DESC1 desc;
366 adapter->GetDesc1(&desc);
367 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
368 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
370 activeAdapter = adapter;
371 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
377 if (!activeAdapter) {
378 qWarning(
"No adapter");
381 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
384 QDxgiVSyncService::instance()->refAdapter(adapterLuid);
387 ID3D12InfoQueue *infoQueue;
388 if (SUCCEEDED(dev->QueryInterface(__uuidof(ID3D12InfoQueue),
reinterpret_cast<
void **>(&infoQueue)))) {
389 if (qEnvironmentVariableIntValue(
"QT_D3D_DEBUG_BREAK")) {
390 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION,
true);
391 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR,
true);
392 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING,
true);
394 D3D12_INFO_QUEUE_FILTER filter = {};
395 D3D12_MESSAGE_ID suppressedMessages[3] = {
397 D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
399 D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
401 D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE
403 filter.DenyList.NumIDs = 3;
404 filter.DenyList.pIDList = suppressedMessages;
407 D3D12_MESSAGE_SEVERITY infoSev = D3D12_MESSAGE_SEVERITY_INFO;
408 filter.DenyList.NumSeverities = 1;
409 filter.DenyList.pSeverityList = &infoSev;
410 infoQueue->PushStorageFilter(&filter);
411#ifdef QRHI_D3D12_INFOQUEUE1_AVAILABLE
416 if (SUCCEEDED(infoQueue->QueryInterface(__uuidof(ID3D12InfoQueue1),
reinterpret_cast<
void **>(&infoQueue1)))) {
421 if (SUCCEEDED(infoQueue1->RegisterMessageCallback(qd3d12_message_callback,
422 D3D12_MESSAGE_CALLBACK_IGNORE_FILTERS,
424 &infoQueueCallbackCookie)))
428 infoQueue1->SetMuteDebugOutput(
true);
430 infoQueue1->Release();
431 infoQueue1 =
nullptr;
435 infoQueue->Release();
439 if (!importedCommandQueue) {
440 D3D12_COMMAND_QUEUE_DESC queueDesc = {};
441 queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
442 queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
443 hr = dev->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue),
reinterpret_cast<
void **>(&cmdQueue));
445 qWarning(
"Failed to create command queue: %s", qPrintable(QSystemError::windowsComString(hr)));
450 hr = dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence),
reinterpret_cast<
void **>(&fullFence));
452 qWarning(
"Failed to create fence: %s", qPrintable(QSystemError::windowsComString(hr)));
455 fullFenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
456 fullFenceCounter = 0;
458 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
459 hr = dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
460 __uuidof(ID3D12CommandAllocator),
461 reinterpret_cast<
void **>(&cmdAllocators[i]));
463 qWarning(
"Failed to create command allocator: %s", qPrintable(QSystemError::windowsComString(hr)));
468 if (!vma.create(dev, activeAdapter)) {
469 qWarning(
"Failed to initialize graphics memory suballocator");
473 if (!rtvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
"main RTV pool")) {
474 qWarning(
"Could not create RTV pool");
478 if (!dsvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
"main DSV pool")) {
479 qWarning(
"Could not create DSV pool");
483 if (!cbvSrvUavPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
"main CBV-SRV-UAV pool")) {
484 qWarning(
"Could not create CBV-SRV-UAV pool");
488 resourcePool.create(
"main resource pool");
489 pipelinePool.create(
"main pipeline pool");
490 rootSignaturePool.create(
"main root signature pool");
491 releaseQueue.create(&resourcePool, &pipelinePool, &rootSignaturePool);
492 barrierGen.create(&resourcePool);
494 if (!samplerMgr.create(dev)) {
495 qWarning(
"Could not create sampler pool and shader-visible sampler heap");
499 mipmapGen.create(
this);
500 mipmapGen3D.create(
this);
502 const qint32 smallStagingSize = aligned(SMALL_STAGING_AREA_BYTES_PER_FRAME_START, QD3D12StagingArea::ALIGNMENT);
503 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
504 if (!smallStagingAreas[i].create(
this, smallStagingSize, D3D12_HEAP_TYPE_UPLOAD)) {
505 qWarning(
"Could not create host-visible staging area");
508 QString decoratedName = QLatin1String(
"Small staging area buffer/");
509 decoratedName += QString::number(i);
510 smallStagingAreas[i].mem.buffer->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
513 if (!shaderVisibleCbvSrvUavHeap.create(dev,
514 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
515 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE))
517 qWarning(
"Could not create first shader-visible CBV/SRV/UAV heap");
521 if (flags.testFlag(QRhi::EnableTimestamps)) {
522 static bool wantsStablePowerState = qEnvironmentVariableIntValue(
"QT_D3D_STABLE_POWER_STATE");
538 if (wantsStablePowerState)
539 dev->SetStablePowerState(TRUE);
541 hr = cmdQueue->GetTimestampFrequency(×tampTicksPerSecond);
543 qWarning(
"Failed to query timestamp frequency: %s",
544 qPrintable(QSystemError::windowsComString(hr)));
547 if (!timestampQueryHeap.create(dev, QD3D12_FRAMES_IN_FLIGHT * 2, D3D12_QUERY_HEAP_TYPE_TIMESTAMP)) {
548 qWarning(
"Failed to create timestamp query pool");
551 const quint32 readbackBufSize = QD3D12_FRAMES_IN_FLIGHT * 2 *
sizeof(quint64);
552 if (!timestampReadbackArea.create(
this, readbackBufSize, D3D12_HEAP_TYPE_READBACK)) {
553 qWarning(
"Failed to create timestamp readback buffer");
556 timestampReadbackArea.mem.buffer->SetName(L"Timestamp readback buffer");
557 memset(timestampReadbackArea.mem.p, 0, readbackBufSize);
561 D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
562 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3,
sizeof(options3)))) {
563 caps.multiView = options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
565 caps.textureViewFormat = options3.CastingFullyTypedFormatSupported;
568#ifdef QRHI_D3D12_CL5_AVAILABLE
569 D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {};
570 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6,
sizeof(options6)))) {
571 caps.vrs = options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED;
572 caps.vrsMap = options6.VariableShadingRateTier == D3D12_VARIABLE_SHADING_RATE_TIER_2;
573 caps.vrsAdditionalRates = options6.AdditionalShadingRatesSupported;
574 shadingRateImageTileSize = options6.ShadingRateImageTileSize;
579 caps.vrsAdditionalRates =
false;
583 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
584 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
586 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
587 sigDesc.ByteStride =
sizeof(D3D12_DRAW_ARGUMENTS);
588 sigDesc.NumArgumentDescs = 1;
589 sigDesc.pArgumentDescs = &arg;
591 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&drawCommandSignature));
593 qWarning(
"Failed to create draw command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
599 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
600 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
602 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
603 sigDesc.ByteStride =
sizeof(D3D12_DRAW_INDEXED_ARGUMENTS);
604 sigDesc.NumArgumentDescs = 1;
605 sigDesc.pArgumentDescs = &arg;
607 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&drawIndexedCommandSignature));
609 qWarning(
"Failed to create draw indexed command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
615 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
616 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH;
618 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
619 sigDesc.ByteStride =
sizeof(D3D12_DISPATCH_ARGUMENTS);
620 sigDesc.NumArgumentDescs = 1;
621 sigDesc.pArgumentDescs = &arg;
623 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&dispatchCommandSignature));
625 qWarning(
"Failed to create dispatch command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
631 offscreenActive =
false;
633 nativeHandlesStruct.dev = dev;
634 nativeHandlesStruct.minimumFeatureLevel = minimumFeatureLevel;
635 nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
636 nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
637 nativeHandlesStruct.commandQueue = cmdQueue;
642void QRhiD3D12::destroy()
644 if (!deviceLost && fullFence && fullFenceEvent)
647 releaseQueue.releaseAll();
649 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
650 if (offscreenCb[i]) {
651 if (offscreenCb[i]->cmdList)
652 offscreenCb[i]->cmdList->Release();
653 delete offscreenCb[i];
654 offscreenCb[i] =
nullptr;
658 timestampQueryHeap.destroy();
659 timestampReadbackArea.destroy();
661 shaderVisibleCbvSrvUavHeap.destroy();
663 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i)
664 smallStagingAreas[i].destroy();
667 mipmapGen3D.destroy();
668 samplerMgr.destroy();
669 resourcePool.destroy();
670 pipelinePool.destroy();
671 rootSignaturePool.destroy();
674 cbvSrvUavPool.destroy();
676 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
677 if (cmdAllocators[i]) {
678 cmdAllocators[i]->Release();
679 cmdAllocators[i] =
nullptr;
683 if (fullFenceEvent) {
684 CloseHandle(fullFenceEvent);
685 fullFenceEvent =
nullptr;
689 fullFence->Release();
693 if (!importedCommandQueue) {
702#ifdef QRHI_D3D12_INFOQUEUE1_AVAILABLE
704 infoQueue1->UnregisterMessageCallback(infoQueueCallbackCookie);
705 infoQueue1->Release();
706 infoQueue1 =
nullptr;
707 infoQueueCallbackCookie = 0;
711 if (!importedDevice) {
719 dcompDevice->Release();
720 dcompDevice =
nullptr;
724 activeAdapter->Release();
725 activeAdapter =
nullptr;
729 dxgiFactory->Release();
730 dxgiFactory =
nullptr;
733 QDxgiVSyncService::instance()->derefAdapter(adapterLuid);
736 importedDevice =
false;
737 importedCommandQueue =
false;
739 if (drawCommandSignature) {
740 drawCommandSignature->Release();
741 drawCommandSignature =
nullptr;
744 if (drawIndexedCommandSignature) {
745 drawIndexedCommandSignature->Release();
746 drawIndexedCommandSignature =
nullptr;
749 if (dispatchCommandSignature) {
750 dispatchCommandSignature->Release();
751 dispatchCommandSignature =
nullptr;
754 for (ID3D12CommandSignature *sig : std::as_const(drawCommandSignaturesByStride))
756 drawCommandSignaturesByStride.clear();
758 for (ID3D12CommandSignature *sig : std::as_const(drawIndexedCommandSignaturesByStride))
760 drawIndexedCommandSignaturesByStride.clear();
762 destroyPipelineLibrary();
765QRhi::AdapterList QRhiD3D12::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
767 LUID requestedLuid = {};
769 QRhiD3D12NativeHandles *h =
static_cast<QRhiD3D12NativeHandles *>(nativeHandles);
770 const LUID adapterLuid = { h->adapterLuidLow, h->adapterLuidHigh };
771 if (adapterLuid.LowPart || adapterLuid.HighPart)
772 requestedLuid = adapterLuid;
775 IDXGIFactory2 *dxgi =
nullptr;
776 if (FAILED(CreateDXGIFactory2(0, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgi))))
779 QRhi::AdapterList list;
780 IDXGIAdapter1 *adapter;
781 for (
int adapterIndex = 0; dxgi->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
782 DXGI_ADAPTER_DESC1 desc;
783 adapter->GetDesc1(&desc);
785 if (requestedLuid.LowPart || requestedLuid.HighPart) {
786 if (desc.AdapterLuid.LowPart != requestedLuid.LowPart
787 || desc.AdapterLuid.HighPart != requestedLuid.HighPart)
792 QD3D12Adapter *a =
new QD3D12Adapter;
793 a->luid = desc.AdapterLuid;
794 QRhiD3D::fillDriverInfo(&a->adapterInfo, desc);
802QRhiDriverInfo QD3D12Adapter::info()
const
807QList<
int> QRhiD3D12::supportedSampleCounts()
const
809 return { 1, 2, 4, 8 };
812QList<QSize> QRhiD3D12::supportedShadingRates(
int sampleCount)
const
815 switch (sampleCount) {
818 if (caps.vrsAdditionalRates) {
819 sizes.append(QSize(4, 4));
820 sizes.append(QSize(4, 2));
821 sizes.append(QSize(2, 4));
823 sizes.append(QSize(2, 2));
824 sizes.append(QSize(2, 1));
825 sizes.append(QSize(1, 2));
828 if (caps.vrsAdditionalRates)
829 sizes.append(QSize(2, 4));
830 sizes.append(QSize(2, 2));
831 sizes.append(QSize(2, 1));
832 sizes.append(QSize(1, 2));
835 sizes.append(QSize(2, 2));
836 sizes.append(QSize(2, 1));
837 sizes.append(QSize(1, 2));
842 sizes.append(QSize(1, 1));
846QRhiSwapChain *QRhiD3D12::createSwapChain()
848 return new QD3D12SwapChain(
this);
851QRhiBuffer *QRhiD3D12::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
853 return new QD3D12Buffer(
this, type, usage, size);
856int QRhiD3D12::ubufAlignment()
const
858 return D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
861bool QRhiD3D12::isYUpInFramebuffer()
const
866bool QRhiD3D12::isYUpInNDC()
const
871bool QRhiD3D12::isClipDepthZeroToOne()
const
876QMatrix4x4 QRhiD3D12::clipSpaceCorrMatrix()
const
881 static constexpr QMatrix4x4 m(1.0f, 0.0f, 0.0f, 0.0f,
882 0.0f, 1.0f, 0.0f, 0.0f,
883 0.0f, 0.0f, 0.5f, 0.5f,
884 0.0f, 0.0f, 0.0f, 1.0f);
888bool QRhiD3D12::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags)
const
892 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ASTC_12x12)
898bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature)
const
901 case QRhi::MultisampleTexture:
903 case QRhi::MultisampleRenderBuffer:
905 case QRhi::DebugMarkers:
906#ifdef QRHI_D3D12_HAS_OLD_PIX
911 case QRhi::Timestamps:
913 case QRhi::Instancing:
915 case QRhi::CustomInstanceStepRate:
917 case QRhi::PrimitiveRestart:
919 case QRhi::NonDynamicUniformBuffers:
921 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
923 case QRhi::NPOTTextureRepeat:
925 case QRhi::RedOrAlpha8IsRed:
927 case QRhi::ElementIndexUint:
931 case QRhi::WideLines:
933 case QRhi::VertexShaderPointSize:
935 case QRhi::BaseVertex:
937 case QRhi::BaseInstance:
939 case QRhi::TriangleFanTopology:
941 case QRhi::ReadBackNonUniformBuffer:
943 case QRhi::ReadBackNonBaseMipLevel:
945 case QRhi::TexelFetch:
947 case QRhi::RenderToNonBaseMipLevel:
949 case QRhi::IntAttributes:
951 case QRhi::ScreenSpaceDerivatives:
953 case QRhi::ReadBackAnyTextureFormat:
955 case QRhi::PipelineCacheDataLoadSave:
956#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
961 case QRhi::ImageDataStride:
963 case QRhi::RenderBufferImport:
965 case QRhi::ThreeDimensionalTextures:
967 case QRhi::RenderTo3DTextureSlice:
969 case QRhi::TextureArrays:
971 case QRhi::Tessellation:
973 case QRhi::GeometryShader:
975 case QRhi::TextureArrayRange:
977 case QRhi::NonFillPolygonMode:
979 case QRhi::OneDimensionalTextures:
981 case QRhi::OneDimensionalTextureMipmaps:
983 case QRhi::HalfAttributes:
985 case QRhi::RenderToOneDimensionalTexture:
987 case QRhi::ThreeDimensionalTextureMipmaps:
989 case QRhi::MultiView:
990 return caps.multiView;
991 case QRhi::TextureViewFormat:
992 return caps.textureViewFormat;
993 case QRhi::ResolveDepthStencil:
997 case QRhi::VariableRateShading:
999 case QRhi::VariableRateShadingMap:
1000 case QRhi::VariableRateShadingMapWithTexture:
1002 case QRhi::PerRenderTargetBlending:
1003 case QRhi::SampleVariables:
1005 case QRhi::InstanceIndexIncludesBaseInstance:
1007 case QRhi::DepthClamp:
1009 case QRhi::DrawIndirect:
1010 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
1011 case QRhi::DrawIndirectMulti:
1012 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
1013 case QRhi::ShaderDrawParameters:
1015 case QRhi::DispatchIndirect:
1016 return dispatchCommandSignature !=
nullptr;
1017 case QRhi::DrawIndirectCount:
1019 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
1024int QRhiD3D12::resourceLimit(QRhi::ResourceLimit limit)
const
1027 case QRhi::TextureSizeMin:
1029 case QRhi::TextureSizeMax:
1031 case QRhi::MaxColorAttachments:
1033 case QRhi::FramesInFlight:
1034 return QD3D12_FRAMES_IN_FLIGHT;
1035 case QRhi::MaxAsyncReadbackFrames:
1036 return QD3D12_FRAMES_IN_FLIGHT;
1037 case QRhi::MaxThreadGroupsPerDimension:
1039 case QRhi::MaxThreadsPerThreadGroup:
1041 case QRhi::MaxThreadGroupX:
1043 case QRhi::MaxThreadGroupY:
1045 case QRhi::MaxThreadGroupZ:
1047 case QRhi::TextureArraySizeMax:
1049 case QRhi::MaxUniformBufferRange:
1051 case QRhi::MaxVertexInputs:
1053 case QRhi::MaxVertexOutputs:
1055 case QRhi::MaxVertexStorageBuffers:
1056 case QRhi::MaxFragmentStorageBuffers:
1058 case QRhi::ShadingRateImageTileSize:
1059 return shadingRateImageTileSize;
1064const QRhiNativeHandles *QRhiD3D12::nativeHandles()
1066 return &nativeHandlesStruct;
1069QRhiDriverInfo QRhiD3D12::driverInfo()
const
1071 return driverInfoStruct;
1074QRhiStats QRhiD3D12::statistics()
1077 result.totalPipelineCreationTime = totalPipelineCreationTime();
1079 D3D12MA::Budget budgets[2];
1080 vma.getBudget(&budgets[0], &budgets[1]);
1081 for (
int i = 0; i < 2; ++i) {
1082 const D3D12MA::Statistics &stats(budgets[i].Stats);
1083 result.blockCount += stats.BlockCount;
1084 result.allocCount += stats.AllocationCount;
1085 result.usedBytes += stats.AllocationBytes;
1086 result.unusedBytes += stats.BlockBytes - stats.AllocationBytes;
1087 result.totalUsageBytes += budgets[i].UsageBytes;
1093bool QRhiD3D12::makeThreadLocalNativeContextCurrent()
1099void QRhiD3D12::setQueueSubmitParams(QRhiNativeHandles *)
1104void QRhiD3D12::releaseCachedResources()
1106 shaderBytecodeCache.data.clear();
1115static inline void addToKey(QCryptographicHash *h,
const void *p, size_t size)
1117 h->addData(QByteArrayView(
static_cast<
const char *>(p), qsizetype(size)));
1121static inline void addToKey(QCryptographicHash *h,
const T &v)
1123 addToKey(h, &v,
sizeof(T));
1126static inline void addToKey(QCryptographicHash *h,
const QByteArray &b)
1128 const quint32 size = quint32(b.size());
1133static inline void addToKey(QCryptographicHash *h,
const QVector<quint32> &v)
1135 const quint32 count = quint32(v.count());
1137 addToKey(h, v.constData(), v.count() *
sizeof(quint32));
1140bool QRhiD3D12::createPipelineLibrary(
const QByteArray &blob)
1142#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1143 destroyPipelineLibrary();
1145 pipelineLibraryBlob = blob;
1146 HRESULT hr = dev->CreatePipelineLibrary(pipelineLibraryBlob.isEmpty() ?
nullptr
1147 : pipelineLibraryBlob.constData(),
1148 SIZE_T(pipelineLibraryBlob.size()),
1149 __uuidof(ID3D12PipelineLibrary1),
1150 reinterpret_cast<
void **>(&pipelineLibrary));
1156 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline library: %s",
1157 qPrintable(QSystemError::windowsComString(hr)));
1158 pipelineLibrary =
nullptr;
1159 pipelineLibraryBlob.clear();
1169bool QRhiD3D12::ensurePipelineLibrary()
1171#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1172 if (pipelineLibrary)
1174 if (!rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
1176 return createPipelineLibrary(QByteArray());
1182void QRhiD3D12::destroyPipelineLibrary()
1184#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1185 if (pipelineLibrary) {
1186 pipelineLibrary->Release();
1187 pipelineLibrary =
nullptr;
1189 pipelineLibraryBlob.clear();
1190 pipelineLibraryNames.clear();
1194ID3D12PipelineState *QRhiD3D12::loadOrCreatePipelineState(
const D3D12_PIPELINE_STATE_STREAM_DESC *streamDesc,
1195 const QByteArray &cacheKey,
1198 ID3D12PipelineState *pso =
nullptr;
1200#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1201 QVarLengthArray<
wchar_t, 64> name;
1202 if (ensurePipelineLibrary() && !cacheKey.isEmpty()) {
1203 name.resize(cacheKey.size() + 1);
1204 for (qsizetype i = 0; i < cacheKey.size(); ++i)
1205 name[i] =
wchar_t(cacheKey.at(i));
1206 name[cacheKey.size()] = 0;
1207 HRESULT hr = pipelineLibrary->LoadPipeline(name.constData(),
1209 __uuidof(ID3D12PipelineState),
1210 reinterpret_cast<
void **>(&pso));
1216 HRESULT hr = dev->CreatePipelineState(streamDesc,
1217 __uuidof(ID3D12PipelineState),
1218 reinterpret_cast<
void **>(&pso));
1220 qWarning(
"Failed to create %s pipeline state: %s",
1221 what, qPrintable(QSystemError::windowsComString(hr)));
1225#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1226 if (pipelineLibrary && !name.isEmpty() && !pipelineLibraryNames.contains(cacheKey)) {
1227 if (SUCCEEDED(pipelineLibrary->StorePipeline(name.constData(), pso)))
1228 pipelineLibraryNames.insert(cacheKey);
1235struct QD3D12PipelineCacheDataHeader
1243 quint64 adapterLuid;
1246QByteArray QRhiD3D12::pipelineCacheData()
1248 static_assert(
sizeof(QD3D12PipelineCacheDataHeader) == 32);
1251#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1252 if (!pipelineLibrary || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
1255 const SIZE_T dataSize = pipelineLibrary->GetSerializedSize();
1259 const size_t headerSize =
sizeof(QD3D12PipelineCacheDataHeader);
1260 data.resize(qsizetype(headerSize + dataSize));
1261 HRESULT hr = pipelineLibrary->Serialize(data.data() + headerSize, dataSize);
1263 qCDebug(QRHI_LOG_INFO,
"Failed to serialize pipeline library: %s",
1264 qPrintable(QSystemError::windowsComString(hr)));
1265 return QByteArray();
1268 QD3D12PipelineCacheDataHeader header = {};
1269 header.rhiId = pipelineCacheRhiId();
1270 header.arch = quint32(
sizeof(
void *));
1271 header.dataSize = quint32(dataSize);
1272 header.vendorId = quint32(driverInfoStruct.vendorId);
1273 header.deviceId = quint32(driverInfoStruct.deviceId);
1274 header.adapterLuid = (quint64(quint32(adapterLuid.HighPart)) << 32) | quint64(adapterLuid.LowPart);
1275 memcpy(data.data(), &header, headerSize);
1280void QRhiD3D12::setPipelineCacheData(
const QByteArray &data)
1282#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1286 const size_t headerSize =
sizeof(QD3D12PipelineCacheDataHeader);
1287 if (data.size() < qsizetype(headerSize)) {
1288 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
1291 QD3D12PipelineCacheDataHeader header;
1292 memcpy(&header, data.constData(), headerSize);
1294 const quint32 rhiId = pipelineCacheRhiId();
1295 if (header.rhiId != rhiId) {
1296 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
1297 rhiId, header.rhiId);
1300 const quint32 arch = quint32(
sizeof(
void *));
1301 if (header.arch != arch) {
1302 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
1306 if (header.vendorId != quint32(driverInfoStruct.vendorId)) {
1307 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorId does not match (%u, %u)",
1308 quint32(driverInfoStruct.vendorId), header.vendorId);
1311 if (header.deviceId != quint32(driverInfoStruct.deviceId)) {
1312 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceId does not match (%u, %u)",
1313 quint32(driverInfoStruct.deviceId), header.deviceId);
1316 const quint64 luid = (quint64(quint32(adapterLuid.HighPart)) << 32) | quint64(adapterLuid.LowPart);
1317 if (header.adapterLuid != luid) {
1318 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: adapter LUID does not match");
1321 if (quint64(data.size()) < quint64(headerSize) + header.dataSize) {
1322 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
1329 if (createPipelineLibrary(data.mid(qsizetype(headerSize)))) {
1330 qCDebug(QRHI_LOG_INFO,
"Created pipeline library with initial data of %u bytes",
1338bool QRhiD3D12::isDeviceLost()
const
1343QRhiRenderBuffer *QRhiD3D12::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
1344 int sampleCount, QRhiRenderBuffer::Flags flags,
1345 QRhiTexture::Format backingFormatHint)
1347 return new QD3D12RenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
1350QRhiTexture *QRhiD3D12::createTexture(QRhiTexture::Format format,
1351 const QSize &pixelSize,
int depth,
int arraySize,
1352 int sampleCount, QRhiTexture::Flags flags)
1354 return new QD3D12Texture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
1357QRhiSampler *QRhiD3D12::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
1358 QRhiSampler::Filter mipmapMode,
1359 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
1361 return new QD3D12Sampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
1364QRhiTextureRenderTarget *QRhiD3D12::createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
1365 QRhiTextureRenderTarget::Flags flags)
1367 return new QD3D12TextureRenderTarget(
this, desc, flags);
1370QRhiShadingRateMap *QRhiD3D12::createShadingRateMap()
1372 return new QD3D12ShadingRateMap(
this);
1375QRhiGraphicsPipeline *QRhiD3D12::createGraphicsPipeline()
1377 return new QD3D12GraphicsPipeline(
this);
1380QRhiComputePipeline *QRhiD3D12::createComputePipeline()
1382 return new QD3D12ComputePipeline(
this);
1385QRhiShaderResourceBindings *QRhiD3D12::createShaderResourceBindings()
1387 return new QD3D12ShaderResourceBindings(
this);
1390void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
1392 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1393 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1394 QD3D12GraphicsPipeline *psD = QRHI_RES(QD3D12GraphicsPipeline, ps);
1395 const bool pipelineChanged = cbD->currentGraphicsPipeline != psD || cbD->currentPipelineGeneration != psD->generation;
1397 if (pipelineChanged) {
1398 cbD->currentGraphicsPipeline = psD;
1399 cbD->currentComputePipeline =
nullptr;
1400 cbD->currentPipelineGeneration = psD->generation;
1402 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
1403 Q_ASSERT(pipeline->type == QD3D12Pipeline::Graphics);
1404 cbD->cmdList->SetPipelineState(pipeline->pso);
1405 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
1406 cbD->cmdList->SetGraphicsRootSignature(rs->rootSig);
1409 cbD->cmdList->IASetPrimitiveTopology(psD->topology);
1411 if (psD->viewInstanceMask)
1412 cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
1414 if (cbD->hasCustomScissorSet && !psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor))
1415 setDefaultScissor(cbD);
1419void QD3D12ShaderResourceBindings::cacheUniformBuffer(QD3D12Stage s,
1420 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
1427 bindingCache.cbufs[s].append({ QRHI_RES(QD3D12Buffer, d.buf), d.offset, binding });
1430void QD3D12ShaderResourceBindings::cacheTextures(QD3D12Stage s,
1431 const QRhiShaderResourceBinding::TextureAndSampler *d,
1435 for (
int i = 0; i < count; ++i) {
1436 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d[i].tex);
1437 bindingCache.srvs[s].append(texD->srv.cpuHandle);
1441void QD3D12ShaderResourceBindings::cacheSamplers(QD3D12Stage s,
1442 const QRhiShaderResourceBinding::TextureAndSampler *d,
1447 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, d[0].sampler);
1448 bindingCache.samplers[s].append(samplerD->lookupOrCreateShaderVisibleDescriptor().gpuHandle);
1456 QRHI_RES_RHI(QRhiD3D12);
1457 QVarLengthArray<Q_D3D12_SAMPLER_DESC, 8> descs;
1458 for (
int i = 0; i < count; ++i)
1459 descs.append({ QRHI_RES(QD3D12Sampler, d[i].sampler)->desc });
1460 bindingCache.samplers[s].append(rhiD->samplerMgr.getShaderVisibleDescriptors(descs).gpuHandle);
1463void QD3D12ShaderResourceBindings::cacheStorageBuffer(QD3D12Stage s,
1464 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
1465 QD3D12ShaderResourceVisitor::StorageOp,
1468 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1470 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1471 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1472 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
1473 uavDesc.Buffer.FirstElement = d.offset / 4;
1474 uavDesc.Buffer.NumElements = aligned(bufD->m_size - d.offset, 4u) / 4;
1475 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
1476 bindingCache.uavs[s].append({ bufD->handles[0], uavDesc });
1479void QD3D12ShaderResourceBindings::cacheStorageImage(QD3D12Stage s,
1480 const QRhiShaderResourceBinding::Data::StorageImageData &d,
1481 QD3D12ShaderResourceVisitor::StorageOp,
1484 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1485 const bool isCube = texD->m_flags.testFlag(QRhiTexture::CubeMap);
1486 const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
1487 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1488 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1489 uavDesc.Format = texD->rtFormat;
1491 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1492 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1493 uavDesc.Texture2DArray.FirstArraySlice = 0;
1494 uavDesc.Texture2DArray.ArraySize = 6;
1495 }
else if (isArray) {
1496 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1497 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1498 uavDesc.Texture2DArray.FirstArraySlice = 0;
1499 uavDesc.Texture2DArray.ArraySize = UINT(qMax(0, texD->m_arraySize));
1501 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1502 uavDesc.Texture3D.MipSlice = UINT(d.level);
1503 uavDesc.Texture3D.WSize = UINT(-1);
1505 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
1506 uavDesc.Texture2D.MipSlice = UINT(d.level);
1508 bindingCache.uavs[s].append({ texD->handle, uavDesc });
1511void QD3D12ShaderResourceBindings::rebuildBindingCache(
const QD3D12ShaderStageData *stageData,
1514 bindingCache.reset();
1516 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
1518 using namespace std::placeholders;
1519 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::cacheUniformBuffer,
this, _1, _2, _3, _4);
1520 visitor.textures = std::bind(&QD3D12ShaderResourceBindings::cacheTextures,
this, _1, _2, _3, _4);
1521 visitor.samplers = std::bind(&QD3D12ShaderResourceBindings::cacheSamplers,
this, _1, _2, _3, _4);
1522 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::cacheStorageBuffer,
this, _1, _2, _3, _4);
1523 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::cacheStorageImage,
this, _1, _2, _3, _4);
1528 for (
int s = 0; s < 6; ++s) {
1529 bindingCache.srvUavCount += bindingCache.srvs[s].count();
1530 bindingCache.srvUavCount += bindingCache.uavs[s].count();
1533 bindingCacheValid =
true;
1534 bindingCacheGeneration = generation;
1537void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
1538 int dynamicOffsetCount,
1539 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1541 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1542 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
1543 QD3D12GraphicsPipeline *gfxPsD = QRHI_RES(QD3D12GraphicsPipeline, cbD->currentGraphicsPipeline);
1544 QD3D12ComputePipeline *compPsD = QRHI_RES(QD3D12ComputePipeline, cbD->currentComputePipeline);
1548 srb = gfxPsD->m_shaderResourceBindings;
1550 srb = compPsD->m_shaderResourceBindings;
1553 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, srb);
1555 bool pipelineChanged =
false;
1557 pipelineChanged = srbD->lastUsedGraphicsPipeline != gfxPsD
1558 || srbD->lastUsedPipelineGeneration != gfxPsD->generation;
1559 srbD->lastUsedGraphicsPipeline = gfxPsD;
1560 srbD->lastUsedComputePipeline =
nullptr;
1561 srbD->lastUsedPipelineGeneration = gfxPsD->generation;
1563 pipelineChanged = srbD->lastUsedComputePipeline != compPsD
1564 || srbD->lastUsedPipelineGeneration != compPsD->generation;
1565 srbD->lastUsedGraphicsPipeline =
nullptr;
1566 srbD->lastUsedComputePipeline = compPsD;
1567 srbD->lastUsedPipelineGeneration = compPsD->generation;
1570 bool srbUpdate =
false;
1572 for (
int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
1573 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings[i]);
1574 QD3D12ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
1576 case QRhiShaderResourceBinding::UniformBuffer:
1578 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.ubuf.buf);
1579 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
1580 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1581 sanityCheckResourceOwnership(bufD);
1582 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1583 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
1585 bd.ubuf.id = bufD->m_id;
1586 bd.ubuf.generation = bufD->generation;
1590 case QRhiShaderResourceBinding::SampledTexture:
1591 case QRhiShaderResourceBinding::Texture:
1592 case QRhiShaderResourceBinding::Sampler:
1594 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
1595 if (bd.stex.count != data->count) {
1596 bd.stex.count = data->count;
1599 for (
int elem = 0; elem < data->count; ++elem) {
1600 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, data->texSamplers[elem].tex);
1601 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, data->texSamplers[elem].sampler);
1605 Q_ASSERT(texD || samplerD);
1606 sanityCheckResourceOwnership(texD);
1607 sanityCheckResourceOwnership(samplerD);
1608 const quint64 texId = texD ? texD->m_id : 0;
1609 const uint texGen = texD ? texD->generation : 0;
1610 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
1611 const uint samplerGen = samplerD ? samplerD->generation : 0;
1612 if (texId != bd.stex.d[elem].texId || texGen != bd.stex.d[elem].texGeneration
1613 || samplerId != bd.stex.d[elem].samplerId
1614 || samplerGen != bd.stex.d[elem].samplerGeneration)
1617 bd.stex.d[elem].texId = texId;
1618 bd.stex.d[elem].texGeneration = texGen;
1619 bd.stex.d[elem].samplerId = samplerId;
1620 bd.stex.d[elem].samplerGeneration = samplerGen;
1624 if (b->stage == QRhiShaderResourceBinding::FragmentStage) {
1625 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1626 }
else if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
1627 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1629 state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1631 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATES(state));
1636 case QRhiShaderResourceBinding::ImageLoad:
1637 case QRhiShaderResourceBinding::ImageStore:
1638 case QRhiShaderResourceBinding::ImageLoadStore:
1640 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, b->u.simage.tex);
1641 sanityCheckResourceOwnership(texD);
1642 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
1644 bd.simage.id = texD->m_id;
1645 bd.simage.generation = texD->generation;
1647 if (QD3D12Resource *res = resourcePool.lookupRef(texD->handle)) {
1648 if (res->uavUsage) {
1649 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1651 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1653 if (b->type == QRhiShaderResourceBinding::ImageStore
1654 || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1657 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1662 if (b->type == QRhiShaderResourceBinding::ImageLoad || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1663 res->uavUsage |= QD3D12Resource::UavUsageRead;
1664 if (b->type == QRhiShaderResourceBinding::ImageStore || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1665 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1666 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1670 case QRhiShaderResourceBinding::BufferLoad:
1671 case QRhiShaderResourceBinding::BufferStore:
1672 case QRhiShaderResourceBinding::BufferLoadStore:
1674 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.sbuf.buf);
1675 sanityCheckResourceOwnership(bufD);
1676 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
1677 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1678 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
1680 bd.sbuf.id = bufD->m_id;
1681 bd.sbuf.generation = bufD->generation;
1683 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
1684 if (res->uavUsage) {
1685 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1687 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1689 if (b->type == QRhiShaderResourceBinding::BufferStore
1690 || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1693 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1698 if (b->type == QRhiShaderResourceBinding::BufferLoad || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1699 res->uavUsage |= QD3D12Resource::UavUsageRead;
1700 if (b->type == QRhiShaderResourceBinding::BufferStore || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1701 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1702 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1709 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1710 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1718 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1724 if (pipelineChanged || srbUpdate || !srbD->bindingCacheValid
1725 || srbD->bindingCacheGeneration != srbD->generation)
1727 const QD3D12ShaderStageData *stageData = gfxPsD ? gfxPsD->stageData.data() : &compPsD->stageData;
1728 srbD->rebuildBindingCache(stageData, gfxPsD ? 5 : 1);
1731 if (pipelineChanged || srbChanged || srbRebuilt || srbUpdate || srbD->hasDynamicOffset) {
1736 const QD3D12ShaderResourceBindings::BindingCache &cache(srbD->bindingCache);
1738 bool gotNewHeap =
false;
1739 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
1740 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1748 qCDebug(QRHI_LOG_INFO,
"Created new shader-visible CBV/SRV/UAV descriptor heap,"
1749 " per-frame slice size is now %u,"
1750 " if this happens frequently then that's not great.",
1751 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[0].capacity);
1752 bindShaderVisibleHeaps(cbD);
1755 int rootParamIndex = 0;
1756 for (
int s = 0; s < 6; ++s) {
1757 for (
const QD3D12ShaderResourceBindings::BindingCache::CBuf &cbuf : cache.cbufs[s]) {
1758 if (QD3D12Resource *res = resourcePool.lookupRef(cbuf.buf->handles[currentFrameSlot])) {
1759 quint32 offset = cbuf.offset;
1760 if (srbD->hasDynamicOffset) {
1761 for (
int i = 0; i < dynamicOffsetCount; ++i) {
1762 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1763 if (dynOfs.first == cbuf.binding) {
1764 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1765 offset += dynOfs.second;
1769 const D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = res->resource->GetGPUVirtualAddress() + offset;
1771 cbD->cmdList->SetGraphicsRootConstantBufferView(rootParamIndex, gpuAddr);
1773 cbD->cmdList->SetComputeRootConstantBufferView(rootParamIndex, gpuAddr);
1775 rootParamIndex += 1;
1778 for (
int s = 0; s < 6; ++s) {
1779 if (!cache.srvs[s].isEmpty()) {
1780 QD3D12DescriptorHeap &gpuSrvHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1781 const UINT count = UINT(cache.srvs[s].count());
1782 const QD3D12Descriptor startDesc = gpuSrvHeap.get(count);
1785 dev->CopyDescriptors(1, &startDesc.cpuHandle, &count,
1786 count, cache.srvs[s].constData(),
nullptr,
1787 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1790 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1792 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1794 rootParamIndex += 1;
1797 for (
int s = 0; s < 6; ++s) {
1800 for (D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor : cache.samplers[s]) {
1802 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerDescriptor);
1804 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, samplerDescriptor);
1806 rootParamIndex += 1;
1809 for (
int s = 0; s < 6; ++s) {
1810 if (!cache.uavs[s].isEmpty()) {
1811 QD3D12DescriptorHeap &gpuUavHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1812 const int count = cache.uavs[s].count();
1813 const QD3D12Descriptor startDesc = gpuUavHeap.get(count);
1814 for (
int i = 0; i < count; ++i) {
1815 const QD3D12ShaderResourceBindings::BindingCache::Uav &uav(cache.uavs[s][i]);
1816 if (QD3D12Resource *res = resourcePool.lookupRef(uav.handle)) {
1817 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uav.desc,
1818 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1820 dev->CreateUnorderedAccessView(
nullptr,
nullptr,
nullptr,
1821 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1826 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1828 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1830 rootParamIndex += 1;
1835 cbD->currentGraphicsSrb = srb;
1836 cbD->currentComputeSrb =
nullptr;
1838 cbD->currentGraphicsSrb =
nullptr;
1839 cbD->currentComputeSrb = srb;
1841 cbD->currentSrbGeneration = srbD->generation;
1845void QRhiD3D12::setVertexInput(QRhiCommandBuffer *cb,
1846 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1847 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1849 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1850 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1852 bool needsBindVBuf =
false;
1853 for (
int i = 0; i < bindingCount; ++i) {
1854 const int inputSlot = startBinding + i;
1855 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1856 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1857 const bool isDynamic = bufD->m_type == QRhiBuffer::Dynamic;
1859 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1861 if (cbD->currentVertexBuffers[inputSlot] != bufD->handles[isDynamic ? currentFrameSlot : 0]
1862 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1864 needsBindVBuf =
true;
1865 cbD->currentVertexBuffers[inputSlot] = bufD->handles[isDynamic ? currentFrameSlot : 0];
1866 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1870 if (needsBindVBuf) {
1871 QVarLengthArray<D3D12_VERTEX_BUFFER_VIEW, 4> vbv;
1872 vbv.reserve(bindingCount);
1874 QD3D12GraphicsPipeline *psD = cbD->currentGraphicsPipeline;
1875 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1876 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1878 for (
int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1879 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1880 const QD3D12ObjectHandle handle = bufD->handles[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
1881 const quint32 offset = bindings[i].second;
1882 const quint32 stride = inputLayout.bindingAt(i)->stride();
1884 if (bufD->m_type != QRhiBuffer::Dynamic) {
1885 barrierGen.addTransitionBarrier(handle, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
1886 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1889 if (QD3D12Resource *res = resourcePool.lookupRef(handle)) {
1891 res->resource->GetGPUVirtualAddress() + offset,
1892 UINT(res->desc.Width - offset),
1898 cbD->cmdList->IASetVertexBuffers(UINT(startBinding), vbv.count(), vbv.constData());
1902 QD3D12Buffer *ibufD = QRHI_RES(QD3D12Buffer, indexBuf);
1903 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1904 const bool isDynamic = ibufD->m_type == QRhiBuffer::Dynamic;
1906 ibufD->executeHostWritesForFrameSlot(currentFrameSlot);
1908 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1909 : DXGI_FORMAT_R32_UINT;
1910 if (cbD->currentIndexBuffer != ibufD->handles[isDynamic ? currentFrameSlot : 0]
1911 || cbD->currentIndexOffset != indexOffset
1912 || cbD->currentIndexFormat != dxgiFormat)
1914 cbD->currentIndexBuffer = ibufD->handles[isDynamic ? currentFrameSlot : 0];
1915 cbD->currentIndexOffset = indexOffset;
1916 cbD->currentIndexFormat = dxgiFormat;
1918 if (ibufD->m_type != QRhiBuffer::Dynamic) {
1919 barrierGen.addTransitionBarrier(cbD->currentIndexBuffer, D3D12_RESOURCE_STATE_INDEX_BUFFER);
1920 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1923 if (QD3D12Resource *res = resourcePool.lookupRef(cbD->currentIndexBuffer)) {
1924 const D3D12_INDEX_BUFFER_VIEW ibv = {
1925 res->resource->GetGPUVirtualAddress() + indexOffset,
1926 UINT(res->desc.Width - indexOffset),
1929 cbD->cmdList->IASetIndexBuffer(&ibv);
1935void QRhiD3D12::setDefaultScissor(QD3D12CommandBuffer *cbD)
1937 cbD->hasCustomScissorSet =
false;
1939 const QSize outputSize = cbD->currentTarget->pixelSize();
1940 std::array<
float, 4> vp = cbD->currentViewport.viewport();
1941 float x = 0, y = 0, w = 0, h = 0;
1943 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
1946 w = outputSize.width();
1947 h = outputSize.height();
1950 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, vp, &x, &y, &w, &h);
1959 cbD->cmdList->RSSetScissorRects(1, &r);
1962void QRhiD3D12::setViewport(QRhiCommandBuffer *cb,
const QRhiViewport &viewport)
1964 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1965 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1966 Q_ASSERT(cbD->currentTarget);
1967 const QSize outputSize = cbD->currentTarget->pixelSize();
1971 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1979 v.MinDepth = viewport.minDepth();
1980 v.MaxDepth = viewport.maxDepth();
1981 cbD->cmdList->RSSetViewports(1, &v);
1983 cbD->currentViewport = viewport;
1984 if (cbD->currentGraphicsPipeline
1985 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
1987 setDefaultScissor(cbD);
1991void QRhiD3D12::setScissor(QRhiCommandBuffer *cb,
const QRhiScissor &scissor)
1993 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1994 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1995 Q_ASSERT(cbD->currentTarget);
1996 const QSize outputSize = cbD->currentTarget->pixelSize();
2000 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
2009 cbD->cmdList->RSSetScissorRects(1, &r);
2011 cbD->hasCustomScissorSet =
true;
2014void QRhiD3D12::setBlendConstants(QRhiCommandBuffer *cb,
const QColor &c)
2016 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2017 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2018 float v[4] = { c.redF(), c.greenF(), c.blueF(), c.alphaF() };
2019 cbD->cmdList->OMSetBlendFactor(v);
2022void QRhiD3D12::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
2024 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2025 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2026 cbD->cmdList->OMSetStencilRef(refValue);
2029static inline D3D12_SHADING_RATE toD3DShadingRate(
const QSize &coarsePixelSize)
2031 if (coarsePixelSize == QSize(1, 2))
2032 return D3D12_SHADING_RATE_1X2;
2033 if (coarsePixelSize == QSize(2, 1))
2034 return D3D12_SHADING_RATE_2X1;
2035 if (coarsePixelSize == QSize(2, 2))
2036 return D3D12_SHADING_RATE_2X2;
2037 if (coarsePixelSize == QSize(2, 4))
2038 return D3D12_SHADING_RATE_2X4;
2039 if (coarsePixelSize == QSize(4, 2))
2040 return D3D12_SHADING_RATE_4X2;
2041 if (coarsePixelSize == QSize(4, 4))
2042 return D3D12_SHADING_RATE_4X4;
2043 return D3D12_SHADING_RATE_1X1;
2046void QRhiD3D12::setShadingRate(QRhiCommandBuffer *cb,
const QSize &coarsePixelSize)
2048 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2049 cbD->hasShadingRateSet =
false;
2051#ifdef QRHI_D3D12_CL5_AVAILABLE
2055 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2056 const D3D12_SHADING_RATE_COMBINER combiners[] = { D3D12_SHADING_RATE_COMBINER_MAX, D3D12_SHADING_RATE_COMBINER_MAX };
2057 cbD->cmdList->RSSetShadingRate(toD3DShadingRate(coarsePixelSize), combiners);
2058 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
2059 cbD->hasShadingRateSet =
true;
2062 Q_UNUSED(coarsePixelSize);
2063 qWarning(
"Attempted to set ShadingRate without building Qt against a sufficiently new Windows SDK and d3d12.h. This cannot work.");
2067void QRhiD3D12::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
2068 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
2070 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2071 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2072 cbD->cmdList->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
2075void QRhiD3D12::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
2076 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
2078 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2079 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2080 cbD->cmdList->DrawIndexedInstanced(indexCount, instanceCount,
2081 firstIndex, vertexOffset,
2085void QRhiD3D12::drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
2086 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
2088 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2089 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2091 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2092 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2093 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
2095 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2097 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2098 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2100 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
2103 ID3D12Resource *indirectBufferRes = indirectRes->resource;
2105 const bool canUseMulti = (stride ==
sizeof(QRhiIndirectDrawCommand) && drawCommandSignature);
2107 if (canUseMulti && drawCount > 1) {
2108 cbD->cmdList->ExecuteIndirect(drawCommandSignature, drawCount,
2109 indirectBufferRes, indirectBufferOffset,
2112 UINT offset = indirectBufferOffset;
2113 for (quint32 i = 0; i < drawCount; ++i) {
2114 cbD->cmdList->ExecuteIndirect(drawCommandSignature, 1,
2115 indirectBufferRes, offset,
2122void QRhiD3D12::drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
2123 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
2125 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2126 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2128 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2129 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2130 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
2132 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2134 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2135 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2137 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
2140 ID3D12Resource *indirectBufferRes = indirectRes->resource;
2142 const bool canUseMulti = (stride ==
sizeof(QRhiIndexedIndirectDrawCommand) && drawIndexedCommandSignature);
2144 if (canUseMulti && drawCount > 1) {
2145 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, drawCount,
2146 indirectBufferRes, indirectBufferOffset,
2149 UINT offset = indirectBufferOffset;
2150 for (quint32 i = 0; i < drawCount; ++i) {
2151 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, 1,
2152 indirectBufferRes, offset,
2159void QRhiD3D12::debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name)
2164 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2165#ifdef QRHI_D3D12_HAS_OLD_PIX
2166 PIXBeginEvent(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(name).utf16()));
2173void QRhiD3D12::debugMarkEnd(QRhiCommandBuffer *cb)
2178 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2179#ifdef QRHI_D3D12_HAS_OLD_PIX
2180 PIXEndEvent(cbD->cmdList);
2186void QRhiD3D12::debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg)
2191 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2192#ifdef QRHI_D3D12_HAS_OLD_PIX
2193 PIXSetMarker(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(msg).utf16()));
2200const QRhiNativeHandles *QRhiD3D12::nativeHandles(QRhiCommandBuffer *cb)
2202 return QRHI_RES(QD3D12CommandBuffer, cb)->nativeHandles();
2205void QRhiD3D12::beginExternal(QRhiCommandBuffer *cb)
2210void QRhiD3D12::endExternal(QRhiCommandBuffer *cb)
2212 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2213 cbD->resetPerPassState();
2214 bindShaderVisibleHeaps(cbD);
2215 if (cbD->currentTarget) {
2216 QD3D12RenderTargetData *rtD = rtData(cbD->currentTarget);
2217 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2220 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2224double QRhiD3D12::lastCompletedGpuTime(QRhiCommandBuffer *cb)
2226 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2227 return cbD->lastGpuTime;
2230static void calculateGpuTime(QD3D12CommandBuffer *cbD,
2231 int timestampPairStartIndex,
2232 const quint8 *readbackBufPtr,
2233 quint64 timestampTicksPerSecond)
2235 const size_t byteOffset = timestampPairStartIndex *
sizeof(quint64);
2236 const quint64 *p =
reinterpret_cast<
const quint64 *>(readbackBufPtr + byteOffset);
2237 const quint64 startTime = *p++;
2238 const quint64 endTime = *p;
2239 if (startTime < endTime) {
2240 const quint64 ticks = endTime - startTime;
2241 const double timeSec = ticks /
double(timestampTicksPerSecond);
2242 cbD->lastGpuTime = timeSec;
2246QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
2256 return QRhi::FrameOpDeviceLost;
2258 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
2259 currentSwapChain = swapChainD;
2260 currentFrameSlot = swapChainD->currentFrameSlot;
2261 QD3D12SwapChain::FrameResources &fr(swapChainD->frameRes[currentFrameSlot]);
2274 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2275 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2277 if (swapChainD->frameLatencyWaitableObject) {
2279 if (swapChainD->lastFrameLatencyWaitSlot != currentFrameSlot) {
2280 WaitForSingleObjectEx(swapChainD->frameLatencyWaitableObject, 1000,
true);
2281 swapChainD->lastFrameLatencyWaitSlot = currentFrameSlot;
2285 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2287 qWarning(
"Failed to reset command allocator: %s",
2288 qPrintable(QSystemError::windowsComString(hr)));
2289 return QRhi::FrameOpError;
2292 if (!startCommandListForCurrentFrameSlot(&fr.cmdList))
2293 return QRhi::FrameOpError;
2295 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
2296 cbD->cmdList = fr.cmdList;
2298 swapChainD->rtWrapper.d.rtv[0] = swapChainD->sampleDesc.Count > 1
2299 ? swapChainD->msaaRtvs[currentFrameSlot].cpuHandle
2300 : swapChainD->rtvs[swapChainD->currentBackBufferIndex].cpuHandle;
2302 swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
2303 : D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
2305 if (swapChainD->stereo) {
2306 swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
2307 ? swapChainD->msaaRtvs[currentFrameSlot].cpuHandle
2308 : swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
2310 swapChainD->rtWrapperRight.d.dsv =
2311 swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
2318 releaseQueue.executeDeferredReleases(currentFrameSlot);
2324 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2327 resetAndResizeSmallStagingArea(currentFrameSlot);
2329 bindShaderVisibleHeaps(cbD);
2331 finishActiveReadbacks();
2333 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2336 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2337 calculateGpuTime(cbD,
2338 timestampPairStartIndex,
2339 timestampReadbackArea.mem.p,
2340 timestampTicksPerSecond);
2342 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2343 D3D12_QUERY_TYPE_TIMESTAMP,
2344 timestampPairStartIndex);
2347 QDxgiVSyncService::instance()->beginFrame(adapterLuid);
2349 return QRhi::FrameOpSuccess;
2352QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
2354 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
2355 Q_ASSERT(currentSwapChain == swapChainD);
2356 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
2358 QD3D12ObjectHandle backBufferResourceHandle = swapChainD->colorBuffers[swapChainD->currentBackBufferIndex];
2359 if (swapChainD->sampleDesc.Count > 1) {
2360 QD3D12ObjectHandle msaaBackBufferResourceHandle = swapChainD->msaaBuffers[currentFrameSlot];
2361 barrierGen.addTransitionBarrier(msaaBackBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2362 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2363 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2364 const QD3D12Resource *src = resourcePool.lookupRef(msaaBackBufferResourceHandle);
2365 const QD3D12Resource *dst = resourcePool.lookupRef(backBufferResourceHandle);
2367 cbD->cmdList->ResolveSubresource(dst->resource, 0, src->resource, 0, swapChainD->colorFormat);
2370 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
2371 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2373 if (timestampQueryHeap.isValid()) {
2374 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2375 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2376 D3D12_QUERY_TYPE_TIMESTAMP,
2377 timestampPairStartIndex + 1);
2378 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2379 D3D12_QUERY_TYPE_TIMESTAMP,
2380 timestampPairStartIndex,
2382 timestampReadbackArea.mem.buffer,
2383 timestampPairStartIndex *
sizeof(quint64));
2386 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2387 HRESULT hr = cmdList->Close();
2389 qWarning(
"Failed to close command list: %s",
2390 qPrintable(QSystemError::windowsComString(hr)));
2391 return QRhi::FrameOpError;
2394 ID3D12CommandList *execList[] = { cmdList };
2395 cmdQueue->ExecuteCommandLists(1, execList);
2397 if (!flags.testFlag(QRhi::SkipPresent)) {
2398 UINT presentFlags = 0;
2399 if (swapChainD->swapInterval == 0
2400 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
2402 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
2404 if (!swapChainD->swapChain) {
2405 qWarning(
"Failed to present, no swapchain");
2406 return QRhi::FrameOpError;
2408 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
2409 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
2410 qWarning(
"Device loss detected in Present()");
2412 return QRhi::FrameOpDeviceLost;
2413 }
else if (FAILED(hr)) {
2414 qWarning(
"Failed to present: %s", qPrintable(QSystemError::windowsComString(hr)));
2415 return QRhi::FrameOpError;
2418 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
2419 dcompDevice->Commit();
2422 swapChainD->addCommandCompletionSignalForCurrentFrameSlot();
2429 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2431 if (!flags.testFlag(QRhi::SkipPresent)) {
2435 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2436 swapChainD->currentBackBufferIndex = swapChainD->swapChain->GetCurrentBackBufferIndex();
2439 currentSwapChain =
nullptr;
2440 return QRhi::FrameOpSuccess;
2443QRhi::FrameOpResult QRhiD3D12::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
2456 currentFrameSlot = (currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2458 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2459 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2461 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2463 qWarning(
"Failed to reset command allocator: %s",
2464 qPrintable(QSystemError::windowsComString(hr)));
2465 return QRhi::FrameOpError;
2468 if (!offscreenCb[currentFrameSlot])
2469 offscreenCb[currentFrameSlot] =
new QD3D12CommandBuffer(
this);
2470 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2471 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2472 return QRhi::FrameOpError;
2474 releaseQueue.executeDeferredReleases(currentFrameSlot);
2476 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2477 resetAndResizeSmallStagingArea(currentFrameSlot);
2479 bindShaderVisibleHeaps(cbD);
2481 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2482 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2483 D3D12_QUERY_TYPE_TIMESTAMP,
2484 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT);
2487 offscreenActive =
true;
2490 return QRhi::FrameOpSuccess;
2493QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
2496 Q_ASSERT(offscreenActive);
2497 offscreenActive =
false;
2499 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2500 if (timestampQueryHeap.isValid()) {
2501 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2502 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2503 D3D12_QUERY_TYPE_TIMESTAMP,
2504 timestampPairStartIndex + 1);
2505 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2506 D3D12_QUERY_TYPE_TIMESTAMP,
2507 timestampPairStartIndex,
2509 timestampReadbackArea.mem.buffer,
2510 timestampPairStartIndex *
sizeof(quint64));
2513 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2514 HRESULT hr = cmdList->Close();
2516 qWarning(
"Failed to close command list: %s",
2517 qPrintable(QSystemError::windowsComString(hr)));
2518 return QRhi::FrameOpError;
2521 ID3D12CommandList *execList[] = { cmdList };
2522 cmdQueue->ExecuteCommandLists(1, execList);
2524 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2531 finishActiveReadbacks(
true);
2534 if (timestampQueryHeap.isValid()) {
2535 calculateGpuTime(cbD,
2536 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT,
2537 timestampReadbackArea.mem.p,
2538 timestampTicksPerSecond);
2541 return QRhi::FrameOpSuccess;
2544QRhi::FrameOpResult QRhiD3D12::finish()
2546 QD3D12CommandBuffer *cbD =
nullptr;
2548 if (offscreenActive) {
2549 Q_ASSERT(!currentSwapChain);
2550 cbD = offscreenCb[currentFrameSlot];
2552 Q_ASSERT(currentSwapChain);
2553 cbD = ¤tSwapChain->cbWrapper;
2556 return QRhi::FrameOpError;
2558 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2560 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2561 HRESULT hr = cmdList->Close();
2563 qWarning(
"Failed to close command list: %s",
2564 qPrintable(QSystemError::windowsComString(hr)));
2565 return QRhi::FrameOpError;
2568 ID3D12CommandList *execList[] = { cmdList };
2569 cmdQueue->ExecuteCommandLists(1, execList);
2571 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2578 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2580 qWarning(
"Failed to reset command allocator: %s",
2581 qPrintable(QSystemError::windowsComString(hr)));
2582 return QRhi::FrameOpError;
2585 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2586 return QRhi::FrameOpError;
2590 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2591 smallStagingAreas[currentFrameSlot].head = 0;
2593 bindShaderVisibleHeaps(cbD);
2596 releaseQueue.releaseAll();
2597 finishActiveReadbacks(
true);
2599 return QRhi::FrameOpSuccess;
2602void QRhiD3D12::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2604 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2605 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2606 enqueueResourceUpdates(cbD, resourceUpdates);
2609void QRhiD3D12::beginPass(QRhiCommandBuffer *cb,
2610 QRhiRenderTarget *rt,
2611 const QColor &colorClearValue,
2612 const QRhiDepthStencilClearValue &depthStencilClearValue,
2613 QRhiResourceUpdateBatch *resourceUpdates,
2614 QRhiCommandBuffer::BeginPassFlags)
2616 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2617 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2619 if (resourceUpdates)
2620 enqueueResourceUpdates(cbD, resourceUpdates);
2622 QD3D12RenderTargetData *rtD = rtData(rt);
2623 bool wantsColorClear =
true;
2624 bool wantsDsClear =
true;
2625 if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) {
2626 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, rt);
2627 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2628 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2629 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2632 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); it != itEnd; ++it) {
2633 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
2634 QD3D12Texture *resolveTexD = QRHI_RES(QD3D12Texture, it->resolveTexture());
2635 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
2637 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2639 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2641 barrierGen.addTransitionBarrier(resolveTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2643 if (rtTex->m_desc.depthStencilBuffer()) {
2644 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rtTex->m_desc.depthStencilBuffer());
2645 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
2646 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2647 }
else if (rtTex->m_desc.depthTexture()) {
2648 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, rtTex->m_desc.depthTexture());
2649 barrierGen.addTransitionBarrier(depthTexD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2651 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2653 Q_ASSERT(currentSwapChain);
2654 barrierGen.addTransitionBarrier(currentSwapChain->sampleDesc.Count > 1
2655 ? currentSwapChain->msaaBuffers[currentFrameSlot]
2656 : currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex],
2657 D3D12_RESOURCE_STATE_RENDER_TARGET);
2658 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2661 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2664 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2666 if (rtD->colorAttCount && wantsColorClear) {
2667 float clearColor[4] = {
2668 colorClearValue.redF(),
2669 colorClearValue.greenF(),
2670 colorClearValue.blueF(),
2671 colorClearValue.alphaF()
2673 for (
int i = 0; i < rtD->colorAttCount; ++i)
2674 cbD->cmdList->ClearRenderTargetView(rtD->rtv[i], clearColor, 0,
nullptr);
2676 if (rtD->dsAttCount && wantsDsClear) {
2677 cbD->cmdList->ClearDepthStencilView(rtD->dsv,
2678 D3D12_CLEAR_FLAGS(D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL),
2679 depthStencilClearValue.depthClearValue(),
2680 UINT8(depthStencilClearValue.stencilClearValue()),
2685 cbD->recordingPass = QD3D12CommandBuffer::RenderPass;
2686 cbD->currentTarget = rt;
2688 bool hasShadingRateMapSet =
false;
2689#ifdef QRHI_D3D12_CL5_AVAILABLE
2690 if (rtD->rp->hasShadingRateMap) {
2691 cbD->setShadingRate(QSize(1, 1));
2692 QD3D12ShadingRateMap *rateMapD = rt->resourceType() == QRhiRenderTarget::TextureRenderTarget
2693 ? QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12TextureRenderTarget, rt)->m_desc.shadingRateMap())
2694 : QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12SwapChainRenderTarget, rt)->swapChain()->shadingRateMap());
2695 if (QD3D12Resource *res = resourcePool.lookupRef(rateMapD->handle)) {
2696 barrierGen.addTransitionBarrier(rateMapD->handle, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
2697 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2698 cbD->cmdList->RSSetShadingRateImage(res->resource);
2699 hasShadingRateMapSet =
true;
2701 }
else if (cbD->hasShadingRateMapSet) {
2702 cbD->cmdList->RSSetShadingRateImage(
nullptr);
2703 cbD->setShadingRate(QSize(1, 1));
2704 }
else if (cbD->hasShadingRateSet) {
2705 cbD->setShadingRate(QSize(1, 1));
2709 cbD->resetPerPassState();
2712 cbD->hasShadingRateMapSet = hasShadingRateMapSet;
2715void QRhiD3D12::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2717 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2718 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2720 if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
2721 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, cbD->currentTarget);
2722 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2725 const QRhiColorAttachment &colorAtt(*it);
2726 if (!colorAtt.resolveTexture())
2729 QD3D12Texture *dstTexD = QRHI_RES(QD3D12Texture, colorAtt.resolveTexture());
2730 QD3D12Resource *dstRes = resourcePool.lookupRef(dstTexD->handle);
2734 QD3D12Texture *srcTexD = QRHI_RES(QD3D12Texture, colorAtt.texture());
2735 QD3D12RenderBuffer *srcRbD = QRHI_RES(QD3D12RenderBuffer, colorAtt.renderBuffer());
2736 Q_ASSERT(srcTexD || srcRbD);
2737 QD3D12Resource *srcRes = resourcePool.lookupRef(srcTexD ? srcTexD->handle : srcRbD->handle);
2742 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2743 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2744 int(srcTexD->dxgiFormat),
int(dstTexD->dxgiFormat));
2747 if (srcTexD->sampleDesc.Count <= 1) {
2748 qWarning(
"Cannot resolve a non-multisample texture");
2751 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2752 qWarning(
"Resolve source and destination sizes do not match");
2756 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2757 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2758 int(srcRbD->dxgiFormat),
int(dstTexD->dxgiFormat));
2761 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2762 qWarning(
"Resolve source and destination sizes do not match");
2773 const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
2774 QBitArray &initialized(dstTexD->subresourceInitialized);
2775 QVarLengthArray<UINT, 4> dstSubresources;
2776 QVarLengthArray<UINT, 4> subresourcesToDiscard;
2777 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2778 const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
2779 UINT(colorAtt.resolveLayer()) + resolveIdx,
2780 dstTexD->mipLevelCount);
2781 dstSubresources.append(dstSubresource);
2782 if (
int(dstSubresource) >= initialized.size())
2783 initialized.resize(
int(dstSubresource) + 1);
2784 if (!initialized.testBit(
int(dstSubresource))) {
2785 initialized.setBit(
int(dstSubresource));
2786 subresourcesToDiscard.append(dstSubresource);
2790 barrierGen.addTransitionBarrier(srcTexD ? srcTexD->handle : srcRbD->handle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2793 if (!subresourcesToDiscard.isEmpty()) {
2794 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2795 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2796 for (UINT dstSubresource : subresourcesToDiscard) {
2797 D3D12_DISCARD_REGION region = {};
2798 region.FirstSubresource = dstSubresource;
2799 region.NumSubresources = 1;
2800 cbD->cmdList->DiscardResource(dstRes->resource, ®ion);
2804 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2805 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2807 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2808 const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
2809 cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresources[resolveIdx],
2810 srcRes->resource, srcSubresource,
2811 dstTexD->dxgiFormat);
2814 if (rtTex->m_desc.depthResolveTexture())
2815 qWarning(
"Resolving multisample depth-stencil buffers is not supported with D3D");
2818 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2819 cbD->currentTarget =
nullptr;
2821 if (resourceUpdates)
2822 enqueueResourceUpdates(cbD, resourceUpdates);
2825void QRhiD3D12::beginComputePass(QRhiCommandBuffer *cb,
2826 QRhiResourceUpdateBatch *resourceUpdates,
2827 QRhiCommandBuffer::BeginPassFlags)
2829 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2830 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2832 if (resourceUpdates)
2833 enqueueResourceUpdates(cbD, resourceUpdates);
2835 cbD->recordingPass = QD3D12CommandBuffer::ComputePass;
2837 cbD->resetPerPassState();
2840void QRhiD3D12::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2842 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2843 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2845 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2847 if (resourceUpdates)
2848 enqueueResourceUpdates(cbD, resourceUpdates);
2851void QRhiD3D12::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
2853 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2854 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2855 QD3D12ComputePipeline *psD = QRHI_RES(QD3D12ComputePipeline, ps);
2856 const bool pipelineChanged = cbD->currentComputePipeline != psD || cbD->currentPipelineGeneration != psD->generation;
2858 if (pipelineChanged) {
2859 cbD->currentGraphicsPipeline =
nullptr;
2860 cbD->currentComputePipeline = psD;
2861 cbD->currentPipelineGeneration = psD->generation;
2863 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
2864 Q_ASSERT(pipeline->type == QD3D12Pipeline::Compute);
2865 cbD->cmdList->SetPipelineState(pipeline->pso);
2866 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
2867 cbD->cmdList->SetComputeRootSignature(rs->rootSig);
2872void QRhiD3D12::dispatch(QRhiCommandBuffer *cb,
int x,
int y,
int z)
2874 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2875 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2876 cbD->cmdList->Dispatch(UINT(x), UINT(y), UINT(z));
2882ID3D12CommandSignature *QRhiD3D12::indirectDrawCommandSignature(
bool indexed, quint32 stride)
2884 const quint32 canonicalStride = indexed ?
sizeof(QRhiIndexedIndirectDrawCommand)
2885 :
sizeof(QRhiIndirectDrawCommand);
2886 if (stride == canonicalStride)
2887 return indexed ? drawIndexedCommandSignature : drawCommandSignature;
2889 QHash<quint32, ID3D12CommandSignature *> &cache(indexed ? drawIndexedCommandSignaturesByStride
2890 : drawCommandSignaturesByStride);
2891 auto it = cache.constFind(stride);
2892 if (it != cache.constEnd())
2895 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
2896 arg.Type = indexed ? D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED : D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
2898 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
2899 sigDesc.ByteStride = stride;
2900 sigDesc.NumArgumentDescs = 1;
2901 sigDesc.pArgumentDescs = &arg;
2903 ID3D12CommandSignature *sig =
nullptr;
2904 HRESULT hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&sig));
2906 qWarning(
"Failed to create indirect draw command signature with stride %u: %s",
2907 stride, qPrintable(QSystemError::windowsComString(hr)));
2911 cache.insert(stride, sig);
2915void QRhiD3D12::drawIndirectCount(QRhiCommandBuffer *cb,
2916 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
2917 QRhiBuffer *countBuffer, quint32 countBufferOffset,
2918 quint32 maxDrawCount, quint32 stride)
2920 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2921 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2923 ID3D12CommandSignature *sig = indirectDrawCommandSignature(
false, stride);
2927 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2928 const bool indirectIsDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2929 const QD3D12ObjectHandle indirectHandle = indirectBufferD->handles[indirectIsDynamic ? currentFrameSlot : 0];
2930 if (indirectIsDynamic)
2931 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2933 barrierGen.addTransitionBarrier(indirectHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2935 QD3D12Buffer *countBufferD = QRHI_RES(QD3D12Buffer, countBuffer);
2936 const bool countIsDynamic = countBufferD->m_type == QRhiBuffer::Dynamic;
2937 const QD3D12ObjectHandle countHandle = countBufferD->handles[countIsDynamic ? currentFrameSlot : 0];
2939 countBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2941 barrierGen.addTransitionBarrier(countHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2943 if (!indirectIsDynamic || !countIsDynamic)
2944 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2946 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectHandle);
2947 QD3D12Resource *countRes = resourcePool.lookupRef(countHandle);
2948 if (!indirectRes || !countRes)
2951 cbD->cmdList->ExecuteIndirect(sig, maxDrawCount,
2952 indirectRes->resource, indirectBufferOffset,
2953 countRes->resource, countBufferOffset);
2956void QRhiD3D12::drawIndexedIndirectCount(QRhiCommandBuffer *cb,
2957 QRhiBuffer *indirectBuffer, quint32 indirectBufferOffset,
2958 QRhiBuffer *countBuffer, quint32 countBufferOffset,
2959 quint32 maxDrawCount, quint32 stride)
2961 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2962 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2964 ID3D12CommandSignature *sig = indirectDrawCommandSignature(
true, stride);
2968 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2969 const bool indirectIsDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2970 const QD3D12ObjectHandle indirectHandle = indirectBufferD->handles[indirectIsDynamic ? currentFrameSlot : 0];
2971 if (indirectIsDynamic)
2972 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2974 barrierGen.addTransitionBarrier(indirectHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2976 QD3D12Buffer *countBufferD = QRHI_RES(QD3D12Buffer, countBuffer);
2977 const bool countIsDynamic = countBufferD->m_type == QRhiBuffer::Dynamic;
2978 const QD3D12ObjectHandle countHandle = countBufferD->handles[countIsDynamic ? currentFrameSlot : 0];
2980 countBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2982 barrierGen.addTransitionBarrier(countHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2984 if (!indirectIsDynamic || !countIsDynamic)
2985 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2987 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectHandle);
2988 QD3D12Resource *countRes = resourcePool.lookupRef(countHandle);
2989 if (!indirectRes || !countRes)
2992 cbD->cmdList->ExecuteIndirect(sig, maxDrawCount,
2993 indirectRes->resource, indirectBufferOffset,
2994 countRes->resource, countBufferOffset);
2997void QRhiD3D12::dispatchIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
2998 quint32 indirectBufferOffset)
3000 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
3001 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
3003 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
3004 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
3005 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
3007 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
3012 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
3013 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3015 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
3019 cbD->cmdList->ExecuteIndirect(dispatchCommandSignature, 1,
3020 indirectRes->resource, indirectBufferOffset,
3024bool QD3D12DescriptorHeap::create(ID3D12Device *device,
3025 quint32 descriptorCount,
3026 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
3027 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags)
3030 capacity = descriptorCount;
3031 this->heapType = heapType;
3032 this->heapFlags = heapFlags;
3034 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
3035 heapDesc.Type = heapType;
3036 heapDesc.NumDescriptors = capacity;
3037 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS(heapFlags);
3039 HRESULT hr = device->CreateDescriptorHeap(&heapDesc, __uuidof(ID3D12DescriptorHeap),
reinterpret_cast<
void **>(&heap));
3041 qWarning(
"Failed to create descriptor heap: %s", qPrintable(QSystemError::windowsComString(hr)));
3043 capacity = descriptorByteSize = 0;
3047 descriptorByteSize = device->GetDescriptorHandleIncrementSize(heapType);
3048 heapStart.cpuHandle = heap->GetCPUDescriptorHandleForHeapStart();
3049 if (heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
3050 heapStart.gpuHandle = heap->GetGPUDescriptorHandleForHeapStart();
3055void QD3D12DescriptorHeap::createWithExisting(
const QD3D12DescriptorHeap &other,
3056 quint32 offsetInDescriptors,
3057 quint32 descriptorCount)
3061 capacity = descriptorCount;
3062 heapType = other.heapType;
3063 heapFlags = other.heapFlags;
3064 descriptorByteSize = other.descriptorByteSize;
3065 heapStart = incremented(other.heapStart, offsetInDescriptors);
3068void QD3D12DescriptorHeap::destroy()
3077void QD3D12DescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3080 releaseQueue->deferredReleaseDescriptorHeap(heap);
3086QD3D12Descriptor QD3D12DescriptorHeap::get(quint32 count)
3088 Q_ASSERT(count > 0);
3089 if (head + count > capacity) {
3090 qWarning(
"Cannot get %u descriptors as that would exceed capacity %u", count, capacity);
3094 return at(head - count);
3097QD3D12Descriptor QD3D12DescriptorHeap::at(quint32 index)
const
3099 const quint32 startOffset = index * descriptorByteSize;
3100 QD3D12Descriptor result;
3101 result.cpuHandle.ptr = heapStart.cpuHandle.ptr + startOffset;
3102 if (heapStart.gpuHandle.ptr != 0)
3103 result.gpuHandle.ptr = heapStart.gpuHandle.ptr + startOffset;
3107bool QD3D12CpuDescriptorPool::create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName)
3109 QD3D12DescriptorHeap firstHeap;
3110 if (!firstHeap.create(device, DESCRIPTORS_PER_HEAP, heapType, D3D12_DESCRIPTOR_HEAP_FLAG_NONE))
3112 heaps.append(HeapWithMap::init(firstHeap, DESCRIPTORS_PER_HEAP));
3113 descriptorByteSize = heaps[0].heap.descriptorByteSize;
3114 this->device = device;
3115 this->debugName = debugName;
3119void QD3D12CpuDescriptorPool::destroy()
3123 static bool leakCheck =
true;
3126 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
3129 for (
const HeapWithMap &heap : std::as_const(heaps)) {
3130 const int leakedDescriptorCount = heap.map.count(
true);
3131 if (leakedDescriptorCount > 0) {
3132 qWarning(
"QD3D12CpuDescriptorPool::destroy(): "
3133 "Heap %p for descriptor pool %p '%s' has %d unreleased descriptors",
3134 &heap.heap,
this, debugName, leakedDescriptorCount);
3138 for (HeapWithMap &heap : heaps)
3139 heap.heap.destroy();
3143QD3D12Descriptor QD3D12CpuDescriptorPool::allocate(quint32 count)
3145 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
3147 HeapWithMap &last(heaps.last());
3148 if (last.heap.head + count <= last.heap.capacity) {
3149 quint32 firstIndex = last.heap.head;
3150 for (quint32 i = 0; i < count; ++i)
3151 last.map.setBit(firstIndex + i);
3152 return last.heap.get(count);
3155 for (HeapWithMap &heap : heaps) {
3156 quint32 freeCount = 0;
3157 for (quint32 i = 0; i < DESCRIPTORS_PER_HEAP; ++i) {
3158 if (heap.map.testBit(i)) {
3162 if (freeCount == count) {
3163 const quint32 firstIndex = i - (freeCount - 1);
3164 for (quint32 j = 0; j < count; ++j)
3165 heap.map.setBit(firstIndex + j);
3169 if (firstIndex + count > heap.heap.head)
3170 heap.heap.head = firstIndex + count;
3171 return heap.heap.at(firstIndex);
3177 QD3D12DescriptorHeap newHeap;
3178 if (!newHeap.create(device, DESCRIPTORS_PER_HEAP, last.heap.heapType, last.heap.heapFlags))
3181 heaps.append(HeapWithMap::init(newHeap, DESCRIPTORS_PER_HEAP));
3183 for (quint32 i = 0; i < count; ++i)
3184 heaps.last().map.setBit(i);
3186 return heaps.last().heap.get(count);
3189void QD3D12CpuDescriptorPool::release(
const QD3D12Descriptor &descriptor, quint32 count)
3191 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
3192 if (!descriptor.isValid())
3195 const SIZE_T addr = descriptor.cpuHandle.ptr;
3196 for (HeapWithMap &heap : heaps) {
3197 const SIZE_T begin = heap.heap.heapStart.cpuHandle.ptr;
3198 const SIZE_T end = begin + heap.heap.descriptorByteSize * heap.heap.capacity;
3199 if (addr >= begin && addr < end) {
3200 quint32 firstIndex = (addr - begin) / heap.heap.descriptorByteSize;
3201 for (quint32 i = 0; i < count; ++i)
3202 heap.map.setBit(firstIndex + i,
false);
3207 qWarning(
"QD3D12CpuDescriptorPool::release: Descriptor with address %llu is not in any heap",
3208 quint64(descriptor.cpuHandle.ptr));
3211bool QD3D12QueryHeap::create(ID3D12Device *device,
3213 D3D12_QUERY_HEAP_TYPE heapType)
3215 capacity = queryCount;
3217 D3D12_QUERY_HEAP_DESC heapDesc = {};
3218 heapDesc.Type = heapType;
3219 heapDesc.Count = capacity;
3221 HRESULT hr = device->CreateQueryHeap(&heapDesc, __uuidof(ID3D12QueryHeap),
reinterpret_cast<
void **>(&heap));
3223 qWarning(
"Failed to create query heap: %s", qPrintable(QSystemError::windowsComString(hr)));
3232void QD3D12QueryHeap::destroy()
3241bool QD3D12StagingArea::create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType)
3243 Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
3244 D3D12_RESOURCE_DESC resourceDesc = {};
3245 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
3246 resourceDesc.Width = capacity;
3247 resourceDesc.Height = 1;
3248 resourceDesc.DepthOrArraySize = 1;
3249 resourceDesc.MipLevels = 1;
3250 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
3251 resourceDesc.SampleDesc = { 1, 0 };
3252 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
3253 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
3254 UINT state = heapType == D3D12_HEAP_TYPE_UPLOAD ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
3255 HRESULT hr = rhi->vma.createResource(heapType,
3257 D3D12_RESOURCE_STATES(state),
3260 __uuidof(ID3D12Resource),
3261 reinterpret_cast<
void **>(&resource));
3263 qWarning(
"Failed to create buffer for staging area: %s",
3264 qPrintable(QSystemError::windowsComString(hr)));
3268 hr = resource->Map(0,
nullptr, &p);
3270 qWarning(
"Failed to map buffer for staging area: %s",
3271 qPrintable(QSystemError::windowsComString(hr)));
3276 mem.p =
static_cast<quint8 *>(p);
3277 mem.gpuAddr = resource->GetGPUVirtualAddress();
3278 mem.buffer = resource;
3279 mem.bufferOffset = 0;
3281 this->capacity = capacity;
3287void QD3D12StagingArea::destroy()
3290 resource->Release();
3294 allocation->Release();
3295 allocation =
nullptr;
3300void QD3D12StagingArea::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3303 releaseQueue->deferredReleaseResourceAndAllocation(resource, allocation);
3307QD3D12StagingArea::Allocation QD3D12StagingArea::get(quint32 byteSize)
3309 const quint32 allocSize = aligned(byteSize, ALIGNMENT);
3310 if (head + allocSize > capacity) {
3311 qWarning(
"Failed to allocate %u (%u) bytes from staging area of size %u with %u bytes left",
3312 allocSize, byteSize, capacity, remainingCapacity());
3315 const quint32 offset = head;
3319 mem.gpuAddr + offset,
3328void QD3D12ReleaseQueue::deferredReleaseResource(
const QD3D12ObjectHandle &handle)
3330 DeferredReleaseEntry e;
3335void QD3D12ReleaseQueue::deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
3336 QD3D12CpuDescriptorPool *pool,
3337 const QD3D12Descriptor &viewsStart,
3340 DeferredReleaseEntry e;
3341 e.type = DeferredReleaseEntry::Resource;
3343 e.poolForViews = pool;
3344 e.viewsStart = viewsStart;
3345 e.viewCount = viewCount;
3349void QD3D12ReleaseQueue::deferredReleasePipeline(
const QD3D12ObjectHandle &handle)
3351 DeferredReleaseEntry e;
3352 e.type = DeferredReleaseEntry::Pipeline;
3357void QD3D12ReleaseQueue::deferredReleaseRootSignature(
const QD3D12ObjectHandle &handle)
3359 DeferredReleaseEntry e;
3360 e.type = DeferredReleaseEntry::RootSignature;
3365void QD3D12ReleaseQueue::deferredReleaseCallback(std::function<
void(
void*)> callback,
void *userData)
3367 DeferredReleaseEntry e;
3368 e.type = DeferredReleaseEntry::Callback;
3369 e.callback = callback;
3370 e.callbackUserData = userData;
3374void QD3D12ReleaseQueue::deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
3375 D3D12MA::Allocation *allocation)
3377 DeferredReleaseEntry e;
3378 e.type = DeferredReleaseEntry::ResourceAndAllocation;
3379 e.resourceAndAllocation = { resource, allocation };
3383void QD3D12ReleaseQueue::deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap)
3385 DeferredReleaseEntry e;
3386 e.type = DeferredReleaseEntry::DescriptorHeap;
3387 e.descriptorHeap = heap;
3391void QD3D12ReleaseQueue::deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
3392 const QD3D12Descriptor &viewsStart,
3395 DeferredReleaseEntry e;
3396 e.type = DeferredReleaseEntry::Views;
3397 e.poolForViews = pool;
3398 e.viewsStart = viewsStart;
3399 e.viewCount = viewCount;
3403void QD3D12ReleaseQueue::activatePendingDeferredReleaseRequests(
int frameSlot)
3405 for (DeferredReleaseEntry &e : queue) {
3406 if (!e.frameSlotToBeReleasedIn.has_value())
3407 e.frameSlotToBeReleasedIn = frameSlot;
3411void QD3D12ReleaseQueue::executeDeferredReleases(
int frameSlot,
bool forced)
3413 for (
int i = queue.count() - 1; i >= 0; --i) {
3414 const DeferredReleaseEntry &e(queue[i]);
3415 if (forced || (e.frameSlotToBeReleasedIn.has_value() && e.frameSlotToBeReleasedIn.value() == frameSlot)) {
3417 case DeferredReleaseEntry::Resource:
3418 resourcePool->remove(e.handle);
3419 if (e.poolForViews && e.viewsStart.isValid() && e.viewCount > 0)
3420 e.poolForViews->release(e.viewsStart, e.viewCount);
3422 case DeferredReleaseEntry::Pipeline:
3423 pipelinePool->remove(e.handle);
3425 case DeferredReleaseEntry::RootSignature:
3426 rootSignaturePool->remove(e.handle);
3428 case DeferredReleaseEntry::Callback:
3429 e.callback(e.callbackUserData);
3431 case DeferredReleaseEntry::ResourceAndAllocation:
3434 e.resourceAndAllocation.first->Release();
3435 if (e.resourceAndAllocation.second)
3436 e.resourceAndAllocation.second->Release();
3438 case DeferredReleaseEntry::DescriptorHeap:
3439 e.descriptorHeap->Release();
3441 case DeferredReleaseEntry::Views:
3442 e.poolForViews->release(e.viewsStart, e.viewCount);
3450void QD3D12ReleaseQueue::releaseAll()
3452 executeDeferredReleases(0,
true);
3455void QD3D12ResourceBarrierGenerator::addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle,
3456 D3D12_RESOURCE_STATES stateAfter)
3458 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3459 if (stateAfter != res->state) {
3460 transitionResourceBarriers.append({ resourceHandle, res->state, stateAfter });
3461 res->state = stateAfter;
3466void QD3D12ResourceBarrierGenerator::enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD)
3468 QVarLengthArray<D3D12_RESOURCE_BARRIER, PREALLOC> barriers;
3469 for (
const TransitionResourceBarrier &trb : transitionResourceBarriers) {
3470 if (QD3D12Resource *res = resourcePool->lookupRef(trb.resourceHandle)) {
3471 D3D12_RESOURCE_BARRIER barrier = {};
3472 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
3473 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3474 barrier.Transition.pResource = res->resource;
3475 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
3476 barrier.Transition.StateBefore = trb.stateBefore;
3477 barrier.Transition.StateAfter = trb.stateAfter;
3478 barriers.append(barrier);
3481 transitionResourceBarriers.clear();
3482 if (!barriers.isEmpty())
3483 cbD->cmdList->ResourceBarrier(barriers.count(), barriers.constData());
3486void QD3D12ResourceBarrierGenerator::enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
3487 const QD3D12ObjectHandle &resourceHandle,
3489 D3D12_RESOURCE_STATES stateBefore,
3490 D3D12_RESOURCE_STATES stateAfter)
3492 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3493 D3D12_RESOURCE_BARRIER barrier = {};
3494 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
3495 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3496 barrier.Transition.pResource = res->resource;
3497 barrier.Transition.Subresource = subresource;
3498 barrier.Transition.StateBefore = stateBefore;
3499 barrier.Transition.StateAfter = stateAfter;
3500 cbD->cmdList->ResourceBarrier(1, &barrier);
3504void QD3D12ResourceBarrierGenerator::enqueueUavBarrier(QD3D12CommandBuffer *cbD,
3505 const QD3D12ObjectHandle &resourceHandle)
3507 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3508 D3D12_RESOURCE_BARRIER barrier = {};
3509 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
3510 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3511 barrier.UAV.pResource = res->resource;
3512 cbD->cmdList->ResourceBarrier(1, &barrier);
3516void QD3D12ShaderBytecodeCache::insertWithCapacityLimit(
const QRhiShaderStage &key,
const Shader &s)
3518 if (data.count() >= QRhiD3D12::MAX_SHADER_CACHE_ENTRIES)
3520 data.insert(key, s);
3523bool QD3D12ShaderVisibleDescriptorHeap::create(ID3D12Device *device,
3524 D3D12_DESCRIPTOR_HEAP_TYPE type,
3525 quint32 perFrameDescriptorCount)
3527 Q_ASSERT(type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
3529 quint32 size = perFrameDescriptorCount * QD3D12_FRAMES_IN_FLIGHT;
3532 const quint32 CBV_SRV_UAV_MAX = 1000000;
3533 const quint32 SAMPLER_MAX = 2048;
3534 if (type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
3535 size = qMin(size, CBV_SRV_UAV_MAX);
3536 else if (type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
3537 size = qMin(size, SAMPLER_MAX);
3539 if (!heap.create(device, size, type, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
3540 qWarning(
"Failed to create shader-visible descriptor heap of size %u", size);
3544 perFrameDescriptorCount = size / QD3D12_FRAMES_IN_FLIGHT;
3545 quint32 currentOffsetInDescriptors = 0;
3546 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3547 perFrameHeapSlice[i].createWithExisting(heap, currentOffsetInDescriptors, perFrameDescriptorCount);
3548 currentOffsetInDescriptors += perFrameDescriptorCount;
3554void QD3D12ShaderVisibleDescriptorHeap::destroy()
3559void QD3D12ShaderVisibleDescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3561 heap.destroyWithDeferredRelease(releaseQueue);
3564static inline std::pair<
int,
int> mapBinding(
int binding,
const QShader::NativeResourceBindingMap &map)
3567 return { binding, binding };
3569 auto it = map.constFind(binding);
3570 if (it != map.cend())
3579void QD3D12ShaderResourceVisitor::visit()
3581 for (
int bindingIdx = 0, bindingCount = srb->m_bindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
3582 const QRhiShaderResourceBinding &b(srb->m_bindings[bindingIdx]);
3583 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
3585 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
3586 const QD3D12ShaderStageData *sd = &stageData[stageIdx];
3590 if (!bd->stage.testFlag(qd3d12_stageToSrb(sd->stage)))
3594 case QRhiShaderResourceBinding::UniformBuffer:
3596 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3597 if (shaderRegister >= 0 && uniformBuffer)
3598 uniformBuffer(sd->stage, bd->u.ubuf, shaderRegister, bd->binding);
3601 case QRhiShaderResourceBinding::SampledTexture:
3603 Q_ASSERT(bd->u.stex.count > 0);
3604 const int textureBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3605 const int samplerBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).second;
3606 if (textureBaseShaderRegister >= 0 && textures)
3607 textures(sd->stage, bd->u.stex.texSamplers, bd->u.stex.count, textureBaseShaderRegister);
3608 if (samplerBaseShaderRegister >= 0 && samplers)
3609 samplers(sd->stage, bd->u.stex.texSamplers, bd->u.stex.count, samplerBaseShaderRegister);
3612 case QRhiShaderResourceBinding::Texture:
3614 Q_ASSERT(bd->u.stex.count > 0);
3615 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3616 if (baseShaderRegister >= 0 && textures)
3617 textures(sd->stage, bd->u.stex.texSamplers, bd->u.stex.count, baseShaderRegister);
3620 case QRhiShaderResourceBinding::Sampler:
3622 Q_ASSERT(bd->u.stex.count > 0);
3623 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3624 if (baseShaderRegister >= 0 && samplers)
3625 samplers(sd->stage, bd->u.stex.texSamplers, bd->u.stex.count, baseShaderRegister);
3628 case QRhiShaderResourceBinding::ImageLoad:
3630 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3631 if (shaderRegister >= 0 && storageImage)
3632 storageImage(sd->stage, bd->u.simage, Load, shaderRegister);
3635 case QRhiShaderResourceBinding::ImageStore:
3637 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3638 if (shaderRegister >= 0 && storageImage)
3639 storageImage(sd->stage, bd->u.simage, Store, shaderRegister);
3642 case QRhiShaderResourceBinding::ImageLoadStore:
3644 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3645 if (shaderRegister >= 0 && storageImage)
3646 storageImage(sd->stage, bd->u.simage, LoadStore, shaderRegister);
3649 case QRhiShaderResourceBinding::BufferLoad:
3651 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3652 if (shaderRegister >= 0 && storageBuffer)
3653 storageBuffer(sd->stage, bd->u.sbuf, Load, shaderRegister);
3656 case QRhiShaderResourceBinding::BufferStore:
3658 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3659 if (shaderRegister >= 0 && storageBuffer)
3660 storageBuffer(sd->stage, bd->u.sbuf, Store, shaderRegister);
3663 case QRhiShaderResourceBinding::BufferLoadStore:
3665 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3666 if (shaderRegister >= 0 && storageBuffer)
3667 storageBuffer(sd->stage, bd->u.sbuf, LoadStore, shaderRegister);
3675bool QD3D12SamplerManager::create(ID3D12Device *device)
3678 if (!shaderVisibleSamplerHeap.create(device,
3679 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
3680 MAX_SAMPLERS / QD3D12_FRAMES_IN_FLIGHT))
3682 qWarning(
"Could not create shader-visible SAMPLER heap");
3686 this->device = device;
3690void QD3D12SamplerManager::destroy()
3693 shaderVisibleSamplerHeap.destroy();
3698QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc)
3700 auto it = gpuMap.constFind({desc});
3701 if (it != gpuMap.cend())
3704 QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
3705 if (descriptor.isValid()) {
3706 device->CreateSampler(&desc, descriptor.cpuHandle);
3707 gpuMap.insert({desc}, descriptor);
3709 qWarning(
"Out of shader-visible SAMPLER descriptor heap space,"
3710 " this should not happen, maximum number of unique samplers is %u",
3711 shaderVisibleSamplerHeap.heap.capacity);
3717QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptors(
const QVarLengthArray<Q_D3D12_SAMPLER_DESC, 8> &descs)
3723 auto it = gpuArrayMap.constFind({ descs });
3724 if (it != gpuArrayMap.cend())
3727 const quint32 count = quint32(descs.count());
3728 QD3D12Descriptor startDescriptor = shaderVisibleSamplerHeap.heap.get(count);
3729 if (startDescriptor.isValid()) {
3730 for (quint32 i = 0; i < count; ++i) {
3731 device->CreateSampler(&descs[
int(i)].desc,
3732 shaderVisibleSamplerHeap.heap.incremented(startDescriptor, i).cpuHandle);
3734 gpuArrayMap.insert({ descs }, startDescriptor);
3741 qWarning(
"Out of shader-visible SAMPLER descriptor heap space when reserving"
3742 " %u consecutive descriptors for a sampler array, maximum number of"
3743 " sampler descriptors is %u",
3744 count, shaderVisibleSamplerHeap.heap.capacity);
3747 return startDescriptor;
3750void QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
3755bool QD3D12MipmapGenerator::ensureCreated()
3757 if (!pipelineHandle.isNull())
3763 if (!buildPipeline()) {
3764 createFailed =
true;
3771bool QD3D12MipmapGenerator::buildPipeline()
3773 qCDebug(QRHI_LOG_INFO,
"Building mipmap generator compute pipeline on first use");
3775 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3776 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3779 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3780 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3781 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3784 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3785 descriptorRanges[0].NumDescriptors = 1;
3786 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3787 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3788 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3789 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3790 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3793 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3794 descriptorRanges[1].NumDescriptors = 4;
3795 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3796 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3797 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3798 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3801 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3802 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3803 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3804 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3805 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3806 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3808 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3809 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3810 rsDesc.Desc_1_1.NumParameters = 3;
3811 rsDesc.Desc_1_1.pParameters = rootParams;
3812 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3813 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3815 ID3DBlob *signature =
nullptr;
3816 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3818 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3821 ID3D12RootSignature *rootSig =
nullptr;
3822 hr = rhiD->dev->CreateRootSignature(0,
3823 signature->GetBufferPointer(),
3824 signature->GetBufferSize(),
3825 __uuidof(ID3D12RootSignature),
3826 reinterpret_cast<
void **>(&rootSig));
3827 signature->Release();
3829 qWarning(
"Failed to create root signature: %s",
3830 qPrintable(QSystemError::windowsComString(hr)));
3834 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3836 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3837 psoDesc.pRootSignature = rootSig;
3838 psoDesc.CS.pShaderBytecode = g_csMipmap;
3839 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap);
3840 ID3D12PipelineState *pso =
nullptr;
3841 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3842 __uuidof(ID3D12PipelineState),
3843 reinterpret_cast<
void **>(&pso));
3845 qWarning(
"Failed to create compute pipeline state: %s",
3846 qPrintable(QSystemError::windowsComString(hr)));
3847 rhiD->rootSignaturePool.remove(rootSigHandle);
3852 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3857void QD3D12MipmapGenerator::destroy()
3864 rhiD->pipelinePool.remove(pipelineHandle);
3865 pipelineHandle = {};
3866 rhiD->rootSignaturePool.remove(rootSigHandle);
3868 createFailed =
false;
3871void QD3D12MipmapGenerator::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3873 if (!ensureCreated())
3876 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3879 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3882 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3886 const quint32 mipLevelCount = res->desc.MipLevels;
3887 if (mipLevelCount < 2)
3890 if (res->desc.SampleDesc.Count > 1) {
3891 qWarning(
"Cannot generate mipmaps for MSAA texture");
3895 const bool is1D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D;
3897 qWarning(
"Cannot generate mipmaps for 1D texture");
3901 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3902 const bool isCubeOrArray = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
3903 && res->desc.DepthOrArraySize > 1;
3904 const quint32 layerCount = isCubeOrArray ? res->desc.DepthOrArraySize : 1;
3907 qWarning(
"2D mipmap generator invoked for 3D texture, this should not happen");
3911 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3912 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3914 cbD->cmdList->SetPipelineState(pipeline->pso);
3915 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3917 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3920 quint32 srcMipLevel;
3921 quint32 numMipLevels;
3926 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount * layerCount);
3927 std::optional<QD3D12StagingArea> ownStagingArea;
3928 rhiD->recordSmallStagingAreaDemand(allocSize);
3929 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3930 ownStagingArea = QD3D12StagingArea();
3931 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3932 qWarning(
"Could not create staging area for mipmap generation");
3936 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3937 ? &ownStagingArea.value()
3938 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3940 bool gotNewHeap =
false;
3941 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3942 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3943 rhiD->currentFrameSlot,
3944 (1 + 4) * mipLevelCount * layerCount,
3947 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3951 rhiD->bindShaderVisibleHeaps(cbD);
3953 for (quint32 layer = 0; layer < layerCount; ++layer) {
3954 for (quint32 level = 0; level < mipLevelCount ;) {
3955 UINT subresource = calcSubresource(level, layer, res->desc.MipLevels);
3956 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3957 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3958 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3960 quint32 levelPlusOneMipWidth = res->desc.Width >> (level + 1);
3961 quint32 levelPlusOneMipHeight = res->desc.Height >> (level + 1);
3962 const quint32 dw = levelPlusOneMipWidth == 1 ? levelPlusOneMipHeight : levelPlusOneMipWidth;
3963 const quint32 dh = levelPlusOneMipHeight == 1 ? levelPlusOneMipWidth : levelPlusOneMipHeight;
3965 const quint32 additionalMips = qCountTrailingZeroBits(dw | dh);
3966 const quint32 numGenMips = qMin(1u + qMin(3u, additionalMips), res->desc.MipLevels - level);
3967 levelPlusOneMipWidth = qMax(1u, levelPlusOneMipWidth);
3968 levelPlusOneMipHeight = qMax(1u, levelPlusOneMipHeight);
3970 CBufData cbufData = {
3973 1.0f /
float(levelPlusOneMipWidth),
3974 1.0f /
float(levelPlusOneMipHeight)
3977 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3978 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3979 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3981 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3982 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3983 srvDesc.Format = res->desc.Format;
3984 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3985 if (isCubeOrArray) {
3986 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
3987 srvDesc.Texture2DArray.MipLevels = res->desc.MipLevels;
3988 srvDesc.Texture2DArray.FirstArraySlice = layer;
3989 srvDesc.Texture2DArray.ArraySize = 1;
3991 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
3992 srvDesc.Texture2D.MipLevels = res->desc.MipLevels;
3994 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3995 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3997 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(4);
3998 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
4000 for (quint32 uavIdx = 0; uavIdx < 4; ++uavIdx) {
4001 const quint32 uavMipLevel = qMin(level + 1u + uavIdx, res->desc.MipLevels - 1u);
4002 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
4003 uavDesc.Format = res->desc.Format;
4004 if (isCubeOrArray) {
4005 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
4006 uavDesc.Texture2DArray.MipSlice = uavMipLevel;
4007 uavDesc.Texture2DArray.FirstArraySlice = layer;
4008 uavDesc.Texture2DArray.ArraySize = 1;
4010 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
4011 uavDesc.Texture2D.MipSlice = uavMipLevel;
4013 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
4014 uavCpuHandle.ptr += descriptorByteSize;
4016 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
4018 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, 1);
4020 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
4021 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4022 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
4023 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4025 level += numGenMips;
4029 if (ownStagingArea.has_value())
4030 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
4033void QD3D12MipmapGenerator3D::create(QRhiD3D12 *rhiD)
4038bool QD3D12MipmapGenerator3D::ensureCreated()
4040 if (!pipelineHandle.isNull())
4046 if (!buildPipeline()) {
4047 createFailed =
true;
4054bool QD3D12MipmapGenerator3D::buildPipeline()
4056 qCDebug(QRHI_LOG_INFO,
"Building 3D texture mipmap generator compute pipeline on first use");
4058 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
4059 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
4062 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
4063 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4064 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
4067 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
4068 descriptorRanges[0].NumDescriptors = 1;
4069 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
4070 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
4071 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4072 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
4073 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
4076 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
4077 descriptorRanges[1].NumDescriptors = 1;
4078 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
4079 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4080 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
4081 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
4084 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
4085 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
4086 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4087 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4088 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4089 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
4091 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
4092 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
4093 rsDesc.Desc_1_1.NumParameters = 3;
4094 rsDesc.Desc_1_1.pParameters = rootParams;
4095 rsDesc.Desc_1_1.NumStaticSamplers = 1;
4096 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
4098 ID3DBlob *signature =
nullptr;
4099 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
4101 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
4104 ID3D12RootSignature *rootSig =
nullptr;
4105 hr = rhiD->dev->CreateRootSignature(0,
4106 signature->GetBufferPointer(),
4107 signature->GetBufferSize(),
4108 __uuidof(ID3D12RootSignature),
4109 reinterpret_cast<
void **>(&rootSig));
4110 signature->Release();
4112 qWarning(
"Failed to create root signature: %s",
4113 qPrintable(QSystemError::windowsComString(hr)));
4117 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
4119 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
4120 psoDesc.pRootSignature = rootSig;
4121 psoDesc.CS.pShaderBytecode = g_csMipmap3D;
4122 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap3D);
4123 ID3D12PipelineState *pso =
nullptr;
4124 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
4125 __uuidof(ID3D12PipelineState),
4126 reinterpret_cast<
void **>(&pso));
4128 qWarning(
"Failed to create compute pipeline state: %s",
4129 qPrintable(QSystemError::windowsComString(hr)));
4130 rhiD->rootSignaturePool.remove(rootSigHandle);
4135 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
4140void QD3D12MipmapGenerator3D::destroy()
4145 rhiD->pipelinePool.remove(pipelineHandle);
4146 pipelineHandle = {};
4147 rhiD->rootSignaturePool.remove(rootSigHandle);
4149 createFailed =
false;
4152void QD3D12MipmapGenerator3D::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
4154 if (!ensureCreated())
4157 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
4160 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
4163 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
4167 const quint32 mipLevelCount = res->desc.MipLevels;
4168 if (mipLevelCount < 2)
4171 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
4173 qWarning(
"3D mipmap generator invoked for non-3D texture, this should not happen");
4177 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4178 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
4180 cbD->cmdList->SetPipelineState(pipeline->pso);
4181 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
4183 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
4189 quint32 srcMipLevel;
4192 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount);
4193 std::optional<QD3D12StagingArea> ownStagingArea;
4194 rhiD->recordSmallStagingAreaDemand(allocSize);
4195 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
4196 ownStagingArea = QD3D12StagingArea();
4197 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
4198 qWarning(
"Could not create staging area for mipmap generation");
4202 QD3D12StagingArea *workArea = ownStagingArea.has_value()
4203 ? &ownStagingArea.value()
4204 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
4206 bool gotNewHeap =
false;
4207 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
4208 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
4209 rhiD->currentFrameSlot,
4210 (1 + 1) * mipLevelCount,
4213 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
4217 rhiD->bindShaderVisibleHeaps(cbD);
4219 for (quint32 level = 0; level < mipLevelCount; ++level) {
4220 UINT subresource = calcSubresource(level, 0u, res->desc.MipLevels);
4221 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4222 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
4223 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
4225 quint32 levelPlusOneMipWidth = qMax<quint32>(1, res->desc.Width >> (level + 1));
4226 quint32 levelPlusOneMipHeight = qMax<quint32>(1, res->desc.Height >> (level + 1));
4227 quint32 levelPlusOneMipDepth = qMax<quint32>(1, res->desc.DepthOrArraySize >> (level + 1));
4229 CBufData cbufData = {
4230 1.0f /
float(levelPlusOneMipWidth),
4231 1.0f /
float(levelPlusOneMipHeight),
4232 1.0f /
float(levelPlusOneMipDepth),
4236 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
4237 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
4238 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
4240 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4241 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4242 srvDesc.Format = res->desc.Format;
4243 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4244 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4245 srvDesc.Texture3D.MipLevels = res->desc.MipLevels;
4247 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4248 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
4250 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4251 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
4252 const quint32 uavMipLevel = qMin(level + 1u, res->desc.MipLevels - 1u);
4253 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
4254 uavDesc.Format = res->desc.Format;
4255 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
4256 uavDesc.Texture3D.MipSlice = uavMipLevel;
4257 uavDesc.Texture3D.WSize = UINT(-1);
4258 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
4259 uavCpuHandle.ptr += descriptorByteSize;
4260 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
4262 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, levelPlusOneMipDepth);
4264 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
4265 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4266 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
4267 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4270 if (ownStagingArea.has_value())
4271 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
4274bool QD3D12MemoryAllocator::create(ID3D12Device *device, IDXGIAdapter1 *adapter)
4276 this->device = device;
4283 static bool disableMA = qEnvironmentVariableIntValue(
"QT_D3D_NO_SUBALLOC");
4287 DXGI_ADAPTER_DESC1 desc;
4288 adapter->GetDesc1(&desc);
4289 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
4292 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
4293 allocatorDesc.pDevice = device;
4294 allocatorDesc.pAdapter = adapter;
4297 allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED;
4298 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
4300 qWarning(
"Failed to initialize D3D12 Memory Allocator: %s",
4301 qPrintable(QSystemError::windowsComString(hr)));
4307void QD3D12MemoryAllocator::destroy()
4310 allocator->Release();
4311 allocator =
nullptr;
4315HRESULT QD3D12MemoryAllocator::createResource(D3D12_HEAP_TYPE heapType,
4316 const D3D12_RESOURCE_DESC *resourceDesc,
4317 D3D12_RESOURCE_STATES initialState,
4318 const D3D12_CLEAR_VALUE *optimizedClearValue,
4319 D3D12MA::Allocation **maybeAllocation,
4320 REFIID riidResource,
4324 D3D12MA::ALLOCATION_DESC allocDesc = {};
4325 allocDesc.HeapType = heapType;
4326 return allocator->CreateResource(&allocDesc,
4329 optimizedClearValue,
4334 *maybeAllocation =
nullptr;
4335 D3D12_HEAP_PROPERTIES heapProps = {};
4336 heapProps.Type = heapType;
4337 return device->CreateCommittedResource(&heapProps,
4338 D3D12_HEAP_FLAG_NONE,
4341 optimizedClearValue,
4347void QD3D12MemoryAllocator::getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget)
4350 allocator->GetBudget(localBudget, nonLocalBudget);
4353 *nonLocalBudget = {};
4357void QRhiD3D12::waitGpu()
4359 fullFenceCounter += 1u;
4360 if (SUCCEEDED(cmdQueue->Signal(fullFence, fullFenceCounter))) {
4361 if (SUCCEEDED(fullFence->SetEventOnCompletion(fullFenceCounter, fullFenceEvent)))
4362 WaitForSingleObject(fullFenceEvent, INFINITE);
4366DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleDesc(
int sampleCount, DXGI_FORMAT format)
const
4368 DXGI_SAMPLE_DESC desc;
4372 const int s = effectiveSampleCount(sampleCount);
4375 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
4376 msaaInfo.Format = format;
4377 msaaInfo.SampleCount = UINT(s);
4378 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo,
sizeof(msaaInfo)))) {
4379 if (msaaInfo.NumQualityLevels > 0) {
4380 desc.Count = UINT(s);
4381 desc.Quality = msaaInfo.NumQualityLevels - 1;
4383 qWarning(
"No quality levels for multisampling with sample count %d", s);
4391bool QRhiD3D12::startCommandListForCurrentFrameSlot(D3D12GraphicsCommandList **cmdList)
4393 ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
4395 HRESULT hr = dev->CreateCommandList(0,
4396 D3D12_COMMAND_LIST_TYPE_DIRECT,
4399 __uuidof(D3D12GraphicsCommandList),
4400 reinterpret_cast<
void **>(cmdList));
4402 qWarning(
"Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
4406 HRESULT hr = (*cmdList)->Reset(cmdAlloc,
nullptr);
4408 qWarning(
"Failed to reset command list: %s", qPrintable(QSystemError::windowsComString(hr)));
4415static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
4418 case DXGI_FORMAT_R8G8B8A8_UNORM:
4419 return QRhiTexture::RGBA8;
4420 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
4422 (*flags) |= QRhiTexture::sRGB;
4423 return QRhiTexture::RGBA8;
4424 case DXGI_FORMAT_B8G8R8A8_UNORM:
4425 return QRhiTexture::BGRA8;
4426 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
4428 (*flags) |= QRhiTexture::sRGB;
4429 return QRhiTexture::BGRA8;
4430 case DXGI_FORMAT_R16G16B16A16_FLOAT:
4431 return QRhiTexture::RGBA16F;
4432 case DXGI_FORMAT_R32G32B32A32_FLOAT:
4433 return QRhiTexture::RGBA32F;
4434 case DXGI_FORMAT_R10G10B10A2_UNORM:
4435 return QRhiTexture::RGB10A2;
4437 qWarning(
"DXGI_FORMAT %d cannot be read back", format);
4440 return QRhiTexture::UnknownFormat;
4443void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
4445 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
4447 for (
int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
4448 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
4449 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
4450 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4451 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4452 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4453 if (u.offset == 0 && u.data.size() == bufD->m_size)
4454 bufD->pendingHostWrites[i].clear();
4455 bufD->pendingHostWrites[i].append({ u.offset, u.data });
4457 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
4458 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4459 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4460 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
4468 QD3D12StagingArea::Allocation stagingAlloc;
4469 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(bufD->m_size, 1);
4470 recordSmallStagingAreaDemand(allocSize);
4471 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
4472 stagingAlloc = smallStagingAreas[currentFrameSlot].get(bufD->m_size);
4474 std::optional<QD3D12StagingArea> ownStagingArea;
4475 if (!stagingAlloc.isValid()) {
4476 ownStagingArea = QD3D12StagingArea();
4477 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
4479 stagingAlloc = ownStagingArea->get(allocSize);
4480 if (!stagingAlloc.isValid()) {
4481 ownStagingArea->destroy();
4486 memcpy(stagingAlloc.p + u.offset, u.data.constData(), u.data.size());
4488 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
4489 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4491 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
4492 cbD->cmdList->CopyBufferRegion(res->resource,
4494 stagingAlloc.buffer,
4495 stagingAlloc.bufferOffset + u.offset,
4499 if (ownStagingArea.has_value())
4500 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4501 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
4502 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4503 if (bufD->m_type == QRhiBuffer::Dynamic) {
4504 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
4505 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[currentFrameSlot])) {
4506 Q_ASSERT(res->cpuMapPtr);
4507 u.result->data.resize(u.readSize);
4508 memcpy(u.result->data.data(),
reinterpret_cast<
char *>(res->cpuMapPtr) + u.offset, u.readSize);
4510 if (u.result->completed)
4511 u.result->completed();
4513 QD3D12Readback readback;
4514 readback.frameSlot = currentFrameSlot;
4515 readback.result = u.result;
4516 readback.byteSize = u.readSize;
4517 const quint32 allocSize = aligned(u.readSize, QD3D12StagingArea::ALIGNMENT);
4518 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
4519 if (u.result->completed)
4520 u.result->completed();
4523 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(u.readSize);
4524 if (!stagingAlloc.isValid()) {
4525 readback.staging.destroy();
4526 if (u.result->completed)
4527 u.result->completed();
4530 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4531 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
4532 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4533 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
4534 cbD->cmdList->CopyBufferRegion(stagingAlloc.buffer, 0, res->resource, u.offset, u.readSize);
4535 activeReadbacks.append(readback);
4537 readback.staging.destroy();
4538 if (u.result->completed)
4539 u.result->completed();
4545 for (
int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
4546 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
4547 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
4548 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4549 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4550 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
4553 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4554 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4555 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4556 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4557 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level])) {
4558 D3D12_SUBRESOURCE_FOOTPRINT footprint = {};
4559 footprint.Format = res->desc.Format;
4560 footprint.Depth = 1;
4561 quint32 totalBytes = 0;
4563 QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
4564 : subresDesc.sourceSize();
4565 const QPoint srcPos = subresDesc.sourceTopLeft();
4566 QPoint dstPos = subresDesc.destinationTopLeft();
4568 if (subresDesc.image().isNull()
4569 && !subresDesc.data().isEmpty()
4570 && !isCompressedFormat(texD->m_format))
4572 subresSize = clampedSubResourceUploadSize(subresSize, dstPos, level, texD->m_pixelSize);
4573 quint32 bytesPerPixel = 0;
4574 textureFormatInfo(texD->m_format, subresSize,
nullptr,
nullptr, &bytesPerPixel);
4575 subresSize = clampedSubResourceUploadSizeForSourceData(subresSize,
4576 subresDesc.dataStride(),
4578 subresDesc.data().size());
4579 if (subresSize.isEmpty())
4583 if (!subresDesc.image().isNull()) {
4584 const QImage img = subresDesc.image();
4585 const int bpl = img.bytesPerLine();
4586 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4587 totalBytes = footprint.RowPitch * img.height();
4588 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
4591 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
4592 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4593 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
4594 totalBytes = footprint.RowPitch * rowCount;
4595 }
else if (!subresDesc.data().isEmpty()) {
4597 if (subresDesc.dataStride())
4598 bpl = subresDesc.dataStride();
4600 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4601 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4602 totalBytes = footprint.RowPitch * subresSize.height();
4604 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4608 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(totalBytes, 1);
4609 QD3D12StagingArea::Allocation stagingAlloc;
4610 recordSmallStagingAreaDemand(allocSize);
4611 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
4612 stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
4614 std::optional<QD3D12StagingArea> ownStagingArea;
4615 if (!stagingAlloc.isValid()) {
4616 ownStagingArea = QD3D12StagingArea();
4617 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
4619 stagingAlloc = ownStagingArea->get(allocSize);
4620 if (!stagingAlloc.isValid()) {
4621 ownStagingArea->destroy();
4626 D3D12_TEXTURE_COPY_LOCATION dst;
4627 dst.pResource = res->resource;
4628 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4629 dst.SubresourceIndex = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
4630 D3D12_TEXTURE_COPY_LOCATION src;
4631 src.pResource = stagingAlloc.buffer;
4632 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4633 src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
4637 if (!subresDesc.image().isNull()) {
4638 const QImage img = subresDesc.image();
4639 const int bpc = qMax(1, img.depth() / 8);
4640 const int bpl = img.bytesPerLine();
4642 QSize size = subresDesc.sourceSize().isEmpty() ? img.size() : subresDesc.sourceSize();
4643 size.setWidth(qMin(size.width(), img.width() - srcPos.x()));
4644 size.setHeight(qMin(size.height(), img.height() - srcPos.y()));
4645 size = clampedSubResourceUploadSize(size, dstPos, level, texD->m_pixelSize);
4647 footprint.Width = size.width();
4648 footprint.Height = size.height();
4652 srcBox.right = UINT(size.width());
4653 srcBox.bottom = UINT(size.height());
4657 const uchar *imgPtr = img.constBits();
4658 const quint32 lineBytes = size.width() * bpc;
4659 for (
int y = 0, h = size.height(); y < h; ++y) {
4660 memcpy(stagingAlloc.p + y * footprint.RowPitch,
4661 imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
4664 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
4667 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
4669 dstPos.setX(aligned(dstPos.x(), blockDim.width()));
4670 dstPos.setY(aligned(dstPos.y(), blockDim.height()));
4675 srcBox.right = aligned(subresSize.width(), blockDim.width());
4676 srcBox.bottom = aligned(subresSize.height(), blockDim.height());
4681 footprint.Width = aligned(subresSize.width(), blockDim.width());
4682 footprint.Height = aligned(subresSize.height(), blockDim.height());
4684 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4685 const QByteArray imgData = subresDesc.data();
4686 const char *imgPtr = imgData.constData();
4687 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
4688 for (
int y = 0; y < rowCount; ++y) {
4689 const quint64 srcOffset = quint64(y) * bpl;
4690 if (srcOffset >= quint64(imgData.size()))
4692 const quint32 n = quint32(qMin(quint64(copyBytes),
4693 quint64(imgData.size()) - srcOffset));
4694 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + srcOffset, n);
4696 }
else if (!subresDesc.data().isEmpty()) {
4699 srcBox.right = subresSize.width();
4700 srcBox.bottom = subresSize.height();
4704 footprint.Width = subresSize.width();
4705 footprint.Height = subresSize.height();
4708 if (subresDesc.dataStride())
4709 bpl = subresDesc.dataStride();
4711 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4713 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4714 const QByteArray data = subresDesc.data();
4715 const char *imgPtr = data.constData();
4716 for (
int y = 0, h = subresSize.height(); y < h; ++y) {
4721 const quint64 srcOffset = quint64(y) * bpl;
4722 if (srcOffset >= quint64(data.size()))
4724 const quint32 n = quint32(qMin(quint64(copyBytes),
4725 quint64(data.size()) - srcOffset));
4726 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + srcOffset, n);
4730 src.PlacedFootprint.Footprint = footprint;
4732 cbD->cmdList->CopyTextureRegion(&dst,
4735 is3D ? UINT(layer) : 0u,
4739 if (ownStagingArea.has_value())
4740 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4744 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
4745 Q_ASSERT(u.src && u.dst);
4746 QD3D12Texture *srcD = QRHI_RES(QD3D12Texture, u.src);
4747 QD3D12Texture *dstD = QRHI_RES(QD3D12Texture, u.dst);
4748 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4749 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4750 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
4751 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
4752 if (!srcRes || !dstRes)
4755 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4756 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4757 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4759 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
4760 srcIs3D ? 0u : UINT(u.desc.sourceLayer()),
4761 srcD->mipLevelCount);
4762 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
4763 dstIs3D ? 0u : UINT(u.desc.destinationLayer()),
4764 dstD->mipLevelCount);
4765 const QPoint dp = u.desc.destinationTopLeft();
4766 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4767 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4768 const QPoint sp = u.desc.sourceTopLeft();
4771 srcBox.left = UINT(sp.x());
4772 srcBox.top = UINT(sp.y());
4773 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
4775 srcBox.right = srcBox.left + UINT(copySize.width());
4776 srcBox.bottom = srcBox.top + UINT(copySize.height());
4777 srcBox.back = srcBox.front + 1;
4779 D3D12_TEXTURE_COPY_LOCATION src;
4780 src.pResource = srcRes->resource;
4781 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4782 src.SubresourceIndex = srcSubresource;
4783 D3D12_TEXTURE_COPY_LOCATION dst;
4784 dst.pResource = dstRes->resource;
4785 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4786 dst.SubresourceIndex = dstSubresource;
4788 cbD->cmdList->CopyTextureRegion(&dst,
4791 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
4794 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
4795 QD3D12Readback readback;
4796 readback.frameSlot = currentFrameSlot;
4797 readback.result = u.result;
4799 QD3D12ObjectHandle srcHandle;
4802 if (u.rb.texture()) {
4803 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.rb.texture());
4804 if (texD->sampleDesc.Count > 1) {
4805 qWarning(
"Multisample texture cannot be read back");
4808 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4809 if (u.rb.rect().isValid())
4812 rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4813 readback.format = texD->m_format;
4814 srcHandle = texD->handle;
4816 Q_ASSERT(currentSwapChain);
4817 if (u.rb.rect().isValid())
4820 rect = QRect({0, 0}, currentSwapChain->pixelSize);
4821 readback.format = swapchainReadbackTextureFormat(currentSwapChain->colorFormat,
nullptr);
4822 if (readback.format == QRhiTexture::UnknownFormat)
4824 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
4826 readback.pixelSize = rect.size();
4828 textureFormatInfo(readback.format,
4830 &readback.bytesPerLine,
4834 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
4838 const UINT subresource = calcSubresource(UINT(u.rb.level()),
4839 is3D ? 0u : UINT(u.rb.layer()),
4840 srcRes->desc.MipLevels);
4841 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
4844 UINT64 totalBytes = 0;
4845 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
4846 &layout,
nullptr,
nullptr, &totalBytes);
4847 readback.stagingRowPitch = layout.Footprint.RowPitch;
4849 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT);
4850 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
4851 if (u.result->completed)
4852 u.result->completed();
4855 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
4856 if (!stagingAlloc.isValid()) {
4857 readback.staging.destroy();
4858 if (u.result->completed)
4859 u.result->completed();
4862 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4864 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4865 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4867 D3D12_TEXTURE_COPY_LOCATION dst;
4868 dst.pResource = stagingAlloc.buffer;
4869 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4870 dst.PlacedFootprint.Offset = 0;
4871 dst.PlacedFootprint.Footprint = layout.Footprint;
4873 D3D12_TEXTURE_COPY_LOCATION src;
4874 src.pResource = srcRes->resource;
4875 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4876 src.SubresourceIndex = subresource;
4878 D3D12_BOX srcBox = {};
4879 srcBox.left = UINT(rect.left());
4880 srcBox.top = UINT(rect.top());
4881 srcBox.front = is3D ? UINT(u.rb.layer()) : 0u;
4883 srcBox.right = srcBox.left + UINT(rect.width());
4884 srcBox.bottom = srcBox.top + UINT(rect.height());
4885 srcBox.back = srcBox.front + 1;
4887 cbD->cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &srcBox);
4888 activeReadbacks.append(readback);
4889 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
4890 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4891 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
4897 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
4898 if (res && texD->mipLevelCount >= 2
4899 && (res->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET))
4901 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
4902 const UINT layerCount = is3D ? 1u : UINT(res->desc.DepthOrArraySize);
4903 QBitArray &initialized(texD->subresourceInitialized);
4904 QVarLengthArray<UINT, 16> subresourcesToDiscard;
4905 for (UINT layer = 0; layer < layerCount; ++layer) {
4906 for (UINT level = 1; level < texD->mipLevelCount; ++level) {
4907 const UINT subresource = calcSubresource(level, layer, texD->mipLevelCount);
4908 if (
int(subresource) >= initialized.size())
4909 initialized.resize(
int(subresource) + 1);
4910 if (!initialized.testBit(
int(subresource))) {
4911 initialized.setBit(
int(subresource));
4912 subresourcesToDiscard.append(subresource);
4916 if (!subresourcesToDiscard.isEmpty()) {
4918 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
4919 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4920 for (UINT subresource : subresourcesToDiscard) {
4921 D3D12_DISCARD_REGION region = {};
4922 region.FirstSubresource = subresource;
4923 region.NumSubresources = 1;
4924 cbD->cmdList->DiscardResource(res->resource, ®ion);
4929 if (texD->flags().testFlag(QRhiTexture::ThreeDimensional))
4930 mipmapGen3D.generate(cbD, texD->handle);
4932 mipmapGen.generate(cbD, texD->handle);
4939void QRhiD3D12::finishActiveReadbacks(
bool forced)
4941 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4943 for (
int i = activeReadbacks.size() - 1; i >= 0; --i) {
4944 QD3D12Readback &readback(activeReadbacks[i]);
4945 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
4946 readback.result->format = readback.format;
4947 readback.result->pixelSize = readback.pixelSize;
4948 readback.result->data.resize(
int(readback.byteSize));
4950 if (readback.format != QRhiTexture::UnknownFormat) {
4951 quint8 *dstPtr =
reinterpret_cast<quint8 *>(readback.result->data.data());
4952 const quint8 *srcPtr = readback.staging.mem.p;
4953 const quint32 lineSize = qMin(readback.bytesPerLine, readback.stagingRowPitch);
4954 for (
int y = 0, h = readback.pixelSize.height(); y < h; ++y)
4955 memcpy(dstPtr + y * readback.bytesPerLine, srcPtr + y * readback.stagingRowPitch, lineSize);
4957 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
4960 readback.staging.destroy();
4962 if (readback.result->completed)
4963 completedCallbacks.append(readback.result->completed);
4965 activeReadbacks.remove(i);
4969 for (
auto f : completedCallbacks)
4973bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
4974 D3D12_DESCRIPTOR_HEAP_TYPE type,
4976 quint32 neededDescriptorCount,
4984 if (h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
4985 const quint32 newPerFrameSize = qMax(h->perFrameHeapSlice[frameSlot].capacity * 2,
4986 neededDescriptorCount);
4987 QD3D12ShaderVisibleDescriptorHeap newHeap;
4988 if (!newHeap.create(dev, type, newPerFrameSize)) {
4989 qWarning(
"Could not create new shader-visible descriptor heap");
4992 h->destroyWithDeferredRelease(&releaseQueue);
4999void QRhiD3D12::resetAndResizeSmallStagingArea(
int frameSlot)
5001 QD3D12StagingArea &area(smallStagingAreas[frameSlot]);
5007 const quint32 needed = smallStagingAreaBytesNeeded[frameSlot];
5008 smallStagingAreaBytesNeeded[frameSlot] = 0;
5010 quint32 newCapacity = 0;
5011 if (needed > area.capacity) {
5014 smallStagingAreaLowDemandFrames[frameSlot] = 0;
5015 newCapacity = qMin(qNextPowerOfTwo(needed), SMALL_STAGING_AREA_BYTES_PER_FRAME_MAX);
5016 }
else if (needed <= area.capacity / 4 && area.capacity > SMALL_STAGING_AREA_BYTES_PER_FRAME_START) {
5017 if (++smallStagingAreaLowDemandFrames[frameSlot] >= SMALL_STAGING_AREA_LOW_DEMAND_FRAMES) {
5018 smallStagingAreaLowDemandFrames[frameSlot] = 0;
5019 newCapacity = qMax(area.capacity / 2, SMALL_STAGING_AREA_BYTES_PER_FRAME_START);
5022 smallStagingAreaLowDemandFrames[frameSlot] = 0;
5025 if (newCapacity && newCapacity != area.capacity) {
5026 QD3D12StagingArea newArea;
5027 if (newArea.create(
this, aligned(newCapacity, QD3D12StagingArea::ALIGNMENT), D3D12_HEAP_TYPE_UPLOAD)) {
5028 area.destroyWithDeferredRelease(&releaseQueue);
5030 QString decoratedName = QLatin1String(
"Small staging area buffer/");
5031 decoratedName += QString::number(frameSlot);
5032 area.mem.buffer->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
5041void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
5043 ID3D12DescriptorHeap *heaps[] = {
5044 shaderVisibleCbvSrvUavHeap.heap.heap,
5045 samplerMgr.shaderVisibleSamplerHeap.heap.heap
5047 cbD->cmdList->SetDescriptorHeaps(2, heaps);
5050QD3D12Buffer::QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
5051 : QRhiBuffer(rhi, type, usage, size)
5055QD3D12Buffer::~QD3D12Buffer()
5060void QD3D12Buffer::destroy()
5062 if (handles[0].isNull())
5065 QRHI_RES_RHI(QRhiD3D12);
5074 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
5076 rhiD->releaseQueue.deferredReleaseResource(handles[i]);
5078 pendingHostWrites[i].clear();
5082 rhiD->unregisterResource(
this);
5085bool QD3D12Buffer::create()
5087 if (!handles[0].isNull())
5090 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
5091 qWarning(
"UniformBuffer must always be Dynamic");
5095 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
5096 qWarning(
"StorageBuffer cannot be combined with Dynamic");
5100 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
5101 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
5103 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
5104 if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
5105 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5107 QRHI_RES_RHI(QRhiD3D12);
5109 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
5110 if (i == 0 || m_type == Dynamic) {
5111 D3D12_RESOURCE_DESC resourceDesc = {};
5112 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
5113 resourceDesc.Width = roundedSize;
5114 resourceDesc.Height = 1;
5115 resourceDesc.DepthOrArraySize = 1;
5116 resourceDesc.MipLevels = 1;
5117 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
5118 resourceDesc.SampleDesc = { 1, 0 };
5119 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
5120 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
5121 ID3D12Resource *resource =
nullptr;
5122 D3D12MA::Allocation *allocation =
nullptr;
5124 D3D12_HEAP_TYPE heapType = m_type == Dynamic
5125 ? D3D12_HEAP_TYPE_UPLOAD
5126 : D3D12_HEAP_TYPE_DEFAULT;
5127 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
5128 ? D3D12_RESOURCE_STATE_GENERIC_READ
5129 : D3D12_RESOURCE_STATE_COMMON;
5130 hr = rhiD->vma.createResource(heapType,
5136 reinterpret_cast<
void **>(&resource));
5139 if (!m_objectName.isEmpty()) {
5140 QString decoratedName = QString::fromUtf8(m_objectName);
5141 if (m_type == Dynamic) {
5142 decoratedName += QLatin1Char(
'/');
5143 decoratedName += QString::number(i);
5145 resource->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
5147 void *cpuMemPtr =
nullptr;
5148 if (m_type == Dynamic) {
5150 hr = resource->Map(0,
nullptr, &cpuMemPtr);
5152 qWarning(
"Map() failed to dynamic buffer");
5153 resource->Release();
5155 allocation->Release();
5159 handles[i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
5167 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
5168 qPrintable(QSystemError::windowsComString(hr)),
5171 int(rhiD->vma.isUsingD3D12MA()));
5176 rhiD->registerResource(
this);
5180QRhiBuffer::NativeBuffer QD3D12Buffer::nativeBuffer()
5183 Q_ASSERT(
sizeof(b.objects) /
sizeof(b.objects[0]) >= size_t(QD3D12_FRAMES_IN_FLIGHT));
5184 QRHI_RES_RHI(QRhiD3D12);
5185 if (m_type == Dynamic) {
5186 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
5187 executeHostWritesForFrameSlot(i);
5188 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[i]))
5189 b.objects[i] = res->resource;
5191 b.objects[i] =
nullptr;
5193 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
5196 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[0]))
5197 b.objects[0] = res->resource;
5199 b.objects[0] =
nullptr;
5204char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
5212 Q_ASSERT(m_type == Dynamic);
5213 QRHI_RES_RHI(QRhiD3D12);
5214 Q_ASSERT(rhiD->inFrame);
5215 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
5216 return static_cast<
char *>(res->cpuMapPtr);
5221void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
5226void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
5228 if (pendingHostWrites[frameSlot].isEmpty())
5231 Q_ASSERT(m_type == QRhiBuffer::Dynamic);
5232 QRHI_RES_RHI(QRhiD3D12);
5233 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
5234 Q_ASSERT(res->cpuMapPtr);
5235 for (
const QD3D12Buffer::HostWrite &u : std::as_const(pendingHostWrites[frameSlot]))
5236 memcpy(
static_cast<
char *>(res->cpuMapPtr) + u.offset, u.data.constData(), u.data.size());
5238 pendingHostWrites[frameSlot].clear();
5241static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
5243 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
5245 case QRhiTexture::RGBA8:
5246 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
5247 case QRhiTexture::BGRA8:
5248 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
5249 case QRhiTexture::R8:
5250 return DXGI_FORMAT_R8_UNORM;
5251 case QRhiTexture::R8SI:
5252 return DXGI_FORMAT_R8_SINT;
5253 case QRhiTexture::R8UI:
5254 return DXGI_FORMAT_R8_UINT;
5255 case QRhiTexture::RG8:
5256 return DXGI_FORMAT_R8G8_UNORM;
5257 case QRhiTexture::R16:
5258 return DXGI_FORMAT_R16_UNORM;
5259 case QRhiTexture::RG16:
5260 return DXGI_FORMAT_R16G16_UNORM;
5261 case QRhiTexture::RED_OR_ALPHA8:
5262 return DXGI_FORMAT_R8_UNORM;
5264 case QRhiTexture::RGBA16F:
5265 return DXGI_FORMAT_R16G16B16A16_FLOAT;
5266 case QRhiTexture::RGBA32F:
5267 return DXGI_FORMAT_R32G32B32A32_FLOAT;
5268 case QRhiTexture::R16F:
5269 return DXGI_FORMAT_R16_FLOAT;
5270 case QRhiTexture::R32F:
5271 return DXGI_FORMAT_R32_FLOAT;
5273 case QRhiTexture::RGB10A2:
5274 return DXGI_FORMAT_R10G10B10A2_UNORM;
5276 case QRhiTexture::R32SI:
5277 return DXGI_FORMAT_R32_SINT;
5278 case QRhiTexture::R32UI:
5279 return DXGI_FORMAT_R32_UINT;
5280 case QRhiTexture::RG32SI:
5281 return DXGI_FORMAT_R32G32_SINT;
5282 case QRhiTexture::RG32UI:
5283 return DXGI_FORMAT_R32G32_UINT;
5284 case QRhiTexture::RGBA32SI:
5285 return DXGI_FORMAT_R32G32B32A32_SINT;
5286 case QRhiTexture::RGBA32UI:
5287 return DXGI_FORMAT_R32G32B32A32_UINT;
5289 case QRhiTexture::D16:
5290 return DXGI_FORMAT_R16_TYPELESS;
5291 case QRhiTexture::D24:
5292 return DXGI_FORMAT_R24G8_TYPELESS;
5293 case QRhiTexture::D24S8:
5294 return DXGI_FORMAT_R24G8_TYPELESS;
5295 case QRhiTexture::D32F:
5296 return DXGI_FORMAT_R32_TYPELESS;
5297 case QRhiTexture::Format::D32FS8:
5298 return DXGI_FORMAT_R32G8X24_TYPELESS;
5300 case QRhiTexture::BC1:
5301 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
5302 case QRhiTexture::BC2:
5303 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
5304 case QRhiTexture::BC3:
5305 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
5306 case QRhiTexture::BC4:
5307 return DXGI_FORMAT_BC4_UNORM;
5308 case QRhiTexture::BC5:
5309 return DXGI_FORMAT_BC5_UNORM;
5310 case QRhiTexture::BC6H:
5311 return DXGI_FORMAT_BC6H_UF16;
5312 case QRhiTexture::BC7:
5313 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
5315 case QRhiTexture::ETC2_RGB8:
5316 case QRhiTexture::ETC2_RGB8A1:
5317 case QRhiTexture::ETC2_RGBA8:
5318 qWarning(
"QRhiD3D12 does not support ETC2 textures");
5319 return DXGI_FORMAT_R8G8B8A8_UNORM;
5321 case QRhiTexture::ASTC_4x4:
5322 case QRhiTexture::ASTC_5x4:
5323 case QRhiTexture::ASTC_5x5:
5324 case QRhiTexture::ASTC_6x5:
5325 case QRhiTexture::ASTC_6x6:
5326 case QRhiTexture::ASTC_8x5:
5327 case QRhiTexture::ASTC_8x6:
5328 case QRhiTexture::ASTC_8x8:
5329 case QRhiTexture::ASTC_10x5:
5330 case QRhiTexture::ASTC_10x6:
5331 case QRhiTexture::ASTC_10x8:
5332 case QRhiTexture::ASTC_10x10:
5333 case QRhiTexture::ASTC_12x10:
5334 case QRhiTexture::ASTC_12x12:
5335 qWarning(
"QRhiD3D12 does not support ASTC textures");
5336 return DXGI_FORMAT_R8G8B8A8_UNORM;
5341 return DXGI_FORMAT_R8G8B8A8_UNORM;
5344QD3D12RenderBuffer::QD3D12RenderBuffer(QRhiImplementation *rhi,
5346 const QSize &pixelSize,
5349 QRhiTexture::Format backingFormatHint)
5350 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
5354QD3D12RenderBuffer::~QD3D12RenderBuffer()
5359void QD3D12RenderBuffer::destroy()
5361 if (handle.isNull())
5364 QRHI_RES_RHI(QRhiD3D12);
5367 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->rtvPool, rtv, 1);
5368 else if (dsv.isValid())
5369 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->dsvPool, dsv, 1);
5377 rhiD->unregisterResource(
this);
5380bool QD3D12RenderBuffer::create()
5382 if (!handle.isNull())
5385 if (m_pixelSize.isEmpty())
5388 QRHI_RES_RHI(QRhiD3D12);
5391 case QRhiRenderBuffer::Color:
5393 dxgiFormat = toD3DTextureFormat(backingFormat(), {});
5394 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5395 D3D12_RESOURCE_DESC resourceDesc = {};
5396 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
5397 resourceDesc.Width = UINT64(m_pixelSize.width());
5398 resourceDesc.Height = UINT(m_pixelSize.height());
5399 resourceDesc.DepthOrArraySize = 1;
5400 resourceDesc.MipLevels = 1;
5401 resourceDesc.Format = dxgiFormat;
5402 resourceDesc.SampleDesc = sampleDesc;
5403 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5404 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
5405 D3D12_CLEAR_VALUE clearValue = {};
5406 clearValue.Format = dxgiFormat;
5408 ID3D12Resource *resource =
nullptr;
5409 D3D12MA::Allocation *allocation =
nullptr;
5410 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5412 D3D12_RESOURCE_STATE_RENDER_TARGET,
5415 __uuidof(ID3D12Resource),
5416 reinterpret_cast<
void **>(&resource));
5418 qWarning(
"Failed to create color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
5421 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
5422 rtv = rhiD->rtvPool.allocate(1);
5425 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5426 rtvDesc.Format = dxgiFormat;
5427 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
5428 : D3D12_RTV_DIMENSION_TEXTURE2D;
5429 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
5432 case QRhiRenderBuffer::DepthStencil:
5434 dxgiFormat = DS_FORMAT;
5435 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5436 D3D12_RESOURCE_DESC resourceDesc = {};
5437 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
5438 resourceDesc.Width = UINT64(m_pixelSize.width());
5439 resourceDesc.Height = UINT(m_pixelSize.height());
5440 resourceDesc.DepthOrArraySize = 1;
5441 resourceDesc.MipLevels = 1;
5442 resourceDesc.Format = dxgiFormat;
5443 resourceDesc.SampleDesc = sampleDesc;
5444 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5445 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
5446 if (m_flags.testFlag(UsedWithSwapChainOnly))
5447 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
5448 D3D12_CLEAR_VALUE clearValue = {};
5449 clearValue.Format = dxgiFormat;
5450 clearValue.DepthStencil.Depth = 1.0f;
5451 clearValue.DepthStencil.Stencil = 0;
5452 ID3D12Resource *resource =
nullptr;
5453 D3D12MA::Allocation *allocation =
nullptr;
5454 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5456 D3D12_RESOURCE_STATE_DEPTH_WRITE,
5459 __uuidof(ID3D12Resource),
5460 reinterpret_cast<
void **>(&resource));
5462 qWarning(
"Failed to create depth-stencil buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
5465 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE, allocation);
5466 dsv = rhiD->dsvPool.allocate(1);
5469 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5470 dsvDesc.Format = dxgiFormat;
5471 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
5472 : D3D12_DSV_DIMENSION_TEXTURE2D;
5473 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
5478 if (!m_objectName.isEmpty()) {
5479 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
5480 const QString name = QString::fromUtf8(m_objectName);
5481 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
5486 rhiD->registerResource(
this);
5490QRhiTexture::Format QD3D12RenderBuffer::backingFormat()
const
5492 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
5493 return m_backingFormatHint;
5495 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
5498QD3D12Texture::QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
5499 int arraySize,
int sampleCount, Flags flags)
5500 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
5504QD3D12Texture::~QD3D12Texture()
5509void QD3D12Texture::destroy()
5511 if (handle.isNull())
5514 QRHI_RES_RHI(QRhiD3D12);
5516 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->cbvSrvUavPool, srv, 1);
5520 subresourceInitialized.clear();
5523 rhiD->unregisterResource(
this);
5526static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
5529 case QRhiTexture::Format::D16:
5530 return DXGI_FORMAT_R16_FLOAT;
5531 case QRhiTexture::Format::D24:
5532 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
5533 case QRhiTexture::Format::D24S8:
5534 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
5535 case QRhiTexture::Format::D32F:
5536 return DXGI_FORMAT_R32_FLOAT;
5537 case QRhiTexture::Format::D32FS8:
5538 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
5542 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
5545static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
5549 case QRhiTexture::Format::D16:
5550 return DXGI_FORMAT_D16_UNORM;
5551 case QRhiTexture::Format::D24:
5552 return DXGI_FORMAT_D24_UNORM_S8_UINT;
5553 case QRhiTexture::Format::D24S8:
5554 return DXGI_FORMAT_D24_UNORM_S8_UINT;
5555 case QRhiTexture::Format::D32F:
5556 return DXGI_FORMAT_D32_FLOAT;
5557 case QRhiTexture::Format::D32FS8:
5558 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
5562 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
5565static inline bool isDepthTextureFormat(QRhiTexture::Format format)
5568 case QRhiTexture::Format::D16:
5569 case QRhiTexture::Format::D24:
5570 case QRhiTexture::Format::D24S8:
5571 case QRhiTexture::Format::D32F:
5572 case QRhiTexture::Format::D32FS8:
5579bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
5581 if (!handle.isNull())
5584 QRHI_RES_RHI(QRhiD3D12);
5585 if (!rhiD->isTextureFormatSupported(m_format, m_flags))
5588 const bool isDepth = isDepthTextureFormat(m_format);
5589 const bool isCube = m_flags.testFlag(CubeMap);
5590 const bool is3D = m_flags.testFlag(ThreeDimensional);
5591 const bool isArray = m_flags.testFlag(TextureArray);
5592 const bool hasMipMaps = m_flags.testFlag(MipMapped);
5593 const bool is1D = m_flags.testFlag(OneDimensional);
5595 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
5596 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
5598 dxgiFormat = toD3DTextureFormat(m_format, m_flags);
5600 srvFormat = toD3DDepthTextureSRVFormat(m_format);
5601 rtFormat = toD3DDepthTextureDSVFormat(m_format);
5603 srvFormat = dxgiFormat;
5604 rtFormat = dxgiFormat;
5606 if (m_writeViewFormat.format != UnknownFormat) {
5608 rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
5610 rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
5612 if (m_readViewFormat.format != UnknownFormat) {
5614 srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
5616 srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
5619 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
5620 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5621 if (sampleDesc.Count > 1) {
5623 qWarning(
"Cubemap texture cannot be multisample");
5627 qWarning(
"3D texture cannot be multisample");
5631 qWarning(
"Multisample texture cannot have mipmaps");
5635 if (isDepth && hasMipMaps) {
5636 qWarning(
"Depth texture cannot have mipmaps");
5639 if (isCube && is3D) {
5640 qWarning(
"Texture cannot be both cube and 3D");
5643 if (isArray && is3D) {
5644 qWarning(
"Texture cannot be both array and 3D");
5647 if (isCube && is1D) {
5648 qWarning(
"Texture cannot be both cube and 1D");
5652 qWarning(
"Texture cannot be both 1D and 3D");
5655 if (m_depth > 1 && !is3D) {
5656 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
5659 if (m_arraySize > 0 && !isArray) {
5660 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
5663 if (m_arraySize < 1 && isArray) {
5664 qWarning(
"Texture is an array but array size is %d", m_arraySize);
5668 if (!rhiD->textureFormatInfo(m_format, size,
nullptr,
nullptr,
nullptr))
5672 *adjustedSize = size;
5677bool QD3D12Texture::finishCreate()
5679 QRHI_RES_RHI(QRhiD3D12);
5680 const bool isCube = m_flags.testFlag(CubeMap);
5681 const bool is3D = m_flags.testFlag(ThreeDimensional);
5682 const bool isArray = m_flags.testFlag(TextureArray);
5683 const bool is1D = m_flags.testFlag(OneDimensional);
5685 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
5686 srvDesc.Format = srvFormat;
5687 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
5690 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
5691 srvDesc.TextureCube.MipLevels = mipLevelCount;
5695 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
5696 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
5697 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5698 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
5699 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
5701 srvDesc.Texture1DArray.FirstArraySlice = 0;
5702 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
5705 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
5706 srvDesc.Texture1D.MipLevels = mipLevelCount;
5708 }
else if (isArray) {
5709 if (sampleDesc.Count > 1) {
5710 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
5711 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5712 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
5713 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
5715 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
5716 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
5719 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
5720 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
5721 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5722 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
5723 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
5725 srvDesc.Texture2DArray.FirstArraySlice = 0;
5726 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
5730 if (sampleDesc.Count > 1) {
5731 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
5733 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
5734 srvDesc.Texture3D.MipLevels = mipLevelCount;
5736 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
5737 srvDesc.Texture2D.MipLevels = mipLevelCount;
5742 srv = rhiD->cbvSrvUavPool.allocate(1);
5746 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
5747 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
5748 if (!m_objectName.isEmpty()) {
5749 const QString name = QString::fromUtf8(m_objectName);
5750 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
5760bool QD3D12Texture::create()
5763 if (!prepareCreate(&size))
5766 const bool isDepth = isDepthTextureFormat(m_format);
5767 const bool isCube = m_flags.testFlag(CubeMap);
5768 const bool is3D = m_flags.testFlag(ThreeDimensional);
5769 const bool isArray = m_flags.testFlag(TextureArray);
5770 const bool is1D = m_flags.testFlag(OneDimensional);
5772 QRHI_RES_RHI(QRhiD3D12);
5774 bool needsOptimizedClearValueSpecified =
false;
5775 UINT resourceFlags = 0;
5776 if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
5778 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
5780 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
5781 needsOptimizedClearValueSpecified =
true;
5783 if (m_flags.testFlag(UsedWithGenerateMips)) {
5785 qWarning(
"Depth texture cannot have mipmaps generated");
5788 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5790 if (m_flags.testFlag(UsedWithLoadStore))
5791 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5793 D3D12_RESOURCE_DESC resourceDesc = {};
5794 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
5795 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
5796 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
5797 resourceDesc.Width = UINT64(size.width());
5798 resourceDesc.Height = UINT(size.height());
5799 resourceDesc.DepthOrArraySize = isCube ? 6
5800 : (isArray ? UINT(qMax(0, m_arraySize))
5801 : (is3D ? qMax(1, m_depth)
5803 resourceDesc.MipLevels = mipLevelCount;
5804 resourceDesc.Format = dxgiFormat;
5805 resourceDesc.SampleDesc = sampleDesc;
5806 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5807 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
5808 D3D12_CLEAR_VALUE clearValue = {};
5809 clearValue.Format = dxgiFormat;
5811 clearValue.Format = toD3DDepthTextureDSVFormat(m_format);
5812 clearValue.DepthStencil.Depth = 1.0f;
5813 clearValue.DepthStencil.Stencil = 0;
5815 ID3D12Resource *resource =
nullptr;
5816 D3D12MA::Allocation *allocation =
nullptr;
5817 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5819 D3D12_RESOURCE_STATE_COMMON,
5820 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
5822 __uuidof(ID3D12Resource),
5823 reinterpret_cast<
void **>(&resource));
5825 qWarning(
"Failed to create texture: '%s'"
5826 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
5827 qPrintable(QSystemError::windowsComString(hr)),
5828 int(resourceDesc.Dimension),
5829 uint(resourceDesc.Width),
5830 uint(resourceDesc.Height),
5831 uint(resourceDesc.DepthOrArraySize),
5832 uint(resourceDesc.MipLevels),
5833 int(resourceDesc.Format),
5834 int(resourceDesc.SampleDesc.Count));
5835 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
5836 rhiD->deviceLost =
true;
5840 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON, allocation);
5842 if (!finishCreate())
5845 rhiD->registerResource(
this);
5849bool QD3D12Texture::createFrom(QRhiTexture::NativeTexture src)
5854 if (!prepareCreate())
5857 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *>(src.object);
5858 D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(src.layout);
5860 QRHI_RES_RHI(QRhiD3D12);
5861 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource, state);
5863 if (!finishCreate())
5866 rhiD->registerResource(
this);
5870QRhiTexture::NativeTexture QD3D12Texture::nativeTexture()
5872 QRHI_RES_RHI(QRhiD3D12);
5873 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
5874 return { quint64(res->resource),
int(res->state) };
5879void QD3D12Texture::setNativeLayout(
int layout)
5881 QRHI_RES_RHI(QRhiD3D12);
5882 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
5883 res->state = D3D12_RESOURCE_STATES(layout);
5886QD3D12Sampler::QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
5887 AddressMode u, AddressMode v, AddressMode w)
5888 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
5892QD3D12Sampler::~QD3D12Sampler()
5897void QD3D12Sampler::destroy()
5899 shaderVisibleDescriptor = {};
5901 QRHI_RES_RHI(QRhiD3D12);
5903 rhiD->unregisterResource(
this);
5906static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
5908 if (minFilter == QRhiSampler::Nearest) {
5909 if (magFilter == QRhiSampler::Nearest) {
5910 if (mipFilter == QRhiSampler::Linear)
5911 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
5913 return D3D12_FILTER_MIN_MAG_MIP_POINT;
5915 if (mipFilter == QRhiSampler::Linear)
5916 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
5918 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
5921 if (magFilter == QRhiSampler::Nearest) {
5922 if (mipFilter == QRhiSampler::Linear)
5923 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
5925 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
5927 if (mipFilter == QRhiSampler::Linear)
5928 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
5930 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
5933 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
5936static inline D3D12_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
5939 case QRhiSampler::Repeat:
5940 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
5941 case QRhiSampler::ClampToEdge:
5942 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
5943 case QRhiSampler::Mirror:
5944 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
5946 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
5949static inline D3D12_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
5952 case QRhiSampler::Never:
5953 return D3D12_COMPARISON_FUNC_NEVER;
5954 case QRhiSampler::Less:
5955 return D3D12_COMPARISON_FUNC_LESS;
5956 case QRhiSampler::Equal:
5957 return D3D12_COMPARISON_FUNC_EQUAL;
5958 case QRhiSampler::LessOrEqual:
5959 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5960 case QRhiSampler::Greater:
5961 return D3D12_COMPARISON_FUNC_GREATER;
5962 case QRhiSampler::NotEqual:
5963 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5964 case QRhiSampler::GreaterOrEqual:
5965 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5966 case QRhiSampler::Always:
5967 return D3D12_COMPARISON_FUNC_ALWAYS;
5969 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
5972bool QD3D12Sampler::create()
5975 desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
5976 if (m_compareOp != Never)
5977 desc.Filter = D3D12_FILTER(desc.Filter | 0x80);
5978 desc.AddressU = toD3DAddressMode(m_addressU);
5979 desc.AddressV = toD3DAddressMode(m_addressV);
5980 desc.AddressW = toD3DAddressMode(m_addressW);
5981 desc.MaxAnisotropy = 1.0f;
5982 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
5983 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
5987 shaderVisibleDescriptor = {};
5991 QRHI_RES_RHI(QRhiD3D12);
5992 rhiD->registerResource(
this,
false);
5996QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
5998 if (!shaderVisibleDescriptor.isValid()) {
5999 QRHI_RES_RHI(QRhiD3D12);
6000 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(desc);
6002 return shaderVisibleDescriptor;
6005QD3D12ShadingRateMap::QD3D12ShadingRateMap(QRhiImplementation *rhi)
6006 : QRhiShadingRateMap(rhi)
6010QD3D12ShadingRateMap::~QD3D12ShadingRateMap()
6015void QD3D12ShadingRateMap::destroy()
6017 if (handle.isNull())
6023bool QD3D12ShadingRateMap::createFrom(QRhiTexture *src)
6025 if (!handle.isNull())
6028 handle = QRHI_RES(QD3D12Texture, src)->handle;
6033QD3D12TextureRenderTarget::QD3D12TextureRenderTarget(QRhiImplementation *rhi,
6034 const QRhiTextureRenderTargetDescription &desc,
6036 : QRhiTextureRenderTarget(rhi, desc, flags),
6041QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
6046void QD3D12TextureRenderTarget::destroy()
6048 if (!rtv[0].isValid() && !dsv.isValid())
6051 QRHI_RES_RHI(QRhiD3D12);
6052 if (dsv.isValid()) {
6053 if (ownsDsv && rhiD)
6054 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
6058 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i) {
6059 if (rtv[i].isValid()) {
6060 if (ownsRtv[i] && rhiD)
6061 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[i], 1);
6067 rhiD->unregisterResource(
this);
6070QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDescriptor()
6074 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6076 rpD->colorAttachmentCount = 0;
6077 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it) {
6078 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
6079 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
6081 rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
6083 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
6084 rpD->colorAttachmentCount += 1;
6087 rpD->hasDepthStencil =
false;
6088 if (m_desc.depthStencilBuffer()) {
6089 rpD->hasDepthStencil =
true;
6090 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
6091 }
else if (m_desc.depthTexture()) {
6092 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
6093 rpD->hasDepthStencil =
true;
6094 rpD->dsFormat = toD3DDepthTextureDSVFormat(depthTexD->format());
6097 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
6099 rpD->updateSerializedFormat();
6101 QRHI_RES_RHI(QRhiD3D12);
6102 rhiD->registerResource(rpD);
6106bool QD3D12TextureRenderTarget::create()
6108 if (rtv[0].isValid() || dsv.isValid())
6111 QRHI_RES_RHI(QRhiD3D12);
6112 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
6113 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
6114 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
6115 d.colorAttCount = 0;
6118 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
6119 d.colorAttCount += 1;
6120 const QRhiColorAttachment &colorAtt(*it);
6121 QRhiTexture *texture = colorAtt.texture();
6122 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
6123 Q_ASSERT(texture || rb);
6125 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, texture);
6126 QD3D12Resource *res = rhiD->resourcePool.lookupRef(texD->handle);
6128 qWarning(
"Could not look up texture handle for render target");
6131 const bool isMultiView = it->multiViewCount() >= 2;
6132 UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
6133 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6134 rtvDesc.Format = texD->rtFormat;
6135 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
6136 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
6137 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
6138 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
6139 rtvDesc.Texture2DArray.ArraySize = layerCount;
6140 }
else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
6141 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
6142 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
6143 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
6144 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
6145 rtvDesc.Texture1DArray.ArraySize = layerCount;
6147 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
6148 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
6150 }
else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
6151 if (texD->sampleDesc.Count > 1) {
6152 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
6153 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
6154 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
6156 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
6157 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
6158 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
6159 rtvDesc.Texture2DArray.ArraySize = layerCount;
6161 }
else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
6162 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
6163 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
6164 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
6165 rtvDesc.Texture3D.WSize = layerCount;
6167 if (texD->sampleDesc.Count > 1) {
6168 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
6170 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
6171 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
6174 rtv[attIndex] = rhiD->rtvPool.allocate(1);
6175 if (!rtv[attIndex].isValid()) {
6176 qWarning(
"Failed to allocate RTV for texture render target");
6179 rhiD->dev->CreateRenderTargetView(res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
6180 ownsRtv[attIndex] =
true;
6181 if (attIndex == 0) {
6182 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
6183 d.sampleCount =
int(texD->sampleDesc.Count);
6186 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rb);
6187 ownsRtv[attIndex] =
false;
6188 rtv[attIndex] = rbD->rtv;
6189 if (attIndex == 0) {
6190 d.pixelSize = rbD->pixelSize();
6191 d.sampleCount =
int(rbD->sampleDesc.Count);
6198 if (hasDepthStencil) {
6199 if (m_desc.depthTexture()) {
6201 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
6202 QD3D12Resource *res = rhiD->resourcePool.lookupRef(depthTexD->handle);
6204 qWarning(
"Could not look up depth texture handle");
6207 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
6208 dsvDesc.Format = depthTexD->rtFormat;
6209 const bool isMultisample = depthTexD->sampleDesc.Count > 1;
6210 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
6211 if (isMultisample) {
6212 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
6213 if (m_desc.depthLayer() >= 0) {
6214 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_desc.depthLayer());
6215 dsvDesc.Texture2DMSArray.ArraySize = 1;
6216 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
6217 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
6218 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
6220 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
6221 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
6224 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
6225 if (m_desc.depthLayer() >= 0) {
6226 dsvDesc.Texture2DArray.FirstArraySlice = UINT(m_desc.depthLayer());
6227 dsvDesc.Texture2DArray.ArraySize = 1;
6228 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
6229 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
6230 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
6232 dsvDesc.Texture2DArray.FirstArraySlice = 0;
6233 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
6238 dsvDesc.ViewDimension = isMultisample ? D3D12_DSV_DIMENSION_TEXTURE2DMS
6239 : D3D12_DSV_DIMENSION_TEXTURE2D;
6241 dsv = rhiD->dsvPool.allocate(1);
6242 if (!dsv.isValid()) {
6243 qWarning(
"Failed to allocate DSV for texture render target");
6246 rhiD->dev->CreateDepthStencilView(res->resource, &dsvDesc, dsv.cpuHandle);
6247 if (d.colorAttCount == 0) {
6248 d.pixelSize = depthTexD->pixelSize();
6249 d.sampleCount =
int(depthTexD->sampleDesc.Count);
6253 QD3D12RenderBuffer *depthRbD = QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
6254 dsv = depthRbD->dsv;
6255 if (d.colorAttCount == 0) {
6256 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
6257 d.sampleCount =
int(depthRbD->sampleDesc.Count);
6265 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
6266 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i)
6267 d.rtv[i] = i < d.colorAttCount ? rtv[i].cpuHandle : nullDescHandle;
6268 d.dsv = dsv.cpuHandle;
6269 d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6271 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &d.currentResIdList);
6273 rhiD->registerResource(
this);
6277QSize QD3D12TextureRenderTarget::pixelSize()
const
6279 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc, d.currentResIdList))
6280 const_cast<QD3D12TextureRenderTarget *>(
this)->create();
6285float QD3D12TextureRenderTarget::devicePixelRatio()
const
6290int QD3D12TextureRenderTarget::sampleCount()
const
6292 return d.sampleCount;
6295QD3D12ShaderResourceBindings::QD3D12ShaderResourceBindings(QRhiImplementation *rhi)
6296 : QRhiShaderResourceBindings(rhi)
6300QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
6305void QD3D12ShaderResourceBindings::destroy()
6307 bindingCache.reset();
6308 bindingCacheValid =
false;
6309 boundResourceData.clear();
6311 QRHI_RES_RHI(QRhiD3D12);
6313 rhiD->unregisterResource(
this);
6316bool QD3D12ShaderResourceBindings::create()
6318 QRHI_RES_RHI(QRhiD3D12);
6319 if (!rhiD->sanityCheckShaderResourceBindings(
this))
6322 rhiD->updateLayoutDesc(
this);
6324 boundResourceData.resize(m_bindings.count());
6325 for (BoundResourceData &bd : boundResourceData)
6326 memset(&bd, 0,
sizeof(BoundResourceData));
6328 bindingCache.reset();
6329 bindingCacheValid =
false;
6331 hasDynamicOffset =
false;
6332 for (
const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
6333 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
6334 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
6335 hasDynamicOffset =
true;
6349 rhiD->registerResource(
this,
false);
6353void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
6357 Q_ASSERT(boundResourceData.count() == m_bindings.count());
6358 for (BoundResourceData &bd : boundResourceData)
6359 memset(&bd, 0,
sizeof(BoundResourceData));
6361 bindingCache.reset();
6362 bindingCacheValid =
false;
6372void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
6373 const QRhiShaderResourceBinding::Data::UniformBufferData &,
6377 D3D12_ROOT_PARAMETER1 rootParam = {};
6378 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
6379 rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
6380 rootParam.Descriptor.ShaderRegister = shaderRegister;
6381 rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
6382 visitorData.cbParams[s].append(rootParam);
6385void QD3D12ShaderResourceBindings::visitTextures(QD3D12Stage s,
6386 const QRhiShaderResourceBinding::TextureAndSampler *,
6388 int baseShaderRegister)
6393 D3D12_DESCRIPTOR_RANGE1 range = {};
6394 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
6395 range.NumDescriptors = UINT(count);
6396 range.BaseShaderRegister = baseShaderRegister;
6397 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[s];
6398 visitorData.currentSrvRangeOffset[s] += UINT(count);
6399 visitorData.srvRanges[s].append(range);
6400 if (visitorData.srvRanges[s].count() == 1) {
6401 visitorData.srvTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6402 visitorData.srvTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6406void QD3D12ShaderResourceBindings::visitSamplers(QD3D12Stage s,
6407 const QRhiShaderResourceBinding::TextureAndSampler *,
6409 int baseShaderRegister)
6417 int &rangeStoreIdx(visitorData.samplerRangeHeads[s]);
6418 if (rangeStoreIdx == 16) {
6419 qWarning(
"Sampler binding count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi", s);
6422 D3D12_DESCRIPTOR_RANGE1 range = {};
6423 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
6424 range.NumDescriptors = UINT(count);
6425 range.BaseShaderRegister = baseShaderRegister;
6426 visitorData.samplerRanges[s][rangeStoreIdx] = range;
6427 D3D12_ROOT_PARAMETER1 param = {};
6428 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6429 param.ShaderVisibility = qd3d12_stageToVisibility(s);
6430 param.DescriptorTable.NumDescriptorRanges = 1;
6431 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[s][rangeStoreIdx];
6433 visitorData.samplerTables[s].append(param);
6436void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage s,
6437 const QRhiShaderResourceBinding::Data::StorageBufferData &,
6438 QD3D12ShaderResourceVisitor::StorageOp,
6441 D3D12_DESCRIPTOR_RANGE1 range = {};
6442 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
6443 range.NumDescriptors = 1;
6444 range.BaseShaderRegister = shaderRegister;
6445 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
6446 visitorData.currentUavRangeOffset[s] += 1;
6447 visitorData.uavRanges[s].append(range);
6448 if (visitorData.uavRanges[s].count() == 1) {
6449 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6450 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6454void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage s,
6455 const QRhiShaderResourceBinding::Data::StorageImageData &,
6456 QD3D12ShaderResourceVisitor::StorageOp,
6459 D3D12_DESCRIPTOR_RANGE1 range = {};
6460 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
6461 range.NumDescriptors = 1;
6462 range.BaseShaderRegister = shaderRegister;
6463 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
6464 visitorData.currentUavRangeOffset[s] += 1;
6465 visitorData.uavRanges[s].append(range);
6466 if (visitorData.uavRanges[s].count() == 1) {
6467 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6468 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6472QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
6475 QRHI_RES_RHI(QRhiD3D12);
6489 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
6493 using namespace std::placeholders;
6494 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
6495 visitor.textures = std::bind(&QD3D12ShaderResourceBindings::visitTextures,
this, _1, _2, _3, _4);
6496 visitor.samplers = std::bind(&QD3D12ShaderResourceBindings::visitSamplers,
this, _1, _2, _3, _4);
6497 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
6498 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
6522 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> rootParams;
6523 for (
int s = 0; s < 6; ++s) {
6524 if (!visitorData.cbParams[s].isEmpty())
6525 rootParams.append(visitorData.cbParams[s].constData(), visitorData.cbParams[s].count());
6527 for (
int s = 0; s < 6; ++s) {
6528 if (!visitorData.srvRanges[s].isEmpty()) {
6529 visitorData.srvTables[s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[s].count();
6530 visitorData.srvTables[s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[s].constData();
6531 rootParams.append(visitorData.srvTables[s]);
6534 for (
int s = 0; s < 6; ++s) {
6535 if (!visitorData.samplerTables[s].isEmpty())
6536 rootParams.append(visitorData.samplerTables[s].constData(), visitorData.samplerTables[s].count());
6538 for (
int s = 0; s < 6; ++s) {
6539 if (!visitorData.uavRanges[s].isEmpty()) {
6540 visitorData.uavTables[s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[s].count();
6541 visitorData.uavTables[s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[s].constData();
6542 rootParams.append(visitorData.uavTables[s]);
6546 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
6547 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
6548 if (!rootParams.isEmpty()) {
6549 rsDesc.Desc_1_1.NumParameters = rootParams.count();
6550 rsDesc.Desc_1_1.pParameters = rootParams.constData();
6554 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
6555 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
6556 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
6558 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
6560 ID3DBlob *signature =
nullptr;
6561 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
6563 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
6566 ID3D12RootSignature *rootSig =
nullptr;
6567 hr = rhiD->dev->CreateRootSignature(0,
6568 signature->GetBufferPointer(),
6569 signature->GetBufferSize(),
6570 __uuidof(ID3D12RootSignature),
6571 reinterpret_cast<
void **>(&rootSig));
6572 signature->Release();
6574 qWarning(
"Failed to create root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
6578 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
6590static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
6592 const int smMajor = version / 10;
6593 const int smMinor = version % 10;
6594 target[0] = stage[0];
6595 target[1] = stage[1];
6597 target[3] =
'0' + smMajor;
6599 target[5] =
'0' + smMinor;
6603enum class HlslCompileFlag
6605 WithDebugInfo = 0x01
6608static QByteArray legacyCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
6610 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
6612 qWarning(
"Unable to resolve function D3DCompile()");
6613 return QByteArray();
6616 ID3DBlob *bytecode =
nullptr;
6617 ID3DBlob *errors =
nullptr;
6618 UINT d3dCompileFlags = 0;
6619 if (flags &
int(HlslCompileFlag::WithDebugInfo))
6620 d3dCompileFlags |= D3DCOMPILE_DEBUG;
6622 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
6623 nullptr,
nullptr,
nullptr,
6624 hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
6625 if (FAILED(hr) || !bytecode) {
6626 qWarning(
"HLSL shader compilation failed: 0x%x", uint(hr));
6628 *error = QString::fromUtf8(
static_cast<
const char *>(errors->GetBufferPointer()),
6629 int(errors->GetBufferSize()));
6632 return QByteArray();
6636 result.resize(
int(bytecode->GetBufferSize()));
6637 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
6638 bytecode->Release();
6642#ifdef QRHI_D3D12_HAS_DXC
6645#define DXC_CP_UTF8 65001
6648#ifndef DXC_ARG_DEBUG
6649#define DXC_ARG_DEBUG L"-Zi"
6652static QByteArray dxcCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
6654 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
6655 IDxcCompiler *compiler = dxc.first;
6657 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
6658 "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
6659 return QByteArray();
6661 IDxcLibrary *library = dxc.second;
6663 return QByteArray();
6665 IDxcBlobEncoding *sourceBlob =
nullptr;
6666 HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
6667 UINT32(hlslSource.shader().size()),
6671 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
6673 qPrintable(QSystemError::windowsComString(hr)));
6674 return QByteArray();
6677 const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
6678 const QString targetStr = QString::fromLatin1(target);
6680 QVarLengthArray<LPCWSTR, 4> argPtrs;
6682 if (flags &
int(HlslCompileFlag::WithDebugInfo)) {
6683 debugArg = QString::fromUtf16(
reinterpret_cast<
const char16_t *>(DXC_ARG_DEBUG));
6684 argPtrs.append(
reinterpret_cast<LPCWSTR>(debugArg.utf16()));
6687 IDxcOperationResult *result =
nullptr;
6688 hr = compiler->Compile(sourceBlob,
6690 reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
6691 reinterpret_cast<LPCWSTR>(targetStr.utf16()),
6692 argPtrs.data(), argPtrs.count(),
6696 sourceBlob->Release();
6698 result->GetStatus(&hr);
6700 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
6702 qPrintable(QSystemError::windowsComString(hr)));
6704 IDxcBlobEncoding *errorsBlob =
nullptr;
6705 if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
6707 *error = QString::fromUtf8(
static_cast<
const char *>(errorsBlob->GetBufferPointer()),
6708 int(errorsBlob->GetBufferSize()));
6709 errorsBlob->Release();
6713 return QByteArray();
6716 IDxcBlob *bytecode =
nullptr;
6717 if FAILED(result->GetResult(&bytecode)) {
6718 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
6720 qPrintable(QSystemError::windowsComString(hr)));
6721 return QByteArray();
6725 ba.resize(
int(bytecode->GetBufferSize()));
6726 memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
6727 bytecode->Release();
6733static QByteArray compileHlslShaderSource(
const QShader &shader,
6734 QShader::Variant shaderVariant,
6737 QShaderKey *usedShaderKey)
6740 const int shaderModelMax = 67;
6741 for (
int sm = shaderModelMax; sm >= 50; --sm) {
6742 for (QShader::Source type : { QShader::DxilShader, QShader::DxbcShader }) {
6743 QShaderKey key = { type, sm, shaderVariant };
6744 QShaderCode intermediateBytecodeShader = shader.shader(key);
6745 if (!intermediateBytecodeShader.shader().isEmpty()) {
6747 *usedShaderKey = key;
6748 return intermediateBytecodeShader.shader();
6753 QShaderCode hlslSource;
6755 for (
int sm = shaderModelMax; sm >= 50; --sm) {
6756 key = { QShader::HlslShader, sm, shaderVariant };
6757 hlslSource = shader.shader(key);
6758 if (!hlslSource.shader().isEmpty())
6762 if (hlslSource.shader().isEmpty()) {
6763 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" << shader;
6764 return QByteArray();
6768 *usedShaderKey = key;
6771 switch (shader.stage()) {
6772 case QShader::VertexStage:
6773 makeHlslTargetString(target,
"vs", key.sourceVersion().version());
6775 case QShader::TessellationControlStage:
6776 makeHlslTargetString(target,
"hs", key.sourceVersion().version());
6778 case QShader::TessellationEvaluationStage:
6779 makeHlslTargetString(target,
"ds", key.sourceVersion().version());
6781 case QShader::GeometryStage:
6782 makeHlslTargetString(target,
"gs", key.sourceVersion().version());
6784 case QShader::FragmentStage:
6785 makeHlslTargetString(target,
"ps", key.sourceVersion().version());
6787 case QShader::ComputeStage:
6788 makeHlslTargetString(target,
"cs", key.sourceVersion().version());
6791 qWarning(
"compileHlslShaderSource: Unknown stage (%d)",
int(shader.stage()));
6792 return QByteArray();
6795 if (key.sourceVersion().version() >= 60) {
6796#ifdef QRHI_D3D12_HAS_DXC
6797 return dxcCompile(hlslSource, target, flags, error);
6799 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
6800 "but the Qt build has no support for DXC. "
6801 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
6805 return legacyCompile(hlslSource, target, flags, error);
6808static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
6811 if (c.testFlag(QRhiGraphicsPipeline::R))
6812 f |= D3D12_COLOR_WRITE_ENABLE_RED;
6813 if (c.testFlag(QRhiGraphicsPipeline::G))
6814 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
6815 if (c.testFlag(QRhiGraphicsPipeline::B))
6816 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
6817 if (c.testFlag(QRhiGraphicsPipeline::A))
6818 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
6822static inline D3D12_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f,
bool rgb)
6831 case QRhiGraphicsPipeline::Zero:
6832 return D3D12_BLEND_ZERO;
6833 case QRhiGraphicsPipeline::One:
6834 return D3D12_BLEND_ONE;
6835 case QRhiGraphicsPipeline::SrcColor:
6836 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
6837 case QRhiGraphicsPipeline::OneMinusSrcColor:
6838 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
6839 case QRhiGraphicsPipeline::DstColor:
6840 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
6841 case QRhiGraphicsPipeline::OneMinusDstColor:
6842 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
6843 case QRhiGraphicsPipeline::SrcAlpha:
6844 return D3D12_BLEND_SRC_ALPHA;
6845 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6846 return D3D12_BLEND_INV_SRC_ALPHA;
6847 case QRhiGraphicsPipeline::DstAlpha:
6848 return D3D12_BLEND_DEST_ALPHA;
6849 case QRhiGraphicsPipeline::OneMinusDstAlpha:
6850 return D3D12_BLEND_INV_DEST_ALPHA;
6851 case QRhiGraphicsPipeline::ConstantColor:
6852 case QRhiGraphicsPipeline::ConstantAlpha:
6853 return D3D12_BLEND_BLEND_FACTOR;
6854 case QRhiGraphicsPipeline::OneMinusConstantColor:
6855 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
6856 return D3D12_BLEND_INV_BLEND_FACTOR;
6857 case QRhiGraphicsPipeline::SrcAlphaSaturate:
6858 return D3D12_BLEND_SRC_ALPHA_SAT;
6859 case QRhiGraphicsPipeline::Src1Color:
6860 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
6861 case QRhiGraphicsPipeline::OneMinusSrc1Color:
6862 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
6863 case QRhiGraphicsPipeline::Src1Alpha:
6864 return D3D12_BLEND_SRC1_ALPHA;
6865 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
6866 return D3D12_BLEND_INV_SRC1_ALPHA;
6868 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
6871static inline D3D12_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
6874 case QRhiGraphicsPipeline::Add:
6875 return D3D12_BLEND_OP_ADD;
6876 case QRhiGraphicsPipeline::Subtract:
6877 return D3D12_BLEND_OP_SUBTRACT;
6878 case QRhiGraphicsPipeline::ReverseSubtract:
6879 return D3D12_BLEND_OP_REV_SUBTRACT;
6880 case QRhiGraphicsPipeline::Min:
6881 return D3D12_BLEND_OP_MIN;
6882 case QRhiGraphicsPipeline::Max:
6883 return D3D12_BLEND_OP_MAX;
6885 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
6888static inline D3D12_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
6891 case QRhiGraphicsPipeline::None:
6892 return D3D12_CULL_MODE_NONE;
6893 case QRhiGraphicsPipeline::Front:
6894 return D3D12_CULL_MODE_FRONT;
6895 case QRhiGraphicsPipeline::Back:
6896 return D3D12_CULL_MODE_BACK;
6898 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
6901static inline D3D12_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
6904 case QRhiGraphicsPipeline::Fill:
6905 return D3D12_FILL_MODE_SOLID;
6906 case QRhiGraphicsPipeline::Line:
6907 return D3D12_FILL_MODE_WIREFRAME;
6909 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
6912static inline D3D12_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
6915 case QRhiGraphicsPipeline::Never:
6916 return D3D12_COMPARISON_FUNC_NEVER;
6917 case QRhiGraphicsPipeline::Less:
6918 return D3D12_COMPARISON_FUNC_LESS;
6919 case QRhiGraphicsPipeline::Equal:
6920 return D3D12_COMPARISON_FUNC_EQUAL;
6921 case QRhiGraphicsPipeline::LessOrEqual:
6922 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
6923 case QRhiGraphicsPipeline::Greater:
6924 return D3D12_COMPARISON_FUNC_GREATER;
6925 case QRhiGraphicsPipeline::NotEqual:
6926 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
6927 case QRhiGraphicsPipeline::GreaterOrEqual:
6928 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
6929 case QRhiGraphicsPipeline::Always:
6930 return D3D12_COMPARISON_FUNC_ALWAYS;
6932 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
6935static inline D3D12_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
6938 case QRhiGraphicsPipeline::StencilZero:
6939 return D3D12_STENCIL_OP_ZERO;
6940 case QRhiGraphicsPipeline::Keep:
6941 return D3D12_STENCIL_OP_KEEP;
6942 case QRhiGraphicsPipeline::Replace:
6943 return D3D12_STENCIL_OP_REPLACE;
6944 case QRhiGraphicsPipeline::IncrementAndClamp:
6945 return D3D12_STENCIL_OP_INCR_SAT;
6946 case QRhiGraphicsPipeline::DecrementAndClamp:
6947 return D3D12_STENCIL_OP_DECR_SAT;
6948 case QRhiGraphicsPipeline::Invert:
6949 return D3D12_STENCIL_OP_INVERT;
6950 case QRhiGraphicsPipeline::IncrementAndWrap:
6951 return D3D12_STENCIL_OP_INCR;
6952 case QRhiGraphicsPipeline::DecrementAndWrap:
6953 return D3D12_STENCIL_OP_DECR;
6955 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
6958static inline D3D12_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t,
int patchControlPointCount)
6961 case QRhiGraphicsPipeline::Triangles:
6962 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
6963 case QRhiGraphicsPipeline::TriangleStrip:
6964 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
6965 case QRhiGraphicsPipeline::TriangleFan:
6966 qWarning(
"Triangle fans are not supported with D3D");
6967 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
6968 case QRhiGraphicsPipeline::Lines:
6969 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
6970 case QRhiGraphicsPipeline::LineStrip:
6971 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
6972 case QRhiGraphicsPipeline::Points:
6973 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
6974 case QRhiGraphicsPipeline::Patches:
6975 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
6976 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
6978 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
6981static inline D3D12_PRIMITIVE_TOPOLOGY_TYPE toD3DTopologyType(QRhiGraphicsPipeline::Topology t)
6984 case QRhiGraphicsPipeline::Triangles:
6985 case QRhiGraphicsPipeline::TriangleStrip:
6986 case QRhiGraphicsPipeline::TriangleFan:
6987 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
6988 case QRhiGraphicsPipeline::Lines:
6989 case QRhiGraphicsPipeline::LineStrip:
6990 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
6991 case QRhiGraphicsPipeline::Points:
6992 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
6993 case QRhiGraphicsPipeline::Patches:
6994 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
6996 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
6999static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
7002 case QRhiVertexInputAttribute::Float4:
7003 return DXGI_FORMAT_R32G32B32A32_FLOAT;
7004 case QRhiVertexInputAttribute::Float3:
7005 return DXGI_FORMAT_R32G32B32_FLOAT;
7006 case QRhiVertexInputAttribute::Float2:
7007 return DXGI_FORMAT_R32G32_FLOAT;
7008 case QRhiVertexInputAttribute::Float:
7009 return DXGI_FORMAT_R32_FLOAT;
7010 case QRhiVertexInputAttribute::UNormByte4:
7011 return DXGI_FORMAT_R8G8B8A8_UNORM;
7012 case QRhiVertexInputAttribute::UNormByte2:
7013 return DXGI_FORMAT_R8G8_UNORM;
7014 case QRhiVertexInputAttribute::UNormByte:
7015 return DXGI_FORMAT_R8_UNORM;
7016 case QRhiVertexInputAttribute::UInt4:
7017 return DXGI_FORMAT_R32G32B32A32_UINT;
7018 case QRhiVertexInputAttribute::UInt3:
7019 return DXGI_FORMAT_R32G32B32_UINT;
7020 case QRhiVertexInputAttribute::UInt2:
7021 return DXGI_FORMAT_R32G32_UINT;
7022 case QRhiVertexInputAttribute::UInt:
7023 return DXGI_FORMAT_R32_UINT;
7024 case QRhiVertexInputAttribute::SInt4:
7025 return DXGI_FORMAT_R32G32B32A32_SINT;
7026 case QRhiVertexInputAttribute::SInt3:
7027 return DXGI_FORMAT_R32G32B32_SINT;
7028 case QRhiVertexInputAttribute::SInt2:
7029 return DXGI_FORMAT_R32G32_SINT;
7030 case QRhiVertexInputAttribute::SInt:
7031 return DXGI_FORMAT_R32_SINT;
7032 case QRhiVertexInputAttribute::Half4:
7034 case QRhiVertexInputAttribute::Half3:
7035 return DXGI_FORMAT_R16G16B16A16_FLOAT;
7036 case QRhiVertexInputAttribute::Half2:
7037 return DXGI_FORMAT_R16G16_FLOAT;
7038 case QRhiVertexInputAttribute::Half:
7039 return DXGI_FORMAT_R16_FLOAT;
7040 case QRhiVertexInputAttribute::UShort4:
7042 case QRhiVertexInputAttribute::UShort3:
7043 return DXGI_FORMAT_R16G16B16A16_UINT;
7044 case QRhiVertexInputAttribute::UShort2:
7045 return DXGI_FORMAT_R16G16_UINT;
7046 case QRhiVertexInputAttribute::UShort:
7047 return DXGI_FORMAT_R16_UINT;
7048 case QRhiVertexInputAttribute::SShort4:
7050 case QRhiVertexInputAttribute::SShort3:
7051 return DXGI_FORMAT_R16G16B16A16_SINT;
7052 case QRhiVertexInputAttribute::SShort2:
7053 return DXGI_FORMAT_R16G16_SINT;
7054 case QRhiVertexInputAttribute::SShort:
7055 return DXGI_FORMAT_R16_SINT;
7057 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
7060QD3D12GraphicsPipeline::QD3D12GraphicsPipeline(QRhiImplementation *rhi)
7061 : QRhiGraphicsPipeline(rhi)
7065QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
7070void QD3D12GraphicsPipeline::destroy()
7072 if (handle.isNull())
7075 QRHI_RES_RHI(QRhiD3D12);
7077 rhiD->releaseQueue.deferredReleasePipeline(handle);
7078 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
7085 rhiD->unregisterResource(
this);
7088bool QD3D12GraphicsPipeline::create()
7090 if (!handle.isNull())
7093 QRHI_RES_RHI(QRhiD3D12);
7094 if (!rhiD->sanityCheckGraphicsPipeline(
this))
7097 rhiD->pipelineCreationStart();
7099 QByteArray shaderBytecode[5];
7100 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
7101 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
7102 stageData[d3dStage].valid =
true;
7103 stageData[d3dStage].stage = d3dStage;
7104 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
7105 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
7106 shaderBytecode[d3dStage] = cacheIt->bytecode;
7107 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
7110 QShaderKey shaderKey;
7111 int compileFlags = 0;
7112 if (m_flags.testFlag(CompileShadersWithDebugInfo))
7113 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
7114 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
7115 shaderStage.shaderVariant(),
7119 if (bytecode.isEmpty()) {
7120 qWarning(
"HLSL graphics shader compilation failed: %s", qPrintable(error));
7124 shaderBytecode[d3dStage] = bytecode;
7125 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
7126 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
7127 { bytecode, stageData[d3dStage].nativeResourceBindingMap });
7131 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
7133 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
7134 if (rootSigHandle.isNull()) {
7135 qWarning(
"Failed to create root signature");
7139 ID3D12RootSignature *rootSig =
nullptr;
7140 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
7141 rootSig = rs->rootSig;
7143 qWarning(
"Cannot create graphics pipeline state without root signature");
7147 QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7148 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
7149 if (rpD->colorAttachmentCount > 0) {
7150 format = DXGI_FORMAT(rpD->colorFormat[0]);
7151 }
else if (rpD->hasDepthStencil) {
7152 format = DXGI_FORMAT(rpD->dsFormat);
7154 qWarning(
"Cannot create graphics pipeline state without color or depthStencil format");
7157 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
7160 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
7161 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
7162 QD3D12PipelineStateSubObject<D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE> primitiveRestartValue;
7163 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
7164 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
7165 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
7166 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
7167 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
7168 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
7169 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
7170 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
7171 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
7172 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
7173 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
7174 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
7175 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
7176 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
7179 stream.rootSig.object = rootSig;
7181 QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
7182 QByteArrayList matrixSliceSemantics;
7183 if (!shaderBytecode[VS].isEmpty()) {
7184 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
7187 D3D12_INPUT_ELEMENT_DESC desc = {};
7192 const int matrixSlice = it->matrixSlice();
7193 if (matrixSlice < 0) {
7194 desc.SemanticName =
"TEXCOORD";
7195 desc.SemanticIndex = UINT(it->location());
7199 std::snprintf(sem.data(), sem.size(),
"TEXCOORD%d_", it->location() - matrixSlice);
7200 matrixSliceSemantics.append(sem);
7201 desc.SemanticName = matrixSliceSemantics.last().constData();
7202 desc.SemanticIndex = UINT(matrixSlice);
7204 desc.Format = toD3DAttributeFormat(it->format());
7205 desc.InputSlot = UINT(it->binding());
7206 desc.AlignedByteOffset = it->offset();
7207 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
7208 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
7209 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
7210 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
7212 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
7214 inputDescs.append(desc);
7218 stream.inputLayout.object.NumElements = inputDescs.count();
7219 stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ?
nullptr : inputDescs.constData();
7221 stream.primitiveRestartValue.object = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
7223 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
7224 topology = toD3DTopology(m_topology, m_patchControlPointCount);
7226 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
7227 const int d3dStage = qd3d12_stage(shaderStage.type());
7230 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7231 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7234 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7235 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7238 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7239 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7242 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7243 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7246 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7247 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7255 stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
7256 stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
7257 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
7258 stream.rasterizerState.object.DepthBias = m_depthBias;
7259 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
7260 stream.rasterizerState.object.DepthClipEnable = m_depthClamp ? FALSE : TRUE;
7261 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
7263 stream.depthStencilState.object.DepthEnable = m_depthTest;
7264 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
7265 stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
7266 stream.depthStencilState.object.StencilEnable = m_stencilTest;
7267 if (m_stencilTest) {
7268 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
7269 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
7270 stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
7271 stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
7272 stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
7273 stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
7274 stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
7275 stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
7276 stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
7277 stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
7280 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
7281 for (
int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
7282 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
7283 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
7284 blend.BlendEnable = b.enable;
7285 blend.SrcBlend = toD3DBlendFactor(b.srcColor,
true);
7286 blend.DestBlend = toD3DBlendFactor(b.dstColor,
true);
7287 blend.BlendOp = toD3DBlendOp(b.opColor);
7288 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha,
false);
7289 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha,
false);
7290 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
7291 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
7292 stream.blendState.object.RenderTarget[i] = blend;
7294 if (m_targetBlends.isEmpty()) {
7295 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
7296 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
7297 stream.blendState.object.RenderTarget[0] = blend;
7300 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
7301 for (
int i = 0; i < rpD->colorAttachmentCount; ++i)
7302 stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
7304 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
7306 stream.sampleDesc.object = sampleDesc;
7308 stream.sampleMask.object = 0xFFFFFFFF;
7310 viewInstanceMask = 0;
7311 const bool isMultiView = m_multiViewCount >= 2;
7312 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
7313 QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
7315 for (
int i = 0; i < m_multiViewCount; ++i) {
7316 viewInstanceMask |= (1 << i);
7317 viewInstanceLocations.append({ 0, UINT(i) });
7319 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
7322 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
7324 QCryptographicHash keyHash(QCryptographicHash::Sha1);
7325 for (
const QByteArray &bytecode : shaderBytecode)
7326 addToKey(&keyHash, bytecode);
7327 for (
const D3D12_INPUT_ELEMENT_DESC &desc : inputDescs) {
7328 keyHash.addData(QByteArrayView(desc.SemanticName));
7329 addToKey(&keyHash, desc.SemanticIndex);
7330 addToKey(&keyHash, desc.Format);
7331 addToKey(&keyHash, desc.InputSlot);
7332 addToKey(&keyHash, desc.AlignedByteOffset);
7333 addToKey(&keyHash, desc.InputSlotClass);
7334 addToKey(&keyHash, desc.InstanceDataStepRate);
7336 addToKey(&keyHash, stream.primitiveRestartValue.object);
7337 addToKey(&keyHash, stream.primitiveTopology.object);
7338 addToKey(&keyHash, stream.rasterizerState.object);
7339 addToKey(&keyHash, stream.depthStencilState.object);
7340 addToKey(&keyHash, stream.blendState.object);
7341 addToKey(&keyHash, stream.rtFormats.object);
7342 addToKey(&keyHash, stream.dsFormat.object);
7343 addToKey(&keyHash, stream.sampleDesc.object);
7344 addToKey(&keyHash, stream.sampleMask.object);
7345 addToKey(&keyHash, stream.viewInstancingDesc.object.ViewInstanceCount);
7346 addToKey(&keyHash, stream.viewInstancingDesc.object.Flags);
7347 addToKey(&keyHash, viewInstanceLocations.constData(),
7348 viewInstanceLocations.count() *
sizeof(D3D12_VIEW_INSTANCE_LOCATION));
7351 addToKey(&keyHash, srbD->serializedLayoutDescription());
7353 ID3D12PipelineState *pso = rhiD->loadOrCreatePipelineState(&streamDesc, keyHash.result().toHex(),
"graphics");
7355 rhiD->rootSignaturePool.remove(rootSigHandle);
7360 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
7362 rhiD->pipelineCreationEnd();
7364 rhiD->registerResource(
this);
7368QD3D12ComputePipeline::QD3D12ComputePipeline(QRhiImplementation *rhi)
7369 : QRhiComputePipeline(rhi)
7373QD3D12ComputePipeline::~QD3D12ComputePipeline()
7378void QD3D12ComputePipeline::destroy()
7380 if (handle.isNull())
7383 QRHI_RES_RHI(QRhiD3D12);
7385 rhiD->releaseQueue.deferredReleasePipeline(handle);
7386 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
7393 rhiD->unregisterResource(
this);
7396bool QD3D12ComputePipeline::create()
7398 if (!handle.isNull())
7401 QRHI_RES_RHI(QRhiD3D12);
7402 rhiD->pipelineCreationStart();
7404 stageData.valid =
true;
7405 stageData.stage = CS;
7407 QByteArray shaderBytecode;
7408 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(m_shaderStage);
7409 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
7410 shaderBytecode = cacheIt->bytecode;
7411 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
7414 QShaderKey shaderKey;
7415 int compileFlags = 0;
7416 if (m_flags.testFlag(CompileShadersWithDebugInfo))
7417 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
7418 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
7419 m_shaderStage.shaderVariant(),
7423 if (bytecode.isEmpty()) {
7424 qWarning(
"HLSL compute shader compilation failed: %s", qPrintable(error));
7428 shaderBytecode = bytecode;
7429 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
7430 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
7431 stageData.nativeResourceBindingMap });
7434 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
7436 rootSigHandle = srbD->createRootSignature(&stageData, 1);
7437 if (rootSigHandle.isNull()) {
7438 qWarning(
"Failed to create root signature");
7442 ID3D12RootSignature *rootSig =
nullptr;
7443 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
7444 rootSig = rs->rootSig;
7446 qWarning(
"Cannot create compute pipeline state without root signature");
7451 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
7452 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
7454 stream.rootSig.object = rootSig;
7455 stream.CS.object.pShaderBytecode = shaderBytecode.constData();
7456 stream.CS.object.BytecodeLength = shaderBytecode.size();
7457 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
7459 QCryptographicHash keyHash(QCryptographicHash::Sha1);
7460 addToKey(&keyHash, shaderBytecode);
7461 addToKey(&keyHash, srbD->serializedLayoutDescription());
7463 ID3D12PipelineState *pso = rhiD->loadOrCreatePipelineState(&streamDesc, keyHash.result().toHex(),
"compute");
7465 rhiD->rootSignaturePool.remove(rootSigHandle);
7470 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
7472 rhiD->pipelineCreationEnd();
7474 rhiD->registerResource(
this);
7481QD3D12RenderPassDescriptor::QD3D12RenderPassDescriptor(QRhiImplementation *rhi)
7482 : QRhiRenderPassDescriptor(rhi)
7484 serializedFormatData.reserve(16);
7487QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
7492void QD3D12RenderPassDescriptor::destroy()
7494 QRHI_RES_RHI(QRhiD3D12);
7496 rhiD->unregisterResource(
this);
7499bool QD3D12RenderPassDescriptor::isCompatible(
const QRhiRenderPassDescriptor *other)
const
7504 const QD3D12RenderPassDescriptor *o = QRHI_RES(
const QD3D12RenderPassDescriptor, other);
7506 if (colorAttachmentCount != o->colorAttachmentCount)
7509 if (hasDepthStencil != o->hasDepthStencil)
7512 for (
int i = 0; i < colorAttachmentCount; ++i) {
7513 if (colorFormat[i] != o->colorFormat[i])
7517 if (hasDepthStencil) {
7518 if (dsFormat != o->dsFormat)
7522 if (hasShadingRateMap != o->hasShadingRateMap)
7528void QD3D12RenderPassDescriptor::updateSerializedFormat()
7530 serializedFormatData.clear();
7531 auto p = std::back_inserter(serializedFormatData);
7533 *p++ = colorAttachmentCount;
7534 *p++ = hasDepthStencil;
7535 for (
int i = 0; i < colorAttachmentCount; ++i)
7536 *p++ = colorFormat[i];
7537 *p++ = hasDepthStencil ? dsFormat : 0;
7540QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor()
const
7542 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
7543 rpD->colorAttachmentCount = colorAttachmentCount;
7544 rpD->hasDepthStencil = hasDepthStencil;
7545 memcpy(rpD->colorFormat, colorFormat,
sizeof(colorFormat));
7546 rpD->dsFormat = dsFormat;
7547 rpD->hasShadingRateMap = hasShadingRateMap;
7549 rpD->updateSerializedFormat();
7551 QRHI_RES_RHI(QRhiD3D12);
7552 rhiD->registerResource(rpD);
7556QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat()
const
7558 return serializedFormatData;
7561QD3D12CommandBuffer::QD3D12CommandBuffer(QRhiImplementation *rhi)
7562 : QRhiCommandBuffer(rhi)
7567QD3D12CommandBuffer::~QD3D12CommandBuffer()
7572void QD3D12CommandBuffer::destroy()
7577const QRhiNativeHandles *QD3D12CommandBuffer::nativeHandles()
7579 nativeHandlesStruct.commandList = cmdList;
7580 return &nativeHandlesStruct;
7583QD3D12SwapChainRenderTarget::QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
7584 : QRhiSwapChainRenderTarget(rhi, swapchain),
7589QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
7594void QD3D12SwapChainRenderTarget::destroy()
7599QSize QD3D12SwapChainRenderTarget::pixelSize()
const
7604float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
7609int QD3D12SwapChainRenderTarget::sampleCount()
const
7611 return d.sampleCount;
7614QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
7615 : QRhiSwapChain(rhi),
7616 rtWrapper(rhi,
this),
7617 rtWrapperRight(rhi,
this),
7622QD3D12SwapChain::~QD3D12SwapChain()
7627void QD3D12SwapChain::destroy()
7634 swapChain->Release();
7635 swapChain =
nullptr;
7636 sourceSwapChain1->Release();
7637 sourceSwapChain1 =
nullptr;
7639 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7640 FrameResources &fr(frameRes[i]);
7642 fr.fence->Release();
7644 CloseHandle(fr.fenceEvent);
7646 fr.cmdList->Release();
7651 dcompVisual->Release();
7652 dcompVisual =
nullptr;
7656 dcompTarget->Release();
7657 dcompTarget =
nullptr;
7660 if (frameLatencyWaitableObject) {
7661 CloseHandle(frameLatencyWaitableObject);
7662 frameLatencyWaitableObject =
nullptr;
7665 QDxgiVSyncService::instance()->unregisterWindow(window);
7667 QRHI_RES_RHI(QRhiD3D12);
7669 rhiD->swapchains.remove(
this);
7670 rhiD->unregisterResource(
this);
7674void QD3D12SwapChain::releaseBuffers()
7676 QRHI_RES_RHI(QRhiD3D12);
7678 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7679 rhiD->resourcePool.remove(colorBuffers[i]);
7680 rhiD->rtvPool.release(rtvs[i], 1);
7682 rhiD->rtvPool.release(rtvsRight[i], 1);
7684 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7685 if (!msaaBuffers[i].isNull())
7686 rhiD->resourcePool.remove(msaaBuffers[i]);
7687 if (msaaRtvs[i].isValid())
7688 rhiD->rtvPool.release(msaaRtvs[i], 1);
7692void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
7694 FrameResources &fr(frameRes[frameSlot]);
7695 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
7696 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
7697 WaitForSingleObject(fr.fenceEvent, INFINITE);
7701void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
7703 QRHI_RES_RHI(QRhiD3D12);
7704 FrameResources &fr(frameRes[currentFrameSlot]);
7705 fr.fenceCounter += 1u;
7706 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
7709QRhiCommandBuffer *QD3D12SwapChain::currentFrameCommandBuffer()
7714QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
7719QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
7721 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
7724QSize QD3D12SwapChain::surfacePixelSize()
7727 return m_window->size() * m_window->devicePixelRatio();
7730bool QD3D12SwapChain::isFormatSupported(Format f)
7736 qWarning(
"Attempted to call isFormatSupported() without a window set");
7740 QRHI_RES_RHI(QRhiD3D12);
7741 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window))
7742 return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
7747QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
7749 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
7752 QRHI_RES_RHI(QRhiD3D12);
7753 info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window);
7758QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
7763 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
7764 rpD->colorAttachmentCount = 1;
7765 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
7766 rpD->colorFormat[0] =
int(srgbAdjustedColorFormat);
7767 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
7769 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
7771 rpD->updateSerializedFormat();
7773 QRHI_RES_RHI(QRhiD3D12);
7774 rhiD->registerResource(rpD);
7778bool QRhiD3D12::ensureDirectCompositionDevice()
7783 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
7784 dcompDevice = QRhiD3D::createDirectCompositionDevice();
7785 return dcompDevice ?
true :
false;
7788static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
7789static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
7791void QD3D12SwapChain::chooseFormats()
7793 colorFormat = DEFAULT_FORMAT;
7794 srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
7795 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
7796 QRHI_RES_RHI(QRhiD3D12);
7797 if (m_format != SDR) {
7798 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) {
7801 case HDRExtendedSrgbLinear:
7802 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
7803 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
7804 srgbAdjustedColorFormat = colorFormat;
7807 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
7808 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
7809 srgbAdjustedColorFormat = colorFormat;
7818 qWarning(
"The output associated with the window is not HDR capable "
7819 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
7822 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
7825bool QD3D12SwapChain::createOrResize()
7831 const bool needsRegistration = !window || window != m_window;
7834 if (window && window != m_window)
7838 m_currentPixelSize = surfacePixelSize();
7839 pixelSize = m_currentPixelSize;
7841 if (pixelSize.isEmpty())
7844 HWND hwnd =
reinterpret_cast<HWND>(window->winId());
7846 QRHI_RES_RHI(QRhiD3D12);
7847 stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
7849 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
7850 if (rhiD->ensureDirectCompositionDevice()) {
7852 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
false, &dcompTarget);
7854 qWarning(
"Failed to create Direct Composition target for the window: %s",
7855 qPrintable(QSystemError::windowsComString(hr)));
7858 if (dcompTarget && !dcompVisual) {
7859 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
7861 qWarning(
"Failed to create DirectComposition visual: %s",
7862 qPrintable(QSystemError::windowsComString(hr)));
7867 if (window->requestedFormat().alphaBufferSize() <= 0)
7868 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
7869 "This may lead to problems.");
7872 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
7874 if (swapInterval == 0 && rhiD->supportsAllowTearing)
7875 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
7879 const bool useFrameLatencyWaitableObject = rhiD->maxFrameLatency != 0
7880 && swapInterval != 0
7881 && rhiD->driverInfoStruct.deviceType != QRhiDriverInfo::CpuDevice;
7882 if (useFrameLatencyWaitableObject)
7883 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
7888 DXGI_SWAP_CHAIN_DESC1 desc = {};
7889 desc.Width = UINT(pixelSize.width());
7890 desc.Height = UINT(pixelSize.height());
7891 desc.Format = colorFormat;
7892 desc.SampleDesc.Count = 1;
7893 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
7894 desc.BufferCount = BUFFER_COUNT;
7895 desc.Flags = swapChainFlags;
7896 desc.Scaling = DXGI_SCALING_NONE;
7897 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
7898 desc.Stereo = stereo;
7904 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
7909 desc.Scaling = DXGI_SCALING_STRETCH;
7913 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
7915 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
7920 if (FAILED(hr) && m_format != SDR) {
7921 colorFormat = DEFAULT_FORMAT;
7922 desc.Format = DEFAULT_FORMAT;
7924 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
7926 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
7929 if (SUCCEEDED(hr)) {
7930 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<
void **>(&swapChain)))) {
7931 qWarning(
"IDXGISwapChain3 not available");
7934 if (m_format != SDR) {
7935 hr = swapChain->SetColorSpace1(hdrColorSpace);
7937 qWarning(
"Failed to set color space on swapchain: %s",
7938 qPrintable(QSystemError::windowsComString(hr)));
7941 if (useFrameLatencyWaitableObject) {
7942 swapChain->SetMaximumFrameLatency(rhiD->maxFrameLatency);
7943 frameLatencyWaitableObject = swapChain->GetFrameLatencyWaitableObject();
7946 hr = dcompVisual->SetContent(swapChain);
7947 if (SUCCEEDED(hr)) {
7948 hr = dcompTarget->SetRoot(dcompVisual);
7950 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
7951 qPrintable(QSystemError::windowsComString(hr)));
7954 qWarning(
"Failed to set content for Direct Composition visual: %s",
7955 qPrintable(QSystemError::windowsComString(hr)));
7959 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
7962 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
7963 qWarning(
"Device loss detected during swapchain creation");
7964 rhiD->deviceLost =
true;
7966 }
else if (FAILED(hr)) {
7967 qWarning(
"Failed to create D3D12 swapchain: %s"
7968 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
7969 qPrintable(QSystemError::windowsComString(hr)),
7970 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
7971 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
7975 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7976 hr = rhiD->dev->CreateFence(0,
7977 D3D12_FENCE_FLAG_NONE,
7978 __uuidof(ID3D12Fence),
7979 reinterpret_cast<
void **>(&frameRes[i].fence));
7981 qWarning(
"Failed to create fence for swapchain: %s",
7982 qPrintable(QSystemError::windowsComString(hr)));
7985 frameRes[i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
7987 frameRes[i].fenceCounter = 0;
7991 hr = swapChain->ResizeBuffers(BUFFER_COUNT,
7992 UINT(pixelSize.width()),
7993 UINT(pixelSize.height()),
7996 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
7997 qWarning(
"Device loss detected in ResizeBuffers()");
7998 rhiD->deviceLost =
true;
8000 }
else if (FAILED(hr)) {
8001 qWarning(
"Failed to resize D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
8006 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
8007 ID3D12Resource *colorBuffer;
8008 hr = swapChain->GetBuffer(i, __uuidof(ID3D12Resource),
reinterpret_cast<
void **>(&colorBuffer));
8010 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
8011 i, qPrintable(QSystemError::windowsComString(hr)));
8014 colorBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
8015 rtvs[i] = rhiD->rtvPool.allocate(1);
8016 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
8017 rtvDesc.Format = srgbAdjustedColorFormat;
8018 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
8019 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
8022 rtvsRight[i] = rhiD->rtvPool.allocate(1);
8023 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
8024 rtvDesc.Format = srgbAdjustedColorFormat;
8025 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
8026 rtvDesc.Texture2DArray.ArraySize = 1;
8027 rtvDesc.Texture2DArray.FirstArraySlice = 1;
8028 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
8032 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
8033 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
8034 m_depthStencil->sampleCount(), m_sampleCount);
8036 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
8037 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
8038 m_depthStencil->setPixelSize(pixelSize);
8039 if (!m_depthStencil->create())
8040 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
8041 pixelSize.width(), pixelSize.height());
8043 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
8044 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
8045 pixelSize.width(), pixelSize.height());
8049 ds = m_depthStencil ? QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
8051 if (sampleDesc.Count > 1) {
8052 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
8053 D3D12_RESOURCE_DESC resourceDesc = {};
8054 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
8055 resourceDesc.Width = UINT64(pixelSize.width());
8056 resourceDesc.Height = UINT(pixelSize.height());
8057 resourceDesc.DepthOrArraySize = 1;
8058 resourceDesc.MipLevels = 1;
8059 resourceDesc.Format = srgbAdjustedColorFormat;
8060 resourceDesc.SampleDesc = sampleDesc;
8061 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
8062 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
8063 D3D12_CLEAR_VALUE clearValue = {};
8064 clearValue.Format = colorFormat;
8065 ID3D12Resource *resource =
nullptr;
8066 D3D12MA::Allocation *allocation =
nullptr;
8067 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
8069 D3D12_RESOURCE_STATE_RENDER_TARGET,
8072 __uuidof(ID3D12Resource),
8073 reinterpret_cast<
void **>(&resource));
8075 qWarning(
"Failed to create MSAA color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
8078 msaaBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
8079 msaaRtvs[i] = rhiD->rtvPool.allocate(1);
8080 if (!msaaRtvs[i].isValid())
8082 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
8083 rtvDesc.Format = srgbAdjustedColorFormat;
8084 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
8085 : D3D12_RTV_DIMENSION_TEXTURE2D;
8086 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[i].cpuHandle);
8090 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
8091 currentFrameSlot = 0;
8092 lastFrameLatencyWaitSlot = -1;
8094 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
8095 QD3D12SwapChainRenderTarget *rtD = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
8096 rtD->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
8097 rtD->d.pixelSize = pixelSize;
8098 rtD->d.dpr =
float(window->devicePixelRatio());
8099 rtD->d.sampleCount =
int(sampleDesc.Count);
8100 rtD->d.colorAttCount = 1;
8101 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
8103 rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
8104 QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
8105 rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
8106 rtDr->d.pixelSize = pixelSize;
8107 rtDr->d.dpr =
float(window->devicePixelRatio());
8108 rtDr->d.sampleCount =
int(sampleDesc.Count);
8109 rtDr->d.colorAttCount = 1;
8110 rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
8112 QDxgiVSyncService::instance()->registerWindow(window);
8114 if (needsRegistration || !rhiD->swapchains.contains(
this))
8115 rhiD->swapchains.insert(
this);
8117 rhiD->registerResource(
this);