6#include <QtCore/private/qsystemerror_p.h>
13#define QRHI_D3D12_HAS_OLD_PIX
16#ifdef __ID3D12Device2_INTERFACE_DEFINED__
21
22
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
66
67
68
69
70
73
74
75
76
77
78
79
80
81
82
83
84
87
88
89
90
91
92
95
96
97
98
99
100
101
102
103
104
105
108
109
110
111
112
113
116
117
118
119
120
121
124
125
126
127
128
129
130
133
134
135
136
137
138
139
140
141
142
143
144
145
146
149
150
153static const D3D_FEATURE_LEVEL MIN_FEATURE_LEVEL = D3D_FEATURE_LEVEL_11_0;
155QRhiD3D12::QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importParams)
157 debugLayer = params->enableDebugLayer;
159 if (importParams->dev) {
160 ID3D12Device *d3d12Device =
reinterpret_cast<ID3D12Device *>(importParams->dev);
161 if (SUCCEEDED(d3d12Device->QueryInterface(__uuidof(ID3D12Device2),
reinterpret_cast<
void **>(&dev)))) {
163 d3d12Device->Release();
164 importedDevice =
true;
166 qWarning(
"ID3D12Device2 not supported, cannot import device");
169 if (importParams->commandQueue) {
170 cmdQueue =
reinterpret_cast<ID3D12CommandQueue *>(importParams->commandQueue);
171 importedCommandQueue =
true;
173 minimumFeatureLevel = D3D_FEATURE_LEVEL(importParams->minimumFeatureLevel);
174 adapterLuid.LowPart = importParams->adapterLuidLow;
175 adapterLuid.HighPart = importParams->adapterLuidHigh;
180inline Int aligned(Int v, Int byteAlign)
182 return (v + byteAlign - 1) & ~(byteAlign - 1);
185static inline UINT calcSubresource(UINT mipSlice, UINT arraySlice, UINT mipLevels)
187 return mipSlice + arraySlice * mipLevels;
190static inline QD3D12RenderTargetData *rtData(QRhiRenderTarget *rt)
192 switch (rt->resourceType()) {
193 case QRhiResource::SwapChainRenderTarget:
194 return &QRHI_RES(QD3D12SwapChainRenderTarget, rt)->d;
195 case QRhiResource::TextureRenderTarget:
196 return &QRHI_RES(QD3D12TextureRenderTarget, rt)->d;
201 Q_UNREACHABLE_RETURN(
nullptr);
204bool QRhiD3D12::create(QRhi::Flags flags)
208 UINT factoryFlags = 0;
210 factoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
211 HRESULT hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
215 qCDebug(QRHI_LOG_INFO,
"Debug layer was requested but is not available. "
216 "Attempting to create DXGIFactory2 without it.");
217 factoryFlags &= ~DXGI_CREATE_FACTORY_DEBUG;
218 hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
223 qWarning(
"CreateDXGIFactory2() failed to create DXGI factory: %s",
224 qPrintable(QSystemError::windowsComString(hr)));
229 if (qEnvironmentVariableIsSet(
"QT_D3D_MAX_FRAME_LATENCY"))
230 maxFrameLatency = UINT(qMax(0, qEnvironmentVariableIntValue(
"QT_D3D_MAX_FRAME_LATENCY")));
231 if (maxFrameLatency != 0)
232 qCDebug(QRHI_LOG_INFO,
"Using frame latency waitable object with max frame latency %u", maxFrameLatency);
234 supportsAllowTearing =
false;
235 IDXGIFactory5 *factory5 =
nullptr;
236 if (SUCCEEDED(dxgiFactory->QueryInterface(__uuidof(IDXGIFactory5),
reinterpret_cast<
void **>(&factory5)))) {
237 BOOL allowTearing =
false;
238 if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing,
sizeof(allowTearing))))
239 supportsAllowTearing = allowTearing;
244 ID3D12Debug1 *debug =
nullptr;
245 if (SUCCEEDED(D3D12GetDebugInterface(__uuidof(ID3D12Debug1),
reinterpret_cast<
void **>(&debug)))) {
246 qCDebug(QRHI_LOG_INFO,
"Enabling D3D12 debug layer");
247 debug->EnableDebugLayer();
252 if (!importedDevice) {
253 IDXGIAdapter1 *adapter;
254 int requestedAdapterIndex = -1;
255 if (qEnvironmentVariableIsSet(
"QT_D3D_ADAPTER_INDEX"))
256 requestedAdapterIndex = qEnvironmentVariableIntValue(
"QT_D3D_ADAPTER_INDEX");
258 if (requestedRhiAdapter)
259 adapterLuid =
static_cast<QD3D12Adapter *>(requestedRhiAdapter)->luid;
262 if (requestedAdapterIndex < 0 && (adapterLuid.LowPart || adapterLuid.HighPart)) {
263 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
264 DXGI_ADAPTER_DESC1 desc;
265 adapter->GetDesc1(&desc);
267 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
268 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
270 requestedAdapterIndex = adapterIndex;
276 if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
277 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
278 DXGI_ADAPTER_DESC1 desc;
279 adapter->GetDesc1(&desc);
281 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
282 requestedAdapterIndex = adapterIndex;
288 activeAdapter =
nullptr;
289 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
290 DXGI_ADAPTER_DESC1 desc;
291 adapter->GetDesc1(&desc);
292 const QString name = QString::fromUtf16(
reinterpret_cast<
char16_t *>(desc.Description));
293 qCDebug(QRHI_LOG_INFO,
"Adapter %d: '%s' (vendor 0x%X device 0x%X flags 0x%X)",
299 if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
300 activeAdapter = adapter;
301 adapterLuid = desc.AdapterLuid;
302 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
303 qCDebug(QRHI_LOG_INFO,
" using this adapter");
308 if (!activeAdapter) {
309 qWarning(
"No adapter");
313 if (minimumFeatureLevel == 0)
314 minimumFeatureLevel = MIN_FEATURE_LEVEL;
316 hr = D3D12CreateDevice(activeAdapter,
318 __uuidof(ID3D12Device2),
319 reinterpret_cast<
void **>(&dev));
321 qWarning(
"Failed to create D3D12 device: %s", qPrintable(QSystemError::windowsComString(hr)));
327 adapterLuid = dev->GetAdapterLuid();
328 IDXGIAdapter1 *adapter;
329 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
330 DXGI_ADAPTER_DESC1 desc;
331 adapter->GetDesc1(&desc);
332 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
333 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
335 activeAdapter = adapter;
336 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
342 if (!activeAdapter) {
343 qWarning(
"No adapter");
346 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
349 QDxgiVSyncService::instance()->refAdapter(adapterLuid);
352 ID3D12InfoQueue *infoQueue;
353 if (SUCCEEDED(dev->QueryInterface(__uuidof(ID3D12InfoQueue),
reinterpret_cast<
void **>(&infoQueue)))) {
354 if (qEnvironmentVariableIntValue(
"QT_D3D_DEBUG_BREAK")) {
355 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION,
true);
356 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR,
true);
357 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING,
true);
359 D3D12_INFO_QUEUE_FILTER filter = {};
360 D3D12_MESSAGE_ID suppressedMessages[2] = {
362 D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
364 D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE
366 filter.DenyList.NumIDs = 2;
367 filter.DenyList.pIDList = suppressedMessages;
370 D3D12_MESSAGE_SEVERITY infoSev = D3D12_MESSAGE_SEVERITY_INFO;
371 filter.DenyList.NumSeverities = 1;
372 filter.DenyList.pSeverityList = &infoSev;
373 infoQueue->PushStorageFilter(&filter);
374 infoQueue->Release();
378 if (!importedCommandQueue) {
379 D3D12_COMMAND_QUEUE_DESC queueDesc = {};
380 queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
381 queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
382 hr = dev->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue),
reinterpret_cast<
void **>(&cmdQueue));
384 qWarning(
"Failed to create command queue: %s", qPrintable(QSystemError::windowsComString(hr)));
389 hr = dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence),
reinterpret_cast<
void **>(&fullFence));
391 qWarning(
"Failed to create fence: %s", qPrintable(QSystemError::windowsComString(hr)));
394 fullFenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
395 fullFenceCounter = 0;
397 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
398 hr = dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
399 __uuidof(ID3D12CommandAllocator),
400 reinterpret_cast<
void **>(&cmdAllocators[i]));
402 qWarning(
"Failed to create command allocator: %s", qPrintable(QSystemError::windowsComString(hr)));
407 if (!vma.create(dev, activeAdapter)) {
408 qWarning(
"Failed to initialize graphics memory suballocator");
412 if (!rtvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
"main RTV pool")) {
413 qWarning(
"Could not create RTV pool");
417 if (!dsvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
"main DSV pool")) {
418 qWarning(
"Could not create DSV pool");
422 if (!cbvSrvUavPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
"main CBV-SRV-UAV pool")) {
423 qWarning(
"Could not create CBV-SRV-UAV pool");
427 resourcePool.create(
"main resource pool");
428 pipelinePool.create(
"main pipeline pool");
429 rootSignaturePool.create(
"main root signature pool");
430 releaseQueue.create(&resourcePool, &pipelinePool, &rootSignaturePool);
431 barrierGen.create(&resourcePool);
433 if (!samplerMgr.create(dev)) {
434 qWarning(
"Could not create sampler pool and shader-visible sampler heap");
438 if (!mipmapGen.create(
this)) {
439 qWarning(
"Could not initialize mipmap generator");
443 const qint32 smallStagingSize = aligned(SMALL_STAGING_AREA_BYTES_PER_FRAME, QD3D12StagingArea::ALIGNMENT);
444 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
445 if (!smallStagingAreas[i].create(
this, smallStagingSize, D3D12_HEAP_TYPE_UPLOAD)) {
446 qWarning(
"Could not create host-visible staging area");
449 QString decoratedName = QLatin1String(
"Small staging area buffer/");
450 decoratedName += QString::number(i);
451 smallStagingAreas[i].mem.buffer->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
454 if (!shaderVisibleCbvSrvUavHeap.create(dev,
455 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
456 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE))
458 qWarning(
"Could not create first shader-visible CBV/SRV/UAV heap");
462 if (flags.testFlag(QRhi::EnableTimestamps)) {
463 static bool wantsStablePowerState = qEnvironmentVariableIntValue(
"QT_D3D_STABLE_POWER_STATE");
479 if (wantsStablePowerState)
480 dev->SetStablePowerState(TRUE);
482 hr = cmdQueue->GetTimestampFrequency(×tampTicksPerSecond);
484 qWarning(
"Failed to query timestamp frequency: %s",
485 qPrintable(QSystemError::windowsComString(hr)));
488 if (!timestampQueryHeap.create(dev, QD3D12_FRAMES_IN_FLIGHT * 2, D3D12_QUERY_HEAP_TYPE_TIMESTAMP)) {
489 qWarning(
"Failed to create timestamp query pool");
492 const quint32 readbackBufSize = QD3D12_FRAMES_IN_FLIGHT * 2 *
sizeof(quint64);
493 if (!timestampReadbackArea.create(
this, readbackBufSize, D3D12_HEAP_TYPE_READBACK)) {
494 qWarning(
"Failed to create timestamp readback buffer");
497 timestampReadbackArea.mem.buffer->SetName(L"Timestamp readback buffer");
498 memset(timestampReadbackArea.mem.p, 0, readbackBufSize);
502 D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
503 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3,
sizeof(options3)))) {
504 caps.multiView = options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
506 caps.textureViewFormat = options3.CastingFullyTypedFormatSupported;
509#ifdef QRHI_D3D12_CL5_AVAILABLE
510 D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {};
511 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6,
sizeof(options6)))) {
512 caps.vrs = options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED;
513 caps.vrsMap = options6.VariableShadingRateTier == D3D12_VARIABLE_SHADING_RATE_TIER_2;
514 caps.vrsAdditionalRates = options6.AdditionalShadingRatesSupported;
515 shadingRateImageTileSize = options6.ShadingRateImageTileSize;
520 caps.vrsAdditionalRates =
false;
524 offscreenActive =
false;
526 nativeHandlesStruct.dev = dev;
527 nativeHandlesStruct.minimumFeatureLevel = minimumFeatureLevel;
528 nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
529 nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
530 nativeHandlesStruct.commandQueue = cmdQueue;
535void QRhiD3D12::destroy()
537 if (!deviceLost && fullFence && fullFenceEvent)
540 releaseQueue.releaseAll();
542 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
543 if (offscreenCb[i]) {
544 if (offscreenCb[i]->cmdList)
545 offscreenCb[i]->cmdList->Release();
546 delete offscreenCb[i];
547 offscreenCb[i] =
nullptr;
551 timestampQueryHeap.destroy();
552 timestampReadbackArea.destroy();
554 shaderVisibleCbvSrvUavHeap.destroy();
556 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i)
557 smallStagingAreas[i].destroy();
560 samplerMgr.destroy();
561 resourcePool.destroy();
562 pipelinePool.destroy();
563 rootSignaturePool.destroy();
566 cbvSrvUavPool.destroy();
568 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
569 if (cmdAllocators[i]) {
570 cmdAllocators[i]->Release();
571 cmdAllocators[i] =
nullptr;
575 if (fullFenceEvent) {
576 CloseHandle(fullFenceEvent);
577 fullFenceEvent =
nullptr;
581 fullFence->Release();
585 if (!importedCommandQueue) {
594 if (!importedDevice) {
602 dcompDevice->Release();
603 dcompDevice =
nullptr;
607 activeAdapter->Release();
608 activeAdapter =
nullptr;
612 dxgiFactory->Release();
613 dxgiFactory =
nullptr;
617 importedDevice =
false;
618 importedCommandQueue =
false;
620 QDxgiVSyncService::instance()->derefAdapter(adapterLuid);
623QRhi::AdapterList QRhiD3D12::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
625 LUID requestedLuid = {};
627 QRhiD3D12NativeHandles *h =
static_cast<QRhiD3D12NativeHandles *>(nativeHandles);
628 const LUID adapterLuid = { h->adapterLuidLow, h->adapterLuidHigh };
629 if (adapterLuid.LowPart || adapterLuid.HighPart)
630 requestedLuid = adapterLuid;
633 IDXGIFactory2 *dxgi =
nullptr;
634 if (FAILED(CreateDXGIFactory2(0, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgi))))
637 QRhi::AdapterList list;
638 IDXGIAdapter1 *adapter;
639 for (
int adapterIndex = 0; dxgi->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
640 DXGI_ADAPTER_DESC1 desc;
641 adapter->GetDesc1(&desc);
643 if (requestedLuid.LowPart || requestedLuid.HighPart) {
644 if (desc.AdapterLuid.LowPart != requestedLuid.LowPart
645 || desc.AdapterLuid.HighPart != requestedLuid.HighPart)
650 QD3D12Adapter *a =
new QD3D12Adapter;
651 a->luid = desc.AdapterLuid;
652 QRhiD3D::fillDriverInfo(&a->adapterInfo, desc);
660QRhiDriverInfo QD3D12Adapter::info()
const
665QList<
int> QRhiD3D12::supportedSampleCounts()
const
667 return { 1, 2, 4, 8 };
670QList<QSize> QRhiD3D12::supportedShadingRates(
int sampleCount)
const
673 switch (sampleCount) {
676 if (caps.vrsAdditionalRates) {
677 sizes.append(QSize(4, 4));
678 sizes.append(QSize(4, 2));
679 sizes.append(QSize(2, 4));
681 sizes.append(QSize(2, 2));
682 sizes.append(QSize(2, 1));
683 sizes.append(QSize(1, 2));
686 if (caps.vrsAdditionalRates)
687 sizes.append(QSize(2, 4));
688 sizes.append(QSize(2, 2));
689 sizes.append(QSize(2, 1));
690 sizes.append(QSize(1, 2));
693 sizes.append(QSize(2, 2));
694 sizes.append(QSize(2, 1));
695 sizes.append(QSize(1, 2));
700 sizes.append(QSize(1, 1));
704QRhiSwapChain *QRhiD3D12::createSwapChain()
706 return new QD3D12SwapChain(
this);
709QRhiBuffer *QRhiD3D12::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
711 return new QD3D12Buffer(
this, type, usage, size);
714int QRhiD3D12::ubufAlignment()
const
716 return D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
719bool QRhiD3D12::isYUpInFramebuffer()
const
724bool QRhiD3D12::isYUpInNDC()
const
729bool QRhiD3D12::isClipDepthZeroToOne()
const
734QMatrix4x4 QRhiD3D12::clipSpaceCorrMatrix()
const
739 if (m.isIdentity()) {
741 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
742 0.0f, 1.0f, 0.0f, 0.0f,
743 0.0f, 0.0f, 0.5f, 0.5f,
744 0.0f, 0.0f, 0.0f, 1.0f);
749bool QRhiD3D12::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags)
const
753 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ASTC_12x12)
759bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature)
const
762 case QRhi::MultisampleTexture:
764 case QRhi::MultisampleRenderBuffer:
766 case QRhi::DebugMarkers:
767#ifdef QRHI_D3D12_HAS_OLD_PIX
772 case QRhi::Timestamps:
774 case QRhi::Instancing:
776 case QRhi::CustomInstanceStepRate:
778 case QRhi::PrimitiveRestart:
780 case QRhi::NonDynamicUniformBuffers:
782 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
784 case QRhi::NPOTTextureRepeat:
786 case QRhi::RedOrAlpha8IsRed:
788 case QRhi::ElementIndexUint:
792 case QRhi::WideLines:
794 case QRhi::VertexShaderPointSize:
796 case QRhi::BaseVertex:
798 case QRhi::BaseInstance:
800 case QRhi::TriangleFanTopology:
802 case QRhi::ReadBackNonUniformBuffer:
804 case QRhi::ReadBackNonBaseMipLevel:
806 case QRhi::TexelFetch:
808 case QRhi::RenderToNonBaseMipLevel:
810 case QRhi::IntAttributes:
812 case QRhi::ScreenSpaceDerivatives:
814 case QRhi::ReadBackAnyTextureFormat:
816 case QRhi::PipelineCacheDataLoadSave:
818 case QRhi::ImageDataStride:
820 case QRhi::RenderBufferImport:
822 case QRhi::ThreeDimensionalTextures:
824 case QRhi::RenderTo3DTextureSlice:
826 case QRhi::TextureArrays:
828 case QRhi::Tessellation:
830 case QRhi::GeometryShader:
832 case QRhi::TextureArrayRange:
834 case QRhi::NonFillPolygonMode:
836 case QRhi::OneDimensionalTextures:
838 case QRhi::OneDimensionalTextureMipmaps:
840 case QRhi::HalfAttributes:
842 case QRhi::RenderToOneDimensionalTexture:
844 case QRhi::ThreeDimensionalTextureMipmaps:
846 case QRhi::MultiView:
847 return caps.multiView;
848 case QRhi::TextureViewFormat:
849 return caps.textureViewFormat;
850 case QRhi::ResolveDepthStencil:
854 case QRhi::VariableRateShading:
856 case QRhi::VariableRateShadingMap:
857 case QRhi::VariableRateShadingMapWithTexture:
859 case QRhi::PerRenderTargetBlending:
865int QRhiD3D12::resourceLimit(QRhi::ResourceLimit limit)
const
868 case QRhi::TextureSizeMin:
870 case QRhi::TextureSizeMax:
872 case QRhi::MaxColorAttachments:
874 case QRhi::FramesInFlight:
875 return QD3D12_FRAMES_IN_FLIGHT;
876 case QRhi::MaxAsyncReadbackFrames:
877 return QD3D12_FRAMES_IN_FLIGHT;
878 case QRhi::MaxThreadGroupsPerDimension:
880 case QRhi::MaxThreadsPerThreadGroup:
882 case QRhi::MaxThreadGroupX:
884 case QRhi::MaxThreadGroupY:
886 case QRhi::MaxThreadGroupZ:
888 case QRhi::TextureArraySizeMax:
890 case QRhi::MaxUniformBufferRange:
892 case QRhi::MaxVertexInputs:
894 case QRhi::MaxVertexOutputs:
896 case QRhi::ShadingRateImageTileSize:
897 return shadingRateImageTileSize;
902const QRhiNativeHandles *QRhiD3D12::nativeHandles()
904 return &nativeHandlesStruct;
907QRhiDriverInfo QRhiD3D12::driverInfo()
const
909 return driverInfoStruct;
912QRhiStats QRhiD3D12::statistics()
915 result.totalPipelineCreationTime = totalPipelineCreationTime();
917 D3D12MA::Budget budgets[2];
918 vma.getBudget(&budgets[0], &budgets[1]);
919 for (
int i = 0; i < 2; ++i) {
920 const D3D12MA::Statistics &stats(budgets[i].Stats);
921 result.blockCount += stats.BlockCount;
922 result.allocCount += stats.AllocationCount;
923 result.usedBytes += stats.AllocationBytes;
924 result.unusedBytes += stats.BlockBytes - stats.AllocationBytes;
925 result.totalUsageBytes += budgets[i].UsageBytes;
931bool QRhiD3D12::makeThreadLocalNativeContextCurrent()
937void QRhiD3D12::setQueueSubmitParams(QRhiNativeHandles *)
942void QRhiD3D12::releaseCachedResources()
944 shaderBytecodeCache.data.clear();
947bool QRhiD3D12::isDeviceLost()
const
952QByteArray QRhiD3D12::pipelineCacheData()
957void QRhiD3D12::setPipelineCacheData(
const QByteArray &data)
962QRhiRenderBuffer *QRhiD3D12::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
963 int sampleCount, QRhiRenderBuffer::Flags flags,
964 QRhiTexture::Format backingFormatHint)
966 return new QD3D12RenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
969QRhiTexture *QRhiD3D12::createTexture(QRhiTexture::Format format,
970 const QSize &pixelSize,
int depth,
int arraySize,
971 int sampleCount, QRhiTexture::Flags flags)
973 return new QD3D12Texture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
976QRhiSampler *QRhiD3D12::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
977 QRhiSampler::Filter mipmapMode,
978 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
980 return new QD3D12Sampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
983QRhiTextureRenderTarget *QRhiD3D12::createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
984 QRhiTextureRenderTarget::Flags flags)
986 return new QD3D12TextureRenderTarget(
this, desc, flags);
989QRhiShadingRateMap *QRhiD3D12::createShadingRateMap()
991 return new QD3D12ShadingRateMap(
this);
994QRhiGraphicsPipeline *QRhiD3D12::createGraphicsPipeline()
996 return new QD3D12GraphicsPipeline(
this);
999QRhiComputePipeline *QRhiD3D12::createComputePipeline()
1001 return new QD3D12ComputePipeline(
this);
1004QRhiShaderResourceBindings *QRhiD3D12::createShaderResourceBindings()
1006 return new QD3D12ShaderResourceBindings(
this);
1009void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
1011 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1012 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1013 QD3D12GraphicsPipeline *psD = QRHI_RES(QD3D12GraphicsPipeline, ps);
1014 const bool pipelineChanged = cbD->currentGraphicsPipeline != psD || cbD->currentPipelineGeneration != psD->generation;
1016 if (pipelineChanged) {
1017 cbD->currentGraphicsPipeline = psD;
1018 cbD->currentComputePipeline =
nullptr;
1019 cbD->currentPipelineGeneration = psD->generation;
1021 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
1022 Q_ASSERT(pipeline->type == QD3D12Pipeline::Graphics);
1023 cbD->cmdList->SetPipelineState(pipeline->pso);
1024 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
1025 cbD->cmdList->SetGraphicsRootSignature(rs->rootSig);
1028 cbD->cmdList->IASetPrimitiveTopology(psD->topology);
1030 if (psD->viewInstanceMask)
1031 cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
1035void QD3D12CommandBuffer::visitUniformBuffer(QD3D12Stage s,
1036 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
1039 int dynamicOffsetCount,
1040 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1042 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1043 quint32 offset = d.offset;
1044 if (d.hasDynamicOffset) {
1045 for (
int i = 0; i < dynamicOffsetCount; ++i) {
1046 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1047 if (dynOfs.first == binding) {
1048 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1049 offset += dynOfs.second;
1053 QRHI_RES_RHI(QRhiD3D12);
1054 visitorData.cbufs[s].append({ bufD->handles[rhiD->currentFrameSlot], offset });
1057void QD3D12CommandBuffer::visitTexture(QD3D12Stage s,
1058 const QRhiShaderResourceBinding::TextureAndSampler &d,
1061 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1062 visitorData.srvs[s].append(texD->srv);
1065void QD3D12CommandBuffer::visitSampler(QD3D12Stage s,
1066 const QRhiShaderResourceBinding::TextureAndSampler &d,
1069 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, d.sampler);
1070 visitorData.samplers[s].append(samplerD->lookupOrCreateShaderVisibleDescriptor());
1073void QD3D12CommandBuffer::visitStorageBuffer(QD3D12Stage s,
1074 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
1075 QD3D12ShaderResourceVisitor::StorageOp,
1078 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1080 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1081 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1082 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
1083 uavDesc.Buffer.FirstElement = d.offset / 4;
1084 uavDesc.Buffer.NumElements = aligned(bufD->m_size - d.offset, 4u) / 4;
1085 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
1086 visitorData.uavs[s].append({ bufD->handles[0], uavDesc });
1089void QD3D12CommandBuffer::visitStorageImage(QD3D12Stage s,
1090 const QRhiShaderResourceBinding::Data::StorageImageData &d,
1091 QD3D12ShaderResourceVisitor::StorageOp,
1094 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1095 const bool isCube = texD->m_flags.testFlag(QRhiTexture::CubeMap);
1096 const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
1097 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1098 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1099 uavDesc.Format = texD->rtFormat;
1101 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1102 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1103 uavDesc.Texture2DArray.FirstArraySlice = 0;
1104 uavDesc.Texture2DArray.ArraySize = 6;
1105 }
else if (isArray) {
1106 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1107 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1108 uavDesc.Texture2DArray.FirstArraySlice = 0;
1109 uavDesc.Texture2DArray.ArraySize = UINT(qMax(0, texD->m_arraySize));
1111 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1112 uavDesc.Texture3D.MipSlice = UINT(d.level);
1113 uavDesc.Texture3D.WSize = UINT(-1);
1115 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
1116 uavDesc.Texture2D.MipSlice = UINT(d.level);
1118 visitorData.uavs[s].append({ texD->handle, uavDesc });
1121void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
1122 int dynamicOffsetCount,
1123 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1125 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1126 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
1127 QD3D12GraphicsPipeline *gfxPsD = QRHI_RES(QD3D12GraphicsPipeline, cbD->currentGraphicsPipeline);
1128 QD3D12ComputePipeline *compPsD = QRHI_RES(QD3D12ComputePipeline, cbD->currentComputePipeline);
1132 srb = gfxPsD->m_shaderResourceBindings;
1134 srb = compPsD->m_shaderResourceBindings;
1137 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, srb);
1139 for (
int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
1140 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings[i]);
1142 case QRhiShaderResourceBinding::UniformBuffer:
1144 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.ubuf.buf);
1145 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
1146 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1147 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1150 case QRhiShaderResourceBinding::SampledTexture:
1151 case QRhiShaderResourceBinding::Texture:
1152 case QRhiShaderResourceBinding::Sampler:
1154 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
1155 for (
int elem = 0; elem < data->count; ++elem) {
1156 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, data->texSamplers[elem].tex);
1157 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, data->texSamplers[elem].sampler);
1161 Q_ASSERT(texD || samplerD);
1164 if (b->stage == QRhiShaderResourceBinding::FragmentStage) {
1165 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1166 }
else if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
1167 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1169 state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1171 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATES(state));
1172 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1177 case QRhiShaderResourceBinding::ImageLoad:
1178 case QRhiShaderResourceBinding::ImageStore:
1179 case QRhiShaderResourceBinding::ImageLoadStore:
1181 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, b->u.simage.tex);
1182 if (QD3D12Resource *res = resourcePool.lookupRef(texD->handle)) {
1183 if (res->uavUsage) {
1184 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1186 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1188 if (b->type == QRhiShaderResourceBinding::ImageStore
1189 || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1192 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1197 if (b->type == QRhiShaderResourceBinding::ImageLoad || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1198 res->uavUsage |= QD3D12Resource::UavUsageRead;
1199 if (b->type == QRhiShaderResourceBinding::ImageStore || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1200 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1201 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1202 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1206 case QRhiShaderResourceBinding::BufferLoad:
1207 case QRhiShaderResourceBinding::BufferStore:
1208 case QRhiShaderResourceBinding::BufferLoadStore:
1210 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.sbuf.buf);
1211 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
1212 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1213 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
1214 if (res->uavUsage) {
1215 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1217 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1219 if (b->type == QRhiShaderResourceBinding::BufferStore
1220 || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1223 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1228 if (b->type == QRhiShaderResourceBinding::BufferLoad || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1229 res->uavUsage |= QD3D12Resource::UavUsageRead;
1230 if (b->type == QRhiShaderResourceBinding::BufferStore || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1231 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1232 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1233 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1240 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1241 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1243 if (srbChanged || srbRebuilt || srbD->hasDynamicOffset) {
1244 const QD3D12ShaderStageData *stageData = gfxPsD ? gfxPsD->stageData.data() : &compPsD->stageData;
1250 QD3D12ShaderResourceVisitor visitor(srbD, stageData, gfxPsD ? 5 : 1);
1252 QD3D12CommandBuffer::VisitorData &visitorData(cbD->visitorData);
1255 using namespace std::placeholders;
1256 visitor.uniformBuffer = std::bind(&QD3D12CommandBuffer::visitUniformBuffer, cbD, _1, _2, _3, _4, dynamicOffsetCount, dynamicOffsets);
1257 visitor.texture = std::bind(&QD3D12CommandBuffer::visitTexture, cbD, _1, _2, _3);
1258 visitor.sampler = std::bind(&QD3D12CommandBuffer::visitSampler, cbD, _1, _2, _3);
1259 visitor.storageBuffer = std::bind(&QD3D12CommandBuffer::visitStorageBuffer, cbD, _1, _2, _3, _4);
1260 visitor.storageImage = std::bind(&QD3D12CommandBuffer::visitStorageImage, cbD, _1, _2, _3, _4);
1264 quint32 cbvSrvUavCount = 0;
1265 for (
int s = 0; s < 6; ++s) {
1267 cbvSrvUavCount += visitorData.srvs[s].count();
1268 cbvSrvUavCount += visitorData.uavs[s].count();
1271 bool gotNewHeap =
false;
1272 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
1273 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1281 qCDebug(QRHI_LOG_INFO,
"Created new shader-visible CBV/SRV/UAV descriptor heap,"
1282 " per-frame slice size is now %u,"
1283 " if this happens frequently then that's not great.",
1284 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[0].capacity);
1285 bindShaderVisibleHeaps(cbD);
1288 int rootParamIndex = 0;
1289 for (
int s = 0; s < 6; ++s) {
1290 if (!visitorData.cbufs[s].isEmpty()) {
1291 for (
int i = 0, count = visitorData.cbufs[s].count(); i < count; ++i) {
1292 const auto &cbuf(visitorData.cbufs[s][i]);
1293 if (QD3D12Resource *res = resourcePool.lookupRef(cbuf.first)) {
1294 quint32 offset = cbuf.second;
1295 D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = res->resource->GetGPUVirtualAddress() + offset;
1296 if (cbD->currentGraphicsPipeline)
1297 cbD->cmdList->SetGraphicsRootConstantBufferView(rootParamIndex, gpuAddr);
1299 cbD->cmdList->SetComputeRootConstantBufferView(rootParamIndex, gpuAddr);
1301 rootParamIndex += 1;
1305 for (
int s = 0; s < 6; ++s) {
1306 if (!visitorData.srvs[s].isEmpty()) {
1307 QD3D12DescriptorHeap &gpuSrvHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1308 QD3D12Descriptor startDesc = gpuSrvHeap.get(visitorData.srvs[s].count());
1309 for (
int i = 0, count = visitorData.srvs[s].count(); i < count; ++i) {
1310 const auto &srv(visitorData.srvs[s][i]);
1311 dev->CopyDescriptorsSimple(1, gpuSrvHeap.incremented(startDesc, i).cpuHandle, srv.cpuHandle,
1312 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1315 if (cbD->currentGraphicsPipeline)
1316 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1317 else if (cbD->currentComputePipeline)
1318 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1320 rootParamIndex += 1;
1323 for (
int s = 0; s < 6; ++s) {
1326 for (
const QD3D12Descriptor &samplerDescriptor : visitorData.samplers[s]) {
1327 if (cbD->currentGraphicsPipeline)
1328 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1329 else if (cbD->currentComputePipeline)
1330 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1332 rootParamIndex += 1;
1335 for (
int s = 0; s < 6; ++s) {
1336 if (!visitorData.uavs[s].isEmpty()) {
1337 QD3D12DescriptorHeap &gpuUavHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1338 QD3D12Descriptor startDesc = gpuUavHeap.get(visitorData.uavs[s].count());
1339 for (
int i = 0, count = visitorData.uavs[s].count(); i < count; ++i) {
1340 const auto &uav(visitorData.uavs[s][i]);
1341 if (QD3D12Resource *res = resourcePool.lookupRef(uav.first)) {
1342 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uav.second,
1343 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1345 dev->CreateUnorderedAccessView(
nullptr,
nullptr,
nullptr,
1346 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1350 if (cbD->currentGraphicsPipeline)
1351 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1352 else if (cbD->currentComputePipeline)
1353 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1355 rootParamIndex += 1;
1360 cbD->currentGraphicsSrb = srb;
1361 cbD->currentComputeSrb =
nullptr;
1363 cbD->currentGraphicsSrb =
nullptr;
1364 cbD->currentComputeSrb = srb;
1366 cbD->currentSrbGeneration = srbD->generation;
1370void QRhiD3D12::setVertexInput(QRhiCommandBuffer *cb,
1371 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1372 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1374 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1375 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1377 bool needsBindVBuf =
false;
1378 for (
int i = 0; i < bindingCount; ++i) {
1379 const int inputSlot = startBinding + i;
1380 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1381 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1382 const bool isDynamic = bufD->m_type == QRhiBuffer::Dynamic;
1384 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1386 if (cbD->currentVertexBuffers[inputSlot] != bufD->handles[isDynamic ? currentFrameSlot : 0]
1387 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1389 needsBindVBuf =
true;
1390 cbD->currentVertexBuffers[inputSlot] = bufD->handles[isDynamic ? currentFrameSlot : 0];
1391 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1395 if (needsBindVBuf) {
1396 QVarLengthArray<D3D12_VERTEX_BUFFER_VIEW, 4> vbv;
1397 vbv.reserve(bindingCount);
1399 QD3D12GraphicsPipeline *psD = cbD->currentGraphicsPipeline;
1400 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1401 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1403 for (
int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1404 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1405 const QD3D12ObjectHandle handle = bufD->handles[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
1406 const quint32 offset = bindings[i].second;
1407 const quint32 stride = inputLayout.bindingAt(i)->stride();
1409 if (bufD->m_type != QRhiBuffer::Dynamic) {
1410 barrierGen.addTransitionBarrier(handle, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
1411 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1414 if (QD3D12Resource *res = resourcePool.lookupRef(handle)) {
1416 res->resource->GetGPUVirtualAddress() + offset,
1417 UINT(res->desc.Width - offset),
1423 cbD->cmdList->IASetVertexBuffers(UINT(startBinding), vbv.count(), vbv.constData());
1427 QD3D12Buffer *ibufD = QRHI_RES(QD3D12Buffer, indexBuf);
1428 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1429 const bool isDynamic = ibufD->m_type == QRhiBuffer::Dynamic;
1431 ibufD->executeHostWritesForFrameSlot(currentFrameSlot);
1433 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1434 : DXGI_FORMAT_R32_UINT;
1435 if (cbD->currentIndexBuffer != ibufD->handles[isDynamic ? currentFrameSlot : 0]
1436 || cbD->currentIndexOffset != indexOffset
1437 || cbD->currentIndexFormat != dxgiFormat)
1439 cbD->currentIndexBuffer = ibufD->handles[isDynamic ? currentFrameSlot : 0];
1440 cbD->currentIndexOffset = indexOffset;
1441 cbD->currentIndexFormat = dxgiFormat;
1443 if (ibufD->m_type != QRhiBuffer::Dynamic) {
1444 barrierGen.addTransitionBarrier(cbD->currentIndexBuffer, D3D12_RESOURCE_STATE_INDEX_BUFFER);
1445 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1448 if (QD3D12Resource *res = resourcePool.lookupRef(cbD->currentIndexBuffer)) {
1449 const D3D12_INDEX_BUFFER_VIEW ibv = {
1450 res->resource->GetGPUVirtualAddress() + indexOffset,
1451 UINT(res->desc.Width - indexOffset),
1454 cbD->cmdList->IASetIndexBuffer(&ibv);
1460void QRhiD3D12::setViewport(QRhiCommandBuffer *cb,
const QRhiViewport &viewport)
1462 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1463 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1464 Q_ASSERT(cbD->currentTarget);
1465 const QSize outputSize = cbD->currentTarget->pixelSize();
1469 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1477 v.MinDepth = viewport.minDepth();
1478 v.MaxDepth = viewport.maxDepth();
1479 cbD->cmdList->RSSetViewports(1, &v);
1481 if (cbD->currentGraphicsPipeline
1482 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
1484 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, viewport.viewport(), &x, &y, &w, &h);
1491 cbD->cmdList->RSSetScissorRects(1, &r);
1495void QRhiD3D12::setScissor(QRhiCommandBuffer *cb,
const QRhiScissor &scissor)
1497 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1498 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1499 Q_ASSERT(cbD->currentTarget);
1500 const QSize outputSize = cbD->currentTarget->pixelSize();
1504 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
1513 cbD->cmdList->RSSetScissorRects(1, &r);
1516void QRhiD3D12::setBlendConstants(QRhiCommandBuffer *cb,
const QColor &c)
1518 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1519 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1520 float v[4] = { c.redF(), c.greenF(), c.blueF(), c.alphaF() };
1521 cbD->cmdList->OMSetBlendFactor(v);
1524void QRhiD3D12::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
1526 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1527 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1528 cbD->cmdList->OMSetStencilRef(refValue);
1531static inline D3D12_SHADING_RATE toD3DShadingRate(
const QSize &coarsePixelSize)
1533 if (coarsePixelSize == QSize(1, 2))
1534 return D3D12_SHADING_RATE_1X2;
1535 if (coarsePixelSize == QSize(2, 1))
1536 return D3D12_SHADING_RATE_2X1;
1537 if (coarsePixelSize == QSize(2, 2))
1538 return D3D12_SHADING_RATE_2X2;
1539 if (coarsePixelSize == QSize(2, 4))
1540 return D3D12_SHADING_RATE_2X4;
1541 if (coarsePixelSize == QSize(4, 2))
1542 return D3D12_SHADING_RATE_4X2;
1543 if (coarsePixelSize == QSize(4, 4))
1544 return D3D12_SHADING_RATE_4X4;
1545 return D3D12_SHADING_RATE_1X1;
1548void QRhiD3D12::setShadingRate(QRhiCommandBuffer *cb,
const QSize &coarsePixelSize)
1550 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1551 cbD->hasShadingRateSet =
false;
1553#ifdef QRHI_D3D12_CL5_AVAILABLE
1557 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1558 const D3D12_SHADING_RATE_COMBINER combiners[] = { D3D12_SHADING_RATE_COMBINER_MAX, D3D12_SHADING_RATE_COMBINER_MAX };
1559 cbD->cmdList->RSSetShadingRate(toD3DShadingRate(coarsePixelSize), combiners);
1560 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
1561 cbD->hasShadingRateSet =
true;
1564 Q_UNUSED(coarsePixelSize);
1565 qWarning(
"Attempted to set ShadingRate without building Qt against a sufficiently new Windows SDK and d3d12.h. This cannot work.");
1569void QRhiD3D12::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
1570 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
1572 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1573 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1574 cbD->cmdList->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
1577void QRhiD3D12::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
1578 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
1580 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1581 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1582 cbD->cmdList->DrawIndexedInstanced(indexCount, instanceCount,
1583 firstIndex, vertexOffset,
1587void QRhiD3D12::debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name)
1592 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1593#ifdef QRHI_D3D12_HAS_OLD_PIX
1594 PIXBeginEvent(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(name).utf16()));
1601void QRhiD3D12::debugMarkEnd(QRhiCommandBuffer *cb)
1606 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1607#ifdef QRHI_D3D12_HAS_OLD_PIX
1608 PIXEndEvent(cbD->cmdList);
1614void QRhiD3D12::debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg)
1619 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1620#ifdef QRHI_D3D12_HAS_OLD_PIX
1621 PIXSetMarker(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(msg).utf16()));
1628const QRhiNativeHandles *QRhiD3D12::nativeHandles(QRhiCommandBuffer *cb)
1630 return QRHI_RES(QD3D12CommandBuffer, cb)->nativeHandles();
1633void QRhiD3D12::beginExternal(QRhiCommandBuffer *cb)
1638void QRhiD3D12::endExternal(QRhiCommandBuffer *cb)
1640 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1641 cbD->resetPerPassState();
1642 bindShaderVisibleHeaps(cbD);
1643 if (cbD->currentTarget) {
1644 QD3D12RenderTargetData *rtD = rtData(cbD->currentTarget);
1645 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
1648 rtD->dsAttCount ? &rtD->dsv :
nullptr);
1652double QRhiD3D12::lastCompletedGpuTime(QRhiCommandBuffer *cb)
1654 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1655 return cbD->lastGpuTime;
1658static void calculateGpuTime(QD3D12CommandBuffer *cbD,
1659 int timestampPairStartIndex,
1660 const quint8 *readbackBufPtr,
1661 quint64 timestampTicksPerSecond)
1663 const size_t byteOffset = timestampPairStartIndex *
sizeof(quint64);
1664 const quint64 *p =
reinterpret_cast<
const quint64 *>(readbackBufPtr + byteOffset);
1665 const quint64 startTime = *p++;
1666 const quint64 endTime = *p;
1667 if (startTime < endTime) {
1668 const quint64 ticks = endTime - startTime;
1669 const double timeSec = ticks /
double(timestampTicksPerSecond);
1670 cbD->lastGpuTime = timeSec;
1674QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
1678 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
1679 currentSwapChain = swapChainD;
1680 currentFrameSlot = swapChainD->currentFrameSlot;
1681 QD3D12SwapChain::FrameResources &fr(swapChainD->frameRes[currentFrameSlot]);
1694 for (QD3D12SwapChain *sc : std::as_const(swapchains))
1695 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
1697 if (swapChainD->frameLatencyWaitableObject)
1698 WaitForSingleObjectEx(swapChainD->frameLatencyWaitableObject, 1000,
true);
1700 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
1702 qWarning(
"Failed to reset command allocator: %s",
1703 qPrintable(QSystemError::windowsComString(hr)));
1704 return QRhi::FrameOpError;
1707 if (!startCommandListForCurrentFrameSlot(&fr.cmdList))
1708 return QRhi::FrameOpError;
1710 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1711 cbD->cmdList = fr.cmdList;
1713 swapChainD->rtWrapper.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1714 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1715 : swapChainD->rtvs[swapChainD->currentBackBufferIndex].cpuHandle;
1717 swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
1718 : D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
1720 if (swapChainD->stereo) {
1721 swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1722 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1723 : swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
1725 swapChainD->rtWrapperRight.d.dsv =
1726 swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
1733 releaseQueue.executeDeferredReleases(currentFrameSlot);
1739 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1741 smallStagingAreas[currentFrameSlot].head = 0;
1743 bindShaderVisibleHeaps(cbD);
1745 finishActiveReadbacks();
1747 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
1750 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1751 calculateGpuTime(cbD,
1752 timestampPairStartIndex,
1753 timestampReadbackArea.mem.p,
1754 timestampTicksPerSecond);
1756 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1757 D3D12_QUERY_TYPE_TIMESTAMP,
1758 timestampPairStartIndex);
1761 QDxgiVSyncService::instance()->beginFrame(adapterLuid);
1763 return QRhi::FrameOpSuccess;
1766QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
1768 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
1769 Q_ASSERT(currentSwapChain == swapChainD);
1770 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1772 QD3D12ObjectHandle backBufferResourceHandle = swapChainD->colorBuffers[swapChainD->currentBackBufferIndex];
1773 if (swapChainD->sampleDesc.Count > 1) {
1774 QD3D12ObjectHandle msaaBackBufferResourceHandle = swapChainD->msaaBuffers[swapChainD->currentBackBufferIndex];
1775 barrierGen.addTransitionBarrier(msaaBackBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
1776 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
1777 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1778 const QD3D12Resource *src = resourcePool.lookupRef(msaaBackBufferResourceHandle);
1779 const QD3D12Resource *dst = resourcePool.lookupRef(backBufferResourceHandle);
1781 cbD->cmdList->ResolveSubresource(dst->resource, 0, src->resource, 0, swapChainD->colorFormat);
1784 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
1785 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1787 if (timestampQueryHeap.isValid()) {
1788 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1789 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1790 D3D12_QUERY_TYPE_TIMESTAMP,
1791 timestampPairStartIndex + 1);
1792 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
1793 D3D12_QUERY_TYPE_TIMESTAMP,
1794 timestampPairStartIndex,
1796 timestampReadbackArea.mem.buffer,
1797 timestampPairStartIndex *
sizeof(quint64));
1800 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
1801 HRESULT hr = cmdList->Close();
1803 qWarning(
"Failed to close command list: %s",
1804 qPrintable(QSystemError::windowsComString(hr)));
1805 return QRhi::FrameOpError;
1808 ID3D12CommandList *execList[] = { cmdList };
1809 cmdQueue->ExecuteCommandLists(1, execList);
1811 if (!flags.testFlag(QRhi::SkipPresent)) {
1812 UINT presentFlags = 0;
1813 if (swapChainD->swapInterval == 0
1814 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
1816 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
1818 if (!swapChainD->swapChain) {
1819 qWarning(
"Failed to present, no swapchain");
1820 return QRhi::FrameOpError;
1822 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
1823 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
1824 qWarning(
"Device loss detected in Present()");
1826 return QRhi::FrameOpDeviceLost;
1827 }
else if (FAILED(hr)) {
1828 qWarning(
"Failed to present: %s", qPrintable(QSystemError::windowsComString(hr)));
1829 return QRhi::FrameOpError;
1832 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
1833 dcompDevice->Commit();
1836 swapChainD->addCommandCompletionSignalForCurrentFrameSlot();
1843 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
1845 if (!flags.testFlag(QRhi::SkipPresent)) {
1849 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
1850 swapChainD->currentBackBufferIndex = swapChainD->swapChain->GetCurrentBackBufferIndex();
1853 currentSwapChain =
nullptr;
1854 return QRhi::FrameOpSuccess;
1857QRhi::FrameOpResult QRhiD3D12::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
1870 currentFrameSlot = (currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
1872 for (QD3D12SwapChain *sc : std::as_const(swapchains))
1873 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
1875 if (!offscreenCb[currentFrameSlot])
1876 offscreenCb[currentFrameSlot] =
new QD3D12CommandBuffer(
this);
1877 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
1878 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
1879 return QRhi::FrameOpError;
1881 releaseQueue.executeDeferredReleases(currentFrameSlot);
1883 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1884 smallStagingAreas[currentFrameSlot].head = 0;
1886 bindShaderVisibleHeaps(cbD);
1888 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
1889 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1890 D3D12_QUERY_TYPE_TIMESTAMP,
1891 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT);
1894 offscreenActive =
true;
1897 return QRhi::FrameOpSuccess;
1900QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
1903 Q_ASSERT(offscreenActive);
1904 offscreenActive =
false;
1906 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
1907 if (timestampQueryHeap.isValid()) {
1908 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1909 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1910 D3D12_QUERY_TYPE_TIMESTAMP,
1911 timestampPairStartIndex + 1);
1912 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
1913 D3D12_QUERY_TYPE_TIMESTAMP,
1914 timestampPairStartIndex,
1916 timestampReadbackArea.mem.buffer,
1917 timestampPairStartIndex *
sizeof(quint64));
1920 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
1921 HRESULT hr = cmdList->Close();
1923 qWarning(
"Failed to close command list: %s",
1924 qPrintable(QSystemError::windowsComString(hr)));
1925 return QRhi::FrameOpError;
1928 ID3D12CommandList *execList[] = { cmdList };
1929 cmdQueue->ExecuteCommandLists(1, execList);
1931 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
1938 finishActiveReadbacks(
true);
1941 if (timestampQueryHeap.isValid()) {
1942 calculateGpuTime(cbD,
1943 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT,
1944 timestampReadbackArea.mem.p,
1945 timestampTicksPerSecond);
1948 return QRhi::FrameOpSuccess;
1951QRhi::FrameOpResult QRhiD3D12::finish()
1953 QD3D12CommandBuffer *cbD =
nullptr;
1955 if (offscreenActive) {
1956 Q_ASSERT(!currentSwapChain);
1957 cbD = offscreenCb[currentFrameSlot];
1959 Q_ASSERT(currentSwapChain);
1960 cbD = ¤tSwapChain->cbWrapper;
1963 return QRhi::FrameOpError;
1965 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
1967 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
1968 HRESULT hr = cmdList->Close();
1970 qWarning(
"Failed to close command list: %s",
1971 qPrintable(QSystemError::windowsComString(hr)));
1972 return QRhi::FrameOpError;
1975 ID3D12CommandList *execList[] = { cmdList };
1976 cmdQueue->ExecuteCommandLists(1, execList);
1978 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
1985 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
1987 qWarning(
"Failed to reset command allocator: %s",
1988 qPrintable(QSystemError::windowsComString(hr)));
1989 return QRhi::FrameOpError;
1992 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
1993 return QRhi::FrameOpError;
1997 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1998 smallStagingAreas[currentFrameSlot].head = 0;
2000 bindShaderVisibleHeaps(cbD);
2003 releaseQueue.releaseAll();
2004 finishActiveReadbacks(
true);
2006 return QRhi::FrameOpSuccess;
2009void QRhiD3D12::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2011 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2012 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2013 enqueueResourceUpdates(cbD, resourceUpdates);
2016void QRhiD3D12::beginPass(QRhiCommandBuffer *cb,
2017 QRhiRenderTarget *rt,
2018 const QColor &colorClearValue,
2019 const QRhiDepthStencilClearValue &depthStencilClearValue,
2020 QRhiResourceUpdateBatch *resourceUpdates,
2021 QRhiCommandBuffer::BeginPassFlags)
2023 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2024 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2026 if (resourceUpdates)
2027 enqueueResourceUpdates(cbD, resourceUpdates);
2029 QD3D12RenderTargetData *rtD = rtData(rt);
2030 bool wantsColorClear =
true;
2031 bool wantsDsClear =
true;
2032 if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) {
2033 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, rt);
2034 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2035 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2036 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2039 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); it != itEnd; ++it) {
2040 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
2041 QD3D12Texture *resolveTexD = QRHI_RES(QD3D12Texture, it->resolveTexture());
2042 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
2044 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2046 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2048 barrierGen.addTransitionBarrier(resolveTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2050 if (rtTex->m_desc.depthStencilBuffer()) {
2051 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rtTex->m_desc.depthStencilBuffer());
2052 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
2053 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2054 }
else if (rtTex->m_desc.depthTexture()) {
2055 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, rtTex->m_desc.depthTexture());
2056 barrierGen.addTransitionBarrier(depthTexD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2058 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2060 Q_ASSERT(currentSwapChain);
2061 barrierGen.addTransitionBarrier(currentSwapChain->sampleDesc.Count > 1
2062 ? currentSwapChain->msaaBuffers[currentSwapChain->currentBackBufferIndex]
2063 : currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex],
2064 D3D12_RESOURCE_STATE_RENDER_TARGET);
2065 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2068 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2071 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2073 if (rtD->colorAttCount && wantsColorClear) {
2074 float clearColor[4] = {
2075 colorClearValue.redF(),
2076 colorClearValue.greenF(),
2077 colorClearValue.blueF(),
2078 colorClearValue.alphaF()
2080 for (
int i = 0; i < rtD->colorAttCount; ++i)
2081 cbD->cmdList->ClearRenderTargetView(rtD->rtv[i], clearColor, 0,
nullptr);
2083 if (rtD->dsAttCount && wantsDsClear) {
2084 cbD->cmdList->ClearDepthStencilView(rtD->dsv,
2085 D3D12_CLEAR_FLAGS(D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL),
2086 depthStencilClearValue.depthClearValue(),
2087 UINT8(depthStencilClearValue.stencilClearValue()),
2092 cbD->recordingPass = QD3D12CommandBuffer::RenderPass;
2093 cbD->currentTarget = rt;
2095 bool hasShadingRateMapSet =
false;
2096#ifdef QRHI_D3D12_CL5_AVAILABLE
2097 if (rtD->rp->hasShadingRateMap) {
2098 cbD->setShadingRate(QSize(1, 1));
2099 QD3D12ShadingRateMap *rateMapD = rt->resourceType() == QRhiRenderTarget::TextureRenderTarget
2100 ? QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12TextureRenderTarget, rt)->m_desc.shadingRateMap())
2101 : QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12SwapChainRenderTarget, rt)->swapChain()->shadingRateMap());
2102 if (QD3D12Resource *res = resourcePool.lookupRef(rateMapD->handle)) {
2103 barrierGen.addTransitionBarrier(rateMapD->handle, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
2104 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2105 cbD->cmdList->RSSetShadingRateImage(res->resource);
2106 hasShadingRateMapSet =
true;
2108 }
else if (cbD->hasShadingRateMapSet) {
2109 cbD->cmdList->RSSetShadingRateImage(
nullptr);
2110 cbD->setShadingRate(QSize(1, 1));
2111 }
else if (cbD->hasShadingRateSet) {
2112 cbD->setShadingRate(QSize(1, 1));
2116 cbD->resetPerPassState();
2119 cbD->hasShadingRateMapSet = hasShadingRateMapSet;
2122void QRhiD3D12::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2124 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2125 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2127 if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
2128 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, cbD->currentTarget);
2129 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2132 const QRhiColorAttachment &colorAtt(*it);
2133 if (!colorAtt.resolveTexture())
2136 QD3D12Texture *dstTexD = QRHI_RES(QD3D12Texture, colorAtt.resolveTexture());
2137 QD3D12Resource *dstRes = resourcePool.lookupRef(dstTexD->handle);
2141 QD3D12Texture *srcTexD = QRHI_RES(QD3D12Texture, colorAtt.texture());
2142 QD3D12RenderBuffer *srcRbD = QRHI_RES(QD3D12RenderBuffer, colorAtt.renderBuffer());
2143 Q_ASSERT(srcTexD || srcRbD);
2144 QD3D12Resource *srcRes = resourcePool.lookupRef(srcTexD ? srcTexD->handle : srcRbD->handle);
2149 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2150 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2151 int(srcTexD->dxgiFormat),
int(dstTexD->dxgiFormat));
2154 if (srcTexD->sampleDesc.Count <= 1) {
2155 qWarning(
"Cannot resolve a non-multisample texture");
2158 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2159 qWarning(
"Resolve source and destination sizes do not match");
2163 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2164 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2165 int(srcRbD->dxgiFormat),
int(dstTexD->dxgiFormat));
2168 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2169 qWarning(
"Resolve source and destination sizes do not match");
2174 barrierGen.addTransitionBarrier(srcTexD ? srcTexD->handle : srcRbD->handle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2175 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2176 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2178 const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
2179 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2180 const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
2181 const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
2182 UINT(colorAtt.resolveLayer()) + resolveIdx,
2183 dstTexD->mipLevelCount);
2184 cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresource,
2185 srcRes->resource, srcSubresource,
2186 dstTexD->dxgiFormat);
2189 if (rtTex->m_desc.depthResolveTexture())
2190 qWarning(
"Resolving multisample depth-stencil buffers is not supported with D3D");
2193 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2194 cbD->currentTarget =
nullptr;
2196 if (resourceUpdates)
2197 enqueueResourceUpdates(cbD, resourceUpdates);
2200void QRhiD3D12::beginComputePass(QRhiCommandBuffer *cb,
2201 QRhiResourceUpdateBatch *resourceUpdates,
2202 QRhiCommandBuffer::BeginPassFlags)
2204 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2205 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2207 if (resourceUpdates)
2208 enqueueResourceUpdates(cbD, resourceUpdates);
2210 cbD->recordingPass = QD3D12CommandBuffer::ComputePass;
2212 cbD->resetPerPassState();
2215void QRhiD3D12::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2217 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2218 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2220 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2222 if (resourceUpdates)
2223 enqueueResourceUpdates(cbD, resourceUpdates);
2226void QRhiD3D12::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
2228 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2229 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2230 QD3D12ComputePipeline *psD = QRHI_RES(QD3D12ComputePipeline, ps);
2231 const bool pipelineChanged = cbD->currentComputePipeline != psD || cbD->currentPipelineGeneration != psD->generation;
2233 if (pipelineChanged) {
2234 cbD->currentGraphicsPipeline =
nullptr;
2235 cbD->currentComputePipeline = psD;
2236 cbD->currentPipelineGeneration = psD->generation;
2238 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
2239 Q_ASSERT(pipeline->type == QD3D12Pipeline::Compute);
2240 cbD->cmdList->SetPipelineState(pipeline->pso);
2241 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
2242 cbD->cmdList->SetComputeRootSignature(rs->rootSig);
2247void QRhiD3D12::dispatch(QRhiCommandBuffer *cb,
int x,
int y,
int z)
2249 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2250 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2251 cbD->cmdList->Dispatch(UINT(x), UINT(y), UINT(z));
2254bool QD3D12DescriptorHeap::create(ID3D12Device *device,
2255 quint32 descriptorCount,
2256 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
2257 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags)
2260 capacity = descriptorCount;
2261 this->heapType = heapType;
2262 this->heapFlags = heapFlags;
2264 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
2265 heapDesc.Type = heapType;
2266 heapDesc.NumDescriptors = capacity;
2267 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS(heapFlags);
2269 HRESULT hr = device->CreateDescriptorHeap(&heapDesc, __uuidof(ID3D12DescriptorHeap),
reinterpret_cast<
void **>(&heap));
2271 qWarning(
"Failed to create descriptor heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2273 capacity = descriptorByteSize = 0;
2277 descriptorByteSize = device->GetDescriptorHandleIncrementSize(heapType);
2278 heapStart.cpuHandle = heap->GetCPUDescriptorHandleForHeapStart();
2279 if (heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
2280 heapStart.gpuHandle = heap->GetGPUDescriptorHandleForHeapStart();
2285void QD3D12DescriptorHeap::createWithExisting(
const QD3D12DescriptorHeap &other,
2286 quint32 offsetInDescriptors,
2287 quint32 descriptorCount)
2291 capacity = descriptorCount;
2292 heapType = other.heapType;
2293 heapFlags = other.heapFlags;
2294 descriptorByteSize = other.descriptorByteSize;
2295 heapStart = incremented(other.heapStart, offsetInDescriptors);
2298void QD3D12DescriptorHeap::destroy()
2307void QD3D12DescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2310 releaseQueue->deferredReleaseDescriptorHeap(heap);
2316QD3D12Descriptor QD3D12DescriptorHeap::get(quint32 count)
2318 Q_ASSERT(count > 0);
2319 if (head + count > capacity) {
2320 qWarning(
"Cannot get %u descriptors as that would exceed capacity %u", count, capacity);
2324 return at(head - count);
2327QD3D12Descriptor QD3D12DescriptorHeap::at(quint32 index)
const
2329 const quint32 startOffset = index * descriptorByteSize;
2330 QD3D12Descriptor result;
2331 result.cpuHandle.ptr = heapStart.cpuHandle.ptr + startOffset;
2332 if (heapStart.gpuHandle.ptr != 0)
2333 result.gpuHandle.ptr = heapStart.gpuHandle.ptr + startOffset;
2337bool QD3D12CpuDescriptorPool::create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName)
2339 QD3D12DescriptorHeap firstHeap;
2340 if (!firstHeap.create(device, DESCRIPTORS_PER_HEAP, heapType, D3D12_DESCRIPTOR_HEAP_FLAG_NONE))
2342 heaps.append(HeapWithMap::init(firstHeap, DESCRIPTORS_PER_HEAP));
2343 descriptorByteSize = heaps[0].heap.descriptorByteSize;
2344 this->device = device;
2345 this->debugName = debugName;
2349void QD3D12CpuDescriptorPool::destroy()
2353 static bool leakCheck =
true;
2356 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
2359 for (HeapWithMap &heap : heaps) {
2360 const int leakedDescriptorCount = heap.map.count(
true);
2361 if (leakedDescriptorCount > 0) {
2362 qWarning(
"QD3D12CpuDescriptorPool::destroy(): "
2363 "Heap %p for descriptor pool %p '%s' has %d unreleased descriptors",
2364 &heap.heap,
this, debugName, leakedDescriptorCount);
2368 for (HeapWithMap &heap : heaps)
2369 heap.heap.destroy();
2373QD3D12Descriptor QD3D12CpuDescriptorPool::allocate(quint32 count)
2375 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2377 HeapWithMap &last(heaps.last());
2378 if (last.heap.head + count <= last.heap.capacity) {
2379 quint32 firstIndex = last.heap.head;
2380 for (quint32 i = 0; i < count; ++i)
2381 last.map.setBit(firstIndex + i);
2382 return last.heap.get(count);
2385 for (HeapWithMap &heap : heaps) {
2386 quint32 freeCount = 0;
2387 for (quint32 i = 0; i < DESCRIPTORS_PER_HEAP; ++i) {
2388 if (heap.map.testBit(i)) {
2392 if (freeCount == count) {
2393 quint32 firstIndex = i - (freeCount - 1);
2394 for (quint32 j = 0; j < count; ++j) {
2395 heap.map.setBit(firstIndex + j);
2396 return heap.heap.at(firstIndex);
2403 QD3D12DescriptorHeap newHeap;
2404 if (!newHeap.create(device, DESCRIPTORS_PER_HEAP, last.heap.heapType, last.heap.heapFlags))
2407 heaps.append(HeapWithMap::init(newHeap, DESCRIPTORS_PER_HEAP));
2409 for (quint32 i = 0; i < count; ++i)
2410 heaps.last().map.setBit(i);
2412 return heaps.last().heap.get(count);
2415void QD3D12CpuDescriptorPool::release(
const QD3D12Descriptor &descriptor, quint32 count)
2417 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2418 if (!descriptor.isValid())
2421 const SIZE_T addr = descriptor.cpuHandle.ptr;
2422 for (HeapWithMap &heap : heaps) {
2423 const SIZE_T begin = heap.heap.heapStart.cpuHandle.ptr;
2424 const SIZE_T end = begin + heap.heap.descriptorByteSize * heap.heap.capacity;
2425 if (addr >= begin && addr < end) {
2426 quint32 firstIndex = (addr - begin) / heap.heap.descriptorByteSize;
2427 for (quint32 i = 0; i < count; ++i)
2428 heap.map.setBit(firstIndex + i,
false);
2433 qWarning(
"QD3D12CpuDescriptorPool::release: Descriptor with address %llu is not in any heap",
2434 quint64(descriptor.cpuHandle.ptr));
2437bool QD3D12QueryHeap::create(ID3D12Device *device,
2439 D3D12_QUERY_HEAP_TYPE heapType)
2441 capacity = queryCount;
2443 D3D12_QUERY_HEAP_DESC heapDesc = {};
2444 heapDesc.Type = heapType;
2445 heapDesc.Count = capacity;
2447 HRESULT hr = device->CreateQueryHeap(&heapDesc, __uuidof(ID3D12QueryHeap),
reinterpret_cast<
void **>(&heap));
2449 qWarning(
"Failed to create query heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2458void QD3D12QueryHeap::destroy()
2467bool QD3D12StagingArea::create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType)
2469 Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
2470 D3D12_RESOURCE_DESC resourceDesc = {};
2471 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
2472 resourceDesc.Width = capacity;
2473 resourceDesc.Height = 1;
2474 resourceDesc.DepthOrArraySize = 1;
2475 resourceDesc.MipLevels = 1;
2476 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
2477 resourceDesc.SampleDesc = { 1, 0 };
2478 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2479 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
2480 UINT state = heapType == D3D12_HEAP_TYPE_UPLOAD ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
2481 HRESULT hr = rhi->vma.createResource(heapType,
2483 D3D12_RESOURCE_STATES(state),
2486 __uuidof(ID3D12Resource),
2487 reinterpret_cast<
void **>(&resource));
2489 qWarning(
"Failed to create buffer for staging area: %s",
2490 qPrintable(QSystemError::windowsComString(hr)));
2494 hr = resource->Map(0,
nullptr, &p);
2496 qWarning(
"Failed to map buffer for staging area: %s",
2497 qPrintable(QSystemError::windowsComString(hr)));
2502 mem.p =
static_cast<quint8 *>(p);
2503 mem.gpuAddr = resource->GetGPUVirtualAddress();
2504 mem.buffer = resource;
2505 mem.bufferOffset = 0;
2507 this->capacity = capacity;
2513void QD3D12StagingArea::destroy()
2516 resource->Release();
2520 allocation->Release();
2521 allocation =
nullptr;
2526void QD3D12StagingArea::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2529 releaseQueue->deferredReleaseResourceAndAllocation(resource, allocation);
2533QD3D12StagingArea::Allocation QD3D12StagingArea::get(quint32 byteSize)
2535 const quint32 allocSize = aligned(byteSize, ALIGNMENT);
2536 if (head + allocSize > capacity) {
2537 qWarning(
"Failed to allocate %u (%u) bytes from staging area of size %u with %u bytes left",
2538 allocSize, byteSize, capacity, remainingCapacity());
2541 const quint32 offset = head;
2545 mem.gpuAddr + offset,
2554void QD3D12ReleaseQueue::deferredReleaseResource(
const QD3D12ObjectHandle &handle)
2556 DeferredReleaseEntry e;
2561void QD3D12ReleaseQueue::deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
2562 QD3D12CpuDescriptorPool *pool,
2563 const QD3D12Descriptor &viewsStart,
2566 DeferredReleaseEntry e;
2567 e.type = DeferredReleaseEntry::Resource;
2569 e.poolForViews = pool;
2570 e.viewsStart = viewsStart;
2571 e.viewCount = viewCount;
2575void QD3D12ReleaseQueue::deferredReleasePipeline(
const QD3D12ObjectHandle &handle)
2577 DeferredReleaseEntry e;
2578 e.type = DeferredReleaseEntry::Pipeline;
2583void QD3D12ReleaseQueue::deferredReleaseRootSignature(
const QD3D12ObjectHandle &handle)
2585 DeferredReleaseEntry e;
2586 e.type = DeferredReleaseEntry::RootSignature;
2591void QD3D12ReleaseQueue::deferredReleaseCallback(std::function<
void(
void*)> callback,
void *userData)
2593 DeferredReleaseEntry e;
2594 e.type = DeferredReleaseEntry::Callback;
2595 e.callback = callback;
2596 e.callbackUserData = userData;
2600void QD3D12ReleaseQueue::deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
2601 D3D12MA::Allocation *allocation)
2603 DeferredReleaseEntry e;
2604 e.type = DeferredReleaseEntry::ResourceAndAllocation;
2605 e.resourceAndAllocation = { resource, allocation };
2609void QD3D12ReleaseQueue::deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap)
2611 DeferredReleaseEntry e;
2612 e.type = DeferredReleaseEntry::DescriptorHeap;
2613 e.descriptorHeap = heap;
2617void QD3D12ReleaseQueue::deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
2618 const QD3D12Descriptor &viewsStart,
2621 DeferredReleaseEntry e;
2622 e.type = DeferredReleaseEntry::Views;
2623 e.poolForViews = pool;
2624 e.viewsStart = viewsStart;
2625 e.viewCount = viewCount;
2629void QD3D12ReleaseQueue::activatePendingDeferredReleaseRequests(
int frameSlot)
2631 for (DeferredReleaseEntry &e : queue) {
2632 if (!e.frameSlotToBeReleasedIn.has_value())
2633 e.frameSlotToBeReleasedIn = frameSlot;
2637void QD3D12ReleaseQueue::executeDeferredReleases(
int frameSlot,
bool forced)
2639 for (
int i = queue.count() - 1; i >= 0; --i) {
2640 const DeferredReleaseEntry &e(queue[i]);
2641 if (forced || (e.frameSlotToBeReleasedIn.has_value() && e.frameSlotToBeReleasedIn.value() == frameSlot)) {
2643 case DeferredReleaseEntry::Resource:
2644 resourcePool->remove(e.handle);
2645 if (e.poolForViews && e.viewsStart.isValid() && e.viewCount > 0)
2646 e.poolForViews->release(e.viewsStart, e.viewCount);
2648 case DeferredReleaseEntry::Pipeline:
2649 pipelinePool->remove(e.handle);
2651 case DeferredReleaseEntry::RootSignature:
2652 rootSignaturePool->remove(e.handle);
2654 case DeferredReleaseEntry::Callback:
2655 e.callback(e.callbackUserData);
2657 case DeferredReleaseEntry::ResourceAndAllocation:
2660 e.resourceAndAllocation.first->Release();
2661 if (e.resourceAndAllocation.second)
2662 e.resourceAndAllocation.second->Release();
2664 case DeferredReleaseEntry::DescriptorHeap:
2665 e.descriptorHeap->Release();
2667 case DeferredReleaseEntry::Views:
2668 e.poolForViews->release(e.viewsStart, e.viewCount);
2676void QD3D12ReleaseQueue::releaseAll()
2678 executeDeferredReleases(0,
true);
2681void QD3D12ResourceBarrierGenerator::addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle,
2682 D3D12_RESOURCE_STATES stateAfter)
2684 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2685 if (stateAfter != res->state) {
2686 transitionResourceBarriers.append({ resourceHandle, res->state, stateAfter });
2687 res->state = stateAfter;
2692void QD3D12ResourceBarrierGenerator::enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD)
2694 QVarLengthArray<D3D12_RESOURCE_BARRIER, PREALLOC> barriers;
2695 for (
const TransitionResourceBarrier &trb : transitionResourceBarriers) {
2696 if (QD3D12Resource *res = resourcePool->lookupRef(trb.resourceHandle)) {
2697 D3D12_RESOURCE_BARRIER barrier = {};
2698 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2699 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2700 barrier.Transition.pResource = res->resource;
2701 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
2702 barrier.Transition.StateBefore = trb.stateBefore;
2703 barrier.Transition.StateAfter = trb.stateAfter;
2704 barriers.append(barrier);
2707 transitionResourceBarriers.clear();
2708 if (!barriers.isEmpty())
2709 cbD->cmdList->ResourceBarrier(barriers.count(), barriers.constData());
2712void QD3D12ResourceBarrierGenerator::enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
2713 const QD3D12ObjectHandle &resourceHandle,
2715 D3D12_RESOURCE_STATES stateBefore,
2716 D3D12_RESOURCE_STATES stateAfter)
2718 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2719 D3D12_RESOURCE_BARRIER barrier = {};
2720 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2721 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2722 barrier.Transition.pResource = res->resource;
2723 barrier.Transition.Subresource = subresource;
2724 barrier.Transition.StateBefore = stateBefore;
2725 barrier.Transition.StateAfter = stateAfter;
2726 cbD->cmdList->ResourceBarrier(1, &barrier);
2730void QD3D12ResourceBarrierGenerator::enqueueUavBarrier(QD3D12CommandBuffer *cbD,
2731 const QD3D12ObjectHandle &resourceHandle)
2733 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2734 D3D12_RESOURCE_BARRIER barrier = {};
2735 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
2736 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2737 barrier.UAV.pResource = res->resource;
2738 cbD->cmdList->ResourceBarrier(1, &barrier);
2742void QD3D12ShaderBytecodeCache::insertWithCapacityLimit(
const QRhiShaderStage &key,
const Shader &s)
2744 if (data.count() >= QRhiD3D12::MAX_SHADER_CACHE_ENTRIES)
2746 data.insert(key, s);
2749bool QD3D12ShaderVisibleDescriptorHeap::create(ID3D12Device *device,
2750 D3D12_DESCRIPTOR_HEAP_TYPE type,
2751 quint32 perFrameDescriptorCount)
2753 Q_ASSERT(type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
2755 quint32 size = perFrameDescriptorCount * QD3D12_FRAMES_IN_FLIGHT;
2758 const quint32 CBV_SRV_UAV_MAX = 1000000;
2759 const quint32 SAMPLER_MAX = 2048;
2760 if (type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
2761 size = qMin(size, CBV_SRV_UAV_MAX);
2762 else if (type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
2763 size = qMin(size, SAMPLER_MAX);
2765 if (!heap.create(device, size, type, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
2766 qWarning(
"Failed to create shader-visible descriptor heap of size %u", size);
2770 perFrameDescriptorCount = size / QD3D12_FRAMES_IN_FLIGHT;
2771 quint32 currentOffsetInDescriptors = 0;
2772 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
2773 perFrameHeapSlice[i].createWithExisting(heap, currentOffsetInDescriptors, perFrameDescriptorCount);
2774 currentOffsetInDescriptors += perFrameDescriptorCount;
2780void QD3D12ShaderVisibleDescriptorHeap::destroy()
2785void QD3D12ShaderVisibleDescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2787 heap.destroyWithDeferredRelease(releaseQueue);
2790static inline std::pair<
int,
int> mapBinding(
int binding,
const QShader::NativeResourceBindingMap &map)
2793 return { binding, binding };
2795 auto it = map.constFind(binding);
2796 if (it != map.cend())
2805void QD3D12ShaderResourceVisitor::visit()
2807 for (
int bindingIdx = 0, bindingCount = srb->m_bindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
2808 const QRhiShaderResourceBinding &b(srb->m_bindings[bindingIdx]);
2809 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
2811 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
2812 const QD3D12ShaderStageData *sd = &stageData[stageIdx];
2816 if (!bd->stage.testFlag(qd3d12_stageToSrb(sd->stage)))
2820 case QRhiShaderResourceBinding::UniformBuffer:
2822 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2823 if (shaderRegister >= 0 && uniformBuffer)
2824 uniformBuffer(sd->stage, bd->u.ubuf, shaderRegister, bd->binding);
2827 case QRhiShaderResourceBinding::SampledTexture:
2829 Q_ASSERT(bd->u.stex.count > 0);
2830 const int textureBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2831 const int samplerBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).second;
2832 for (
int i = 0; i < bd->u.stex.count; ++i) {
2833 if (textureBaseShaderRegister >= 0 && texture)
2834 texture(sd->stage, bd->u.stex.texSamplers[i], textureBaseShaderRegister + i);
2835 if (samplerBaseShaderRegister >= 0 && sampler)
2836 sampler(sd->stage, bd->u.stex.texSamplers[i], samplerBaseShaderRegister + i);
2840 case QRhiShaderResourceBinding::Texture:
2842 Q_ASSERT(bd->u.stex.count > 0);
2843 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2844 if (baseShaderRegister >= 0 && texture) {
2845 for (
int i = 0; i < bd->u.stex.count; ++i)
2846 texture(sd->stage, bd->u.stex.texSamplers[i], baseShaderRegister + i);
2850 case QRhiShaderResourceBinding::Sampler:
2852 Q_ASSERT(bd->u.stex.count > 0);
2853 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2854 if (baseShaderRegister >= 0 && sampler) {
2855 for (
int i = 0; i < bd->u.stex.count; ++i)
2856 sampler(sd->stage, bd->u.stex.texSamplers[i], baseShaderRegister + i);
2860 case QRhiShaderResourceBinding::ImageLoad:
2862 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2863 if (shaderRegister >= 0 && storageImage)
2864 storageImage(sd->stage, bd->u.simage, Load, shaderRegister);
2867 case QRhiShaderResourceBinding::ImageStore:
2869 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2870 if (shaderRegister >= 0 && storageImage)
2871 storageImage(sd->stage, bd->u.simage, Store, shaderRegister);
2874 case QRhiShaderResourceBinding::ImageLoadStore:
2876 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2877 if (shaderRegister >= 0 && storageImage)
2878 storageImage(sd->stage, bd->u.simage, LoadStore, shaderRegister);
2881 case QRhiShaderResourceBinding::BufferLoad:
2883 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2884 if (shaderRegister >= 0 && storageBuffer)
2885 storageBuffer(sd->stage, bd->u.sbuf, Load, shaderRegister);
2888 case QRhiShaderResourceBinding::BufferStore:
2890 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2891 if (shaderRegister >= 0 && storageBuffer)
2892 storageBuffer(sd->stage, bd->u.sbuf, Store, shaderRegister);
2895 case QRhiShaderResourceBinding::BufferLoadStore:
2897 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2898 if (shaderRegister >= 0 && storageBuffer)
2899 storageBuffer(sd->stage, bd->u.sbuf, LoadStore, shaderRegister);
2907bool QD3D12SamplerManager::create(ID3D12Device *device)
2910 if (!shaderVisibleSamplerHeap.create(device,
2911 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
2912 MAX_SAMPLERS / QD3D12_FRAMES_IN_FLIGHT))
2914 qWarning(
"Could not create shader-visible SAMPLER heap");
2918 this->device = device;
2922void QD3D12SamplerManager::destroy()
2925 shaderVisibleSamplerHeap.destroy();
2930QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc)
2932 auto it = gpuMap.constFind({desc});
2933 if (it != gpuMap.cend())
2936 QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
2937 if (descriptor.isValid()) {
2938 device->CreateSampler(&desc, descriptor.cpuHandle);
2939 gpuMap.insert({desc}, descriptor);
2941 qWarning(
"Out of shader-visible SAMPLER descriptor heap space,"
2942 " this should not happen, maximum number of unique samplers is %u",
2943 shaderVisibleSamplerHeap.heap.capacity);
2949bool QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
2953 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
2954 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
2957 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
2958 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
2959 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
2962 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
2963 descriptorRanges[0].NumDescriptors = 1;
2964 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
2965 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
2966 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
2967 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
2968 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
2971 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
2972 descriptorRanges[1].NumDescriptors = 4;
2973 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
2974 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
2975 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
2976 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
2979 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
2980 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
2981 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
2982 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
2983 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
2984 samplerDesc.MaxLOD = 10000.0f;
2985 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
2987 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
2988 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
2989 rsDesc.Desc_1_1.NumParameters = 3;
2990 rsDesc.Desc_1_1.pParameters = rootParams;
2991 rsDesc.Desc_1_1.NumStaticSamplers = 1;
2992 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
2994 ID3DBlob *signature =
nullptr;
2995 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
2997 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3000 ID3D12RootSignature *rootSig =
nullptr;
3001 hr = rhiD->dev->CreateRootSignature(0,
3002 signature->GetBufferPointer(),
3003 signature->GetBufferSize(),
3004 __uuidof(ID3D12RootSignature),
3005 reinterpret_cast<
void **>(&rootSig));
3006 signature->Release();
3008 qWarning(
"Failed to create root signature: %s",
3009 qPrintable(QSystemError::windowsComString(hr)));
3013 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3015 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3016 psoDesc.pRootSignature = rootSig;
3017 psoDesc.CS.pShaderBytecode = g_csMipmap;
3018 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap);
3019 ID3D12PipelineState *pso =
nullptr;
3020 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3021 __uuidof(ID3D12PipelineState),
3022 reinterpret_cast<
void **>(&pso));
3024 qWarning(
"Failed to create compute pipeline state: %s",
3025 qPrintable(QSystemError::windowsComString(hr)));
3026 rhiD->rootSignaturePool.remove(rootSigHandle);
3031 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3036void QD3D12MipmapGenerator::destroy()
3038 rhiD->pipelinePool.remove(pipelineHandle);
3039 pipelineHandle = {};
3040 rhiD->rootSignaturePool.remove(rootSigHandle);
3044void QD3D12MipmapGenerator::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3046 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3049 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3052 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3056 const quint32 mipLevelCount = res->desc.MipLevels;
3057 if (mipLevelCount < 2)
3060 if (res->desc.SampleDesc.Count > 1) {
3061 qWarning(
"Cannot generate mipmaps for MSAA texture");
3065 const bool is1D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D;
3067 qWarning(
"Cannot generate mipmaps for 1D texture");
3071 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3072 const bool isCubeOrArray = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
3073 && res->desc.DepthOrArraySize > 1;
3074 const quint32 layerCount = isCubeOrArray ? res->desc.DepthOrArraySize : 1;
3078 qWarning(
"3D texture mipmapping is not implemented for D3D12 atm");
3082 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3083 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3085 cbD->cmdList->SetPipelineState(pipeline->pso);
3086 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3088 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3091 quint32 srcMipLevel;
3092 quint32 numMipLevels;
3097 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount * layerCount);
3098 std::optional<QD3D12StagingArea> ownStagingArea;
3099 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3100 ownStagingArea = QD3D12StagingArea();
3101 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3102 qWarning(
"Could not create staging area for mipmap generation");
3106 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3107 ? &ownStagingArea.value()
3108 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3110 bool gotNewHeap =
false;
3111 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3112 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3113 rhiD->currentFrameSlot,
3114 (1 + 4) * mipLevelCount * layerCount,
3117 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3121 rhiD->bindShaderVisibleHeaps(cbD);
3123 for (quint32 layer = 0; layer < layerCount; ++layer) {
3124 for (quint32 level = 0; level < mipLevelCount ;) {
3125 UINT subresource = calcSubresource(level, layer, res->desc.MipLevels);
3126 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3127 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3128 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3130 quint32 levelPlusOneMipWidth = res->desc.Width >> (level + 1);
3131 quint32 levelPlusOneMipHeight = res->desc.Height >> (level + 1);
3132 const quint32 dw = levelPlusOneMipWidth == 1 ? levelPlusOneMipHeight : levelPlusOneMipWidth;
3133 const quint32 dh = levelPlusOneMipHeight == 1 ? levelPlusOneMipWidth : levelPlusOneMipHeight;
3135 const quint32 additionalMips = qCountTrailingZeroBits(dw | dh);
3136 const quint32 numGenMips = qMin(1u + qMin(3u, additionalMips), res->desc.MipLevels - level);
3137 levelPlusOneMipWidth = qMax(1u, levelPlusOneMipWidth);
3138 levelPlusOneMipHeight = qMax(1u, levelPlusOneMipHeight);
3140 CBufData cbufData = {
3143 1.0f /
float(levelPlusOneMipWidth),
3144 1.0f /
float(levelPlusOneMipHeight)
3147 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3148 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3149 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3151 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3152 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3153 srvDesc.Format = res->desc.Format;
3154 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3155 if (isCubeOrArray) {
3156 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
3157 srvDesc.Texture2DArray.MostDetailedMip = level;
3158 srvDesc.Texture2DArray.MipLevels = 1;
3159 srvDesc.Texture2DArray.FirstArraySlice = layer;
3160 srvDesc.Texture2DArray.ArraySize = 1;
3162 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
3163 srvDesc.Texture3D.MostDetailedMip = level;
3164 srvDesc.Texture3D.MipLevels = 1;
3166 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
3167 srvDesc.Texture2D.MostDetailedMip = level;
3168 srvDesc.Texture2D.MipLevels = 1;
3170 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3171 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3173 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(4);
3174 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
3176 for (quint32 uavIdx = 0; uavIdx < 4; ++uavIdx) {
3177 const quint32 uavMipLevel = qMin(level + 1u + uavIdx, res->desc.MipLevels - 1u);
3178 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
3179 uavDesc.Format = res->desc.Format;
3180 if (isCubeOrArray) {
3181 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
3182 uavDesc.Texture2DArray.MipSlice = uavMipLevel;
3183 uavDesc.Texture2DArray.FirstArraySlice = layer;
3184 uavDesc.Texture2DArray.ArraySize = 1;
3186 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
3187 uavDesc.Texture3D.MipSlice = uavMipLevel;
3188 uavDesc.Texture3D.FirstWSlice = 0;
3189 uavDesc.Texture3D.WSize = 1;
3191 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
3192 uavDesc.Texture2D.MipSlice = uavMipLevel;
3194 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
3195 uavCpuHandle.ptr += descriptorByteSize;
3197 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
3199 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, 1);
3201 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
3202 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3203 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
3204 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3206 level += numGenMips;
3210 if (ownStagingArea.has_value())
3211 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
3214bool QD3D12MemoryAllocator::create(ID3D12Device *device, IDXGIAdapter1 *adapter)
3216 this->device = device;
3223 static bool disableMA = qEnvironmentVariableIntValue(
"QT_D3D_NO_SUBALLOC");
3227 DXGI_ADAPTER_DESC1 desc;
3228 adapter->GetDesc1(&desc);
3229 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
3232 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
3233 allocatorDesc.pDevice = device;
3234 allocatorDesc.pAdapter = adapter;
3237 allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED;
3238 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
3240 qWarning(
"Failed to initialize D3D12 Memory Allocator: %s",
3241 qPrintable(QSystemError::windowsComString(hr)));
3247void QD3D12MemoryAllocator::destroy()
3250 allocator->Release();
3251 allocator =
nullptr;
3255HRESULT QD3D12MemoryAllocator::createResource(D3D12_HEAP_TYPE heapType,
3256 const D3D12_RESOURCE_DESC *resourceDesc,
3257 D3D12_RESOURCE_STATES initialState,
3258 const D3D12_CLEAR_VALUE *optimizedClearValue,
3259 D3D12MA::Allocation **maybeAllocation,
3260 REFIID riidResource,
3264 D3D12MA::ALLOCATION_DESC allocDesc = {};
3265 allocDesc.HeapType = heapType;
3266 return allocator->CreateResource(&allocDesc,
3269 optimizedClearValue,
3274 *maybeAllocation =
nullptr;
3275 D3D12_HEAP_PROPERTIES heapProps = {};
3276 heapProps.Type = heapType;
3277 return device->CreateCommittedResource(&heapProps,
3278 D3D12_HEAP_FLAG_NONE,
3281 optimizedClearValue,
3287void QD3D12MemoryAllocator::getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget)
3290 allocator->GetBudget(localBudget, nonLocalBudget);
3293 *nonLocalBudget = {};
3297void QRhiD3D12::waitGpu()
3299 fullFenceCounter += 1u;
3300 if (SUCCEEDED(cmdQueue->Signal(fullFence, fullFenceCounter))) {
3301 if (SUCCEEDED(fullFence->SetEventOnCompletion(fullFenceCounter, fullFenceEvent)))
3302 WaitForSingleObject(fullFenceEvent, INFINITE);
3306DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleDesc(
int sampleCount, DXGI_FORMAT format)
const
3308 DXGI_SAMPLE_DESC desc;
3312 const int s = effectiveSampleCount(sampleCount);
3315 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
3316 msaaInfo.Format = format;
3317 msaaInfo.SampleCount = UINT(s);
3318 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo,
sizeof(msaaInfo)))) {
3319 if (msaaInfo.NumQualityLevels > 0) {
3320 desc.Count = UINT(s);
3321 desc.Quality = msaaInfo.NumQualityLevels - 1;
3323 qWarning(
"No quality levels for multisampling with sample count %d", s);
3331bool QRhiD3D12::startCommandListForCurrentFrameSlot(D3D12GraphicsCommandList **cmdList)
3333 ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
3335 HRESULT hr = dev->CreateCommandList(0,
3336 D3D12_COMMAND_LIST_TYPE_DIRECT,
3339 __uuidof(D3D12GraphicsCommandList),
3340 reinterpret_cast<
void **>(cmdList));
3342 qWarning(
"Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
3346 HRESULT hr = (*cmdList)->Reset(cmdAlloc,
nullptr);
3348 qWarning(
"Failed to reset command list: %s", qPrintable(QSystemError::windowsComString(hr)));
3355static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
3358 case DXGI_FORMAT_R8G8B8A8_UNORM:
3359 return QRhiTexture::RGBA8;
3360 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
3362 (*flags) |= QRhiTexture::sRGB;
3363 return QRhiTexture::RGBA8;
3364 case DXGI_FORMAT_B8G8R8A8_UNORM:
3365 return QRhiTexture::BGRA8;
3366 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
3368 (*flags) |= QRhiTexture::sRGB;
3369 return QRhiTexture::BGRA8;
3370 case DXGI_FORMAT_R16G16B16A16_FLOAT:
3371 return QRhiTexture::RGBA16F;
3372 case DXGI_FORMAT_R32G32B32A32_FLOAT:
3373 return QRhiTexture::RGBA32F;
3374 case DXGI_FORMAT_R10G10B10A2_UNORM:
3375 return QRhiTexture::RGB10A2;
3377 qWarning(
"DXGI_FORMAT %d cannot be read back", format);
3380 return QRhiTexture::UnknownFormat;
3383void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
3385 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
3387 for (
int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
3388 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
3389 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
3390 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3391 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
3392 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3393 if (u.offset == 0 && u.data.size() == bufD->m_size)
3394 bufD->pendingHostWrites[i].clear();
3395 bufD->pendingHostWrites[i].append({ u.offset, u.data });
3397 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
3398 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3399 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
3400 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
3408 QD3D12StagingArea::Allocation stagingAlloc;
3409 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(bufD->m_size, 1);
3410 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3411 stagingAlloc = smallStagingAreas[currentFrameSlot].get(bufD->m_size);
3413 std::optional<QD3D12StagingArea> ownStagingArea;
3414 if (!stagingAlloc.isValid()) {
3415 ownStagingArea = QD3D12StagingArea();
3416 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3418 stagingAlloc = ownStagingArea->get(allocSize);
3419 if (!stagingAlloc.isValid()) {
3420 ownStagingArea->destroy();
3425 memcpy(stagingAlloc.p + u.offset, u.data.constData(), u.data.size());
3427 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
3428 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3430 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
3431 cbD->cmdList->CopyBufferRegion(res->resource,
3433 stagingAlloc.buffer,
3434 stagingAlloc.bufferOffset + u.offset,
3438 if (ownStagingArea.has_value())
3439 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3440 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
3441 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3442 if (bufD->m_type == QRhiBuffer::Dynamic) {
3443 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
3444 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[currentFrameSlot])) {
3445 Q_ASSERT(res->cpuMapPtr);
3446 u.result->data.resize(u.readSize);
3447 memcpy(u.result->data.data(),
reinterpret_cast<
char *>(res->cpuMapPtr) + u.offset, u.readSize);
3449 if (u.result->completed)
3450 u.result->completed();
3452 QD3D12Readback readback;
3453 readback.frameSlot = currentFrameSlot;
3454 readback.result = u.result;
3455 readback.byteSize = u.readSize;
3456 const quint32 allocSize = aligned(u.readSize, QD3D12StagingArea::ALIGNMENT);
3457 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
3458 if (u.result->completed)
3459 u.result->completed();
3462 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(u.readSize);
3463 if (!stagingAlloc.isValid()) {
3464 readback.staging.destroy();
3465 if (u.result->completed)
3466 u.result->completed();
3469 Q_ASSERT(stagingAlloc.bufferOffset == 0);
3470 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
3471 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3472 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
3473 cbD->cmdList->CopyBufferRegion(stagingAlloc.buffer, 0, res->resource, u.offset, u.readSize);
3474 activeReadbacks.append(readback);
3476 readback.staging.destroy();
3477 if (u.result->completed)
3478 u.result->completed();
3484 for (
int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
3485 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
3486 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
3487 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
3488 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3489 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
3492 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
3493 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3494 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
3495 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
3496 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level])) {
3497 D3D12_SUBRESOURCE_FOOTPRINT footprint = {};
3498 footprint.Format = res->desc.Format;
3499 footprint.Depth = 1;
3500 quint32 totalBytes = 0;
3502 const QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
3503 : subresDesc.sourceSize();
3504 const QPoint srcPos = subresDesc.sourceTopLeft();
3505 QPoint dstPos = subresDesc.destinationTopLeft();
3507 if (!subresDesc.image().isNull()) {
3508 const QImage img = subresDesc.image();
3509 const int bpl = img.bytesPerLine();
3510 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3511 totalBytes = footprint.RowPitch * img.height();
3512 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3515 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3516 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3517 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3518 totalBytes = footprint.RowPitch * rowCount;
3519 }
else if (!subresDesc.data().isEmpty()) {
3521 if (subresDesc.dataStride())
3522 bpl = subresDesc.dataStride();
3524 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
3525 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3526 totalBytes = footprint.RowPitch * subresSize.height();
3528 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
3532 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(totalBytes, 1);
3533 QD3D12StagingArea::Allocation stagingAlloc;
3534 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3535 stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
3537 std::optional<QD3D12StagingArea> ownStagingArea;
3538 if (!stagingAlloc.isValid()) {
3539 ownStagingArea = QD3D12StagingArea();
3540 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3542 stagingAlloc = ownStagingArea->get(allocSize);
3543 if (!stagingAlloc.isValid()) {
3544 ownStagingArea->destroy();
3549 D3D12_TEXTURE_COPY_LOCATION dst;
3550 dst.pResource = res->resource;
3551 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3552 dst.SubresourceIndex = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
3553 D3D12_TEXTURE_COPY_LOCATION src;
3554 src.pResource = stagingAlloc.buffer;
3555 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
3556 src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
3560 if (!subresDesc.image().isNull()) {
3561 const QImage img = subresDesc.image();
3562 const int bpc = qMax(1, img.depth() / 8);
3563 const int bpl = img.bytesPerLine();
3565 QSize size = subresDesc.sourceSize().isEmpty() ? img.size() : subresDesc.sourceSize();
3566 size.setWidth(qMin(size.width(), img.width() - srcPos.x()));
3567 size.setHeight(qMin(size.height(), img.height() - srcPos.y()));
3569 footprint.Width = size.width();
3570 footprint.Height = size.height();
3574 srcBox.right = UINT(size.width());
3575 srcBox.bottom = UINT(size.height());
3579 const uchar *imgPtr = img.constBits();
3580 const quint32 lineBytes = size.width() * bpc;
3581 for (
int y = 0, h = size.height(); y < h; ++y) {
3582 memcpy(stagingAlloc.p + y * footprint.RowPitch,
3583 imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
3586 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3589 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3591 dstPos.setX(aligned(dstPos.x(), blockDim.width()));
3592 dstPos.setY(aligned(dstPos.y(), blockDim.height()));
3597 srcBox.right = aligned(subresSize.width(), blockDim.width());
3598 srcBox.bottom = aligned(subresSize.height(), blockDim.height());
3603 footprint.Width = aligned(subresSize.width(), blockDim.width());
3604 footprint.Height = aligned(subresSize.height(), blockDim.height());
3606 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
3607 const QByteArray imgData = subresDesc.data();
3608 const char *imgPtr = imgData.constData();
3609 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3610 for (
int y = 0; y < rowCount; ++y)
3611 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
3612 }
else if (!subresDesc.data().isEmpty()) {
3615 srcBox.right = subresSize.width();
3616 srcBox.bottom = subresSize.height();
3620 footprint.Width = subresSize.width();
3621 footprint.Height = subresSize.height();
3624 if (subresDesc.dataStride())
3625 bpl = subresDesc.dataStride();
3627 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
3629 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
3630 const QByteArray data = subresDesc.data();
3631 const char *imgPtr = data.constData();
3632 for (
int y = 0, h = subresSize.height(); y < h; ++y)
3633 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
3636 src.PlacedFootprint.Footprint = footprint;
3638 cbD->cmdList->CopyTextureRegion(&dst,
3641 is3D ? UINT(layer) : 0u,
3645 if (ownStagingArea.has_value())
3646 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3650 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
3651 Q_ASSERT(u.src && u.dst);
3652 QD3D12Texture *srcD = QRHI_RES(QD3D12Texture, u.src);
3653 QD3D12Texture *dstD = QRHI_RES(QD3D12Texture, u.dst);
3654 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3655 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3656 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
3657 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
3658 if (!srcRes || !dstRes)
3661 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
3662 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
3663 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3665 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
3666 srcIs3D ? 0u : UINT(u.desc.sourceLayer()),
3667 srcD->mipLevelCount);
3668 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
3669 dstIs3D ? 0u : UINT(u.desc.destinationLayer()),
3670 dstD->mipLevelCount);
3671 const QPoint dp = u.desc.destinationTopLeft();
3672 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
3673 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
3674 const QPoint sp = u.desc.sourceTopLeft();
3677 srcBox.left = UINT(sp.x());
3678 srcBox.top = UINT(sp.y());
3679 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
3681 srcBox.right = srcBox.left + UINT(copySize.width());
3682 srcBox.bottom = srcBox.top + UINT(copySize.height());
3683 srcBox.back = srcBox.front + 1;
3685 D3D12_TEXTURE_COPY_LOCATION src;
3686 src.pResource = srcRes->resource;
3687 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3688 src.SubresourceIndex = srcSubresource;
3689 D3D12_TEXTURE_COPY_LOCATION dst;
3690 dst.pResource = dstRes->resource;
3691 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3692 dst.SubresourceIndex = dstSubresource;
3694 cbD->cmdList->CopyTextureRegion(&dst,
3697 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
3700 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
3701 QD3D12Readback readback;
3702 readback.frameSlot = currentFrameSlot;
3703 readback.result = u.result;
3705 QD3D12ObjectHandle srcHandle;
3707 if (u.rb.texture()) {
3708 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.rb.texture());
3709 if (texD->sampleDesc.Count > 1) {
3710 qWarning(
"Multisample texture cannot be read back");
3713 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3714 readback.pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
3715 readback.format = texD->m_format;
3716 srcHandle = texD->handle;
3718 Q_ASSERT(currentSwapChain);
3719 readback.pixelSize = currentSwapChain->pixelSize;
3720 readback.format = swapchainReadbackTextureFormat(currentSwapChain->colorFormat,
nullptr);
3721 if (readback.format == QRhiTexture::UnknownFormat)
3723 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
3726 textureFormatInfo(readback.format,
3728 &readback.bytesPerLine,
3732 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
3736 const UINT subresource = calcSubresource(UINT(u.rb.level()),
3737 is3D ? 0u : UINT(u.rb.layer()),
3738 srcRes->desc.MipLevels);
3739 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
3742 UINT64 totalBytes = 0;
3743 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
3744 &layout,
nullptr,
nullptr, &totalBytes);
3745 readback.stagingRowPitch = layout.Footprint.RowPitch;
3747 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT);
3748 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
3749 if (u.result->completed)
3750 u.result->completed();
3753 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
3754 if (!stagingAlloc.isValid()) {
3755 readback.staging.destroy();
3756 if (u.result->completed)
3757 u.result->completed();
3760 Q_ASSERT(stagingAlloc.bufferOffset == 0);
3762 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
3763 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3765 D3D12_TEXTURE_COPY_LOCATION dst;
3766 dst.pResource = stagingAlloc.buffer;
3767 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
3768 dst.PlacedFootprint.Offset = 0;
3769 dst.PlacedFootprint.Footprint = layout.Footprint;
3771 D3D12_TEXTURE_COPY_LOCATION src;
3772 src.pResource = srcRes->resource;
3773 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3774 src.SubresourceIndex = subresource;
3776 D3D12_BOX srcBox = {};
3778 srcBox.front = UINT(u.rb.layer());
3779 srcBox.back = srcBox.front + 1;
3780 srcBox.right = readback.pixelSize.width();
3781 srcBox.bottom = readback.pixelSize.height();
3783 cbD->cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, is3D ? &srcBox :
nullptr);
3784 activeReadbacks.append(readback);
3785 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
3786 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
3787 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
3788 mipmapGen.generate(cbD, texD->handle);
3795void QRhiD3D12::finishActiveReadbacks(
bool forced)
3797 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
3799 for (
int i = activeReadbacks.size() - 1; i >= 0; --i) {
3800 QD3D12Readback &readback(activeReadbacks[i]);
3801 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
3802 readback.result->format = readback.format;
3803 readback.result->pixelSize = readback.pixelSize;
3804 readback.result->data.resize(
int(readback.byteSize));
3806 if (readback.format != QRhiTexture::UnknownFormat) {
3807 quint8 *dstPtr =
reinterpret_cast<quint8 *>(readback.result->data.data());
3808 const quint8 *srcPtr = readback.staging.mem.p;
3809 const quint32 lineSize = qMin(readback.bytesPerLine, readback.stagingRowPitch);
3810 for (
int y = 0, h = readback.pixelSize.height(); y < h; ++y)
3811 memcpy(dstPtr + y * readback.bytesPerLine, srcPtr + y * readback.stagingRowPitch, lineSize);
3813 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
3816 readback.staging.destroy();
3818 if (readback.result->completed)
3819 completedCallbacks.append(readback.result->completed);
3821 activeReadbacks.remove(i);
3825 for (
auto f : completedCallbacks)
3829bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
3830 D3D12_DESCRIPTOR_HEAP_TYPE type,
3832 quint32 neededDescriptorCount,
3840 if (h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
3841 const quint32 newPerFrameSize = qMax(h->perFrameHeapSlice[frameSlot].capacity * 2,
3842 neededDescriptorCount);
3843 QD3D12ShaderVisibleDescriptorHeap newHeap;
3844 if (!newHeap.create(dev, type, newPerFrameSize)) {
3845 qWarning(
"Could not create new shader-visible descriptor heap");
3848 h->destroyWithDeferredRelease(&releaseQueue);
3855void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
3857 ID3D12DescriptorHeap *heaps[] = {
3858 shaderVisibleCbvSrvUavHeap.heap.heap,
3859 samplerMgr.shaderVisibleSamplerHeap.heap.heap
3861 cbD->cmdList->SetDescriptorHeaps(2, heaps);
3864QD3D12Buffer::QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
3865 : QRhiBuffer(rhi, type, usage, size)
3869QD3D12Buffer::~QD3D12Buffer()
3874void QD3D12Buffer::destroy()
3876 if (handles[0].isNull())
3879 QRHI_RES_RHI(QRhiD3D12);
3888 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3890 rhiD->releaseQueue.deferredReleaseResource(handles[i]);
3892 pendingHostWrites[i].clear();
3896 rhiD->unregisterResource(
this);
3899bool QD3D12Buffer::create()
3901 if (!handles[0].isNull())
3904 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
3905 qWarning(
"UniformBuffer must always be Dynamic");
3909 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
3910 qWarning(
"StorageBuffer cannot be combined with Dynamic");
3914 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
3915 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
3917 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
3918 if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
3919 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
3921 QRHI_RES_RHI(QRhiD3D12);
3923 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3924 if (i == 0 || m_type == Dynamic) {
3925 D3D12_RESOURCE_DESC resourceDesc = {};
3926 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
3927 resourceDesc.Width = roundedSize;
3928 resourceDesc.Height = 1;
3929 resourceDesc.DepthOrArraySize = 1;
3930 resourceDesc.MipLevels = 1;
3931 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
3932 resourceDesc.SampleDesc = { 1, 0 };
3933 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
3934 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
3935 ID3D12Resource *resource =
nullptr;
3936 D3D12MA::Allocation *allocation =
nullptr;
3938 D3D12_HEAP_TYPE heapType = m_type == Dynamic
3939 ? D3D12_HEAP_TYPE_UPLOAD
3940 : D3D12_HEAP_TYPE_DEFAULT;
3941 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
3942 ? D3D12_RESOURCE_STATE_GENERIC_READ
3943 : D3D12_RESOURCE_STATE_COMMON;
3944 hr = rhiD->vma.createResource(heapType,
3950 reinterpret_cast<
void **>(&resource));
3953 if (!m_objectName.isEmpty()) {
3954 QString decoratedName = QString::fromUtf8(m_objectName);
3955 if (m_type == Dynamic) {
3956 decoratedName += QLatin1Char(
'/');
3957 decoratedName += QString::number(i);
3959 resource->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
3961 void *cpuMemPtr =
nullptr;
3962 if (m_type == Dynamic) {
3964 hr = resource->Map(0,
nullptr, &cpuMemPtr);
3966 qWarning(
"Map() failed to dynamic buffer");
3967 resource->Release();
3969 allocation->Release();
3973 handles[i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
3981 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
3982 qPrintable(QSystemError::windowsComString(hr)),
3985 int(rhiD->vma.isUsingD3D12MA()));
3989 rhiD->registerResource(
this);
3993QRhiBuffer::NativeBuffer QD3D12Buffer::nativeBuffer()
3996 Q_ASSERT(
sizeof(b.objects) /
sizeof(b.objects[0]) >= size_t(QD3D12_FRAMES_IN_FLIGHT));
3997 QRHI_RES_RHI(QRhiD3D12);
3998 if (m_type == Dynamic) {
3999 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4000 executeHostWritesForFrameSlot(i);
4001 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[i]))
4002 b.objects[i] = res->resource;
4004 b.objects[i] =
nullptr;
4006 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
4009 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[0]))
4010 b.objects[0] = res->resource;
4012 b.objects[0] =
nullptr;
4017char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
4025 Q_ASSERT(m_type == Dynamic);
4026 QRHI_RES_RHI(QRhiD3D12);
4027 Q_ASSERT(rhiD->inFrame);
4028 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
4029 return static_cast<
char *>(res->cpuMapPtr);
4034void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
4039void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
4041 if (pendingHostWrites[frameSlot].isEmpty())
4044 Q_ASSERT(m_type == QRhiBuffer::Dynamic);
4045 QRHI_RES_RHI(QRhiD3D12);
4046 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
4047 Q_ASSERT(res->cpuMapPtr);
4048 for (
const QD3D12Buffer::HostWrite &u : std::as_const(pendingHostWrites[frameSlot]))
4049 memcpy(
static_cast<
char *>(res->cpuMapPtr) + u.offset, u.data.constData(), u.data.size());
4051 pendingHostWrites[frameSlot].clear();
4054static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
4056 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
4058 case QRhiTexture::RGBA8:
4059 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
4060 case QRhiTexture::BGRA8:
4061 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
4062 case QRhiTexture::R8:
4063 return DXGI_FORMAT_R8_UNORM;
4064 case QRhiTexture::R8SI:
4065 return DXGI_FORMAT_R8_SINT;
4066 case QRhiTexture::R8UI:
4067 return DXGI_FORMAT_R8_UINT;
4068 case QRhiTexture::RG8:
4069 return DXGI_FORMAT_R8G8_UNORM;
4070 case QRhiTexture::R16:
4071 return DXGI_FORMAT_R16_UNORM;
4072 case QRhiTexture::RG16:
4073 return DXGI_FORMAT_R16G16_UNORM;
4074 case QRhiTexture::RED_OR_ALPHA8:
4075 return DXGI_FORMAT_R8_UNORM;
4077 case QRhiTexture::RGBA16F:
4078 return DXGI_FORMAT_R16G16B16A16_FLOAT;
4079 case QRhiTexture::RGBA32F:
4080 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4081 case QRhiTexture::R16F:
4082 return DXGI_FORMAT_R16_FLOAT;
4083 case QRhiTexture::R32F:
4084 return DXGI_FORMAT_R32_FLOAT;
4086 case QRhiTexture::RGB10A2:
4087 return DXGI_FORMAT_R10G10B10A2_UNORM;
4089 case QRhiTexture::R32SI:
4090 return DXGI_FORMAT_R32_SINT;
4091 case QRhiTexture::R32UI:
4092 return DXGI_FORMAT_R32_UINT;
4093 case QRhiTexture::RG32SI:
4094 return DXGI_FORMAT_R32G32_SINT;
4095 case QRhiTexture::RG32UI:
4096 return DXGI_FORMAT_R32G32_UINT;
4097 case QRhiTexture::RGBA32SI:
4098 return DXGI_FORMAT_R32G32B32A32_SINT;
4099 case QRhiTexture::RGBA32UI:
4100 return DXGI_FORMAT_R32G32B32A32_UINT;
4102 case QRhiTexture::D16:
4103 return DXGI_FORMAT_R16_TYPELESS;
4104 case QRhiTexture::D24:
4105 return DXGI_FORMAT_R24G8_TYPELESS;
4106 case QRhiTexture::D24S8:
4107 return DXGI_FORMAT_R24G8_TYPELESS;
4108 case QRhiTexture::D32F:
4109 return DXGI_FORMAT_R32_TYPELESS;
4110 case QRhiTexture::Format::D32FS8:
4111 return DXGI_FORMAT_R32G8X24_TYPELESS;
4113 case QRhiTexture::BC1:
4114 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
4115 case QRhiTexture::BC2:
4116 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
4117 case QRhiTexture::BC3:
4118 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
4119 case QRhiTexture::BC4:
4120 return DXGI_FORMAT_BC4_UNORM;
4121 case QRhiTexture::BC5:
4122 return DXGI_FORMAT_BC5_UNORM;
4123 case QRhiTexture::BC6H:
4124 return DXGI_FORMAT_BC6H_UF16;
4125 case QRhiTexture::BC7:
4126 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
4128 case QRhiTexture::ETC2_RGB8:
4129 case QRhiTexture::ETC2_RGB8A1:
4130 case QRhiTexture::ETC2_RGBA8:
4131 qWarning(
"QRhiD3D12 does not support ETC2 textures");
4132 return DXGI_FORMAT_R8G8B8A8_UNORM;
4134 case QRhiTexture::ASTC_4x4:
4135 case QRhiTexture::ASTC_5x4:
4136 case QRhiTexture::ASTC_5x5:
4137 case QRhiTexture::ASTC_6x5:
4138 case QRhiTexture::ASTC_6x6:
4139 case QRhiTexture::ASTC_8x5:
4140 case QRhiTexture::ASTC_8x6:
4141 case QRhiTexture::ASTC_8x8:
4142 case QRhiTexture::ASTC_10x5:
4143 case QRhiTexture::ASTC_10x6:
4144 case QRhiTexture::ASTC_10x8:
4145 case QRhiTexture::ASTC_10x10:
4146 case QRhiTexture::ASTC_12x10:
4147 case QRhiTexture::ASTC_12x12:
4148 qWarning(
"QRhiD3D12 does not support ASTC textures");
4149 return DXGI_FORMAT_R8G8B8A8_UNORM;
4154 return DXGI_FORMAT_R8G8B8A8_UNORM;
4157QD3D12RenderBuffer::QD3D12RenderBuffer(QRhiImplementation *rhi,
4159 const QSize &pixelSize,
4162 QRhiTexture::Format backingFormatHint)
4163 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
4167QD3D12RenderBuffer::~QD3D12RenderBuffer()
4172void QD3D12RenderBuffer::destroy()
4174 if (handle.isNull())
4177 QRHI_RES_RHI(QRhiD3D12);
4180 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->rtvPool, rtv, 1);
4181 else if (dsv.isValid())
4182 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->dsvPool, dsv, 1);
4190 rhiD->unregisterResource(
this);
4193bool QD3D12RenderBuffer::create()
4195 if (!handle.isNull())
4198 if (m_pixelSize.isEmpty())
4201 QRHI_RES_RHI(QRhiD3D12);
4204 case QRhiRenderBuffer::Color:
4206 dxgiFormat = toD3DTextureFormat(backingFormat(), {});
4207 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4208 D3D12_RESOURCE_DESC resourceDesc = {};
4209 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4210 resourceDesc.Width = UINT64(m_pixelSize.width());
4211 resourceDesc.Height = UINT(m_pixelSize.height());
4212 resourceDesc.DepthOrArraySize = 1;
4213 resourceDesc.MipLevels = 1;
4214 resourceDesc.Format = dxgiFormat;
4215 resourceDesc.SampleDesc = sampleDesc;
4216 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4217 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4218 D3D12_CLEAR_VALUE clearValue = {};
4219 clearValue.Format = dxgiFormat;
4221 ID3D12Resource *resource =
nullptr;
4222 D3D12MA::Allocation *allocation =
nullptr;
4223 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4225 D3D12_RESOURCE_STATE_RENDER_TARGET,
4228 __uuidof(ID3D12Resource),
4229 reinterpret_cast<
void **>(&resource));
4231 qWarning(
"Failed to create color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4234 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
4235 rtv = rhiD->rtvPool.allocate(1);
4238 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
4239 rtvDesc.Format = dxgiFormat;
4240 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
4241 : D3D12_RTV_DIMENSION_TEXTURE2D;
4242 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
4245 case QRhiRenderBuffer::DepthStencil:
4247 dxgiFormat = DS_FORMAT;
4248 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4249 D3D12_RESOURCE_DESC resourceDesc = {};
4250 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4251 resourceDesc.Width = UINT64(m_pixelSize.width());
4252 resourceDesc.Height = UINT(m_pixelSize.height());
4253 resourceDesc.DepthOrArraySize = 1;
4254 resourceDesc.MipLevels = 1;
4255 resourceDesc.Format = dxgiFormat;
4256 resourceDesc.SampleDesc = sampleDesc;
4257 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4258 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4259 if (m_flags.testFlag(UsedWithSwapChainOnly))
4260 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
4261 D3D12_CLEAR_VALUE clearValue = {};
4262 clearValue.Format = dxgiFormat;
4263 clearValue.DepthStencil.Depth = 1.0f;
4264 clearValue.DepthStencil.Stencil = 0;
4265 ID3D12Resource *resource =
nullptr;
4266 D3D12MA::Allocation *allocation =
nullptr;
4267 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4269 D3D12_RESOURCE_STATE_DEPTH_WRITE,
4272 __uuidof(ID3D12Resource),
4273 reinterpret_cast<
void **>(&resource));
4275 qWarning(
"Failed to create depth-stencil buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4278 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE, allocation);
4279 dsv = rhiD->dsvPool.allocate(1);
4282 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
4283 dsvDesc.Format = dxgiFormat;
4284 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
4285 : D3D12_DSV_DIMENSION_TEXTURE2D;
4286 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
4291 if (!m_objectName.isEmpty()) {
4292 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4293 const QString name = QString::fromUtf8(m_objectName);
4294 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4299 rhiD->registerResource(
this);
4303QRhiTexture::Format QD3D12RenderBuffer::backingFormat()
const
4305 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
4306 return m_backingFormatHint;
4308 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
4311QD3D12Texture::QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
4312 int arraySize,
int sampleCount, Flags flags)
4313 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
4317QD3D12Texture::~QD3D12Texture()
4322void QD3D12Texture::destroy()
4324 if (handle.isNull())
4327 QRHI_RES_RHI(QRhiD3D12);
4329 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->cbvSrvUavPool, srv, 1);
4335 rhiD->unregisterResource(
this);
4338static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
4341 case QRhiTexture::Format::D16:
4342 return DXGI_FORMAT_R16_FLOAT;
4343 case QRhiTexture::Format::D24:
4344 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4345 case QRhiTexture::Format::D24S8:
4346 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4347 case QRhiTexture::Format::D32F:
4348 return DXGI_FORMAT_R32_FLOAT;
4349 case QRhiTexture::Format::D32FS8:
4350 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
4354 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
4357static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
4361 case QRhiTexture::Format::D16:
4362 return DXGI_FORMAT_D16_UNORM;
4363 case QRhiTexture::Format::D24:
4364 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4365 case QRhiTexture::Format::D24S8:
4366 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4367 case QRhiTexture::Format::D32F:
4368 return DXGI_FORMAT_D32_FLOAT;
4369 case QRhiTexture::Format::D32FS8:
4370 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
4374 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
4377static inline bool isDepthTextureFormat(QRhiTexture::Format format)
4380 case QRhiTexture::Format::D16:
4381 case QRhiTexture::Format::D24:
4382 case QRhiTexture::Format::D24S8:
4383 case QRhiTexture::Format::D32F:
4384 case QRhiTexture::Format::D32FS8:
4391bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
4393 if (!handle.isNull())
4396 QRHI_RES_RHI(QRhiD3D12);
4397 if (!rhiD->isTextureFormatSupported(m_format, m_flags))
4400 const bool isDepth = isDepthTextureFormat(m_format);
4401 const bool isCube = m_flags.testFlag(CubeMap);
4402 const bool is3D = m_flags.testFlag(ThreeDimensional);
4403 const bool isArray = m_flags.testFlag(TextureArray);
4404 const bool hasMipMaps = m_flags.testFlag(MipMapped);
4405 const bool is1D = m_flags.testFlag(OneDimensional);
4407 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
4408 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
4410 dxgiFormat = toD3DTextureFormat(m_format, m_flags);
4412 srvFormat = toD3DDepthTextureSRVFormat(m_format);
4413 rtFormat = toD3DDepthTextureDSVFormat(m_format);
4415 srvFormat = dxgiFormat;
4416 rtFormat = dxgiFormat;
4418 if (m_writeViewFormat.format != UnknownFormat) {
4420 rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
4422 rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
4424 if (m_readViewFormat.format != UnknownFormat) {
4426 srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
4428 srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
4431 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
4432 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4433 if (sampleDesc.Count > 1) {
4435 qWarning(
"Cubemap texture cannot be multisample");
4439 qWarning(
"3D texture cannot be multisample");
4443 qWarning(
"Multisample texture cannot have mipmaps");
4447 if (isDepth && hasMipMaps) {
4448 qWarning(
"Depth texture cannot have mipmaps");
4451 if (isCube && is3D) {
4452 qWarning(
"Texture cannot be both cube and 3D");
4455 if (isArray && is3D) {
4456 qWarning(
"Texture cannot be both array and 3D");
4459 if (isCube && is1D) {
4460 qWarning(
"Texture cannot be both cube and 1D");
4464 qWarning(
"Texture cannot be both 1D and 3D");
4467 if (m_depth > 1 && !is3D) {
4468 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
4471 if (m_arraySize > 0 && !isArray) {
4472 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
4475 if (m_arraySize < 1 && isArray) {
4476 qWarning(
"Texture is an array but array size is %d", m_arraySize);
4481 *adjustedSize = size;
4486bool QD3D12Texture::finishCreate()
4488 QRHI_RES_RHI(QRhiD3D12);
4489 const bool isCube = m_flags.testFlag(CubeMap);
4490 const bool is3D = m_flags.testFlag(ThreeDimensional);
4491 const bool isArray = m_flags.testFlag(TextureArray);
4492 const bool is1D = m_flags.testFlag(OneDimensional);
4494 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4495 srvDesc.Format = srvFormat;
4496 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4499 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
4500 srvDesc.TextureCube.MipLevels = mipLevelCount;
4504 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
4505 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
4506 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4507 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4508 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
4510 srvDesc.Texture1DArray.FirstArraySlice = 0;
4511 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
4514 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
4515 srvDesc.Texture1D.MipLevels = mipLevelCount;
4517 }
else if (isArray) {
4518 if (sampleDesc.Count > 1) {
4519 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
4520 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4521 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
4522 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
4524 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
4525 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
4528 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
4529 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
4530 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4531 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4532 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
4534 srvDesc.Texture2DArray.FirstArraySlice = 0;
4535 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
4539 if (sampleDesc.Count > 1) {
4540 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
4542 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4543 srvDesc.Texture3D.MipLevels = mipLevelCount;
4545 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
4546 srvDesc.Texture2D.MipLevels = mipLevelCount;
4551 srv = rhiD->cbvSrvUavPool.allocate(1);
4555 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4556 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4557 if (!m_objectName.isEmpty()) {
4558 const QString name = QString::fromUtf8(m_objectName);
4559 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4569bool QD3D12Texture::create()
4572 if (!prepareCreate(&size))
4575 const bool isDepth = isDepthTextureFormat(m_format);
4576 const bool isCube = m_flags.testFlag(CubeMap);
4577 const bool is3D = m_flags.testFlag(ThreeDimensional);
4578 const bool isArray = m_flags.testFlag(TextureArray);
4579 const bool is1D = m_flags.testFlag(OneDimensional);
4581 QRHI_RES_RHI(QRhiD3D12);
4583 bool needsOptimizedClearValueSpecified =
false;
4584 UINT resourceFlags = 0;
4585 if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
4587 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4589 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4590 needsOptimizedClearValueSpecified =
true;
4592 if (m_flags.testFlag(UsedWithGenerateMips)) {
4594 qWarning(
"Depth texture cannot have mipmaps generated");
4597 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4599 if (m_flags.testFlag(UsedWithLoadStore))
4600 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4602 D3D12_RESOURCE_DESC resourceDesc = {};
4603 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
4604 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
4605 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
4606 resourceDesc.Width = UINT64(size.width());
4607 resourceDesc.Height = UINT(size.height());
4608 resourceDesc.DepthOrArraySize = isCube ? 6
4609 : (isArray ? UINT(qMax(0, m_arraySize))
4610 : (is3D ? qMax(1, m_depth)
4612 resourceDesc.MipLevels = mipLevelCount;
4613 resourceDesc.Format = dxgiFormat;
4614 resourceDesc.SampleDesc = sampleDesc;
4615 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4616 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
4617 D3D12_CLEAR_VALUE clearValue = {};
4618 clearValue.Format = dxgiFormat;
4620 clearValue.Format = toD3DDepthTextureDSVFormat(m_format);
4621 clearValue.DepthStencil.Depth = 1.0f;
4622 clearValue.DepthStencil.Stencil = 0;
4624 ID3D12Resource *resource =
nullptr;
4625 D3D12MA::Allocation *allocation =
nullptr;
4626 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4628 D3D12_RESOURCE_STATE_COMMON,
4629 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
4631 __uuidof(ID3D12Resource),
4632 reinterpret_cast<
void **>(&resource));
4634 qWarning(
"Failed to create texture: '%s'"
4635 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
4636 qPrintable(QSystemError::windowsComString(hr)),
4637 int(resourceDesc.Dimension),
4638 uint(resourceDesc.Width),
4639 uint(resourceDesc.Height),
4640 uint(resourceDesc.DepthOrArraySize),
4641 uint(resourceDesc.MipLevels),
4642 int(resourceDesc.Format),
4643 int(resourceDesc.SampleDesc.Count));
4647 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON, allocation);
4649 if (!finishCreate())
4652 rhiD->registerResource(
this);
4656bool QD3D12Texture::createFrom(QRhiTexture::NativeTexture src)
4661 if (!prepareCreate())
4664 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *>(src.object);
4665 D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(src.layout);
4667 QRHI_RES_RHI(QRhiD3D12);
4668 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource, state);
4670 if (!finishCreate())
4673 rhiD->registerResource(
this);
4677QRhiTexture::NativeTexture QD3D12Texture::nativeTexture()
4679 QRHI_RES_RHI(QRhiD3D12);
4680 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
4681 return { quint64(res->resource),
int(res->state) };
4686void QD3D12Texture::setNativeLayout(
int layout)
4688 QRHI_RES_RHI(QRhiD3D12);
4689 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
4690 res->state = D3D12_RESOURCE_STATES(layout);
4693QD3D12Sampler::QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
4694 AddressMode u, AddressMode v, AddressMode w)
4695 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
4699QD3D12Sampler::~QD3D12Sampler()
4704void QD3D12Sampler::destroy()
4706 shaderVisibleDescriptor = {};
4708 QRHI_RES_RHI(QRhiD3D12);
4710 rhiD->unregisterResource(
this);
4713static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
4715 if (minFilter == QRhiSampler::Nearest) {
4716 if (magFilter == QRhiSampler::Nearest) {
4717 if (mipFilter == QRhiSampler::Linear)
4718 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
4720 return D3D12_FILTER_MIN_MAG_MIP_POINT;
4722 if (mipFilter == QRhiSampler::Linear)
4723 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
4725 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
4728 if (magFilter == QRhiSampler::Nearest) {
4729 if (mipFilter == QRhiSampler::Linear)
4730 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
4732 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
4734 if (mipFilter == QRhiSampler::Linear)
4735 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
4737 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
4740 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
4743static inline D3D12_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
4746 case QRhiSampler::Repeat:
4747 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
4748 case QRhiSampler::ClampToEdge:
4749 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4750 case QRhiSampler::Mirror:
4751 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
4753 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
4756static inline D3D12_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
4759 case QRhiSampler::Never:
4760 return D3D12_COMPARISON_FUNC_NEVER;
4761 case QRhiSampler::Less:
4762 return D3D12_COMPARISON_FUNC_LESS;
4763 case QRhiSampler::Equal:
4764 return D3D12_COMPARISON_FUNC_EQUAL;
4765 case QRhiSampler::LessOrEqual:
4766 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
4767 case QRhiSampler::Greater:
4768 return D3D12_COMPARISON_FUNC_GREATER;
4769 case QRhiSampler::NotEqual:
4770 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
4771 case QRhiSampler::GreaterOrEqual:
4772 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
4773 case QRhiSampler::Always:
4774 return D3D12_COMPARISON_FUNC_ALWAYS;
4776 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
4779bool QD3D12Sampler::create()
4782 desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
4783 if (m_compareOp != Never)
4784 desc.Filter = D3D12_FILTER(desc.Filter | 0x80);
4785 desc.AddressU = toD3DAddressMode(m_addressU);
4786 desc.AddressV = toD3DAddressMode(m_addressV);
4787 desc.AddressW = toD3DAddressMode(m_addressW);
4788 desc.MaxAnisotropy = 1.0f;
4789 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
4790 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
4792 QRHI_RES_RHI(QRhiD3D12);
4793 rhiD->registerResource(
this,
false);
4797QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
4799 if (!shaderVisibleDescriptor.isValid()) {
4800 QRHI_RES_RHI(QRhiD3D12);
4801 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(desc);
4803 return shaderVisibleDescriptor;
4806QD3D12ShadingRateMap::QD3D12ShadingRateMap(QRhiImplementation *rhi)
4807 : QRhiShadingRateMap(rhi)
4811QD3D12ShadingRateMap::~QD3D12ShadingRateMap()
4816void QD3D12ShadingRateMap::destroy()
4818 if (handle.isNull())
4824bool QD3D12ShadingRateMap::createFrom(QRhiTexture *src)
4826 if (!handle.isNull())
4829 handle = QRHI_RES(QD3D12Texture, src)->handle;
4834QD3D12TextureRenderTarget::QD3D12TextureRenderTarget(QRhiImplementation *rhi,
4835 const QRhiTextureRenderTargetDescription &desc,
4837 : QRhiTextureRenderTarget(rhi, desc, flags),
4842QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
4847void QD3D12TextureRenderTarget::destroy()
4849 if (!rtv[0].isValid() && !dsv.isValid())
4852 QRHI_RES_RHI(QRhiD3D12);
4853 if (dsv.isValid()) {
4854 if (ownsDsv && rhiD)
4855 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
4859 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i) {
4860 if (rtv[i].isValid()) {
4861 if (ownsRtv[i] && rhiD)
4862 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[i], 1);
4868 rhiD->unregisterResource(
this);
4871QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDescriptor()
4875 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
4877 rpD->colorAttachmentCount = 0;
4878 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it) {
4879 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
4880 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
4882 rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
4884 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
4885 rpD->colorAttachmentCount += 1;
4888 rpD->hasDepthStencil =
false;
4889 if (m_desc.depthStencilBuffer()) {
4890 rpD->hasDepthStencil =
true;
4891 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
4892 }
else if (m_desc.depthTexture()) {
4893 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
4894 rpD->hasDepthStencil =
true;
4895 rpD->dsFormat = toD3DDepthTextureDSVFormat(depthTexD->format());
4898 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
4900 rpD->updateSerializedFormat();
4902 QRHI_RES_RHI(QRhiD3D12);
4903 rhiD->registerResource(rpD);
4907bool QD3D12TextureRenderTarget::create()
4909 if (rtv[0].isValid() || dsv.isValid())
4912 QRHI_RES_RHI(QRhiD3D12);
4913 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
4914 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
4915 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
4916 d.colorAttCount = 0;
4919 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
4920 d.colorAttCount += 1;
4921 const QRhiColorAttachment &colorAtt(*it);
4922 QRhiTexture *texture = colorAtt.texture();
4923 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
4924 Q_ASSERT(texture || rb);
4926 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, texture);
4927 QD3D12Resource *res = rhiD->resourcePool.lookupRef(texD->handle);
4929 qWarning(
"Could not look up texture handle for render target");
4932 const bool isMultiView = it->multiViewCount() >= 2;
4933 UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
4934 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
4935 rtvDesc.Format = texD->rtFormat;
4936 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
4937 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
4938 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
4939 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
4940 rtvDesc.Texture2DArray.ArraySize = layerCount;
4941 }
else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
4942 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
4943 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
4944 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
4945 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
4946 rtvDesc.Texture1DArray.ArraySize = layerCount;
4948 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
4949 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
4951 }
else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
4952 if (texD->sampleDesc.Count > 1) {
4953 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
4954 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
4955 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
4957 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
4958 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
4959 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
4960 rtvDesc.Texture2DArray.ArraySize = layerCount;
4962 }
else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
4963 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
4964 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
4965 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
4966 rtvDesc.Texture3D.WSize = layerCount;
4968 if (texD->sampleDesc.Count > 1) {
4969 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
4971 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
4972 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
4975 rtv[attIndex] = rhiD->rtvPool.allocate(1);
4976 if (!rtv[attIndex].isValid()) {
4977 qWarning(
"Failed to allocate RTV for texture render target");
4980 rhiD->dev->CreateRenderTargetView(res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
4981 ownsRtv[attIndex] =
true;
4982 if (attIndex == 0) {
4983 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
4984 d.sampleCount =
int(texD->sampleDesc.Count);
4987 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rb);
4988 ownsRtv[attIndex] =
false;
4989 rtv[attIndex] = rbD->rtv;
4990 if (attIndex == 0) {
4991 d.pixelSize = rbD->pixelSize();
4992 d.sampleCount =
int(rbD->sampleDesc.Count);
4999 if (hasDepthStencil) {
5000 if (m_desc.depthTexture()) {
5002 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5003 QD3D12Resource *res = rhiD->resourcePool.lookupRef(depthTexD->handle);
5005 qWarning(
"Could not look up depth texture handle");
5008 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5009 dsvDesc.Format = depthTexD->rtFormat;
5010 dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
5011 : D3D12_DSV_DIMENSION_TEXTURE2D;
5012 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
5013 if (depthTexD->sampleDesc.Count > 1) {
5014 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
5015 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5016 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5017 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5019 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
5020 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5023 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
5024 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5025 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5026 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5028 dsvDesc.Texture2DArray.FirstArraySlice = 0;
5029 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5033 dsv = rhiD->dsvPool.allocate(1);
5034 if (!dsv.isValid()) {
5035 qWarning(
"Failed to allocate DSV for texture render target");
5038 rhiD->dev->CreateDepthStencilView(res->resource, &dsvDesc, dsv.cpuHandle);
5039 if (d.colorAttCount == 0) {
5040 d.pixelSize = depthTexD->pixelSize();
5041 d.sampleCount =
int(depthTexD->sampleDesc.Count);
5045 QD3D12RenderBuffer *depthRbD = QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
5046 dsv = depthRbD->dsv;
5047 if (d.colorAttCount == 0) {
5048 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
5049 d.sampleCount =
int(depthRbD->sampleDesc.Count);
5057 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
5058 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i)
5059 d.rtv[i] = i < d.colorAttCount ? rtv[i].cpuHandle : nullDescHandle;
5060 d.dsv = dsv.cpuHandle;
5061 d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
5063 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &d.currentResIdList);
5065 rhiD->registerResource(
this);
5069QSize QD3D12TextureRenderTarget::pixelSize()
const
5071 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc, d.currentResIdList))
5072 const_cast<QD3D12TextureRenderTarget *>(
this)->create();
5077float QD3D12TextureRenderTarget::devicePixelRatio()
const
5082int QD3D12TextureRenderTarget::sampleCount()
const
5084 return d.sampleCount;
5087QD3D12ShaderResourceBindings::QD3D12ShaderResourceBindings(QRhiImplementation *rhi)
5088 : QRhiShaderResourceBindings(rhi)
5092QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
5097void QD3D12ShaderResourceBindings::destroy()
5099 QRHI_RES_RHI(QRhiD3D12);
5101 rhiD->unregisterResource(
this);
5104bool QD3D12ShaderResourceBindings::create()
5106 QRHI_RES_RHI(QRhiD3D12);
5107 if (!rhiD->sanityCheckShaderResourceBindings(
this))
5110 rhiD->updateLayoutDesc(
this);
5112 hasDynamicOffset =
false;
5113 for (
const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
5114 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
5115 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
5116 hasDynamicOffset =
true;
5130 rhiD->registerResource(
this,
false);
5134void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
5145void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
5146 const QRhiShaderResourceBinding::Data::UniformBufferData &,
5150 D3D12_ROOT_PARAMETER1 rootParam = {};
5151 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
5152 rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
5153 rootParam.Descriptor.ShaderRegister = shaderRegister;
5154 rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
5155 visitorData.cbParams[s].append(rootParam);
5158void QD3D12ShaderResourceBindings::visitTexture(QD3D12Stage s,
5159 const QRhiShaderResourceBinding::TextureAndSampler &,
5162 D3D12_DESCRIPTOR_RANGE1 range = {};
5163 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
5164 range.NumDescriptors = 1;
5165 range.BaseShaderRegister = shaderRegister;
5166 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[s];
5167 visitorData.currentSrvRangeOffset[s] += 1;
5168 visitorData.srvRanges[s].append(range);
5169 if (visitorData.srvRanges[s].count() == 1) {
5170 visitorData.srvTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5171 visitorData.srvTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5175void QD3D12ShaderResourceBindings::visitSampler(QD3D12Stage s,
5176 const QRhiShaderResourceBinding::TextureAndSampler &,
5182 int &rangeStoreIdx(visitorData.samplerRangeHeads[s]);
5183 if (rangeStoreIdx == 16) {
5184 qWarning(
"Sampler count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi", s);
5187 D3D12_DESCRIPTOR_RANGE1 range = {};
5188 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
5189 range.NumDescriptors = 1;
5190 range.BaseShaderRegister = shaderRegister;
5191 visitorData.samplerRanges[s][rangeStoreIdx] = range;
5192 D3D12_ROOT_PARAMETER1 param = {};
5193 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5194 param.ShaderVisibility = qd3d12_stageToVisibility(s);
5195 param.DescriptorTable.NumDescriptorRanges = 1;
5196 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[s][rangeStoreIdx];
5198 visitorData.samplerTables[s].append(param);
5201void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage s,
5202 const QRhiShaderResourceBinding::Data::StorageBufferData &,
5203 QD3D12ShaderResourceVisitor::StorageOp,
5206 D3D12_DESCRIPTOR_RANGE1 range = {};
5207 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5208 range.NumDescriptors = 1;
5209 range.BaseShaderRegister = shaderRegister;
5210 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5211 visitorData.currentUavRangeOffset[s] += 1;
5212 visitorData.uavRanges[s].append(range);
5213 if (visitorData.uavRanges[s].count() == 1) {
5214 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5215 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5219void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage s,
5220 const QRhiShaderResourceBinding::Data::StorageImageData &,
5221 QD3D12ShaderResourceVisitor::StorageOp,
5224 D3D12_DESCRIPTOR_RANGE1 range = {};
5225 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5226 range.NumDescriptors = 1;
5227 range.BaseShaderRegister = shaderRegister;
5228 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5229 visitorData.currentUavRangeOffset[s] += 1;
5230 visitorData.uavRanges[s].append(range);
5231 if (visitorData.uavRanges[s].count() == 1) {
5232 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5233 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5237QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
5240 QRHI_RES_RHI(QRhiD3D12);
5254 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
5258 using namespace std::placeholders;
5259 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
5260 visitor.texture = std::bind(&QD3D12ShaderResourceBindings::visitTexture,
this, _1, _2, _3);
5261 visitor.sampler = std::bind(&QD3D12ShaderResourceBindings::visitSampler,
this, _1, _2, _3);
5262 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
5263 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
5287 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> rootParams;
5288 for (
int s = 0; s < 6; ++s) {
5289 if (!visitorData.cbParams[s].isEmpty())
5290 rootParams.append(visitorData.cbParams[s].constData(), visitorData.cbParams[s].count());
5292 for (
int s = 0; s < 6; ++s) {
5293 if (!visitorData.srvRanges[s].isEmpty()) {
5294 visitorData.srvTables[s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[s].count();
5295 visitorData.srvTables[s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[s].constData();
5296 rootParams.append(visitorData.srvTables[s]);
5299 for (
int s = 0; s < 6; ++s) {
5300 if (!visitorData.samplerTables[s].isEmpty())
5301 rootParams.append(visitorData.samplerTables[s].constData(), visitorData.samplerTables[s].count());
5303 for (
int s = 0; s < 6; ++s) {
5304 if (!visitorData.uavRanges[s].isEmpty()) {
5305 visitorData.uavTables[s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[s].count();
5306 visitorData.uavTables[s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[s].constData();
5307 rootParams.append(visitorData.uavTables[s]);
5311 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
5312 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
5313 if (!rootParams.isEmpty()) {
5314 rsDesc.Desc_1_1.NumParameters = rootParams.count();
5315 rsDesc.Desc_1_1.pParameters = rootParams.constData();
5319 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
5320 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
5321 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
5323 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
5325 ID3DBlob *signature =
nullptr;
5326 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
5328 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5331 ID3D12RootSignature *rootSig =
nullptr;
5332 hr = rhiD->dev->CreateRootSignature(0,
5333 signature->GetBufferPointer(),
5334 signature->GetBufferSize(),
5335 __uuidof(ID3D12RootSignature),
5336 reinterpret_cast<
void **>(&rootSig));
5337 signature->Release();
5339 qWarning(
"Failed to create root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5343 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
5355static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
5357 const int smMajor = version / 10;
5358 const int smMinor = version % 10;
5359 target[0] = stage[0];
5360 target[1] = stage[1];
5362 target[3] =
'0' + smMajor;
5364 target[5] =
'0' + smMinor;
5368enum class HlslCompileFlag
5370 WithDebugInfo = 0x01
5373static QByteArray legacyCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5375 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
5377 qWarning(
"Unable to resolve function D3DCompile()");
5378 return QByteArray();
5381 ID3DBlob *bytecode =
nullptr;
5382 ID3DBlob *errors =
nullptr;
5383 UINT d3dCompileFlags = 0;
5384 if (flags &
int(HlslCompileFlag::WithDebugInfo))
5385 d3dCompileFlags |= D3DCOMPILE_DEBUG;
5387 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
5388 nullptr,
nullptr,
nullptr,
5389 hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
5390 if (FAILED(hr) || !bytecode) {
5391 qWarning(
"HLSL shader compilation failed: 0x%x", uint(hr));
5393 *error = QString::fromUtf8(
static_cast<
const char *>(errors->GetBufferPointer()),
5394 int(errors->GetBufferSize()));
5397 return QByteArray();
5401 result.resize(
int(bytecode->GetBufferSize()));
5402 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
5403 bytecode->Release();
5407#ifdef QRHI_D3D12_HAS_DXC
5410#define DXC_CP_UTF8 65001
5413#ifndef DXC_ARG_DEBUG
5414#define DXC_ARG_DEBUG L"-Zi"
5417static QByteArray dxcCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5419 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
5420 IDxcCompiler *compiler = dxc.first;
5422 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
5423 "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
5424 return QByteArray();
5426 IDxcLibrary *library = dxc.second;
5428 return QByteArray();
5430 IDxcBlobEncoding *sourceBlob =
nullptr;
5431 HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
5432 UINT32(hlslSource.shader().size()),
5436 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
5438 qPrintable(QSystemError::windowsComString(hr)));
5439 return QByteArray();
5442 const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
5443 const QString targetStr = QString::fromLatin1(target);
5445 QVarLengthArray<LPCWSTR, 4> argPtrs;
5447 if (flags &
int(HlslCompileFlag::WithDebugInfo)) {
5448 debugArg = QString::fromUtf16(
reinterpret_cast<
const char16_t *>(DXC_ARG_DEBUG));
5449 argPtrs.append(
reinterpret_cast<LPCWSTR>(debugArg.utf16()));
5452 IDxcOperationResult *result =
nullptr;
5453 hr = compiler->Compile(sourceBlob,
5455 reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
5456 reinterpret_cast<LPCWSTR>(targetStr.utf16()),
5457 argPtrs.data(), argPtrs.count(),
5461 sourceBlob->Release();
5463 result->GetStatus(&hr);
5465 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
5467 qPrintable(QSystemError::windowsComString(hr)));
5469 IDxcBlobEncoding *errorsBlob =
nullptr;
5470 if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
5472 *error = QString::fromUtf8(
static_cast<
const char *>(errorsBlob->GetBufferPointer()),
5473 int(errorsBlob->GetBufferSize()));
5474 errorsBlob->Release();
5478 return QByteArray();
5481 IDxcBlob *bytecode =
nullptr;
5482 if FAILED(result->GetResult(&bytecode)) {
5483 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
5485 qPrintable(QSystemError::windowsComString(hr)));
5486 return QByteArray();
5490 ba.resize(
int(bytecode->GetBufferSize()));
5491 memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
5492 bytecode->Release();
5498static QByteArray compileHlslShaderSource(
const QShader &shader,
5499 QShader::Variant shaderVariant,
5502 QShaderKey *usedShaderKey)
5505 const int shaderModelMax = 67;
5506 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5507 for (QShader::Source type : { QShader::DxilShader, QShader::DxbcShader }) {
5508 QShaderKey key = { type, sm, shaderVariant };
5509 QShaderCode intermediateBytecodeShader = shader.shader(key);
5510 if (!intermediateBytecodeShader.shader().isEmpty()) {
5512 *usedShaderKey = key;
5513 return intermediateBytecodeShader.shader();
5518 QShaderCode hlslSource;
5520 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5521 key = { QShader::HlslShader, sm, shaderVariant };
5522 hlslSource = shader.shader(key);
5523 if (!hlslSource.shader().isEmpty())
5527 if (hlslSource.shader().isEmpty()) {
5528 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" << shader;
5529 return QByteArray();
5533 *usedShaderKey = key;
5536 switch (shader.stage()) {
5537 case QShader::VertexStage:
5538 makeHlslTargetString(target,
"vs", key.sourceVersion().version());
5540 case QShader::TessellationControlStage:
5541 makeHlslTargetString(target,
"hs", key.sourceVersion().version());
5543 case QShader::TessellationEvaluationStage:
5544 makeHlslTargetString(target,
"ds", key.sourceVersion().version());
5546 case QShader::GeometryStage:
5547 makeHlslTargetString(target,
"gs", key.sourceVersion().version());
5549 case QShader::FragmentStage:
5550 makeHlslTargetString(target,
"ps", key.sourceVersion().version());
5552 case QShader::ComputeStage:
5553 makeHlslTargetString(target,
"cs", key.sourceVersion().version());
5557 if (key.sourceVersion().version() >= 60) {
5558#ifdef QRHI_D3D12_HAS_DXC
5559 return dxcCompile(hlslSource, target, flags, error);
5561 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
5562 "but the Qt build has no support for DXC. "
5563 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
5567 return legacyCompile(hlslSource, target, flags, error);
5570static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
5573 if (c.testFlag(QRhiGraphicsPipeline::R))
5574 f |= D3D12_COLOR_WRITE_ENABLE_RED;
5575 if (c.testFlag(QRhiGraphicsPipeline::G))
5576 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
5577 if (c.testFlag(QRhiGraphicsPipeline::B))
5578 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
5579 if (c.testFlag(QRhiGraphicsPipeline::A))
5580 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
5584static inline D3D12_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f,
bool rgb)
5593 case QRhiGraphicsPipeline::Zero:
5594 return D3D12_BLEND_ZERO;
5595 case QRhiGraphicsPipeline::One:
5596 return D3D12_BLEND_ONE;
5597 case QRhiGraphicsPipeline::SrcColor:
5598 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
5599 case QRhiGraphicsPipeline::OneMinusSrcColor:
5600 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
5601 case QRhiGraphicsPipeline::DstColor:
5602 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
5603 case QRhiGraphicsPipeline::OneMinusDstColor:
5604 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
5605 case QRhiGraphicsPipeline::SrcAlpha:
5606 return D3D12_BLEND_SRC_ALPHA;
5607 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
5608 return D3D12_BLEND_INV_SRC_ALPHA;
5609 case QRhiGraphicsPipeline::DstAlpha:
5610 return D3D12_BLEND_DEST_ALPHA;
5611 case QRhiGraphicsPipeline::OneMinusDstAlpha:
5612 return D3D12_BLEND_INV_DEST_ALPHA;
5613 case QRhiGraphicsPipeline::ConstantColor:
5614 case QRhiGraphicsPipeline::ConstantAlpha:
5615 return D3D12_BLEND_BLEND_FACTOR;
5616 case QRhiGraphicsPipeline::OneMinusConstantColor:
5617 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
5618 return D3D12_BLEND_INV_BLEND_FACTOR;
5619 case QRhiGraphicsPipeline::SrcAlphaSaturate:
5620 return D3D12_BLEND_SRC_ALPHA_SAT;
5621 case QRhiGraphicsPipeline::Src1Color:
5622 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
5623 case QRhiGraphicsPipeline::OneMinusSrc1Color:
5624 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
5625 case QRhiGraphicsPipeline::Src1Alpha:
5626 return D3D12_BLEND_SRC1_ALPHA;
5627 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
5628 return D3D12_BLEND_INV_SRC1_ALPHA;
5630 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
5633static inline D3D12_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
5636 case QRhiGraphicsPipeline::Add:
5637 return D3D12_BLEND_OP_ADD;
5638 case QRhiGraphicsPipeline::Subtract:
5639 return D3D12_BLEND_OP_SUBTRACT;
5640 case QRhiGraphicsPipeline::ReverseSubtract:
5641 return D3D12_BLEND_OP_REV_SUBTRACT;
5642 case QRhiGraphicsPipeline::Min:
5643 return D3D12_BLEND_OP_MIN;
5644 case QRhiGraphicsPipeline::Max:
5645 return D3D12_BLEND_OP_MAX;
5647 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
5650static inline D3D12_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
5653 case QRhiGraphicsPipeline::None:
5654 return D3D12_CULL_MODE_NONE;
5655 case QRhiGraphicsPipeline::Front:
5656 return D3D12_CULL_MODE_FRONT;
5657 case QRhiGraphicsPipeline::Back:
5658 return D3D12_CULL_MODE_BACK;
5660 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
5663static inline D3D12_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
5666 case QRhiGraphicsPipeline::Fill:
5667 return D3D12_FILL_MODE_SOLID;
5668 case QRhiGraphicsPipeline::Line:
5669 return D3D12_FILL_MODE_WIREFRAME;
5671 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
5674static inline D3D12_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
5677 case QRhiGraphicsPipeline::Never:
5678 return D3D12_COMPARISON_FUNC_NEVER;
5679 case QRhiGraphicsPipeline::Less:
5680 return D3D12_COMPARISON_FUNC_LESS;
5681 case QRhiGraphicsPipeline::Equal:
5682 return D3D12_COMPARISON_FUNC_EQUAL;
5683 case QRhiGraphicsPipeline::LessOrEqual:
5684 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5685 case QRhiGraphicsPipeline::Greater:
5686 return D3D12_COMPARISON_FUNC_GREATER;
5687 case QRhiGraphicsPipeline::NotEqual:
5688 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5689 case QRhiGraphicsPipeline::GreaterOrEqual:
5690 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5691 case QRhiGraphicsPipeline::Always:
5692 return D3D12_COMPARISON_FUNC_ALWAYS;
5694 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
5697static inline D3D12_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
5700 case QRhiGraphicsPipeline::StencilZero:
5701 return D3D12_STENCIL_OP_ZERO;
5702 case QRhiGraphicsPipeline::Keep:
5703 return D3D12_STENCIL_OP_KEEP;
5704 case QRhiGraphicsPipeline::Replace:
5705 return D3D12_STENCIL_OP_REPLACE;
5706 case QRhiGraphicsPipeline::IncrementAndClamp:
5707 return D3D12_STENCIL_OP_INCR_SAT;
5708 case QRhiGraphicsPipeline::DecrementAndClamp:
5709 return D3D12_STENCIL_OP_DECR_SAT;
5710 case QRhiGraphicsPipeline::Invert:
5711 return D3D12_STENCIL_OP_INVERT;
5712 case QRhiGraphicsPipeline::IncrementAndWrap:
5713 return D3D12_STENCIL_OP_INCR;
5714 case QRhiGraphicsPipeline::DecrementAndWrap:
5715 return D3D12_STENCIL_OP_DECR;
5717 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
5720static inline D3D12_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t,
int patchControlPointCount)
5723 case QRhiGraphicsPipeline::Triangles:
5724 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
5725 case QRhiGraphicsPipeline::TriangleStrip:
5726 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
5727 case QRhiGraphicsPipeline::TriangleFan:
5728 qWarning(
"Triangle fans are not supported with D3D");
5729 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
5730 case QRhiGraphicsPipeline::Lines:
5731 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
5732 case QRhiGraphicsPipeline::LineStrip:
5733 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
5734 case QRhiGraphicsPipeline::Points:
5735 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
5736 case QRhiGraphicsPipeline::Patches:
5737 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
5738 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
5740 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
5743static inline D3D12_PRIMITIVE_TOPOLOGY_TYPE toD3DTopologyType(QRhiGraphicsPipeline::Topology t)
5746 case QRhiGraphicsPipeline::Triangles:
5747 case QRhiGraphicsPipeline::TriangleStrip:
5748 case QRhiGraphicsPipeline::TriangleFan:
5749 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
5750 case QRhiGraphicsPipeline::Lines:
5751 case QRhiGraphicsPipeline::LineStrip:
5752 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
5753 case QRhiGraphicsPipeline::Points:
5754 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
5755 case QRhiGraphicsPipeline::Patches:
5756 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
5758 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
5761static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
5764 case QRhiVertexInputAttribute::Float4:
5765 return DXGI_FORMAT_R32G32B32A32_FLOAT;
5766 case QRhiVertexInputAttribute::Float3:
5767 return DXGI_FORMAT_R32G32B32_FLOAT;
5768 case QRhiVertexInputAttribute::Float2:
5769 return DXGI_FORMAT_R32G32_FLOAT;
5770 case QRhiVertexInputAttribute::Float:
5771 return DXGI_FORMAT_R32_FLOAT;
5772 case QRhiVertexInputAttribute::UNormByte4:
5773 return DXGI_FORMAT_R8G8B8A8_UNORM;
5774 case QRhiVertexInputAttribute::UNormByte2:
5775 return DXGI_FORMAT_R8G8_UNORM;
5776 case QRhiVertexInputAttribute::UNormByte:
5777 return DXGI_FORMAT_R8_UNORM;
5778 case QRhiVertexInputAttribute::UInt4:
5779 return DXGI_FORMAT_R32G32B32A32_UINT;
5780 case QRhiVertexInputAttribute::UInt3:
5781 return DXGI_FORMAT_R32G32B32_UINT;
5782 case QRhiVertexInputAttribute::UInt2:
5783 return DXGI_FORMAT_R32G32_UINT;
5784 case QRhiVertexInputAttribute::UInt:
5785 return DXGI_FORMAT_R32_UINT;
5786 case QRhiVertexInputAttribute::SInt4:
5787 return DXGI_FORMAT_R32G32B32A32_SINT;
5788 case QRhiVertexInputAttribute::SInt3:
5789 return DXGI_FORMAT_R32G32B32_SINT;
5790 case QRhiVertexInputAttribute::SInt2:
5791 return DXGI_FORMAT_R32G32_SINT;
5792 case QRhiVertexInputAttribute::SInt:
5793 return DXGI_FORMAT_R32_SINT;
5794 case QRhiVertexInputAttribute::Half4:
5796 case QRhiVertexInputAttribute::Half3:
5797 return DXGI_FORMAT_R16G16B16A16_FLOAT;
5798 case QRhiVertexInputAttribute::Half2:
5799 return DXGI_FORMAT_R16G16_FLOAT;
5800 case QRhiVertexInputAttribute::Half:
5801 return DXGI_FORMAT_R16_FLOAT;
5802 case QRhiVertexInputAttribute::UShort4:
5804 case QRhiVertexInputAttribute::UShort3:
5805 return DXGI_FORMAT_R16G16B16A16_UINT;
5806 case QRhiVertexInputAttribute::UShort2:
5807 return DXGI_FORMAT_R16G16_UINT;
5808 case QRhiVertexInputAttribute::UShort:
5809 return DXGI_FORMAT_R16_UINT;
5810 case QRhiVertexInputAttribute::SShort4:
5812 case QRhiVertexInputAttribute::SShort3:
5813 return DXGI_FORMAT_R16G16B16A16_SINT;
5814 case QRhiVertexInputAttribute::SShort2:
5815 return DXGI_FORMAT_R16G16_SINT;
5816 case QRhiVertexInputAttribute::SShort:
5817 return DXGI_FORMAT_R16_SINT;
5819 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
5822QD3D12GraphicsPipeline::QD3D12GraphicsPipeline(QRhiImplementation *rhi)
5823 : QRhiGraphicsPipeline(rhi)
5827QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
5832void QD3D12GraphicsPipeline::destroy()
5834 if (handle.isNull())
5837 QRHI_RES_RHI(QRhiD3D12);
5839 rhiD->releaseQueue.deferredReleasePipeline(handle);
5840 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
5847 rhiD->unregisterResource(
this);
5850bool QD3D12GraphicsPipeline::create()
5852 if (!handle.isNull())
5855 QRHI_RES_RHI(QRhiD3D12);
5856 if (!rhiD->sanityCheckGraphicsPipeline(
this))
5859 rhiD->pipelineCreationStart();
5861 QByteArray shaderBytecode[5];
5862 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
5863 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
5864 stageData[d3dStage].valid =
true;
5865 stageData[d3dStage].stage = d3dStage;
5866 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
5867 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
5868 shaderBytecode[d3dStage] = cacheIt->bytecode;
5869 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
5872 QShaderKey shaderKey;
5873 int compileFlags = 0;
5874 if (m_flags.testFlag(CompileShadersWithDebugInfo))
5875 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
5876 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
5877 shaderStage.shaderVariant(),
5881 if (bytecode.isEmpty()) {
5882 qWarning(
"HLSL graphics shader compilation failed: %s", qPrintable(error));
5886 shaderBytecode[d3dStage] = bytecode;
5887 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
5888 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
5889 { bytecode, stageData[d3dStage].nativeResourceBindingMap });
5893 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
5895 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
5896 if (rootSigHandle.isNull()) {
5897 qWarning(
"Failed to create root signature");
5901 ID3D12RootSignature *rootSig =
nullptr;
5902 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
5903 rootSig = rs->rootSig;
5905 qWarning(
"Cannot create graphics pipeline state without root signature");
5909 QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
5910 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
5911 if (rpD->colorAttachmentCount > 0) {
5912 format = DXGI_FORMAT(rpD->colorFormat[0]);
5913 }
else if (rpD->hasDepthStencil) {
5914 format = DXGI_FORMAT(rpD->dsFormat);
5916 qWarning(
"Cannot create graphics pipeline state without color or depthStencil format");
5919 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
5922 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
5923 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
5924 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
5925 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
5926 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
5927 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
5928 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
5929 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
5930 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
5931 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
5932 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
5933 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
5934 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
5935 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
5936 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
5937 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
5940 stream.rootSig.object = rootSig;
5942 QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
5943 QByteArrayList matrixSliceSemantics;
5944 if (!shaderBytecode[VS].isEmpty()) {
5945 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
5948 D3D12_INPUT_ELEMENT_DESC desc = {};
5953 const int matrixSlice = it->matrixSlice();
5954 if (matrixSlice < 0) {
5955 desc.SemanticName =
"TEXCOORD";
5956 desc.SemanticIndex = UINT(it->location());
5960 std::snprintf(sem.data(), sem.size(),
"TEXCOORD%d_", it->location() - matrixSlice);
5961 matrixSliceSemantics.append(sem);
5962 desc.SemanticName = matrixSliceSemantics.last().constData();
5963 desc.SemanticIndex = UINT(matrixSlice);
5965 desc.Format = toD3DAttributeFormat(it->format());
5966 desc.InputSlot = UINT(it->binding());
5967 desc.AlignedByteOffset = it->offset();
5968 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
5969 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
5970 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
5971 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
5973 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
5975 inputDescs.append(desc);
5979 stream.inputLayout.object.NumElements = inputDescs.count();
5980 stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ?
nullptr : inputDescs.constData();
5982 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
5983 topology = toD3DTopology(m_topology, m_patchControlPointCount);
5985 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
5986 const int d3dStage = qd3d12_stage(shaderStage.type());
5989 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
5990 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
5993 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
5994 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
5997 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
5998 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6001 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6002 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6005 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6006 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6014 stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
6015 stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
6016 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
6017 stream.rasterizerState.object.DepthBias = m_depthBias;
6018 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
6019 stream.rasterizerState.object.DepthClipEnable = TRUE;
6020 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
6022 stream.depthStencilState.object.DepthEnable = m_depthTest;
6023 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
6024 stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
6025 stream.depthStencilState.object.StencilEnable = m_stencilTest;
6026 if (m_stencilTest) {
6027 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
6028 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
6029 stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
6030 stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
6031 stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
6032 stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
6033 stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
6034 stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
6035 stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
6036 stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
6039 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
6040 for (
int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
6041 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
6042 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6043 blend.BlendEnable = b.enable;
6044 blend.SrcBlend = toD3DBlendFactor(b.srcColor,
true);
6045 blend.DestBlend = toD3DBlendFactor(b.dstColor,
true);
6046 blend.BlendOp = toD3DBlendOp(b.opColor);
6047 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha,
false);
6048 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha,
false);
6049 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
6050 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
6051 stream.blendState.object.RenderTarget[i] = blend;
6053 if (m_targetBlends.isEmpty()) {
6054 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6055 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
6056 stream.blendState.object.RenderTarget[0] = blend;
6059 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
6060 for (
int i = 0; i < rpD->colorAttachmentCount; ++i)
6061 stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
6063 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
6065 stream.sampleDesc.object = sampleDesc;
6067 stream.sampleMask.object = 0xFFFFFFFF;
6069 viewInstanceMask = 0;
6070 const bool isMultiView = m_multiViewCount >= 2;
6071 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
6072 QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
6074 for (
int i = 0; i < m_multiViewCount; ++i) {
6075 viewInstanceMask |= (1 << i);
6076 viewInstanceLocations.append({ 0, UINT(i) });
6078 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
6081 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6083 ID3D12PipelineState *pso =
nullptr;
6084 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6086 qWarning(
"Failed to create graphics pipeline state: %s",
6087 qPrintable(QSystemError::windowsComString(hr)));
6088 rhiD->rootSignaturePool.remove(rootSigHandle);
6093 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
6095 rhiD->pipelineCreationEnd();
6097 rhiD->registerResource(
this);
6101QD3D12ComputePipeline::QD3D12ComputePipeline(QRhiImplementation *rhi)
6102 : QRhiComputePipeline(rhi)
6106QD3D12ComputePipeline::~QD3D12ComputePipeline()
6111void QD3D12ComputePipeline::destroy()
6113 if (handle.isNull())
6116 QRHI_RES_RHI(QRhiD3D12);
6118 rhiD->releaseQueue.deferredReleasePipeline(handle);
6119 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6126 rhiD->unregisterResource(
this);
6129bool QD3D12ComputePipeline::create()
6131 if (!handle.isNull())
6134 QRHI_RES_RHI(QRhiD3D12);
6135 rhiD->pipelineCreationStart();
6137 stageData.valid =
true;
6138 stageData.stage = CS;
6140 QByteArray shaderBytecode;
6141 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(m_shaderStage);
6142 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6143 shaderBytecode = cacheIt->bytecode;
6144 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6147 QShaderKey shaderKey;
6148 int compileFlags = 0;
6149 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6150 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6151 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
6152 m_shaderStage.shaderVariant(),
6156 if (bytecode.isEmpty()) {
6157 qWarning(
"HLSL compute shader compilation failed: %s", qPrintable(error));
6161 shaderBytecode = bytecode;
6162 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
6163 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
6164 stageData.nativeResourceBindingMap });
6167 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6169 rootSigHandle = srbD->createRootSignature(&stageData, 1);
6170 if (rootSigHandle.isNull()) {
6171 qWarning(
"Failed to create root signature");
6175 ID3D12RootSignature *rootSig =
nullptr;
6176 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6177 rootSig = rs->rootSig;
6179 qWarning(
"Cannot create compute pipeline state without root signature");
6184 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6185 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
6187 stream.rootSig.object = rootSig;
6188 stream.CS.object.pShaderBytecode = shaderBytecode.constData();
6189 stream.CS.object.BytecodeLength = shaderBytecode.size();
6190 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6191 ID3D12PipelineState *pso =
nullptr;
6192 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6194 qWarning(
"Failed to create compute pipeline state: %s",
6195 qPrintable(QSystemError::windowsComString(hr)));
6196 rhiD->rootSignaturePool.remove(rootSigHandle);
6201 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
6203 rhiD->pipelineCreationEnd();
6205 rhiD->registerResource(
this);
6212QD3D12RenderPassDescriptor::QD3D12RenderPassDescriptor(QRhiImplementation *rhi)
6213 : QRhiRenderPassDescriptor(rhi)
6215 serializedFormatData.reserve(16);
6218QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
6223void QD3D12RenderPassDescriptor::destroy()
6225 QRHI_RES_RHI(QRhiD3D12);
6227 rhiD->unregisterResource(
this);
6230bool QD3D12RenderPassDescriptor::isCompatible(
const QRhiRenderPassDescriptor *other)
const
6235 const QD3D12RenderPassDescriptor *o = QRHI_RES(
const QD3D12RenderPassDescriptor, other);
6237 if (colorAttachmentCount != o->colorAttachmentCount)
6240 if (hasDepthStencil != o->hasDepthStencil)
6243 for (
int i = 0; i < colorAttachmentCount; ++i) {
6244 if (colorFormat[i] != o->colorFormat[i])
6248 if (hasDepthStencil) {
6249 if (dsFormat != o->dsFormat)
6253 if (hasShadingRateMap != o->hasShadingRateMap)
6259void QD3D12RenderPassDescriptor::updateSerializedFormat()
6261 serializedFormatData.clear();
6262 auto p = std::back_inserter(serializedFormatData);
6264 *p++ = colorAttachmentCount;
6265 *p++ = hasDepthStencil;
6266 for (
int i = 0; i < colorAttachmentCount; ++i)
6267 *p++ = colorFormat[i];
6268 *p++ = hasDepthStencil ? dsFormat : 0;
6271QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor()
const
6273 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6274 rpD->colorAttachmentCount = colorAttachmentCount;
6275 rpD->hasDepthStencil = hasDepthStencil;
6276 memcpy(rpD->colorFormat, colorFormat,
sizeof(colorFormat));
6277 rpD->dsFormat = dsFormat;
6278 rpD->hasShadingRateMap = hasShadingRateMap;
6280 rpD->updateSerializedFormat();
6282 QRHI_RES_RHI(QRhiD3D12);
6283 rhiD->registerResource(rpD);
6287QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat()
const
6289 return serializedFormatData;
6292QD3D12CommandBuffer::QD3D12CommandBuffer(QRhiImplementation *rhi)
6293 : QRhiCommandBuffer(rhi)
6298QD3D12CommandBuffer::~QD3D12CommandBuffer()
6303void QD3D12CommandBuffer::destroy()
6308const QRhiNativeHandles *QD3D12CommandBuffer::nativeHandles()
6310 nativeHandlesStruct.commandList = cmdList;
6311 return &nativeHandlesStruct;
6314QD3D12SwapChainRenderTarget::QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
6315 : QRhiSwapChainRenderTarget(rhi, swapchain),
6320QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
6325void QD3D12SwapChainRenderTarget::destroy()
6330QSize QD3D12SwapChainRenderTarget::pixelSize()
const
6335float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
6340int QD3D12SwapChainRenderTarget::sampleCount()
const
6342 return d.sampleCount;
6345QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
6346 : QRhiSwapChain(rhi),
6347 rtWrapper(rhi,
this),
6348 rtWrapperRight(rhi,
this),
6353QD3D12SwapChain::~QD3D12SwapChain()
6358void QD3D12SwapChain::destroy()
6365 swapChain->Release();
6366 swapChain =
nullptr;
6367 sourceSwapChain1->Release();
6368 sourceSwapChain1 =
nullptr;
6370 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
6371 FrameResources &fr(frameRes[i]);
6373 fr.fence->Release();
6375 CloseHandle(fr.fenceEvent);
6377 fr.cmdList->Release();
6382 dcompVisual->Release();
6383 dcompVisual =
nullptr;
6387 dcompTarget->Release();
6388 dcompTarget =
nullptr;
6391 if (frameLatencyWaitableObject) {
6392 CloseHandle(frameLatencyWaitableObject);
6393 frameLatencyWaitableObject =
nullptr;
6396 QDxgiVSyncService::instance()->unregisterWindow(window);
6398 QRHI_RES_RHI(QRhiD3D12);
6400 rhiD->swapchains.remove(
this);
6401 rhiD->unregisterResource(
this);
6405void QD3D12SwapChain::releaseBuffers()
6407 QRHI_RES_RHI(QRhiD3D12);
6409 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
6410 rhiD->resourcePool.remove(colorBuffers[i]);
6411 rhiD->rtvPool.release(rtvs[i], 1);
6413 rhiD->rtvPool.release(rtvsRight[i], 1);
6414 if (!msaaBuffers[i].isNull())
6415 rhiD->resourcePool.remove(msaaBuffers[i]);
6416 if (msaaRtvs[i].isValid())
6417 rhiD->rtvPool.release(msaaRtvs[i], 1);
6421void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
6423 FrameResources &fr(frameRes[frameSlot]);
6424 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
6425 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
6426 WaitForSingleObject(fr.fenceEvent, INFINITE);
6430void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
6432 QRHI_RES_RHI(QRhiD3D12);
6433 FrameResources &fr(frameRes[currentFrameSlot]);
6434 fr.fenceCounter += 1u;
6435 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
6438QRhiCommandBuffer *QD3D12SwapChain::currentFrameCommandBuffer()
6443QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
6448QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
6450 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
6453QSize QD3D12SwapChain::surfacePixelSize()
6456 return m_window->size() * m_window->devicePixelRatio();
6459bool QD3D12SwapChain::isFormatSupported(Format f)
6465 qWarning(
"Attempted to call isFormatSupported() without a window set");
6469 QRHI_RES_RHI(QRhiD3D12);
6470 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window))
6471 return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
6476QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
6478 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
6481 QRHI_RES_RHI(QRhiD3D12);
6482 info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window);
6487QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
6492 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6493 rpD->colorAttachmentCount = 1;
6494 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
6495 rpD->colorFormat[0] =
int(srgbAdjustedColorFormat);
6496 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
6498 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
6500 rpD->updateSerializedFormat();
6502 QRHI_RES_RHI(QRhiD3D12);
6503 rhiD->registerResource(rpD);
6507bool QRhiD3D12::ensureDirectCompositionDevice()
6512 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
6513 dcompDevice = QRhiD3D::createDirectCompositionDevice();
6514 return dcompDevice ?
true :
false;
6517static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
6518static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
6520void QD3D12SwapChain::chooseFormats()
6522 colorFormat = DEFAULT_FORMAT;
6523 srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
6524 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
6525 QRHI_RES_RHI(QRhiD3D12);
6526 if (m_format != SDR) {
6527 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) {
6530 case HDRExtendedSrgbLinear:
6531 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
6532 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
6533 srgbAdjustedColorFormat = colorFormat;
6536 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
6537 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
6538 srgbAdjustedColorFormat = colorFormat;
6547 qWarning(
"The output associated with the window is not HDR capable "
6548 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
6551 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
6554bool QD3D12SwapChain::createOrResize()
6560 const bool needsRegistration = !window || window != m_window;
6563 if (window && window != m_window)
6567 m_currentPixelSize = surfacePixelSize();
6568 pixelSize = m_currentPixelSize;
6570 if (pixelSize.isEmpty())
6573 HWND hwnd =
reinterpret_cast<HWND>(window->winId());
6575 QRHI_RES_RHI(QRhiD3D12);
6576 stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
6578 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
6579 if (rhiD->ensureDirectCompositionDevice()) {
6581 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
false, &dcompTarget);
6583 qWarning(
"Failed to create Direct Composition target for the window: %s",
6584 qPrintable(QSystemError::windowsComString(hr)));
6587 if (dcompTarget && !dcompVisual) {
6588 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
6590 qWarning(
"Failed to create DirectComposition visual: %s",
6591 qPrintable(QSystemError::windowsComString(hr)));
6596 if (window->requestedFormat().alphaBufferSize() <= 0)
6597 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
6598 "This may lead to problems.");
6601 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
6603 if (swapInterval == 0 && rhiD->supportsAllowTearing)
6604 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
6608 const bool useFrameLatencyWaitableObject = rhiD->maxFrameLatency != 0
6609 && swapInterval != 0
6610 && rhiD->driverInfoStruct.deviceType != QRhiDriverInfo::CpuDevice;
6611 if (useFrameLatencyWaitableObject)
6612 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
6617 DXGI_SWAP_CHAIN_DESC1 desc = {};
6618 desc.Width = UINT(pixelSize.width());
6619 desc.Height = UINT(pixelSize.height());
6620 desc.Format = colorFormat;
6621 desc.SampleDesc.Count = 1;
6622 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6623 desc.BufferCount = BUFFER_COUNT;
6624 desc.Flags = swapChainFlags;
6625 desc.Scaling = DXGI_SCALING_NONE;
6626 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
6627 desc.Stereo = stereo;
6633 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
6638 desc.Scaling = DXGI_SCALING_STRETCH;
6642 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
6644 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
6649 if (FAILED(hr) && m_format != SDR) {
6650 colorFormat = DEFAULT_FORMAT;
6651 desc.Format = DEFAULT_FORMAT;
6653 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
6655 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
6658 if (SUCCEEDED(hr)) {
6659 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<
void **>(&swapChain)))) {
6660 qWarning(
"IDXGISwapChain3 not available");
6663 if (m_format != SDR) {
6664 hr = swapChain->SetColorSpace1(hdrColorSpace);
6666 qWarning(
"Failed to set color space on swapchain: %s",
6667 qPrintable(QSystemError::windowsComString(hr)));
6670 if (useFrameLatencyWaitableObject) {
6671 swapChain->SetMaximumFrameLatency(rhiD->maxFrameLatency);
6672 frameLatencyWaitableObject = swapChain->GetFrameLatencyWaitableObject();
6675 hr = dcompVisual->SetContent(swapChain);
6676 if (SUCCEEDED(hr)) {
6677 hr = dcompTarget->SetRoot(dcompVisual);
6679 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
6680 qPrintable(QSystemError::windowsComString(hr)));
6683 qWarning(
"Failed to set content for Direct Composition visual: %s",
6684 qPrintable(QSystemError::windowsComString(hr)));
6688 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
6692 qWarning(
"Failed to create D3D12 swapchain: %s"
6693 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
6694 qPrintable(QSystemError::windowsComString(hr)),
6695 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
6696 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
6700 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
6701 hr = rhiD->dev->CreateFence(0,
6702 D3D12_FENCE_FLAG_NONE,
6703 __uuidof(ID3D12Fence),
6704 reinterpret_cast<
void **>(&frameRes[i].fence));
6706 qWarning(
"Failed to create fence for swapchain: %s",
6707 qPrintable(QSystemError::windowsComString(hr)));
6710 frameRes[i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
6712 frameRes[i].fenceCounter = 0;
6716 hr = swapChain->ResizeBuffers(BUFFER_COUNT,
6717 UINT(pixelSize.width()),
6718 UINT(pixelSize.height()),
6721 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
6722 qWarning(
"Device loss detected in ResizeBuffers()");
6723 rhiD->deviceLost =
true;
6725 }
else if (FAILED(hr)) {
6726 qWarning(
"Failed to resize D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
6731 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
6732 ID3D12Resource *colorBuffer;
6733 hr = swapChain->GetBuffer(i, __uuidof(ID3D12Resource),
reinterpret_cast<
void **>(&colorBuffer));
6735 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
6736 i, qPrintable(QSystemError::windowsComString(hr)));
6739 colorBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
6740 rtvs[i] = rhiD->rtvPool.allocate(1);
6741 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6742 rtvDesc.Format = srgbAdjustedColorFormat;
6743 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
6744 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
6747 rtvsRight[i] = rhiD->rtvPool.allocate(1);
6748 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6749 rtvDesc.Format = srgbAdjustedColorFormat;
6750 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
6751 rtvDesc.Texture2DArray.ArraySize = 1;
6752 rtvDesc.Texture2DArray.FirstArraySlice = 1;
6753 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
6757 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
6758 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
6759 m_depthStencil->sampleCount(), m_sampleCount);
6761 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
6762 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
6763 m_depthStencil->setPixelSize(pixelSize);
6764 if (!m_depthStencil->create())
6765 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
6766 pixelSize.width(), pixelSize.height());
6768 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
6769 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
6770 pixelSize.width(), pixelSize.height());
6774 ds = m_depthStencil ? QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
6776 if (sampleDesc.Count > 1) {
6777 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
6778 D3D12_RESOURCE_DESC resourceDesc = {};
6779 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
6780 resourceDesc.Width = UINT64(pixelSize.width());
6781 resourceDesc.Height = UINT(pixelSize.height());
6782 resourceDesc.DepthOrArraySize = 1;
6783 resourceDesc.MipLevels = 1;
6784 resourceDesc.Format = srgbAdjustedColorFormat;
6785 resourceDesc.SampleDesc = sampleDesc;
6786 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
6787 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
6788 D3D12_CLEAR_VALUE clearValue = {};
6789 clearValue.Format = colorFormat;
6790 ID3D12Resource *resource =
nullptr;
6791 D3D12MA::Allocation *allocation =
nullptr;
6792 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
6794 D3D12_RESOURCE_STATE_RENDER_TARGET,
6797 __uuidof(ID3D12Resource),
6798 reinterpret_cast<
void **>(&resource));
6800 qWarning(
"Failed to create MSAA color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
6803 msaaBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
6804 msaaRtvs[i] = rhiD->rtvPool.allocate(1);
6805 if (!msaaRtvs[i].isValid())
6807 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6808 rtvDesc.Format = srgbAdjustedColorFormat;
6809 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
6810 : D3D12_RTV_DIMENSION_TEXTURE2D;
6811 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[i].cpuHandle);
6815 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
6816 currentFrameSlot = 0;
6818 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
6819 QD3D12SwapChainRenderTarget *rtD = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
6820 rtD->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6821 rtD->d.pixelSize = pixelSize;
6822 rtD->d.dpr =
float(window->devicePixelRatio());
6823 rtD->d.sampleCount =
int(sampleDesc.Count);
6824 rtD->d.colorAttCount = 1;
6825 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
6827 rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
6828 QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
6829 rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6830 rtDr->d.pixelSize = pixelSize;
6831 rtDr->d.dpr =
float(window->devicePixelRatio());
6832 rtDr->d.sampleCount =
int(sampleDesc.Count);
6833 rtDr->d.colorAttCount = 1;
6834 rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
6836 QDxgiVSyncService::instance()->registerWindow(window);
6838 if (needsRegistration || !rhiD->swapchains.contains(
this))
6839 rhiD->swapchains.insert(
this);
6841 rhiD->registerResource(
this);