6#include <QtCore/private/qsystemerror_p.h>
14#define QRHI_D3D12_HAS_OLD_PIX
17#ifdef __ID3D12Device2_INTERFACE_DEFINED__
22
23
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
64
67
68
69
70
71
74
75
76
77
78
79
80
81
82
83
84
85
88
89
90
91
92
93
96
97
98
99
100
101
102
103
104
105
106
109
110
111
112
113
114
117
118
119
120
121
122
125
126
127
128
129
130
131
134
135
136
137
138
139
140
141
142
143
144
145
146
147
150
151
154static const D3D_FEATURE_LEVEL MIN_FEATURE_LEVEL = D3D_FEATURE_LEVEL_11_0;
156QRhiD3D12::QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importParams)
158 debugLayer = params->enableDebugLayer;
160 if (importParams->dev) {
161 ID3D12Device *d3d12Device =
reinterpret_cast<ID3D12Device *>(importParams->dev);
162 if (SUCCEEDED(d3d12Device->QueryInterface(__uuidof(ID3D12Device2),
reinterpret_cast<
void **>(&dev)))) {
164 d3d12Device->Release();
165 importedDevice =
true;
167 qWarning(
"ID3D12Device2 not supported, cannot import device");
170 if (importParams->commandQueue) {
171 cmdQueue =
reinterpret_cast<ID3D12CommandQueue *>(importParams->commandQueue);
172 importedCommandQueue =
true;
174 minimumFeatureLevel = D3D_FEATURE_LEVEL(importParams->minimumFeatureLevel);
175 adapterLuid.LowPart = importParams->adapterLuidLow;
176 adapterLuid.HighPart = importParams->adapterLuidHigh;
181inline Int aligned(Int v, Int byteAlign)
183 return (v + byteAlign - 1) & ~(byteAlign - 1);
186static inline UINT calcSubresource(UINT mipSlice, UINT arraySlice, UINT mipLevels)
188 return mipSlice + arraySlice * mipLevels;
191static inline QD3D12RenderTargetData *rtData(QRhiRenderTarget *rt)
193 switch (rt->resourceType()) {
194 case QRhiResource::SwapChainRenderTarget:
195 return &QRHI_RES(QD3D12SwapChainRenderTarget, rt)->d;
196 case QRhiResource::TextureRenderTarget:
197 return &QRHI_RES(QD3D12TextureRenderTarget, rt)->d;
202 Q_UNREACHABLE_RETURN(
nullptr);
205bool QRhiD3D12::create(QRhi::Flags flags)
209 UINT factoryFlags = 0;
211 factoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
212 HRESULT hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
216 qCDebug(QRHI_LOG_INFO,
"Debug layer was requested but is not available. "
217 "Attempting to create DXGIFactory2 without it.");
218 factoryFlags &= ~DXGI_CREATE_FACTORY_DEBUG;
219 hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
224 qWarning(
"CreateDXGIFactory2() failed to create DXGI factory: %s",
225 qPrintable(QSystemError::windowsComString(hr)));
230 if (qEnvironmentVariableIsSet(
"QT_D3D_MAX_FRAME_LATENCY"))
231 maxFrameLatency = UINT(qMax(0, qEnvironmentVariableIntValue(
"QT_D3D_MAX_FRAME_LATENCY")));
232 if (maxFrameLatency != 0)
233 qCDebug(QRHI_LOG_INFO,
"Using frame latency waitable object with max frame latency %u", maxFrameLatency);
235 supportsAllowTearing =
false;
236 IDXGIFactory5 *factory5 =
nullptr;
237 if (SUCCEEDED(dxgiFactory->QueryInterface(__uuidof(IDXGIFactory5),
reinterpret_cast<
void **>(&factory5)))) {
238 BOOL allowTearing =
false;
239 if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing,
sizeof(allowTearing))))
240 supportsAllowTearing = allowTearing;
245 ID3D12Debug1 *debug =
nullptr;
246 if (SUCCEEDED(D3D12GetDebugInterface(__uuidof(ID3D12Debug1),
reinterpret_cast<
void **>(&debug)))) {
247 qCDebug(QRHI_LOG_INFO,
"Enabling D3D12 debug layer");
248 debug->EnableDebugLayer();
253 activeAdapter =
nullptr;
255 if (!importedDevice) {
256 IDXGIAdapter1 *adapter;
257 int requestedAdapterIndex = -1;
258 if (qEnvironmentVariableIsSet(
"QT_D3D_ADAPTER_INDEX"))
259 requestedAdapterIndex = qEnvironmentVariableIntValue(
"QT_D3D_ADAPTER_INDEX");
261 if (requestedRhiAdapter)
262 adapterLuid =
static_cast<QD3D12Adapter *>(requestedRhiAdapter)->luid;
265 if (requestedAdapterIndex < 0 && (adapterLuid.LowPart || adapterLuid.HighPart)) {
266 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
267 DXGI_ADAPTER_DESC1 desc;
268 adapter->GetDesc1(&desc);
270 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
271 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
273 requestedAdapterIndex = adapterIndex;
279 if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
280 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
281 DXGI_ADAPTER_DESC1 desc;
282 adapter->GetDesc1(&desc);
284 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
285 requestedAdapterIndex = adapterIndex;
291 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
292 DXGI_ADAPTER_DESC1 desc;
293 adapter->GetDesc1(&desc);
294 const QString name = QString::fromUtf16(
reinterpret_cast<
char16_t *>(desc.Description));
295 qCDebug(QRHI_LOG_INFO,
"Adapter %d: '%s' (vendor 0x%X device 0x%X flags 0x%X)",
301 if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
302 activeAdapter = adapter;
303 adapterLuid = desc.AdapterLuid;
304 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
305 qCDebug(QRHI_LOG_INFO,
" using this adapter");
310 if (!activeAdapter) {
311 qWarning(
"No adapter");
315 if (minimumFeatureLevel == 0)
316 minimumFeatureLevel = MIN_FEATURE_LEVEL;
318 hr = D3D12CreateDevice(activeAdapter,
320 __uuidof(ID3D12Device2),
321 reinterpret_cast<
void **>(&dev));
323 qWarning(
"Failed to create D3D12 device: %s", qPrintable(QSystemError::windowsComString(hr)));
329 adapterLuid = dev->GetAdapterLuid();
330 IDXGIAdapter1 *adapter;
331 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
332 DXGI_ADAPTER_DESC1 desc;
333 adapter->GetDesc1(&desc);
334 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
335 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
337 activeAdapter = adapter;
338 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
344 if (!activeAdapter) {
345 qWarning(
"No adapter");
348 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
351 QDxgiVSyncService::instance()->refAdapter(adapterLuid);
354 ID3D12InfoQueue *infoQueue;
355 if (SUCCEEDED(dev->QueryInterface(__uuidof(ID3D12InfoQueue),
reinterpret_cast<
void **>(&infoQueue)))) {
356 if (qEnvironmentVariableIntValue(
"QT_D3D_DEBUG_BREAK")) {
357 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION,
true);
358 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR,
true);
359 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING,
true);
361 D3D12_INFO_QUEUE_FILTER filter = {};
362 D3D12_MESSAGE_ID suppressedMessages[2] = {
364 D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
366 D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE
368 filter.DenyList.NumIDs = 2;
369 filter.DenyList.pIDList = suppressedMessages;
372 D3D12_MESSAGE_SEVERITY infoSev = D3D12_MESSAGE_SEVERITY_INFO;
373 filter.DenyList.NumSeverities = 1;
374 filter.DenyList.pSeverityList = &infoSev;
375 infoQueue->PushStorageFilter(&filter);
376 infoQueue->Release();
380 if (!importedCommandQueue) {
381 D3D12_COMMAND_QUEUE_DESC queueDesc = {};
382 queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
383 queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
384 hr = dev->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue),
reinterpret_cast<
void **>(&cmdQueue));
386 qWarning(
"Failed to create command queue: %s", qPrintable(QSystemError::windowsComString(hr)));
391 hr = dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence),
reinterpret_cast<
void **>(&fullFence));
393 qWarning(
"Failed to create fence: %s", qPrintable(QSystemError::windowsComString(hr)));
396 fullFenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
397 fullFenceCounter = 0;
399 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
400 hr = dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
401 __uuidof(ID3D12CommandAllocator),
402 reinterpret_cast<
void **>(&cmdAllocators[i]));
404 qWarning(
"Failed to create command allocator: %s", qPrintable(QSystemError::windowsComString(hr)));
409 if (!vma.create(dev, activeAdapter)) {
410 qWarning(
"Failed to initialize graphics memory suballocator");
414 if (!rtvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
"main RTV pool")) {
415 qWarning(
"Could not create RTV pool");
419 if (!dsvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
"main DSV pool")) {
420 qWarning(
"Could not create DSV pool");
424 if (!cbvSrvUavPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
"main CBV-SRV-UAV pool")) {
425 qWarning(
"Could not create CBV-SRV-UAV pool");
429 resourcePool.create(
"main resource pool");
430 pipelinePool.create(
"main pipeline pool");
431 rootSignaturePool.create(
"main root signature pool");
432 releaseQueue.create(&resourcePool, &pipelinePool, &rootSignaturePool);
433 barrierGen.create(&resourcePool);
435 if (!samplerMgr.create(dev)) {
436 qWarning(
"Could not create sampler pool and shader-visible sampler heap");
440 if (!mipmapGen.create(
this)) {
441 qWarning(
"Could not initialize mipmap generator");
445 if (!mipmapGen3D.create(
this)) {
446 qWarning(
"Could not initialize 3D texture mipmap generator");
450 const qint32 smallStagingSize = aligned(SMALL_STAGING_AREA_BYTES_PER_FRAME, QD3D12StagingArea::ALIGNMENT);
451 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
452 if (!smallStagingAreas[i].create(
this, smallStagingSize, D3D12_HEAP_TYPE_UPLOAD)) {
453 qWarning(
"Could not create host-visible staging area");
456 QString decoratedName = QLatin1String(
"Small staging area buffer/");
457 decoratedName += QString::number(i);
458 smallStagingAreas[i].mem.buffer->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
461 if (!shaderVisibleCbvSrvUavHeap.create(dev,
462 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
463 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE))
465 qWarning(
"Could not create first shader-visible CBV/SRV/UAV heap");
469 if (flags.testFlag(QRhi::EnableTimestamps)) {
470 static bool wantsStablePowerState = qEnvironmentVariableIntValue(
"QT_D3D_STABLE_POWER_STATE");
486 if (wantsStablePowerState)
487 dev->SetStablePowerState(TRUE);
489 hr = cmdQueue->GetTimestampFrequency(×tampTicksPerSecond);
491 qWarning(
"Failed to query timestamp frequency: %s",
492 qPrintable(QSystemError::windowsComString(hr)));
495 if (!timestampQueryHeap.create(dev, QD3D12_FRAMES_IN_FLIGHT * 2, D3D12_QUERY_HEAP_TYPE_TIMESTAMP)) {
496 qWarning(
"Failed to create timestamp query pool");
499 const quint32 readbackBufSize = QD3D12_FRAMES_IN_FLIGHT * 2 *
sizeof(quint64);
500 if (!timestampReadbackArea.create(
this, readbackBufSize, D3D12_HEAP_TYPE_READBACK)) {
501 qWarning(
"Failed to create timestamp readback buffer");
504 timestampReadbackArea.mem.buffer->SetName(L"Timestamp readback buffer");
505 memset(timestampReadbackArea.mem.p, 0, readbackBufSize);
509 D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
510 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3,
sizeof(options3)))) {
511 caps.multiView = options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
513 caps.textureViewFormat = options3.CastingFullyTypedFormatSupported;
516#ifdef QRHI_D3D12_CL5_AVAILABLE
517 D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {};
518 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6,
sizeof(options6)))) {
519 caps.vrs = options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED;
520 caps.vrsMap = options6.VariableShadingRateTier == D3D12_VARIABLE_SHADING_RATE_TIER_2;
521 caps.vrsAdditionalRates = options6.AdditionalShadingRatesSupported;
522 shadingRateImageTileSize = options6.ShadingRateImageTileSize;
527 caps.vrsAdditionalRates =
false;
531 offscreenActive =
false;
533 nativeHandlesStruct.dev = dev;
534 nativeHandlesStruct.minimumFeatureLevel = minimumFeatureLevel;
535 nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
536 nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
537 nativeHandlesStruct.commandQueue = cmdQueue;
542void QRhiD3D12::destroy()
544 if (!deviceLost && fullFence && fullFenceEvent)
547 releaseQueue.releaseAll();
549 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
550 if (offscreenCb[i]) {
551 if (offscreenCb[i]->cmdList)
552 offscreenCb[i]->cmdList->Release();
553 delete offscreenCb[i];
554 offscreenCb[i] =
nullptr;
558 timestampQueryHeap.destroy();
559 timestampReadbackArea.destroy();
561 shaderVisibleCbvSrvUavHeap.destroy();
563 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i)
564 smallStagingAreas[i].destroy();
567 mipmapGen3D.destroy();
568 samplerMgr.destroy();
569 resourcePool.destroy();
570 pipelinePool.destroy();
571 rootSignaturePool.destroy();
574 cbvSrvUavPool.destroy();
576 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
577 if (cmdAllocators[i]) {
578 cmdAllocators[i]->Release();
579 cmdAllocators[i] =
nullptr;
583 if (fullFenceEvent) {
584 CloseHandle(fullFenceEvent);
585 fullFenceEvent =
nullptr;
589 fullFence->Release();
593 if (!importedCommandQueue) {
602 if (!importedDevice) {
610 dcompDevice->Release();
611 dcompDevice =
nullptr;
615 activeAdapter->Release();
616 activeAdapter =
nullptr;
620 dxgiFactory->Release();
621 dxgiFactory =
nullptr;
625 importedDevice =
false;
626 importedCommandQueue =
false;
628 QDxgiVSyncService::instance()->derefAdapter(adapterLuid);
631QRhi::AdapterList QRhiD3D12::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
633 LUID requestedLuid = {};
635 QRhiD3D12NativeHandles *h =
static_cast<QRhiD3D12NativeHandles *>(nativeHandles);
636 const LUID adapterLuid = { h->adapterLuidLow, h->adapterLuidHigh };
637 if (adapterLuid.LowPart || adapterLuid.HighPart)
638 requestedLuid = adapterLuid;
641 IDXGIFactory2 *dxgi =
nullptr;
642 if (FAILED(CreateDXGIFactory2(0, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgi))))
645 QRhi::AdapterList list;
646 IDXGIAdapter1 *adapter;
647 for (
int adapterIndex = 0; dxgi->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
648 DXGI_ADAPTER_DESC1 desc;
649 adapter->GetDesc1(&desc);
651 if (requestedLuid.LowPart || requestedLuid.HighPart) {
652 if (desc.AdapterLuid.LowPart != requestedLuid.LowPart
653 || desc.AdapterLuid.HighPart != requestedLuid.HighPart)
658 QD3D12Adapter *a =
new QD3D12Adapter;
659 a->luid = desc.AdapterLuid;
660 QRhiD3D::fillDriverInfo(&a->adapterInfo, desc);
668QRhiDriverInfo QD3D12Adapter::info()
const
673QList<
int> QRhiD3D12::supportedSampleCounts()
const
675 return { 1, 2, 4, 8 };
678QList<QSize> QRhiD3D12::supportedShadingRates(
int sampleCount)
const
681 switch (sampleCount) {
684 if (caps.vrsAdditionalRates) {
685 sizes.append(QSize(4, 4));
686 sizes.append(QSize(4, 2));
687 sizes.append(QSize(2, 4));
689 sizes.append(QSize(2, 2));
690 sizes.append(QSize(2, 1));
691 sizes.append(QSize(1, 2));
694 if (caps.vrsAdditionalRates)
695 sizes.append(QSize(2, 4));
696 sizes.append(QSize(2, 2));
697 sizes.append(QSize(2, 1));
698 sizes.append(QSize(1, 2));
701 sizes.append(QSize(2, 2));
702 sizes.append(QSize(2, 1));
703 sizes.append(QSize(1, 2));
708 sizes.append(QSize(1, 1));
712QRhiSwapChain *QRhiD3D12::createSwapChain()
714 return new QD3D12SwapChain(
this);
717QRhiBuffer *QRhiD3D12::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
719 return new QD3D12Buffer(
this, type, usage, size);
722int QRhiD3D12::ubufAlignment()
const
724 return D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
727bool QRhiD3D12::isYUpInFramebuffer()
const
732bool QRhiD3D12::isYUpInNDC()
const
737bool QRhiD3D12::isClipDepthZeroToOne()
const
742QMatrix4x4 QRhiD3D12::clipSpaceCorrMatrix()
const
747 if (m.isIdentity()) {
749 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
750 0.0f, 1.0f, 0.0f, 0.0f,
751 0.0f, 0.0f, 0.5f, 0.5f,
752 0.0f, 0.0f, 0.0f, 1.0f);
757bool QRhiD3D12::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags)
const
761 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ASTC_12x12)
767bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature)
const
770 case QRhi::MultisampleTexture:
772 case QRhi::MultisampleRenderBuffer:
774 case QRhi::DebugMarkers:
775#ifdef QRHI_D3D12_HAS_OLD_PIX
780 case QRhi::Timestamps:
782 case QRhi::Instancing:
784 case QRhi::CustomInstanceStepRate:
786 case QRhi::PrimitiveRestart:
788 case QRhi::NonDynamicUniformBuffers:
790 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
792 case QRhi::NPOTTextureRepeat:
794 case QRhi::RedOrAlpha8IsRed:
796 case QRhi::ElementIndexUint:
800 case QRhi::WideLines:
802 case QRhi::VertexShaderPointSize:
804 case QRhi::BaseVertex:
806 case QRhi::BaseInstance:
808 case QRhi::TriangleFanTopology:
810 case QRhi::ReadBackNonUniformBuffer:
812 case QRhi::ReadBackNonBaseMipLevel:
814 case QRhi::TexelFetch:
816 case QRhi::RenderToNonBaseMipLevel:
818 case QRhi::IntAttributes:
820 case QRhi::ScreenSpaceDerivatives:
822 case QRhi::ReadBackAnyTextureFormat:
824 case QRhi::PipelineCacheDataLoadSave:
826 case QRhi::ImageDataStride:
828 case QRhi::RenderBufferImport:
830 case QRhi::ThreeDimensionalTextures:
832 case QRhi::RenderTo3DTextureSlice:
834 case QRhi::TextureArrays:
836 case QRhi::Tessellation:
838 case QRhi::GeometryShader:
840 case QRhi::TextureArrayRange:
842 case QRhi::NonFillPolygonMode:
844 case QRhi::OneDimensionalTextures:
846 case QRhi::OneDimensionalTextureMipmaps:
848 case QRhi::HalfAttributes:
850 case QRhi::RenderToOneDimensionalTexture:
852 case QRhi::ThreeDimensionalTextureMipmaps:
854 case QRhi::MultiView:
855 return caps.multiView;
856 case QRhi::TextureViewFormat:
857 return caps.textureViewFormat;
858 case QRhi::ResolveDepthStencil:
862 case QRhi::VariableRateShading:
864 case QRhi::VariableRateShadingMap:
865 case QRhi::VariableRateShadingMapWithTexture:
867 case QRhi::PerRenderTargetBlending:
868 case QRhi::SampleVariables:
870 case QRhi::InstanceIndexIncludesBaseInstance:
876int QRhiD3D12::resourceLimit(QRhi::ResourceLimit limit)
const
879 case QRhi::TextureSizeMin:
881 case QRhi::TextureSizeMax:
883 case QRhi::MaxColorAttachments:
885 case QRhi::FramesInFlight:
886 return QD3D12_FRAMES_IN_FLIGHT;
887 case QRhi::MaxAsyncReadbackFrames:
888 return QD3D12_FRAMES_IN_FLIGHT;
889 case QRhi::MaxThreadGroupsPerDimension:
891 case QRhi::MaxThreadsPerThreadGroup:
893 case QRhi::MaxThreadGroupX:
895 case QRhi::MaxThreadGroupY:
897 case QRhi::MaxThreadGroupZ:
899 case QRhi::TextureArraySizeMax:
901 case QRhi::MaxUniformBufferRange:
903 case QRhi::MaxVertexInputs:
905 case QRhi::MaxVertexOutputs:
907 case QRhi::ShadingRateImageTileSize:
908 return shadingRateImageTileSize;
913const QRhiNativeHandles *QRhiD3D12::nativeHandles()
915 return &nativeHandlesStruct;
918QRhiDriverInfo QRhiD3D12::driverInfo()
const
920 return driverInfoStruct;
923QRhiStats QRhiD3D12::statistics()
926 result.totalPipelineCreationTime = totalPipelineCreationTime();
928 D3D12MA::Budget budgets[2];
929 vma.getBudget(&budgets[0], &budgets[1]);
930 for (
int i = 0; i < 2; ++i) {
931 const D3D12MA::Statistics &stats(budgets[i].Stats);
932 result.blockCount += stats.BlockCount;
933 result.allocCount += stats.AllocationCount;
934 result.usedBytes += stats.AllocationBytes;
935 result.unusedBytes += stats.BlockBytes - stats.AllocationBytes;
936 result.totalUsageBytes += budgets[i].UsageBytes;
942bool QRhiD3D12::makeThreadLocalNativeContextCurrent()
948void QRhiD3D12::setQueueSubmitParams(QRhiNativeHandles *)
953void QRhiD3D12::releaseCachedResources()
955 shaderBytecodeCache.data.clear();
958bool QRhiD3D12::isDeviceLost()
const
963QByteArray QRhiD3D12::pipelineCacheData()
968void QRhiD3D12::setPipelineCacheData(
const QByteArray &data)
973QRhiRenderBuffer *QRhiD3D12::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
974 int sampleCount, QRhiRenderBuffer::Flags flags,
975 QRhiTexture::Format backingFormatHint)
977 return new QD3D12RenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
980QRhiTexture *QRhiD3D12::createTexture(QRhiTexture::Format format,
981 const QSize &pixelSize,
int depth,
int arraySize,
982 int sampleCount, QRhiTexture::Flags flags)
984 return new QD3D12Texture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
987QRhiSampler *QRhiD3D12::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
988 QRhiSampler::Filter mipmapMode,
989 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
991 return new QD3D12Sampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
994QRhiTextureRenderTarget *QRhiD3D12::createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
995 QRhiTextureRenderTarget::Flags flags)
997 return new QD3D12TextureRenderTarget(
this, desc, flags);
1000QRhiShadingRateMap *QRhiD3D12::createShadingRateMap()
1002 return new QD3D12ShadingRateMap(
this);
1005QRhiGraphicsPipeline *QRhiD3D12::createGraphicsPipeline()
1007 return new QD3D12GraphicsPipeline(
this);
1010QRhiComputePipeline *QRhiD3D12::createComputePipeline()
1012 return new QD3D12ComputePipeline(
this);
1015QRhiShaderResourceBindings *QRhiD3D12::createShaderResourceBindings()
1017 return new QD3D12ShaderResourceBindings(
this);
1020void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
1022 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1023 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1024 QD3D12GraphicsPipeline *psD = QRHI_RES(QD3D12GraphicsPipeline, ps);
1025 const bool pipelineChanged = cbD->currentGraphicsPipeline != psD || cbD->currentPipelineGeneration != psD->generation;
1027 if (pipelineChanged) {
1028 cbD->currentGraphicsPipeline = psD;
1029 cbD->currentComputePipeline =
nullptr;
1030 cbD->currentPipelineGeneration = psD->generation;
1032 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
1033 Q_ASSERT(pipeline->type == QD3D12Pipeline::Graphics);
1034 cbD->cmdList->SetPipelineState(pipeline->pso);
1035 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
1036 cbD->cmdList->SetGraphicsRootSignature(rs->rootSig);
1039 cbD->cmdList->IASetPrimitiveTopology(psD->topology);
1041 if (psD->viewInstanceMask)
1042 cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
1046void QD3D12CommandBuffer::visitUniformBuffer(QD3D12Stage s,
1047 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
1050 int dynamicOffsetCount,
1051 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1053 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1054 quint32 offset = d.offset;
1055 if (d.hasDynamicOffset) {
1056 for (
int i = 0; i < dynamicOffsetCount; ++i) {
1057 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1058 if (dynOfs.first == binding) {
1059 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1060 offset += dynOfs.second;
1064 QRHI_RES_RHI(QRhiD3D12);
1065 visitorData.cbufs[s].append({ bufD->handles[rhiD->currentFrameSlot], offset });
1068void QD3D12CommandBuffer::visitTexture(QD3D12Stage s,
1069 const QRhiShaderResourceBinding::TextureAndSampler &d,
1072 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1073 visitorData.srvs[s].append(texD->srv);
1076void QD3D12CommandBuffer::visitSampler(QD3D12Stage s,
1077 const QRhiShaderResourceBinding::TextureAndSampler &d,
1080 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, d.sampler);
1081 visitorData.samplers[s].append(samplerD->lookupOrCreateShaderVisibleDescriptor());
1084void QD3D12CommandBuffer::visitStorageBuffer(QD3D12Stage s,
1085 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
1086 QD3D12ShaderResourceVisitor::StorageOp,
1089 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1091 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1092 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1093 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
1094 uavDesc.Buffer.FirstElement = d.offset / 4;
1095 uavDesc.Buffer.NumElements = aligned(bufD->m_size - d.offset, 4u) / 4;
1096 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
1097 visitorData.uavs[s].append({ bufD->handles[0], uavDesc });
1100void QD3D12CommandBuffer::visitStorageImage(QD3D12Stage s,
1101 const QRhiShaderResourceBinding::Data::StorageImageData &d,
1102 QD3D12ShaderResourceVisitor::StorageOp,
1105 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1106 const bool isCube = texD->m_flags.testFlag(QRhiTexture::CubeMap);
1107 const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
1108 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1109 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1110 uavDesc.Format = texD->rtFormat;
1112 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1113 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1114 uavDesc.Texture2DArray.FirstArraySlice = 0;
1115 uavDesc.Texture2DArray.ArraySize = 6;
1116 }
else if (isArray) {
1117 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1118 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1119 uavDesc.Texture2DArray.FirstArraySlice = 0;
1120 uavDesc.Texture2DArray.ArraySize = UINT(qMax(0, texD->m_arraySize));
1122 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1123 uavDesc.Texture3D.MipSlice = UINT(d.level);
1124 uavDesc.Texture3D.WSize = UINT(-1);
1126 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
1127 uavDesc.Texture2D.MipSlice = UINT(d.level);
1129 visitorData.uavs[s].append({ texD->handle, uavDesc });
1132void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
1133 int dynamicOffsetCount,
1134 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1136 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1137 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
1138 QD3D12GraphicsPipeline *gfxPsD = QRHI_RES(QD3D12GraphicsPipeline, cbD->currentGraphicsPipeline);
1139 QD3D12ComputePipeline *compPsD = QRHI_RES(QD3D12ComputePipeline, cbD->currentComputePipeline);
1143 srb = gfxPsD->m_shaderResourceBindings;
1145 srb = compPsD->m_shaderResourceBindings;
1148 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, srb);
1150 bool pipelineChanged =
false;
1152 pipelineChanged = srbD->lastUsedGraphicsPipeline != gfxPsD;
1153 srbD->lastUsedGraphicsPipeline = gfxPsD;
1155 pipelineChanged = srbD->lastUsedComputePipeline != compPsD;
1156 srbD->lastUsedComputePipeline = compPsD;
1159 for (
int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
1160 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings[i]);
1162 case QRhiShaderResourceBinding::UniformBuffer:
1164 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.ubuf.buf);
1165 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
1166 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1167 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1170 case QRhiShaderResourceBinding::SampledTexture:
1171 case QRhiShaderResourceBinding::Texture:
1172 case QRhiShaderResourceBinding::Sampler:
1174 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
1175 for (
int elem = 0; elem < data->count; ++elem) {
1176 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, data->texSamplers[elem].tex);
1177 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, data->texSamplers[elem].sampler);
1181 Q_ASSERT(texD || samplerD);
1184 if (b->stage == QRhiShaderResourceBinding::FragmentStage) {
1185 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1186 }
else if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
1187 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1189 state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1191 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATES(state));
1192 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1197 case QRhiShaderResourceBinding::ImageLoad:
1198 case QRhiShaderResourceBinding::ImageStore:
1199 case QRhiShaderResourceBinding::ImageLoadStore:
1201 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, b->u.simage.tex);
1202 if (QD3D12Resource *res = resourcePool.lookupRef(texD->handle)) {
1203 if (res->uavUsage) {
1204 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1206 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1208 if (b->type == QRhiShaderResourceBinding::ImageStore
1209 || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1212 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1217 if (b->type == QRhiShaderResourceBinding::ImageLoad || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1218 res->uavUsage |= QD3D12Resource::UavUsageRead;
1219 if (b->type == QRhiShaderResourceBinding::ImageStore || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1220 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1221 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1222 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1226 case QRhiShaderResourceBinding::BufferLoad:
1227 case QRhiShaderResourceBinding::BufferStore:
1228 case QRhiShaderResourceBinding::BufferLoadStore:
1230 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.sbuf.buf);
1231 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
1232 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1233 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
1234 if (res->uavUsage) {
1235 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1237 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1239 if (b->type == QRhiShaderResourceBinding::BufferStore
1240 || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1243 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1248 if (b->type == QRhiShaderResourceBinding::BufferLoad || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1249 res->uavUsage |= QD3D12Resource::UavUsageRead;
1250 if (b->type == QRhiShaderResourceBinding::BufferStore || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1251 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1252 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1253 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1260 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1261 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1263 if (pipelineChanged || srbChanged || srbRebuilt || srbD->hasDynamicOffset) {
1264 const QD3D12ShaderStageData *stageData = gfxPsD ? gfxPsD->stageData.data() : &compPsD->stageData;
1270 QD3D12ShaderResourceVisitor visitor(srbD, stageData, gfxPsD ? 5 : 1);
1272 QD3D12CommandBuffer::VisitorData &visitorData(cbD->visitorData);
1275 using namespace std::placeholders;
1276 visitor.uniformBuffer = std::bind(&QD3D12CommandBuffer::visitUniformBuffer, cbD, _1, _2, _3, _4, dynamicOffsetCount, dynamicOffsets);
1277 visitor.texture = std::bind(&QD3D12CommandBuffer::visitTexture, cbD, _1, _2, _3);
1278 visitor.sampler = std::bind(&QD3D12CommandBuffer::visitSampler, cbD, _1, _2, _3);
1279 visitor.storageBuffer = std::bind(&QD3D12CommandBuffer::visitStorageBuffer, cbD, _1, _2, _3, _4);
1280 visitor.storageImage = std::bind(&QD3D12CommandBuffer::visitStorageImage, cbD, _1, _2, _3, _4);
1284 quint32 cbvSrvUavCount = 0;
1285 for (
int s = 0; s < 6; ++s) {
1287 cbvSrvUavCount += visitorData.srvs[s].count();
1288 cbvSrvUavCount += visitorData.uavs[s].count();
1291 bool gotNewHeap =
false;
1292 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
1293 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1301 qCDebug(QRHI_LOG_INFO,
"Created new shader-visible CBV/SRV/UAV descriptor heap,"
1302 " per-frame slice size is now %u,"
1303 " if this happens frequently then that's not great.",
1304 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[0].capacity);
1305 bindShaderVisibleHeaps(cbD);
1308 int rootParamIndex = 0;
1309 for (
int s = 0; s < 6; ++s) {
1310 if (!visitorData.cbufs[s].isEmpty()) {
1311 for (
int i = 0, count = visitorData.cbufs[s].count(); i < count; ++i) {
1312 const auto &cbuf(visitorData.cbufs[s][i]);
1313 if (QD3D12Resource *res = resourcePool.lookupRef(cbuf.first)) {
1314 quint32 offset = cbuf.second;
1315 D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = res->resource->GetGPUVirtualAddress() + offset;
1316 if (cbD->currentGraphicsPipeline)
1317 cbD->cmdList->SetGraphicsRootConstantBufferView(rootParamIndex, gpuAddr);
1319 cbD->cmdList->SetComputeRootConstantBufferView(rootParamIndex, gpuAddr);
1321 rootParamIndex += 1;
1325 for (
int s = 0; s < 6; ++s) {
1326 if (!visitorData.srvs[s].isEmpty()) {
1327 QD3D12DescriptorHeap &gpuSrvHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1328 QD3D12Descriptor startDesc = gpuSrvHeap.get(visitorData.srvs[s].count());
1329 for (
int i = 0, count = visitorData.srvs[s].count(); i < count; ++i) {
1330 const auto &srv(visitorData.srvs[s][i]);
1331 dev->CopyDescriptorsSimple(1, gpuSrvHeap.incremented(startDesc, i).cpuHandle, srv.cpuHandle,
1332 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1335 if (cbD->currentGraphicsPipeline)
1336 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1337 else if (cbD->currentComputePipeline)
1338 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1340 rootParamIndex += 1;
1343 for (
int s = 0; s < 6; ++s) {
1346 for (
const QD3D12Descriptor &samplerDescriptor : visitorData.samplers[s]) {
1347 if (cbD->currentGraphicsPipeline)
1348 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1349 else if (cbD->currentComputePipeline)
1350 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1352 rootParamIndex += 1;
1355 for (
int s = 0; s < 6; ++s) {
1356 if (!visitorData.uavs[s].isEmpty()) {
1357 QD3D12DescriptorHeap &gpuUavHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1358 QD3D12Descriptor startDesc = gpuUavHeap.get(visitorData.uavs[s].count());
1359 for (
int i = 0, count = visitorData.uavs[s].count(); i < count; ++i) {
1360 const auto &uav(visitorData.uavs[s][i]);
1361 if (QD3D12Resource *res = resourcePool.lookupRef(uav.first)) {
1362 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uav.second,
1363 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1365 dev->CreateUnorderedAccessView(
nullptr,
nullptr,
nullptr,
1366 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1370 if (cbD->currentGraphicsPipeline)
1371 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1372 else if (cbD->currentComputePipeline)
1373 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1375 rootParamIndex += 1;
1380 cbD->currentGraphicsSrb = srb;
1381 cbD->currentComputeSrb =
nullptr;
1383 cbD->currentGraphicsSrb =
nullptr;
1384 cbD->currentComputeSrb = srb;
1386 cbD->currentSrbGeneration = srbD->generation;
1390void QRhiD3D12::setVertexInput(QRhiCommandBuffer *cb,
1391 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1392 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1394 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1395 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1397 bool needsBindVBuf =
false;
1398 for (
int i = 0; i < bindingCount; ++i) {
1399 const int inputSlot = startBinding + i;
1400 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1401 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1402 const bool isDynamic = bufD->m_type == QRhiBuffer::Dynamic;
1404 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1406 if (cbD->currentVertexBuffers[inputSlot] != bufD->handles[isDynamic ? currentFrameSlot : 0]
1407 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1409 needsBindVBuf =
true;
1410 cbD->currentVertexBuffers[inputSlot] = bufD->handles[isDynamic ? currentFrameSlot : 0];
1411 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1415 if (needsBindVBuf) {
1416 QVarLengthArray<D3D12_VERTEX_BUFFER_VIEW, 4> vbv;
1417 vbv.reserve(bindingCount);
1419 QD3D12GraphicsPipeline *psD = cbD->currentGraphicsPipeline;
1420 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1421 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1423 for (
int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1424 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1425 const QD3D12ObjectHandle handle = bufD->handles[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
1426 const quint32 offset = bindings[i].second;
1427 const quint32 stride = inputLayout.bindingAt(i)->stride();
1429 if (bufD->m_type != QRhiBuffer::Dynamic) {
1430 barrierGen.addTransitionBarrier(handle, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
1431 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1434 if (QD3D12Resource *res = resourcePool.lookupRef(handle)) {
1436 res->resource->GetGPUVirtualAddress() + offset,
1437 UINT(res->desc.Width - offset),
1443 cbD->cmdList->IASetVertexBuffers(UINT(startBinding), vbv.count(), vbv.constData());
1447 QD3D12Buffer *ibufD = QRHI_RES(QD3D12Buffer, indexBuf);
1448 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1449 const bool isDynamic = ibufD->m_type == QRhiBuffer::Dynamic;
1451 ibufD->executeHostWritesForFrameSlot(currentFrameSlot);
1453 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1454 : DXGI_FORMAT_R32_UINT;
1455 if (cbD->currentIndexBuffer != ibufD->handles[isDynamic ? currentFrameSlot : 0]
1456 || cbD->currentIndexOffset != indexOffset
1457 || cbD->currentIndexFormat != dxgiFormat)
1459 cbD->currentIndexBuffer = ibufD->handles[isDynamic ? currentFrameSlot : 0];
1460 cbD->currentIndexOffset = indexOffset;
1461 cbD->currentIndexFormat = dxgiFormat;
1463 if (ibufD->m_type != QRhiBuffer::Dynamic) {
1464 barrierGen.addTransitionBarrier(cbD->currentIndexBuffer, D3D12_RESOURCE_STATE_INDEX_BUFFER);
1465 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1468 if (QD3D12Resource *res = resourcePool.lookupRef(cbD->currentIndexBuffer)) {
1469 const D3D12_INDEX_BUFFER_VIEW ibv = {
1470 res->resource->GetGPUVirtualAddress() + indexOffset,
1471 UINT(res->desc.Width - indexOffset),
1474 cbD->cmdList->IASetIndexBuffer(&ibv);
1480void QRhiD3D12::setViewport(QRhiCommandBuffer *cb,
const QRhiViewport &viewport)
1482 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1483 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1484 Q_ASSERT(cbD->currentTarget);
1485 const QSize outputSize = cbD->currentTarget->pixelSize();
1489 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1497 v.MinDepth = viewport.minDepth();
1498 v.MaxDepth = viewport.maxDepth();
1499 cbD->cmdList->RSSetViewports(1, &v);
1501 if (cbD->currentGraphicsPipeline
1502 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
1504 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, viewport.viewport(), &x, &y, &w, &h);
1511 cbD->cmdList->RSSetScissorRects(1, &r);
1515void QRhiD3D12::setScissor(QRhiCommandBuffer *cb,
const QRhiScissor &scissor)
1517 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1518 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1519 Q_ASSERT(cbD->currentTarget);
1520 const QSize outputSize = cbD->currentTarget->pixelSize();
1524 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
1533 cbD->cmdList->RSSetScissorRects(1, &r);
1536void QRhiD3D12::setBlendConstants(QRhiCommandBuffer *cb,
const QColor &c)
1538 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1539 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1540 float v[4] = { c.redF(), c.greenF(), c.blueF(), c.alphaF() };
1541 cbD->cmdList->OMSetBlendFactor(v);
1544void QRhiD3D12::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
1546 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1547 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1548 cbD->cmdList->OMSetStencilRef(refValue);
1551static inline D3D12_SHADING_RATE toD3DShadingRate(
const QSize &coarsePixelSize)
1553 if (coarsePixelSize == QSize(1, 2))
1554 return D3D12_SHADING_RATE_1X2;
1555 if (coarsePixelSize == QSize(2, 1))
1556 return D3D12_SHADING_RATE_2X1;
1557 if (coarsePixelSize == QSize(2, 2))
1558 return D3D12_SHADING_RATE_2X2;
1559 if (coarsePixelSize == QSize(2, 4))
1560 return D3D12_SHADING_RATE_2X4;
1561 if (coarsePixelSize == QSize(4, 2))
1562 return D3D12_SHADING_RATE_4X2;
1563 if (coarsePixelSize == QSize(4, 4))
1564 return D3D12_SHADING_RATE_4X4;
1565 return D3D12_SHADING_RATE_1X1;
1568void QRhiD3D12::setShadingRate(QRhiCommandBuffer *cb,
const QSize &coarsePixelSize)
1570 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1571 cbD->hasShadingRateSet =
false;
1573#ifdef QRHI_D3D12_CL5_AVAILABLE
1577 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1578 const D3D12_SHADING_RATE_COMBINER combiners[] = { D3D12_SHADING_RATE_COMBINER_MAX, D3D12_SHADING_RATE_COMBINER_MAX };
1579 cbD->cmdList->RSSetShadingRate(toD3DShadingRate(coarsePixelSize), combiners);
1580 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
1581 cbD->hasShadingRateSet =
true;
1584 Q_UNUSED(coarsePixelSize);
1585 qWarning(
"Attempted to set ShadingRate without building Qt against a sufficiently new Windows SDK and d3d12.h. This cannot work.");
1589void QRhiD3D12::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
1590 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
1592 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1593 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1594 cbD->cmdList->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
1597void QRhiD3D12::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
1598 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
1600 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1601 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1602 cbD->cmdList->DrawIndexedInstanced(indexCount, instanceCount,
1603 firstIndex, vertexOffset,
1607void QRhiD3D12::debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name)
1612 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1613#ifdef QRHI_D3D12_HAS_OLD_PIX
1614 PIXBeginEvent(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(name).utf16()));
1621void QRhiD3D12::debugMarkEnd(QRhiCommandBuffer *cb)
1626 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1627#ifdef QRHI_D3D12_HAS_OLD_PIX
1628 PIXEndEvent(cbD->cmdList);
1634void QRhiD3D12::debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg)
1639 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1640#ifdef QRHI_D3D12_HAS_OLD_PIX
1641 PIXSetMarker(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(msg).utf16()));
1648const QRhiNativeHandles *QRhiD3D12::nativeHandles(QRhiCommandBuffer *cb)
1650 return QRHI_RES(QD3D12CommandBuffer, cb)->nativeHandles();
1653void QRhiD3D12::beginExternal(QRhiCommandBuffer *cb)
1658void QRhiD3D12::endExternal(QRhiCommandBuffer *cb)
1660 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1661 cbD->resetPerPassState();
1662 bindShaderVisibleHeaps(cbD);
1663 if (cbD->currentTarget) {
1664 QD3D12RenderTargetData *rtD = rtData(cbD->currentTarget);
1665 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
1668 rtD->dsAttCount ? &rtD->dsv :
nullptr);
1672double QRhiD3D12::lastCompletedGpuTime(QRhiCommandBuffer *cb)
1674 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1675 return cbD->lastGpuTime;
1678static void calculateGpuTime(QD3D12CommandBuffer *cbD,
1679 int timestampPairStartIndex,
1680 const quint8 *readbackBufPtr,
1681 quint64 timestampTicksPerSecond)
1683 const size_t byteOffset = timestampPairStartIndex *
sizeof(quint64);
1684 const quint64 *p =
reinterpret_cast<
const quint64 *>(readbackBufPtr + byteOffset);
1685 const quint64 startTime = *p++;
1686 const quint64 endTime = *p;
1687 if (startTime < endTime) {
1688 const quint64 ticks = endTime - startTime;
1689 const double timeSec = ticks /
double(timestampTicksPerSecond);
1690 cbD->lastGpuTime = timeSec;
1694QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
1698 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
1699 currentSwapChain = swapChainD;
1700 currentFrameSlot = swapChainD->currentFrameSlot;
1701 QD3D12SwapChain::FrameResources &fr(swapChainD->frameRes[currentFrameSlot]);
1714 for (QD3D12SwapChain *sc : std::as_const(swapchains))
1715 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
1717 if (swapChainD->frameLatencyWaitableObject) {
1719 if (swapChainD->lastFrameLatencyWaitSlot != currentFrameSlot) {
1720 WaitForSingleObjectEx(swapChainD->frameLatencyWaitableObject, 1000,
true);
1721 swapChainD->lastFrameLatencyWaitSlot = currentFrameSlot;
1725 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
1727 qWarning(
"Failed to reset command allocator: %s",
1728 qPrintable(QSystemError::windowsComString(hr)));
1729 return QRhi::FrameOpError;
1732 if (!startCommandListForCurrentFrameSlot(&fr.cmdList))
1733 return QRhi::FrameOpError;
1735 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1736 cbD->cmdList = fr.cmdList;
1738 swapChainD->rtWrapper.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1739 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1740 : swapChainD->rtvs[swapChainD->currentBackBufferIndex].cpuHandle;
1742 swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
1743 : D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
1745 if (swapChainD->stereo) {
1746 swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1747 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1748 : swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
1750 swapChainD->rtWrapperRight.d.dsv =
1751 swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
1758 releaseQueue.executeDeferredReleases(currentFrameSlot);
1764 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1766 smallStagingAreas[currentFrameSlot].head = 0;
1768 bindShaderVisibleHeaps(cbD);
1770 finishActiveReadbacks();
1772 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
1775 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1776 calculateGpuTime(cbD,
1777 timestampPairStartIndex,
1778 timestampReadbackArea.mem.p,
1779 timestampTicksPerSecond);
1781 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1782 D3D12_QUERY_TYPE_TIMESTAMP,
1783 timestampPairStartIndex);
1786 QDxgiVSyncService::instance()->beginFrame(adapterLuid);
1788 return QRhi::FrameOpSuccess;
1791QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
1793 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
1794 Q_ASSERT(currentSwapChain == swapChainD);
1795 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1797 QD3D12ObjectHandle backBufferResourceHandle = swapChainD->colorBuffers[swapChainD->currentBackBufferIndex];
1798 if (swapChainD->sampleDesc.Count > 1) {
1799 QD3D12ObjectHandle msaaBackBufferResourceHandle = swapChainD->msaaBuffers[swapChainD->currentBackBufferIndex];
1800 barrierGen.addTransitionBarrier(msaaBackBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
1801 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
1802 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1803 const QD3D12Resource *src = resourcePool.lookupRef(msaaBackBufferResourceHandle);
1804 const QD3D12Resource *dst = resourcePool.lookupRef(backBufferResourceHandle);
1806 cbD->cmdList->ResolveSubresource(dst->resource, 0, src->resource, 0, swapChainD->colorFormat);
1809 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
1810 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1812 if (timestampQueryHeap.isValid()) {
1813 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1814 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1815 D3D12_QUERY_TYPE_TIMESTAMP,
1816 timestampPairStartIndex + 1);
1817 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
1818 D3D12_QUERY_TYPE_TIMESTAMP,
1819 timestampPairStartIndex,
1821 timestampReadbackArea.mem.buffer,
1822 timestampPairStartIndex *
sizeof(quint64));
1825 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
1826 HRESULT hr = cmdList->Close();
1828 qWarning(
"Failed to close command list: %s",
1829 qPrintable(QSystemError::windowsComString(hr)));
1830 return QRhi::FrameOpError;
1833 ID3D12CommandList *execList[] = { cmdList };
1834 cmdQueue->ExecuteCommandLists(1, execList);
1836 if (!flags.testFlag(QRhi::SkipPresent)) {
1837 UINT presentFlags = 0;
1838 if (swapChainD->swapInterval == 0
1839 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
1841 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
1843 if (!swapChainD->swapChain) {
1844 qWarning(
"Failed to present, no swapchain");
1845 return QRhi::FrameOpError;
1847 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
1848 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
1849 qWarning(
"Device loss detected in Present()");
1851 return QRhi::FrameOpDeviceLost;
1852 }
else if (FAILED(hr)) {
1853 qWarning(
"Failed to present: %s", qPrintable(QSystemError::windowsComString(hr)));
1854 return QRhi::FrameOpError;
1857 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
1858 dcompDevice->Commit();
1861 swapChainD->addCommandCompletionSignalForCurrentFrameSlot();
1868 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
1870 if (!flags.testFlag(QRhi::SkipPresent)) {
1874 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
1875 swapChainD->currentBackBufferIndex = swapChainD->swapChain->GetCurrentBackBufferIndex();
1878 currentSwapChain =
nullptr;
1879 return QRhi::FrameOpSuccess;
1882QRhi::FrameOpResult QRhiD3D12::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
1895 currentFrameSlot = (currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
1897 for (QD3D12SwapChain *sc : std::as_const(swapchains))
1898 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
1900 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
1902 qWarning(
"Failed to reset command allocator: %s",
1903 qPrintable(QSystemError::windowsComString(hr)));
1904 return QRhi::FrameOpError;
1907 if (!offscreenCb[currentFrameSlot])
1908 offscreenCb[currentFrameSlot] =
new QD3D12CommandBuffer(
this);
1909 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
1910 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
1911 return QRhi::FrameOpError;
1913 releaseQueue.executeDeferredReleases(currentFrameSlot);
1915 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1916 smallStagingAreas[currentFrameSlot].head = 0;
1918 bindShaderVisibleHeaps(cbD);
1920 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
1921 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1922 D3D12_QUERY_TYPE_TIMESTAMP,
1923 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT);
1926 offscreenActive =
true;
1929 return QRhi::FrameOpSuccess;
1932QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
1935 Q_ASSERT(offscreenActive);
1936 offscreenActive =
false;
1938 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
1939 if (timestampQueryHeap.isValid()) {
1940 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
1941 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
1942 D3D12_QUERY_TYPE_TIMESTAMP,
1943 timestampPairStartIndex + 1);
1944 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
1945 D3D12_QUERY_TYPE_TIMESTAMP,
1946 timestampPairStartIndex,
1948 timestampReadbackArea.mem.buffer,
1949 timestampPairStartIndex *
sizeof(quint64));
1952 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
1953 HRESULT hr = cmdList->Close();
1955 qWarning(
"Failed to close command list: %s",
1956 qPrintable(QSystemError::windowsComString(hr)));
1957 return QRhi::FrameOpError;
1960 ID3D12CommandList *execList[] = { cmdList };
1961 cmdQueue->ExecuteCommandLists(1, execList);
1963 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
1970 finishActiveReadbacks(
true);
1973 if (timestampQueryHeap.isValid()) {
1974 calculateGpuTime(cbD,
1975 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT,
1976 timestampReadbackArea.mem.p,
1977 timestampTicksPerSecond);
1980 return QRhi::FrameOpSuccess;
1983QRhi::FrameOpResult QRhiD3D12::finish()
1985 QD3D12CommandBuffer *cbD =
nullptr;
1987 if (offscreenActive) {
1988 Q_ASSERT(!currentSwapChain);
1989 cbD = offscreenCb[currentFrameSlot];
1991 Q_ASSERT(currentSwapChain);
1992 cbD = ¤tSwapChain->cbWrapper;
1995 return QRhi::FrameOpError;
1997 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
1999 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2000 HRESULT hr = cmdList->Close();
2002 qWarning(
"Failed to close command list: %s",
2003 qPrintable(QSystemError::windowsComString(hr)));
2004 return QRhi::FrameOpError;
2007 ID3D12CommandList *execList[] = { cmdList };
2008 cmdQueue->ExecuteCommandLists(1, execList);
2010 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2017 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2019 qWarning(
"Failed to reset command allocator: %s",
2020 qPrintable(QSystemError::windowsComString(hr)));
2021 return QRhi::FrameOpError;
2024 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2025 return QRhi::FrameOpError;
2029 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2030 smallStagingAreas[currentFrameSlot].head = 0;
2032 bindShaderVisibleHeaps(cbD);
2035 releaseQueue.releaseAll();
2036 finishActiveReadbacks(
true);
2038 return QRhi::FrameOpSuccess;
2041void QRhiD3D12::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2043 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2044 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2045 enqueueResourceUpdates(cbD, resourceUpdates);
2048void QRhiD3D12::beginPass(QRhiCommandBuffer *cb,
2049 QRhiRenderTarget *rt,
2050 const QColor &colorClearValue,
2051 const QRhiDepthStencilClearValue &depthStencilClearValue,
2052 QRhiResourceUpdateBatch *resourceUpdates,
2053 QRhiCommandBuffer::BeginPassFlags)
2055 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2056 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2058 if (resourceUpdates)
2059 enqueueResourceUpdates(cbD, resourceUpdates);
2061 QD3D12RenderTargetData *rtD = rtData(rt);
2062 bool wantsColorClear =
true;
2063 bool wantsDsClear =
true;
2064 if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) {
2065 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, rt);
2066 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2067 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2068 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2071 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); it != itEnd; ++it) {
2072 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
2073 QD3D12Texture *resolveTexD = QRHI_RES(QD3D12Texture, it->resolveTexture());
2074 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
2076 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2078 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2080 barrierGen.addTransitionBarrier(resolveTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2082 if (rtTex->m_desc.depthStencilBuffer()) {
2083 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rtTex->m_desc.depthStencilBuffer());
2084 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
2085 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2086 }
else if (rtTex->m_desc.depthTexture()) {
2087 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, rtTex->m_desc.depthTexture());
2088 barrierGen.addTransitionBarrier(depthTexD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2090 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2092 Q_ASSERT(currentSwapChain);
2093 barrierGen.addTransitionBarrier(currentSwapChain->sampleDesc.Count > 1
2094 ? currentSwapChain->msaaBuffers[currentSwapChain->currentBackBufferIndex]
2095 : currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex],
2096 D3D12_RESOURCE_STATE_RENDER_TARGET);
2097 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2100 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2103 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2105 if (rtD->colorAttCount && wantsColorClear) {
2106 float clearColor[4] = {
2107 colorClearValue.redF(),
2108 colorClearValue.greenF(),
2109 colorClearValue.blueF(),
2110 colorClearValue.alphaF()
2112 for (
int i = 0; i < rtD->colorAttCount; ++i)
2113 cbD->cmdList->ClearRenderTargetView(rtD->rtv[i], clearColor, 0,
nullptr);
2115 if (rtD->dsAttCount && wantsDsClear) {
2116 cbD->cmdList->ClearDepthStencilView(rtD->dsv,
2117 D3D12_CLEAR_FLAGS(D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL),
2118 depthStencilClearValue.depthClearValue(),
2119 UINT8(depthStencilClearValue.stencilClearValue()),
2124 cbD->recordingPass = QD3D12CommandBuffer::RenderPass;
2125 cbD->currentTarget = rt;
2127 bool hasShadingRateMapSet =
false;
2128#ifdef QRHI_D3D12_CL5_AVAILABLE
2129 if (rtD->rp->hasShadingRateMap) {
2130 cbD->setShadingRate(QSize(1, 1));
2131 QD3D12ShadingRateMap *rateMapD = rt->resourceType() == QRhiRenderTarget::TextureRenderTarget
2132 ? QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12TextureRenderTarget, rt)->m_desc.shadingRateMap())
2133 : QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12SwapChainRenderTarget, rt)->swapChain()->shadingRateMap());
2134 if (QD3D12Resource *res = resourcePool.lookupRef(rateMapD->handle)) {
2135 barrierGen.addTransitionBarrier(rateMapD->handle, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
2136 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2137 cbD->cmdList->RSSetShadingRateImage(res->resource);
2138 hasShadingRateMapSet =
true;
2140 }
else if (cbD->hasShadingRateMapSet) {
2141 cbD->cmdList->RSSetShadingRateImage(
nullptr);
2142 cbD->setShadingRate(QSize(1, 1));
2143 }
else if (cbD->hasShadingRateSet) {
2144 cbD->setShadingRate(QSize(1, 1));
2148 cbD->resetPerPassState();
2151 cbD->hasShadingRateMapSet = hasShadingRateMapSet;
2154void QRhiD3D12::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2156 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2157 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2159 if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
2160 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, cbD->currentTarget);
2161 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2164 const QRhiColorAttachment &colorAtt(*it);
2165 if (!colorAtt.resolveTexture())
2168 QD3D12Texture *dstTexD = QRHI_RES(QD3D12Texture, colorAtt.resolveTexture());
2169 QD3D12Resource *dstRes = resourcePool.lookupRef(dstTexD->handle);
2173 QD3D12Texture *srcTexD = QRHI_RES(QD3D12Texture, colorAtt.texture());
2174 QD3D12RenderBuffer *srcRbD = QRHI_RES(QD3D12RenderBuffer, colorAtt.renderBuffer());
2175 Q_ASSERT(srcTexD || srcRbD);
2176 QD3D12Resource *srcRes = resourcePool.lookupRef(srcTexD ? srcTexD->handle : srcRbD->handle);
2181 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2182 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2183 int(srcTexD->dxgiFormat),
int(dstTexD->dxgiFormat));
2186 if (srcTexD->sampleDesc.Count <= 1) {
2187 qWarning(
"Cannot resolve a non-multisample texture");
2190 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2191 qWarning(
"Resolve source and destination sizes do not match");
2195 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2196 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2197 int(srcRbD->dxgiFormat),
int(dstTexD->dxgiFormat));
2200 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2201 qWarning(
"Resolve source and destination sizes do not match");
2206 barrierGen.addTransitionBarrier(srcTexD ? srcTexD->handle : srcRbD->handle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2207 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2208 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2210 const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
2211 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2212 const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
2213 const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
2214 UINT(colorAtt.resolveLayer()) + resolveIdx,
2215 dstTexD->mipLevelCount);
2216 cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresource,
2217 srcRes->resource, srcSubresource,
2218 dstTexD->dxgiFormat);
2221 if (rtTex->m_desc.depthResolveTexture())
2222 qWarning(
"Resolving multisample depth-stencil buffers is not supported with D3D");
2225 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2226 cbD->currentTarget =
nullptr;
2228 if (resourceUpdates)
2229 enqueueResourceUpdates(cbD, resourceUpdates);
2232void QRhiD3D12::beginComputePass(QRhiCommandBuffer *cb,
2233 QRhiResourceUpdateBatch *resourceUpdates,
2234 QRhiCommandBuffer::BeginPassFlags)
2236 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2237 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2239 if (resourceUpdates)
2240 enqueueResourceUpdates(cbD, resourceUpdates);
2242 cbD->recordingPass = QD3D12CommandBuffer::ComputePass;
2244 cbD->resetPerPassState();
2247void QRhiD3D12::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2249 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2250 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2252 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2254 if (resourceUpdates)
2255 enqueueResourceUpdates(cbD, resourceUpdates);
2258void QRhiD3D12::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
2260 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2261 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2262 QD3D12ComputePipeline *psD = QRHI_RES(QD3D12ComputePipeline, ps);
2263 const bool pipelineChanged = cbD->currentComputePipeline != psD || cbD->currentPipelineGeneration != psD->generation;
2265 if (pipelineChanged) {
2266 cbD->currentGraphicsPipeline =
nullptr;
2267 cbD->currentComputePipeline = psD;
2268 cbD->currentPipelineGeneration = psD->generation;
2270 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
2271 Q_ASSERT(pipeline->type == QD3D12Pipeline::Compute);
2272 cbD->cmdList->SetPipelineState(pipeline->pso);
2273 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
2274 cbD->cmdList->SetComputeRootSignature(rs->rootSig);
2279void QRhiD3D12::dispatch(QRhiCommandBuffer *cb,
int x,
int y,
int z)
2281 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2282 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2283 cbD->cmdList->Dispatch(UINT(x), UINT(y), UINT(z));
2286bool QD3D12DescriptorHeap::create(ID3D12Device *device,
2287 quint32 descriptorCount,
2288 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
2289 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags)
2292 capacity = descriptorCount;
2293 this->heapType = heapType;
2294 this->heapFlags = heapFlags;
2296 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
2297 heapDesc.Type = heapType;
2298 heapDesc.NumDescriptors = capacity;
2299 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS(heapFlags);
2301 HRESULT hr = device->CreateDescriptorHeap(&heapDesc, __uuidof(ID3D12DescriptorHeap),
reinterpret_cast<
void **>(&heap));
2303 qWarning(
"Failed to create descriptor heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2305 capacity = descriptorByteSize = 0;
2309 descriptorByteSize = device->GetDescriptorHandleIncrementSize(heapType);
2310 heapStart.cpuHandle = heap->GetCPUDescriptorHandleForHeapStart();
2311 if (heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
2312 heapStart.gpuHandle = heap->GetGPUDescriptorHandleForHeapStart();
2317void QD3D12DescriptorHeap::createWithExisting(
const QD3D12DescriptorHeap &other,
2318 quint32 offsetInDescriptors,
2319 quint32 descriptorCount)
2323 capacity = descriptorCount;
2324 heapType = other.heapType;
2325 heapFlags = other.heapFlags;
2326 descriptorByteSize = other.descriptorByteSize;
2327 heapStart = incremented(other.heapStart, offsetInDescriptors);
2330void QD3D12DescriptorHeap::destroy()
2339void QD3D12DescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2342 releaseQueue->deferredReleaseDescriptorHeap(heap);
2348QD3D12Descriptor QD3D12DescriptorHeap::get(quint32 count)
2350 Q_ASSERT(count > 0);
2351 if (head + count > capacity) {
2352 qWarning(
"Cannot get %u descriptors as that would exceed capacity %u", count, capacity);
2356 return at(head - count);
2359QD3D12Descriptor QD3D12DescriptorHeap::at(quint32 index)
const
2361 const quint32 startOffset = index * descriptorByteSize;
2362 QD3D12Descriptor result;
2363 result.cpuHandle.ptr = heapStart.cpuHandle.ptr + startOffset;
2364 if (heapStart.gpuHandle.ptr != 0)
2365 result.gpuHandle.ptr = heapStart.gpuHandle.ptr + startOffset;
2369bool QD3D12CpuDescriptorPool::create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName)
2371 QD3D12DescriptorHeap firstHeap;
2372 if (!firstHeap.create(device, DESCRIPTORS_PER_HEAP, heapType, D3D12_DESCRIPTOR_HEAP_FLAG_NONE))
2374 heaps.append(HeapWithMap::init(firstHeap, DESCRIPTORS_PER_HEAP));
2375 descriptorByteSize = heaps[0].heap.descriptorByteSize;
2376 this->device = device;
2377 this->debugName = debugName;
2381void QD3D12CpuDescriptorPool::destroy()
2385 static bool leakCheck =
true;
2388 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
2391 for (HeapWithMap &heap : heaps) {
2392 const int leakedDescriptorCount = heap.map.count(
true);
2393 if (leakedDescriptorCount > 0) {
2394 qWarning(
"QD3D12CpuDescriptorPool::destroy(): "
2395 "Heap %p for descriptor pool %p '%s' has %d unreleased descriptors",
2396 &heap.heap,
this, debugName, leakedDescriptorCount);
2400 for (HeapWithMap &heap : heaps)
2401 heap.heap.destroy();
2405QD3D12Descriptor QD3D12CpuDescriptorPool::allocate(quint32 count)
2407 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2409 HeapWithMap &last(heaps.last());
2410 if (last.heap.head + count <= last.heap.capacity) {
2411 quint32 firstIndex = last.heap.head;
2412 for (quint32 i = 0; i < count; ++i)
2413 last.map.setBit(firstIndex + i);
2414 return last.heap.get(count);
2417 for (HeapWithMap &heap : heaps) {
2418 quint32 freeCount = 0;
2419 for (quint32 i = 0; i < DESCRIPTORS_PER_HEAP; ++i) {
2420 if (heap.map.testBit(i)) {
2424 if (freeCount == count) {
2425 quint32 firstIndex = i - (freeCount - 1);
2426 for (quint32 j = 0; j < count; ++j) {
2427 heap.map.setBit(firstIndex + j);
2428 return heap.heap.at(firstIndex);
2435 QD3D12DescriptorHeap newHeap;
2436 if (!newHeap.create(device, DESCRIPTORS_PER_HEAP, last.heap.heapType, last.heap.heapFlags))
2439 heaps.append(HeapWithMap::init(newHeap, DESCRIPTORS_PER_HEAP));
2441 for (quint32 i = 0; i < count; ++i)
2442 heaps.last().map.setBit(i);
2444 return heaps.last().heap.get(count);
2447void QD3D12CpuDescriptorPool::release(
const QD3D12Descriptor &descriptor, quint32 count)
2449 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2450 if (!descriptor.isValid())
2453 const SIZE_T addr = descriptor.cpuHandle.ptr;
2454 for (HeapWithMap &heap : heaps) {
2455 const SIZE_T begin = heap.heap.heapStart.cpuHandle.ptr;
2456 const SIZE_T end = begin + heap.heap.descriptorByteSize * heap.heap.capacity;
2457 if (addr >= begin && addr < end) {
2458 quint32 firstIndex = (addr - begin) / heap.heap.descriptorByteSize;
2459 for (quint32 i = 0; i < count; ++i)
2460 heap.map.setBit(firstIndex + i,
false);
2465 qWarning(
"QD3D12CpuDescriptorPool::release: Descriptor with address %llu is not in any heap",
2466 quint64(descriptor.cpuHandle.ptr));
2469bool QD3D12QueryHeap::create(ID3D12Device *device,
2471 D3D12_QUERY_HEAP_TYPE heapType)
2473 capacity = queryCount;
2475 D3D12_QUERY_HEAP_DESC heapDesc = {};
2476 heapDesc.Type = heapType;
2477 heapDesc.Count = capacity;
2479 HRESULT hr = device->CreateQueryHeap(&heapDesc, __uuidof(ID3D12QueryHeap),
reinterpret_cast<
void **>(&heap));
2481 qWarning(
"Failed to create query heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2490void QD3D12QueryHeap::destroy()
2499bool QD3D12StagingArea::create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType)
2501 Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
2502 D3D12_RESOURCE_DESC resourceDesc = {};
2503 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
2504 resourceDesc.Width = capacity;
2505 resourceDesc.Height = 1;
2506 resourceDesc.DepthOrArraySize = 1;
2507 resourceDesc.MipLevels = 1;
2508 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
2509 resourceDesc.SampleDesc = { 1, 0 };
2510 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2511 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
2512 UINT state = heapType == D3D12_HEAP_TYPE_UPLOAD ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
2513 HRESULT hr = rhi->vma.createResource(heapType,
2515 D3D12_RESOURCE_STATES(state),
2518 __uuidof(ID3D12Resource),
2519 reinterpret_cast<
void **>(&resource));
2521 qWarning(
"Failed to create buffer for staging area: %s",
2522 qPrintable(QSystemError::windowsComString(hr)));
2526 hr = resource->Map(0,
nullptr, &p);
2528 qWarning(
"Failed to map buffer for staging area: %s",
2529 qPrintable(QSystemError::windowsComString(hr)));
2534 mem.p =
static_cast<quint8 *>(p);
2535 mem.gpuAddr = resource->GetGPUVirtualAddress();
2536 mem.buffer = resource;
2537 mem.bufferOffset = 0;
2539 this->capacity = capacity;
2545void QD3D12StagingArea::destroy()
2548 resource->Release();
2552 allocation->Release();
2553 allocation =
nullptr;
2558void QD3D12StagingArea::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2561 releaseQueue->deferredReleaseResourceAndAllocation(resource, allocation);
2565QD3D12StagingArea::Allocation QD3D12StagingArea::get(quint32 byteSize)
2567 const quint32 allocSize = aligned(byteSize, ALIGNMENT);
2568 if (head + allocSize > capacity) {
2569 qWarning(
"Failed to allocate %u (%u) bytes from staging area of size %u with %u bytes left",
2570 allocSize, byteSize, capacity, remainingCapacity());
2573 const quint32 offset = head;
2577 mem.gpuAddr + offset,
2586void QD3D12ReleaseQueue::deferredReleaseResource(
const QD3D12ObjectHandle &handle)
2588 DeferredReleaseEntry e;
2593void QD3D12ReleaseQueue::deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
2594 QD3D12CpuDescriptorPool *pool,
2595 const QD3D12Descriptor &viewsStart,
2598 DeferredReleaseEntry e;
2599 e.type = DeferredReleaseEntry::Resource;
2601 e.poolForViews = pool;
2602 e.viewsStart = viewsStart;
2603 e.viewCount = viewCount;
2607void QD3D12ReleaseQueue::deferredReleasePipeline(
const QD3D12ObjectHandle &handle)
2609 DeferredReleaseEntry e;
2610 e.type = DeferredReleaseEntry::Pipeline;
2615void QD3D12ReleaseQueue::deferredReleaseRootSignature(
const QD3D12ObjectHandle &handle)
2617 DeferredReleaseEntry e;
2618 e.type = DeferredReleaseEntry::RootSignature;
2623void QD3D12ReleaseQueue::deferredReleaseCallback(std::function<
void(
void*)> callback,
void *userData)
2625 DeferredReleaseEntry e;
2626 e.type = DeferredReleaseEntry::Callback;
2627 e.callback = callback;
2628 e.callbackUserData = userData;
2632void QD3D12ReleaseQueue::deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
2633 D3D12MA::Allocation *allocation)
2635 DeferredReleaseEntry e;
2636 e.type = DeferredReleaseEntry::ResourceAndAllocation;
2637 e.resourceAndAllocation = { resource, allocation };
2641void QD3D12ReleaseQueue::deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap)
2643 DeferredReleaseEntry e;
2644 e.type = DeferredReleaseEntry::DescriptorHeap;
2645 e.descriptorHeap = heap;
2649void QD3D12ReleaseQueue::deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
2650 const QD3D12Descriptor &viewsStart,
2653 DeferredReleaseEntry e;
2654 e.type = DeferredReleaseEntry::Views;
2655 e.poolForViews = pool;
2656 e.viewsStart = viewsStart;
2657 e.viewCount = viewCount;
2661void QD3D12ReleaseQueue::activatePendingDeferredReleaseRequests(
int frameSlot)
2663 for (DeferredReleaseEntry &e : queue) {
2664 if (!e.frameSlotToBeReleasedIn.has_value())
2665 e.frameSlotToBeReleasedIn = frameSlot;
2669void QD3D12ReleaseQueue::executeDeferredReleases(
int frameSlot,
bool forced)
2671 for (
int i = queue.count() - 1; i >= 0; --i) {
2672 const DeferredReleaseEntry &e(queue[i]);
2673 if (forced || (e.frameSlotToBeReleasedIn.has_value() && e.frameSlotToBeReleasedIn.value() == frameSlot)) {
2675 case DeferredReleaseEntry::Resource:
2676 resourcePool->remove(e.handle);
2677 if (e.poolForViews && e.viewsStart.isValid() && e.viewCount > 0)
2678 e.poolForViews->release(e.viewsStart, e.viewCount);
2680 case DeferredReleaseEntry::Pipeline:
2681 pipelinePool->remove(e.handle);
2683 case DeferredReleaseEntry::RootSignature:
2684 rootSignaturePool->remove(e.handle);
2686 case DeferredReleaseEntry::Callback:
2687 e.callback(e.callbackUserData);
2689 case DeferredReleaseEntry::ResourceAndAllocation:
2692 e.resourceAndAllocation.first->Release();
2693 if (e.resourceAndAllocation.second)
2694 e.resourceAndAllocation.second->Release();
2696 case DeferredReleaseEntry::DescriptorHeap:
2697 e.descriptorHeap->Release();
2699 case DeferredReleaseEntry::Views:
2700 e.poolForViews->release(e.viewsStart, e.viewCount);
2708void QD3D12ReleaseQueue::releaseAll()
2710 executeDeferredReleases(0,
true);
2713void QD3D12ResourceBarrierGenerator::addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle,
2714 D3D12_RESOURCE_STATES stateAfter)
2716 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2717 if (stateAfter != res->state) {
2718 transitionResourceBarriers.append({ resourceHandle, res->state, stateAfter });
2719 res->state = stateAfter;
2724void QD3D12ResourceBarrierGenerator::enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD)
2726 QVarLengthArray<D3D12_RESOURCE_BARRIER, PREALLOC> barriers;
2727 for (
const TransitionResourceBarrier &trb : transitionResourceBarriers) {
2728 if (QD3D12Resource *res = resourcePool->lookupRef(trb.resourceHandle)) {
2729 D3D12_RESOURCE_BARRIER barrier = {};
2730 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2731 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2732 barrier.Transition.pResource = res->resource;
2733 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
2734 barrier.Transition.StateBefore = trb.stateBefore;
2735 barrier.Transition.StateAfter = trb.stateAfter;
2736 barriers.append(barrier);
2739 transitionResourceBarriers.clear();
2740 if (!barriers.isEmpty())
2741 cbD->cmdList->ResourceBarrier(barriers.count(), barriers.constData());
2744void QD3D12ResourceBarrierGenerator::enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
2745 const QD3D12ObjectHandle &resourceHandle,
2747 D3D12_RESOURCE_STATES stateBefore,
2748 D3D12_RESOURCE_STATES stateAfter)
2750 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2751 D3D12_RESOURCE_BARRIER barrier = {};
2752 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2753 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2754 barrier.Transition.pResource = res->resource;
2755 barrier.Transition.Subresource = subresource;
2756 barrier.Transition.StateBefore = stateBefore;
2757 barrier.Transition.StateAfter = stateAfter;
2758 cbD->cmdList->ResourceBarrier(1, &barrier);
2762void QD3D12ResourceBarrierGenerator::enqueueUavBarrier(QD3D12CommandBuffer *cbD,
2763 const QD3D12ObjectHandle &resourceHandle)
2765 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
2766 D3D12_RESOURCE_BARRIER barrier = {};
2767 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
2768 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2769 barrier.UAV.pResource = res->resource;
2770 cbD->cmdList->ResourceBarrier(1, &barrier);
2774void QD3D12ShaderBytecodeCache::insertWithCapacityLimit(
const QRhiShaderStage &key,
const Shader &s)
2776 if (data.count() >= QRhiD3D12::MAX_SHADER_CACHE_ENTRIES)
2778 data.insert(key, s);
2781bool QD3D12ShaderVisibleDescriptorHeap::create(ID3D12Device *device,
2782 D3D12_DESCRIPTOR_HEAP_TYPE type,
2783 quint32 perFrameDescriptorCount)
2785 Q_ASSERT(type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
2787 quint32 size = perFrameDescriptorCount * QD3D12_FRAMES_IN_FLIGHT;
2790 const quint32 CBV_SRV_UAV_MAX = 1000000;
2791 const quint32 SAMPLER_MAX = 2048;
2792 if (type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
2793 size = qMin(size, CBV_SRV_UAV_MAX);
2794 else if (type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
2795 size = qMin(size, SAMPLER_MAX);
2797 if (!heap.create(device, size, type, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
2798 qWarning(
"Failed to create shader-visible descriptor heap of size %u", size);
2802 perFrameDescriptorCount = size / QD3D12_FRAMES_IN_FLIGHT;
2803 quint32 currentOffsetInDescriptors = 0;
2804 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
2805 perFrameHeapSlice[i].createWithExisting(heap, currentOffsetInDescriptors, perFrameDescriptorCount);
2806 currentOffsetInDescriptors += perFrameDescriptorCount;
2812void QD3D12ShaderVisibleDescriptorHeap::destroy()
2817void QD3D12ShaderVisibleDescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2819 heap.destroyWithDeferredRelease(releaseQueue);
2822static inline std::pair<
int,
int> mapBinding(
int binding,
const QShader::NativeResourceBindingMap &map)
2825 return { binding, binding };
2827 auto it = map.constFind(binding);
2828 if (it != map.cend())
2837void QD3D12ShaderResourceVisitor::visit()
2839 for (
int bindingIdx = 0, bindingCount = srb->m_bindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
2840 const QRhiShaderResourceBinding &b(srb->m_bindings[bindingIdx]);
2841 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
2843 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
2844 const QD3D12ShaderStageData *sd = &stageData[stageIdx];
2848 if (!bd->stage.testFlag(qd3d12_stageToSrb(sd->stage)))
2852 case QRhiShaderResourceBinding::UniformBuffer:
2854 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2855 if (shaderRegister >= 0 && uniformBuffer)
2856 uniformBuffer(sd->stage, bd->u.ubuf, shaderRegister, bd->binding);
2859 case QRhiShaderResourceBinding::SampledTexture:
2861 Q_ASSERT(bd->u.stex.count > 0);
2862 const int textureBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2863 const int samplerBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).second;
2864 for (
int i = 0; i < bd->u.stex.count; ++i) {
2865 if (textureBaseShaderRegister >= 0 && texture)
2866 texture(sd->stage, bd->u.stex.texSamplers[i], textureBaseShaderRegister + i);
2867 if (samplerBaseShaderRegister >= 0 && sampler)
2868 sampler(sd->stage, bd->u.stex.texSamplers[i], samplerBaseShaderRegister + i);
2872 case QRhiShaderResourceBinding::Texture:
2874 Q_ASSERT(bd->u.stex.count > 0);
2875 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2876 if (baseShaderRegister >= 0 && texture) {
2877 for (
int i = 0; i < bd->u.stex.count; ++i)
2878 texture(sd->stage, bd->u.stex.texSamplers[i], baseShaderRegister + i);
2882 case QRhiShaderResourceBinding::Sampler:
2884 Q_ASSERT(bd->u.stex.count > 0);
2885 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2886 if (baseShaderRegister >= 0 && sampler) {
2887 for (
int i = 0; i < bd->u.stex.count; ++i)
2888 sampler(sd->stage, bd->u.stex.texSamplers[i], baseShaderRegister + i);
2892 case QRhiShaderResourceBinding::ImageLoad:
2894 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2895 if (shaderRegister >= 0 && storageImage)
2896 storageImage(sd->stage, bd->u.simage, Load, shaderRegister);
2899 case QRhiShaderResourceBinding::ImageStore:
2901 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2902 if (shaderRegister >= 0 && storageImage)
2903 storageImage(sd->stage, bd->u.simage, Store, shaderRegister);
2906 case QRhiShaderResourceBinding::ImageLoadStore:
2908 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2909 if (shaderRegister >= 0 && storageImage)
2910 storageImage(sd->stage, bd->u.simage, LoadStore, shaderRegister);
2913 case QRhiShaderResourceBinding::BufferLoad:
2915 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2916 if (shaderRegister >= 0 && storageBuffer)
2917 storageBuffer(sd->stage, bd->u.sbuf, Load, shaderRegister);
2920 case QRhiShaderResourceBinding::BufferStore:
2922 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2923 if (shaderRegister >= 0 && storageBuffer)
2924 storageBuffer(sd->stage, bd->u.sbuf, Store, shaderRegister);
2927 case QRhiShaderResourceBinding::BufferLoadStore:
2929 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
2930 if (shaderRegister >= 0 && storageBuffer)
2931 storageBuffer(sd->stage, bd->u.sbuf, LoadStore, shaderRegister);
2939bool QD3D12SamplerManager::create(ID3D12Device *device)
2942 if (!shaderVisibleSamplerHeap.create(device,
2943 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
2944 MAX_SAMPLERS / QD3D12_FRAMES_IN_FLIGHT))
2946 qWarning(
"Could not create shader-visible SAMPLER heap");
2950 this->device = device;
2954void QD3D12SamplerManager::destroy()
2957 shaderVisibleSamplerHeap.destroy();
2962QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc)
2964 auto it = gpuMap.constFind({desc});
2965 if (it != gpuMap.cend())
2968 QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
2969 if (descriptor.isValid()) {
2970 device->CreateSampler(&desc, descriptor.cpuHandle);
2971 gpuMap.insert({desc}, descriptor);
2973 qWarning(
"Out of shader-visible SAMPLER descriptor heap space,"
2974 " this should not happen, maximum number of unique samplers is %u",
2975 shaderVisibleSamplerHeap.heap.capacity);
2981bool QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
2985 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
2986 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
2989 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
2990 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
2991 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
2994 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
2995 descriptorRanges[0].NumDescriptors = 1;
2996 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
2997 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
2998 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
2999 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3000 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3003 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3004 descriptorRanges[1].NumDescriptors = 4;
3005 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3006 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3007 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3008 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3011 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3012 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3013 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3014 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3015 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3016 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3018 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3019 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3020 rsDesc.Desc_1_1.NumParameters = 3;
3021 rsDesc.Desc_1_1.pParameters = rootParams;
3022 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3023 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3025 ID3DBlob *signature =
nullptr;
3026 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3028 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3031 ID3D12RootSignature *rootSig =
nullptr;
3032 hr = rhiD->dev->CreateRootSignature(0,
3033 signature->GetBufferPointer(),
3034 signature->GetBufferSize(),
3035 __uuidof(ID3D12RootSignature),
3036 reinterpret_cast<
void **>(&rootSig));
3037 signature->Release();
3039 qWarning(
"Failed to create root signature: %s",
3040 qPrintable(QSystemError::windowsComString(hr)));
3044 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3046 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3047 psoDesc.pRootSignature = rootSig;
3048 psoDesc.CS.pShaderBytecode = g_csMipmap;
3049 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap);
3050 ID3D12PipelineState *pso =
nullptr;
3051 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3052 __uuidof(ID3D12PipelineState),
3053 reinterpret_cast<
void **>(&pso));
3055 qWarning(
"Failed to create compute pipeline state: %s",
3056 qPrintable(QSystemError::windowsComString(hr)));
3057 rhiD->rootSignaturePool.remove(rootSigHandle);
3062 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3067void QD3D12MipmapGenerator::destroy()
3069 rhiD->pipelinePool.remove(pipelineHandle);
3070 pipelineHandle = {};
3071 rhiD->rootSignaturePool.remove(rootSigHandle);
3075void QD3D12MipmapGenerator::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3077 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3080 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3083 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3087 const quint32 mipLevelCount = res->desc.MipLevels;
3088 if (mipLevelCount < 2)
3091 if (res->desc.SampleDesc.Count > 1) {
3092 qWarning(
"Cannot generate mipmaps for MSAA texture");
3096 const bool is1D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D;
3098 qWarning(
"Cannot generate mipmaps for 1D texture");
3102 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3103 const bool isCubeOrArray = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
3104 && res->desc.DepthOrArraySize > 1;
3105 const quint32 layerCount = isCubeOrArray ? res->desc.DepthOrArraySize : 1;
3108 qWarning(
"2D mipmap generator invoked for 3D texture, this should not happen");
3112 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3113 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3115 cbD->cmdList->SetPipelineState(pipeline->pso);
3116 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3118 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3121 quint32 srcMipLevel;
3122 quint32 numMipLevels;
3127 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount * layerCount);
3128 std::optional<QD3D12StagingArea> ownStagingArea;
3129 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3130 ownStagingArea = QD3D12StagingArea();
3131 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3132 qWarning(
"Could not create staging area for mipmap generation");
3136 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3137 ? &ownStagingArea.value()
3138 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3140 bool gotNewHeap =
false;
3141 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3142 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3143 rhiD->currentFrameSlot,
3144 (1 + 4) * mipLevelCount * layerCount,
3147 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3151 rhiD->bindShaderVisibleHeaps(cbD);
3153 for (quint32 layer = 0; layer < layerCount; ++layer) {
3154 for (quint32 level = 0; level < mipLevelCount ;) {
3155 UINT subresource = calcSubresource(level, layer, res->desc.MipLevels);
3156 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3157 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3158 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3160 quint32 levelPlusOneMipWidth = res->desc.Width >> (level + 1);
3161 quint32 levelPlusOneMipHeight = res->desc.Height >> (level + 1);
3162 const quint32 dw = levelPlusOneMipWidth == 1 ? levelPlusOneMipHeight : levelPlusOneMipWidth;
3163 const quint32 dh = levelPlusOneMipHeight == 1 ? levelPlusOneMipWidth : levelPlusOneMipHeight;
3165 const quint32 additionalMips = qCountTrailingZeroBits(dw | dh);
3166 const quint32 numGenMips = qMin(1u + qMin(3u, additionalMips), res->desc.MipLevels - level);
3167 levelPlusOneMipWidth = qMax(1u, levelPlusOneMipWidth);
3168 levelPlusOneMipHeight = qMax(1u, levelPlusOneMipHeight);
3170 CBufData cbufData = {
3173 1.0f /
float(levelPlusOneMipWidth),
3174 1.0f /
float(levelPlusOneMipHeight)
3177 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3178 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3179 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3181 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3182 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3183 srvDesc.Format = res->desc.Format;
3184 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3185 if (isCubeOrArray) {
3186 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
3187 srvDesc.Texture2DArray.MipLevels = res->desc.MipLevels;
3188 srvDesc.Texture2DArray.FirstArraySlice = layer;
3189 srvDesc.Texture2DArray.ArraySize = 1;
3191 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
3192 srvDesc.Texture2D.MipLevels = res->desc.MipLevels;
3194 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3195 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3197 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(4);
3198 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
3200 for (quint32 uavIdx = 0; uavIdx < 4; ++uavIdx) {
3201 const quint32 uavMipLevel = qMin(level + 1u + uavIdx, res->desc.MipLevels - 1u);
3202 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
3203 uavDesc.Format = res->desc.Format;
3204 if (isCubeOrArray) {
3205 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
3206 uavDesc.Texture2DArray.MipSlice = uavMipLevel;
3207 uavDesc.Texture2DArray.FirstArraySlice = layer;
3208 uavDesc.Texture2DArray.ArraySize = 1;
3210 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
3211 uavDesc.Texture2D.MipSlice = uavMipLevel;
3213 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
3214 uavCpuHandle.ptr += descriptorByteSize;
3216 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
3218 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, 1);
3220 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
3221 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3222 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
3223 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3225 level += numGenMips;
3229 if (ownStagingArea.has_value())
3230 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
3233bool QD3D12MipmapGenerator3D::create(QRhiD3D12 *rhiD)
3237 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3238 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3241 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3242 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3243 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3246 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3247 descriptorRanges[0].NumDescriptors = 1;
3248 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3249 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3250 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3251 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3252 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3255 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3256 descriptorRanges[1].NumDescriptors = 1;
3257 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3258 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3259 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3260 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3263 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3264 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3265 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3266 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3267 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3268 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3270 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3271 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3272 rsDesc.Desc_1_1.NumParameters = 3;
3273 rsDesc.Desc_1_1.pParameters = rootParams;
3274 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3275 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3277 ID3DBlob *signature =
nullptr;
3278 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3280 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3283 ID3D12RootSignature *rootSig =
nullptr;
3284 hr = rhiD->dev->CreateRootSignature(0,
3285 signature->GetBufferPointer(),
3286 signature->GetBufferSize(),
3287 __uuidof(ID3D12RootSignature),
3288 reinterpret_cast<
void **>(&rootSig));
3289 signature->Release();
3291 qWarning(
"Failed to create root signature: %s",
3292 qPrintable(QSystemError::windowsComString(hr)));
3296 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3298 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3299 psoDesc.pRootSignature = rootSig;
3300 psoDesc.CS.pShaderBytecode = g_csMipmap3D;
3301 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap3D);
3302 ID3D12PipelineState *pso =
nullptr;
3303 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3304 __uuidof(ID3D12PipelineState),
3305 reinterpret_cast<
void **>(&pso));
3307 qWarning(
"Failed to create compute pipeline state: %s",
3308 qPrintable(QSystemError::windowsComString(hr)));
3309 rhiD->rootSignaturePool.remove(rootSigHandle);
3314 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3319void QD3D12MipmapGenerator3D::destroy()
3321 rhiD->pipelinePool.remove(pipelineHandle);
3322 pipelineHandle = {};
3323 rhiD->rootSignaturePool.remove(rootSigHandle);
3327void QD3D12MipmapGenerator3D::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3329 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3332 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3335 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3339 const quint32 mipLevelCount = res->desc.MipLevels;
3340 if (mipLevelCount < 2)
3343 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3345 qWarning(
"3D mipmap generator invoked for non-3D texture, this should not happen");
3349 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3350 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3352 cbD->cmdList->SetPipelineState(pipeline->pso);
3353 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3355 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3361 quint32 srcMipLevel;
3364 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount);
3365 std::optional<QD3D12StagingArea> ownStagingArea;
3366 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3367 ownStagingArea = QD3D12StagingArea();
3368 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3369 qWarning(
"Could not create staging area for mipmap generation");
3373 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3374 ? &ownStagingArea.value()
3375 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3377 bool gotNewHeap =
false;
3378 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3379 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3380 rhiD->currentFrameSlot,
3381 (1 + 1) * mipLevelCount,
3384 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3388 rhiD->bindShaderVisibleHeaps(cbD);
3390 for (quint32 level = 0; level < mipLevelCount; ++level) {
3391 UINT subresource = calcSubresource(level, 0u, res->desc.MipLevels);
3392 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3393 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3394 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3396 quint32 levelPlusOneMipWidth = qMax<quint32>(1, res->desc.Width >> (level + 1));
3397 quint32 levelPlusOneMipHeight = qMax<quint32>(1, res->desc.Height >> (level + 1));
3398 quint32 levelPlusOneMipDepth = qMax<quint32>(1, res->desc.DepthOrArraySize >> (level + 1));
3400 CBufData cbufData = {
3401 1.0f /
float(levelPlusOneMipWidth),
3402 1.0f /
float(levelPlusOneMipHeight),
3403 1.0f /
float(levelPlusOneMipDepth),
3407 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3408 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3409 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3411 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3412 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3413 srvDesc.Format = res->desc.Format;
3414 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3415 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
3416 srvDesc.Texture3D.MipLevels = res->desc.MipLevels;
3418 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3419 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3421 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3422 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
3423 const quint32 uavMipLevel = qMin(level + 1u, res->desc.MipLevels - 1u);
3424 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
3425 uavDesc.Format = res->desc.Format;
3426 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
3427 uavDesc.Texture3D.MipSlice = uavMipLevel;
3428 uavDesc.Texture3D.WSize = UINT(-1);
3429 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
3430 uavCpuHandle.ptr += descriptorByteSize;
3431 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
3433 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, levelPlusOneMipDepth);
3435 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
3436 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3437 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
3438 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3441 if (ownStagingArea.has_value())
3442 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
3445bool QD3D12MemoryAllocator::create(ID3D12Device *device, IDXGIAdapter1 *adapter)
3447 this->device = device;
3454 static bool disableMA = qEnvironmentVariableIntValue(
"QT_D3D_NO_SUBALLOC");
3458 DXGI_ADAPTER_DESC1 desc;
3459 adapter->GetDesc1(&desc);
3460 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
3463 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
3464 allocatorDesc.pDevice = device;
3465 allocatorDesc.pAdapter = adapter;
3468 allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED;
3469 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
3471 qWarning(
"Failed to initialize D3D12 Memory Allocator: %s",
3472 qPrintable(QSystemError::windowsComString(hr)));
3478void QD3D12MemoryAllocator::destroy()
3481 allocator->Release();
3482 allocator =
nullptr;
3486HRESULT QD3D12MemoryAllocator::createResource(D3D12_HEAP_TYPE heapType,
3487 const D3D12_RESOURCE_DESC *resourceDesc,
3488 D3D12_RESOURCE_STATES initialState,
3489 const D3D12_CLEAR_VALUE *optimizedClearValue,
3490 D3D12MA::Allocation **maybeAllocation,
3491 REFIID riidResource,
3495 D3D12MA::ALLOCATION_DESC allocDesc = {};
3496 allocDesc.HeapType = heapType;
3497 return allocator->CreateResource(&allocDesc,
3500 optimizedClearValue,
3505 *maybeAllocation =
nullptr;
3506 D3D12_HEAP_PROPERTIES heapProps = {};
3507 heapProps.Type = heapType;
3508 return device->CreateCommittedResource(&heapProps,
3509 D3D12_HEAP_FLAG_NONE,
3512 optimizedClearValue,
3518void QD3D12MemoryAllocator::getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget)
3521 allocator->GetBudget(localBudget, nonLocalBudget);
3524 *nonLocalBudget = {};
3528void QRhiD3D12::waitGpu()
3530 fullFenceCounter += 1u;
3531 if (SUCCEEDED(cmdQueue->Signal(fullFence, fullFenceCounter))) {
3532 if (SUCCEEDED(fullFence->SetEventOnCompletion(fullFenceCounter, fullFenceEvent)))
3533 WaitForSingleObject(fullFenceEvent, INFINITE);
3537DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleDesc(
int sampleCount, DXGI_FORMAT format)
const
3539 DXGI_SAMPLE_DESC desc;
3543 const int s = effectiveSampleCount(sampleCount);
3546 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
3547 msaaInfo.Format = format;
3548 msaaInfo.SampleCount = UINT(s);
3549 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo,
sizeof(msaaInfo)))) {
3550 if (msaaInfo.NumQualityLevels > 0) {
3551 desc.Count = UINT(s);
3552 desc.Quality = msaaInfo.NumQualityLevels - 1;
3554 qWarning(
"No quality levels for multisampling with sample count %d", s);
3562bool QRhiD3D12::startCommandListForCurrentFrameSlot(D3D12GraphicsCommandList **cmdList)
3564 ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
3566 HRESULT hr = dev->CreateCommandList(0,
3567 D3D12_COMMAND_LIST_TYPE_DIRECT,
3570 __uuidof(D3D12GraphicsCommandList),
3571 reinterpret_cast<
void **>(cmdList));
3573 qWarning(
"Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
3577 HRESULT hr = (*cmdList)->Reset(cmdAlloc,
nullptr);
3579 qWarning(
"Failed to reset command list: %s", qPrintable(QSystemError::windowsComString(hr)));
3586static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
3589 case DXGI_FORMAT_R8G8B8A8_UNORM:
3590 return QRhiTexture::RGBA8;
3591 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
3593 (*flags) |= QRhiTexture::sRGB;
3594 return QRhiTexture::RGBA8;
3595 case DXGI_FORMAT_B8G8R8A8_UNORM:
3596 return QRhiTexture::BGRA8;
3597 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
3599 (*flags) |= QRhiTexture::sRGB;
3600 return QRhiTexture::BGRA8;
3601 case DXGI_FORMAT_R16G16B16A16_FLOAT:
3602 return QRhiTexture::RGBA16F;
3603 case DXGI_FORMAT_R32G32B32A32_FLOAT:
3604 return QRhiTexture::RGBA32F;
3605 case DXGI_FORMAT_R10G10B10A2_UNORM:
3606 return QRhiTexture::RGB10A2;
3608 qWarning(
"DXGI_FORMAT %d cannot be read back", format);
3611 return QRhiTexture::UnknownFormat;
3614void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
3616 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
3618 for (
int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
3619 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
3620 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
3621 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3622 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
3623 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3624 if (u.offset == 0 && u.data.size() == bufD->m_size)
3625 bufD->pendingHostWrites[i].clear();
3626 bufD->pendingHostWrites[i].append({ u.offset, u.data });
3628 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
3629 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3630 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
3631 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
3639 QD3D12StagingArea::Allocation stagingAlloc;
3640 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(bufD->m_size, 1);
3641 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3642 stagingAlloc = smallStagingAreas[currentFrameSlot].get(bufD->m_size);
3644 std::optional<QD3D12StagingArea> ownStagingArea;
3645 if (!stagingAlloc.isValid()) {
3646 ownStagingArea = QD3D12StagingArea();
3647 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3649 stagingAlloc = ownStagingArea->get(allocSize);
3650 if (!stagingAlloc.isValid()) {
3651 ownStagingArea->destroy();
3656 memcpy(stagingAlloc.p + u.offset, u.data.constData(), u.data.size());
3658 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
3659 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3661 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
3662 cbD->cmdList->CopyBufferRegion(res->resource,
3664 stagingAlloc.buffer,
3665 stagingAlloc.bufferOffset + u.offset,
3669 if (ownStagingArea.has_value())
3670 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3671 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
3672 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
3673 if (bufD->m_type == QRhiBuffer::Dynamic) {
3674 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
3675 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[currentFrameSlot])) {
3676 Q_ASSERT(res->cpuMapPtr);
3677 u.result->data.resize(u.readSize);
3678 memcpy(u.result->data.data(),
reinterpret_cast<
char *>(res->cpuMapPtr) + u.offset, u.readSize);
3680 if (u.result->completed)
3681 u.result->completed();
3683 QD3D12Readback readback;
3684 readback.frameSlot = currentFrameSlot;
3685 readback.result = u.result;
3686 readback.byteSize = u.readSize;
3687 const quint32 allocSize = aligned(u.readSize, QD3D12StagingArea::ALIGNMENT);
3688 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
3689 if (u.result->completed)
3690 u.result->completed();
3693 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(u.readSize);
3694 if (!stagingAlloc.isValid()) {
3695 readback.staging.destroy();
3696 if (u.result->completed)
3697 u.result->completed();
3700 Q_ASSERT(stagingAlloc.bufferOffset == 0);
3701 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
3702 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3703 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
3704 cbD->cmdList->CopyBufferRegion(stagingAlloc.buffer, 0, res->resource, u.offset, u.readSize);
3705 activeReadbacks.append(readback);
3707 readback.staging.destroy();
3708 if (u.result->completed)
3709 u.result->completed();
3715 for (
int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
3716 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
3717 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
3718 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
3719 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3720 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
3723 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
3724 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3725 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
3726 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
3727 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level])) {
3728 D3D12_SUBRESOURCE_FOOTPRINT footprint = {};
3729 footprint.Format = res->desc.Format;
3730 footprint.Depth = 1;
3731 quint32 totalBytes = 0;
3733 const QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
3734 : subresDesc.sourceSize();
3735 const QPoint srcPos = subresDesc.sourceTopLeft();
3736 QPoint dstPos = subresDesc.destinationTopLeft();
3738 if (!subresDesc.image().isNull()) {
3739 const QImage img = subresDesc.image();
3740 const int bpl = img.bytesPerLine();
3741 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3742 totalBytes = footprint.RowPitch * img.height();
3743 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3746 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3747 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3748 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3749 totalBytes = footprint.RowPitch * rowCount;
3750 }
else if (!subresDesc.data().isEmpty()) {
3752 if (subresDesc.dataStride())
3753 bpl = subresDesc.dataStride();
3755 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
3756 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3757 totalBytes = footprint.RowPitch * subresSize.height();
3759 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
3763 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(totalBytes, 1);
3764 QD3D12StagingArea::Allocation stagingAlloc;
3765 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3766 stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
3768 std::optional<QD3D12StagingArea> ownStagingArea;
3769 if (!stagingAlloc.isValid()) {
3770 ownStagingArea = QD3D12StagingArea();
3771 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3773 stagingAlloc = ownStagingArea->get(allocSize);
3774 if (!stagingAlloc.isValid()) {
3775 ownStagingArea->destroy();
3780 D3D12_TEXTURE_COPY_LOCATION dst;
3781 dst.pResource = res->resource;
3782 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3783 dst.SubresourceIndex = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
3784 D3D12_TEXTURE_COPY_LOCATION src;
3785 src.pResource = stagingAlloc.buffer;
3786 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
3787 src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
3791 if (!subresDesc.image().isNull()) {
3792 const QImage img = subresDesc.image();
3793 const int bpc = qMax(1, img.depth() / 8);
3794 const int bpl = img.bytesPerLine();
3796 QSize size = subresDesc.sourceSize().isEmpty() ? img.size() : subresDesc.sourceSize();
3797 size.setWidth(qMin(size.width(), img.width() - srcPos.x()));
3798 size.setHeight(qMin(size.height(), img.height() - srcPos.y()));
3800 footprint.Width = size.width();
3801 footprint.Height = size.height();
3805 srcBox.right = UINT(size.width());
3806 srcBox.bottom = UINT(size.height());
3810 const uchar *imgPtr = img.constBits();
3811 const quint32 lineBytes = size.width() * bpc;
3812 for (
int y = 0, h = size.height(); y < h; ++y) {
3813 memcpy(stagingAlloc.p + y * footprint.RowPitch,
3814 imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
3817 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3820 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3822 dstPos.setX(aligned(dstPos.x(), blockDim.width()));
3823 dstPos.setY(aligned(dstPos.y(), blockDim.height()));
3828 srcBox.right = aligned(subresSize.width(), blockDim.width());
3829 srcBox.bottom = aligned(subresSize.height(), blockDim.height());
3834 footprint.Width = aligned(subresSize.width(), blockDim.width());
3835 footprint.Height = aligned(subresSize.height(), blockDim.height());
3837 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
3838 const QByteArray imgData = subresDesc.data();
3839 const char *imgPtr = imgData.constData();
3840 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3841 for (
int y = 0; y < rowCount; ++y)
3842 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
3843 }
else if (!subresDesc.data().isEmpty()) {
3846 srcBox.right = subresSize.width();
3847 srcBox.bottom = subresSize.height();
3851 footprint.Width = subresSize.width();
3852 footprint.Height = subresSize.height();
3855 if (subresDesc.dataStride())
3856 bpl = subresDesc.dataStride();
3858 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
3860 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
3861 const QByteArray data = subresDesc.data();
3862 const char *imgPtr = data.constData();
3863 for (
int y = 0, h = subresSize.height(); y < h; ++y)
3864 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
3867 src.PlacedFootprint.Footprint = footprint;
3869 cbD->cmdList->CopyTextureRegion(&dst,
3872 is3D ? UINT(layer) : 0u,
3876 if (ownStagingArea.has_value())
3877 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3881 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
3882 Q_ASSERT(u.src && u.dst);
3883 QD3D12Texture *srcD = QRHI_RES(QD3D12Texture, u.src);
3884 QD3D12Texture *dstD = QRHI_RES(QD3D12Texture, u.dst);
3885 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3886 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3887 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
3888 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
3889 if (!srcRes || !dstRes)
3892 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
3893 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
3894 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3896 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
3897 srcIs3D ? 0u : UINT(u.desc.sourceLayer()),
3898 srcD->mipLevelCount);
3899 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
3900 dstIs3D ? 0u : UINT(u.desc.destinationLayer()),
3901 dstD->mipLevelCount);
3902 const QPoint dp = u.desc.destinationTopLeft();
3903 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
3904 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
3905 const QPoint sp = u.desc.sourceTopLeft();
3908 srcBox.left = UINT(sp.x());
3909 srcBox.top = UINT(sp.y());
3910 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
3912 srcBox.right = srcBox.left + UINT(copySize.width());
3913 srcBox.bottom = srcBox.top + UINT(copySize.height());
3914 srcBox.back = srcBox.front + 1;
3916 D3D12_TEXTURE_COPY_LOCATION src;
3917 src.pResource = srcRes->resource;
3918 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3919 src.SubresourceIndex = srcSubresource;
3920 D3D12_TEXTURE_COPY_LOCATION dst;
3921 dst.pResource = dstRes->resource;
3922 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3923 dst.SubresourceIndex = dstSubresource;
3925 cbD->cmdList->CopyTextureRegion(&dst,
3928 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
3931 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
3932 QD3D12Readback readback;
3933 readback.frameSlot = currentFrameSlot;
3934 readback.result = u.result;
3936 QD3D12ObjectHandle srcHandle;
3939 if (u.rb.texture()) {
3940 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.rb.texture());
3941 if (texD->sampleDesc.Count > 1) {
3942 qWarning(
"Multisample texture cannot be read back");
3945 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3946 if (u.rb.rect().isValid())
3949 rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
3950 readback.format = texD->m_format;
3951 srcHandle = texD->handle;
3953 Q_ASSERT(currentSwapChain);
3954 if (u.rb.rect().isValid())
3957 rect = QRect({0, 0}, currentSwapChain->pixelSize);
3958 readback.format = swapchainReadbackTextureFormat(currentSwapChain->colorFormat,
nullptr);
3959 if (readback.format == QRhiTexture::UnknownFormat)
3961 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
3963 readback.pixelSize = rect.size();
3965 textureFormatInfo(readback.format,
3967 &readback.bytesPerLine,
3971 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
3975 const UINT subresource = calcSubresource(UINT(u.rb.level()),
3976 is3D ? 0u : UINT(u.rb.layer()),
3977 srcRes->desc.MipLevels);
3978 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
3981 UINT64 totalBytes = 0;
3982 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
3983 &layout,
nullptr,
nullptr, &totalBytes);
3984 readback.stagingRowPitch = layout.Footprint.RowPitch;
3986 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT);
3987 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
3988 if (u.result->completed)
3989 u.result->completed();
3992 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
3993 if (!stagingAlloc.isValid()) {
3994 readback.staging.destroy();
3995 if (u.result->completed)
3996 u.result->completed();
3999 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4001 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4002 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4004 D3D12_TEXTURE_COPY_LOCATION dst;
4005 dst.pResource = stagingAlloc.buffer;
4006 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4007 dst.PlacedFootprint.Offset = 0;
4008 dst.PlacedFootprint.Footprint = layout.Footprint;
4010 D3D12_TEXTURE_COPY_LOCATION src;
4011 src.pResource = srcRes->resource;
4012 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4013 src.SubresourceIndex = subresource;
4015 D3D12_BOX srcBox = {};
4016 srcBox.left = UINT(rect.left());
4017 srcBox.top = UINT(rect.top());
4018 srcBox.front = is3D ? UINT(u.rb.layer()) : 0u;
4020 srcBox.right = srcBox.left + UINT(rect.width());
4021 srcBox.bottom = srcBox.top + UINT(rect.height());
4022 srcBox.back = srcBox.front + 1;
4024 cbD->cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &srcBox);
4025 activeReadbacks.append(readback);
4026 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
4027 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4028 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
4029 if (texD->flags().testFlag(QRhiTexture::ThreeDimensional))
4030 mipmapGen3D.generate(cbD, texD->handle);
4032 mipmapGen.generate(cbD, texD->handle);
4039void QRhiD3D12::finishActiveReadbacks(
bool forced)
4041 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4043 for (
int i = activeReadbacks.size() - 1; i >= 0; --i) {
4044 QD3D12Readback &readback(activeReadbacks[i]);
4045 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
4046 readback.result->format = readback.format;
4047 readback.result->pixelSize = readback.pixelSize;
4048 readback.result->data.resize(
int(readback.byteSize));
4050 if (readback.format != QRhiTexture::UnknownFormat) {
4051 quint8 *dstPtr =
reinterpret_cast<quint8 *>(readback.result->data.data());
4052 const quint8 *srcPtr = readback.staging.mem.p;
4053 const quint32 lineSize = qMin(readback.bytesPerLine, readback.stagingRowPitch);
4054 for (
int y = 0, h = readback.pixelSize.height(); y < h; ++y)
4055 memcpy(dstPtr + y * readback.bytesPerLine, srcPtr + y * readback.stagingRowPitch, lineSize);
4057 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
4060 readback.staging.destroy();
4062 if (readback.result->completed)
4063 completedCallbacks.append(readback.result->completed);
4065 activeReadbacks.remove(i);
4069 for (
auto f : completedCallbacks)
4073bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
4074 D3D12_DESCRIPTOR_HEAP_TYPE type,
4076 quint32 neededDescriptorCount,
4084 if (h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
4085 const quint32 newPerFrameSize = qMax(h->perFrameHeapSlice[frameSlot].capacity * 2,
4086 neededDescriptorCount);
4087 QD3D12ShaderVisibleDescriptorHeap newHeap;
4088 if (!newHeap.create(dev, type, newPerFrameSize)) {
4089 qWarning(
"Could not create new shader-visible descriptor heap");
4092 h->destroyWithDeferredRelease(&releaseQueue);
4099void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
4101 ID3D12DescriptorHeap *heaps[] = {
4102 shaderVisibleCbvSrvUavHeap.heap.heap,
4103 samplerMgr.shaderVisibleSamplerHeap.heap.heap
4105 cbD->cmdList->SetDescriptorHeaps(2, heaps);
4108QD3D12Buffer::QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
4109 : QRhiBuffer(rhi, type, usage, size)
4113QD3D12Buffer::~QD3D12Buffer()
4118void QD3D12Buffer::destroy()
4120 if (handles[0].isNull())
4123 QRHI_RES_RHI(QRhiD3D12);
4132 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4134 rhiD->releaseQueue.deferredReleaseResource(handles[i]);
4136 pendingHostWrites[i].clear();
4140 rhiD->unregisterResource(
this);
4143bool QD3D12Buffer::create()
4145 if (!handles[0].isNull())
4148 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
4149 qWarning(
"UniformBuffer must always be Dynamic");
4153 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
4154 qWarning(
"StorageBuffer cannot be combined with Dynamic");
4158 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
4159 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
4161 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
4162 if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
4163 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4165 QRHI_RES_RHI(QRhiD3D12);
4167 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4168 if (i == 0 || m_type == Dynamic) {
4169 D3D12_RESOURCE_DESC resourceDesc = {};
4170 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
4171 resourceDesc.Width = roundedSize;
4172 resourceDesc.Height = 1;
4173 resourceDesc.DepthOrArraySize = 1;
4174 resourceDesc.MipLevels = 1;
4175 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
4176 resourceDesc.SampleDesc = { 1, 0 };
4177 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
4178 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
4179 ID3D12Resource *resource =
nullptr;
4180 D3D12MA::Allocation *allocation =
nullptr;
4182 D3D12_HEAP_TYPE heapType = m_type == Dynamic
4183 ? D3D12_HEAP_TYPE_UPLOAD
4184 : D3D12_HEAP_TYPE_DEFAULT;
4185 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
4186 ? D3D12_RESOURCE_STATE_GENERIC_READ
4187 : D3D12_RESOURCE_STATE_COMMON;
4188 hr = rhiD->vma.createResource(heapType,
4194 reinterpret_cast<
void **>(&resource));
4197 if (!m_objectName.isEmpty()) {
4198 QString decoratedName = QString::fromUtf8(m_objectName);
4199 if (m_type == Dynamic) {
4200 decoratedName += QLatin1Char(
'/');
4201 decoratedName += QString::number(i);
4203 resource->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
4205 void *cpuMemPtr =
nullptr;
4206 if (m_type == Dynamic) {
4208 hr = resource->Map(0,
nullptr, &cpuMemPtr);
4210 qWarning(
"Map() failed to dynamic buffer");
4211 resource->Release();
4213 allocation->Release();
4217 handles[i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
4225 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
4226 qPrintable(QSystemError::windowsComString(hr)),
4229 int(rhiD->vma.isUsingD3D12MA()));
4233 rhiD->registerResource(
this);
4237QRhiBuffer::NativeBuffer QD3D12Buffer::nativeBuffer()
4240 Q_ASSERT(
sizeof(b.objects) /
sizeof(b.objects[0]) >= size_t(QD3D12_FRAMES_IN_FLIGHT));
4241 QRHI_RES_RHI(QRhiD3D12);
4242 if (m_type == Dynamic) {
4243 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4244 executeHostWritesForFrameSlot(i);
4245 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[i]))
4246 b.objects[i] = res->resource;
4248 b.objects[i] =
nullptr;
4250 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
4253 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[0]))
4254 b.objects[0] = res->resource;
4256 b.objects[0] =
nullptr;
4261char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
4269 Q_ASSERT(m_type == Dynamic);
4270 QRHI_RES_RHI(QRhiD3D12);
4271 Q_ASSERT(rhiD->inFrame);
4272 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
4273 return static_cast<
char *>(res->cpuMapPtr);
4278void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
4283void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
4285 if (pendingHostWrites[frameSlot].isEmpty())
4288 Q_ASSERT(m_type == QRhiBuffer::Dynamic);
4289 QRHI_RES_RHI(QRhiD3D12);
4290 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
4291 Q_ASSERT(res->cpuMapPtr);
4292 for (
const QD3D12Buffer::HostWrite &u : std::as_const(pendingHostWrites[frameSlot]))
4293 memcpy(
static_cast<
char *>(res->cpuMapPtr) + u.offset, u.data.constData(), u.data.size());
4295 pendingHostWrites[frameSlot].clear();
4298static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
4300 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
4302 case QRhiTexture::RGBA8:
4303 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
4304 case QRhiTexture::BGRA8:
4305 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
4306 case QRhiTexture::R8:
4307 return DXGI_FORMAT_R8_UNORM;
4308 case QRhiTexture::R8SI:
4309 return DXGI_FORMAT_R8_SINT;
4310 case QRhiTexture::R8UI:
4311 return DXGI_FORMAT_R8_UINT;
4312 case QRhiTexture::RG8:
4313 return DXGI_FORMAT_R8G8_UNORM;
4314 case QRhiTexture::R16:
4315 return DXGI_FORMAT_R16_UNORM;
4316 case QRhiTexture::RG16:
4317 return DXGI_FORMAT_R16G16_UNORM;
4318 case QRhiTexture::RED_OR_ALPHA8:
4319 return DXGI_FORMAT_R8_UNORM;
4321 case QRhiTexture::RGBA16F:
4322 return DXGI_FORMAT_R16G16B16A16_FLOAT;
4323 case QRhiTexture::RGBA32F:
4324 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4325 case QRhiTexture::R16F:
4326 return DXGI_FORMAT_R16_FLOAT;
4327 case QRhiTexture::R32F:
4328 return DXGI_FORMAT_R32_FLOAT;
4330 case QRhiTexture::RGB10A2:
4331 return DXGI_FORMAT_R10G10B10A2_UNORM;
4333 case QRhiTexture::R32SI:
4334 return DXGI_FORMAT_R32_SINT;
4335 case QRhiTexture::R32UI:
4336 return DXGI_FORMAT_R32_UINT;
4337 case QRhiTexture::RG32SI:
4338 return DXGI_FORMAT_R32G32_SINT;
4339 case QRhiTexture::RG32UI:
4340 return DXGI_FORMAT_R32G32_UINT;
4341 case QRhiTexture::RGBA32SI:
4342 return DXGI_FORMAT_R32G32B32A32_SINT;
4343 case QRhiTexture::RGBA32UI:
4344 return DXGI_FORMAT_R32G32B32A32_UINT;
4346 case QRhiTexture::D16:
4347 return DXGI_FORMAT_R16_TYPELESS;
4348 case QRhiTexture::D24:
4349 return DXGI_FORMAT_R24G8_TYPELESS;
4350 case QRhiTexture::D24S8:
4351 return DXGI_FORMAT_R24G8_TYPELESS;
4352 case QRhiTexture::D32F:
4353 return DXGI_FORMAT_R32_TYPELESS;
4354 case QRhiTexture::Format::D32FS8:
4355 return DXGI_FORMAT_R32G8X24_TYPELESS;
4357 case QRhiTexture::BC1:
4358 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
4359 case QRhiTexture::BC2:
4360 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
4361 case QRhiTexture::BC3:
4362 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
4363 case QRhiTexture::BC4:
4364 return DXGI_FORMAT_BC4_UNORM;
4365 case QRhiTexture::BC5:
4366 return DXGI_FORMAT_BC5_UNORM;
4367 case QRhiTexture::BC6H:
4368 return DXGI_FORMAT_BC6H_UF16;
4369 case QRhiTexture::BC7:
4370 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
4372 case QRhiTexture::ETC2_RGB8:
4373 case QRhiTexture::ETC2_RGB8A1:
4374 case QRhiTexture::ETC2_RGBA8:
4375 qWarning(
"QRhiD3D12 does not support ETC2 textures");
4376 return DXGI_FORMAT_R8G8B8A8_UNORM;
4378 case QRhiTexture::ASTC_4x4:
4379 case QRhiTexture::ASTC_5x4:
4380 case QRhiTexture::ASTC_5x5:
4381 case QRhiTexture::ASTC_6x5:
4382 case QRhiTexture::ASTC_6x6:
4383 case QRhiTexture::ASTC_8x5:
4384 case QRhiTexture::ASTC_8x6:
4385 case QRhiTexture::ASTC_8x8:
4386 case QRhiTexture::ASTC_10x5:
4387 case QRhiTexture::ASTC_10x6:
4388 case QRhiTexture::ASTC_10x8:
4389 case QRhiTexture::ASTC_10x10:
4390 case QRhiTexture::ASTC_12x10:
4391 case QRhiTexture::ASTC_12x12:
4392 qWarning(
"QRhiD3D12 does not support ASTC textures");
4393 return DXGI_FORMAT_R8G8B8A8_UNORM;
4398 return DXGI_FORMAT_R8G8B8A8_UNORM;
4401QD3D12RenderBuffer::QD3D12RenderBuffer(QRhiImplementation *rhi,
4403 const QSize &pixelSize,
4406 QRhiTexture::Format backingFormatHint)
4407 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
4411QD3D12RenderBuffer::~QD3D12RenderBuffer()
4416void QD3D12RenderBuffer::destroy()
4418 if (handle.isNull())
4421 QRHI_RES_RHI(QRhiD3D12);
4424 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->rtvPool, rtv, 1);
4425 else if (dsv.isValid())
4426 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->dsvPool, dsv, 1);
4434 rhiD->unregisterResource(
this);
4437bool QD3D12RenderBuffer::create()
4439 if (!handle.isNull())
4442 if (m_pixelSize.isEmpty())
4445 QRHI_RES_RHI(QRhiD3D12);
4448 case QRhiRenderBuffer::Color:
4450 dxgiFormat = toD3DTextureFormat(backingFormat(), {});
4451 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4452 D3D12_RESOURCE_DESC resourceDesc = {};
4453 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4454 resourceDesc.Width = UINT64(m_pixelSize.width());
4455 resourceDesc.Height = UINT(m_pixelSize.height());
4456 resourceDesc.DepthOrArraySize = 1;
4457 resourceDesc.MipLevels = 1;
4458 resourceDesc.Format = dxgiFormat;
4459 resourceDesc.SampleDesc = sampleDesc;
4460 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4461 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4462 D3D12_CLEAR_VALUE clearValue = {};
4463 clearValue.Format = dxgiFormat;
4465 ID3D12Resource *resource =
nullptr;
4466 D3D12MA::Allocation *allocation =
nullptr;
4467 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4469 D3D12_RESOURCE_STATE_RENDER_TARGET,
4472 __uuidof(ID3D12Resource),
4473 reinterpret_cast<
void **>(&resource));
4475 qWarning(
"Failed to create color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4478 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
4479 rtv = rhiD->rtvPool.allocate(1);
4482 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
4483 rtvDesc.Format = dxgiFormat;
4484 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
4485 : D3D12_RTV_DIMENSION_TEXTURE2D;
4486 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
4489 case QRhiRenderBuffer::DepthStencil:
4491 dxgiFormat = DS_FORMAT;
4492 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4493 D3D12_RESOURCE_DESC resourceDesc = {};
4494 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4495 resourceDesc.Width = UINT64(m_pixelSize.width());
4496 resourceDesc.Height = UINT(m_pixelSize.height());
4497 resourceDesc.DepthOrArraySize = 1;
4498 resourceDesc.MipLevels = 1;
4499 resourceDesc.Format = dxgiFormat;
4500 resourceDesc.SampleDesc = sampleDesc;
4501 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4502 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4503 if (m_flags.testFlag(UsedWithSwapChainOnly))
4504 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
4505 D3D12_CLEAR_VALUE clearValue = {};
4506 clearValue.Format = dxgiFormat;
4507 clearValue.DepthStencil.Depth = 1.0f;
4508 clearValue.DepthStencil.Stencil = 0;
4509 ID3D12Resource *resource =
nullptr;
4510 D3D12MA::Allocation *allocation =
nullptr;
4511 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4513 D3D12_RESOURCE_STATE_DEPTH_WRITE,
4516 __uuidof(ID3D12Resource),
4517 reinterpret_cast<
void **>(&resource));
4519 qWarning(
"Failed to create depth-stencil buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4522 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE, allocation);
4523 dsv = rhiD->dsvPool.allocate(1);
4526 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
4527 dsvDesc.Format = dxgiFormat;
4528 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
4529 : D3D12_DSV_DIMENSION_TEXTURE2D;
4530 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
4535 if (!m_objectName.isEmpty()) {
4536 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4537 const QString name = QString::fromUtf8(m_objectName);
4538 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4543 rhiD->registerResource(
this);
4547QRhiTexture::Format QD3D12RenderBuffer::backingFormat()
const
4549 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
4550 return m_backingFormatHint;
4552 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
4555QD3D12Texture::QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
4556 int arraySize,
int sampleCount, Flags flags)
4557 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
4561QD3D12Texture::~QD3D12Texture()
4566void QD3D12Texture::destroy()
4568 if (handle.isNull())
4571 QRHI_RES_RHI(QRhiD3D12);
4573 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->cbvSrvUavPool, srv, 1);
4579 rhiD->unregisterResource(
this);
4582static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
4585 case QRhiTexture::Format::D16:
4586 return DXGI_FORMAT_R16_FLOAT;
4587 case QRhiTexture::Format::D24:
4588 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4589 case QRhiTexture::Format::D24S8:
4590 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4591 case QRhiTexture::Format::D32F:
4592 return DXGI_FORMAT_R32_FLOAT;
4593 case QRhiTexture::Format::D32FS8:
4594 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
4598 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
4601static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
4605 case QRhiTexture::Format::D16:
4606 return DXGI_FORMAT_D16_UNORM;
4607 case QRhiTexture::Format::D24:
4608 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4609 case QRhiTexture::Format::D24S8:
4610 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4611 case QRhiTexture::Format::D32F:
4612 return DXGI_FORMAT_D32_FLOAT;
4613 case QRhiTexture::Format::D32FS8:
4614 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
4618 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
4621static inline bool isDepthTextureFormat(QRhiTexture::Format format)
4624 case QRhiTexture::Format::D16:
4625 case QRhiTexture::Format::D24:
4626 case QRhiTexture::Format::D24S8:
4627 case QRhiTexture::Format::D32F:
4628 case QRhiTexture::Format::D32FS8:
4635bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
4637 if (!handle.isNull())
4640 QRHI_RES_RHI(QRhiD3D12);
4641 if (!rhiD->isTextureFormatSupported(m_format, m_flags))
4644 const bool isDepth = isDepthTextureFormat(m_format);
4645 const bool isCube = m_flags.testFlag(CubeMap);
4646 const bool is3D = m_flags.testFlag(ThreeDimensional);
4647 const bool isArray = m_flags.testFlag(TextureArray);
4648 const bool hasMipMaps = m_flags.testFlag(MipMapped);
4649 const bool is1D = m_flags.testFlag(OneDimensional);
4651 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
4652 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
4654 dxgiFormat = toD3DTextureFormat(m_format, m_flags);
4656 srvFormat = toD3DDepthTextureSRVFormat(m_format);
4657 rtFormat = toD3DDepthTextureDSVFormat(m_format);
4659 srvFormat = dxgiFormat;
4660 rtFormat = dxgiFormat;
4662 if (m_writeViewFormat.format != UnknownFormat) {
4664 rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
4666 rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
4668 if (m_readViewFormat.format != UnknownFormat) {
4670 srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
4672 srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
4675 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
4676 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4677 if (sampleDesc.Count > 1) {
4679 qWarning(
"Cubemap texture cannot be multisample");
4683 qWarning(
"3D texture cannot be multisample");
4687 qWarning(
"Multisample texture cannot have mipmaps");
4691 if (isDepth && hasMipMaps) {
4692 qWarning(
"Depth texture cannot have mipmaps");
4695 if (isCube && is3D) {
4696 qWarning(
"Texture cannot be both cube and 3D");
4699 if (isArray && is3D) {
4700 qWarning(
"Texture cannot be both array and 3D");
4703 if (isCube && is1D) {
4704 qWarning(
"Texture cannot be both cube and 1D");
4708 qWarning(
"Texture cannot be both 1D and 3D");
4711 if (m_depth > 1 && !is3D) {
4712 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
4715 if (m_arraySize > 0 && !isArray) {
4716 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
4719 if (m_arraySize < 1 && isArray) {
4720 qWarning(
"Texture is an array but array size is %d", m_arraySize);
4725 *adjustedSize = size;
4730bool QD3D12Texture::finishCreate()
4732 QRHI_RES_RHI(QRhiD3D12);
4733 const bool isCube = m_flags.testFlag(CubeMap);
4734 const bool is3D = m_flags.testFlag(ThreeDimensional);
4735 const bool isArray = m_flags.testFlag(TextureArray);
4736 const bool is1D = m_flags.testFlag(OneDimensional);
4738 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4739 srvDesc.Format = srvFormat;
4740 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4743 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
4744 srvDesc.TextureCube.MipLevels = mipLevelCount;
4748 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
4749 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
4750 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4751 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4752 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
4754 srvDesc.Texture1DArray.FirstArraySlice = 0;
4755 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
4758 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
4759 srvDesc.Texture1D.MipLevels = mipLevelCount;
4761 }
else if (isArray) {
4762 if (sampleDesc.Count > 1) {
4763 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
4764 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4765 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
4766 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
4768 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
4769 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
4772 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
4773 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
4774 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4775 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4776 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
4778 srvDesc.Texture2DArray.FirstArraySlice = 0;
4779 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
4783 if (sampleDesc.Count > 1) {
4784 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
4786 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4787 srvDesc.Texture3D.MipLevels = mipLevelCount;
4789 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
4790 srvDesc.Texture2D.MipLevels = mipLevelCount;
4795 srv = rhiD->cbvSrvUavPool.allocate(1);
4799 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4800 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4801 if (!m_objectName.isEmpty()) {
4802 const QString name = QString::fromUtf8(m_objectName);
4803 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4813bool QD3D12Texture::create()
4816 if (!prepareCreate(&size))
4819 const bool isDepth = isDepthTextureFormat(m_format);
4820 const bool isCube = m_flags.testFlag(CubeMap);
4821 const bool is3D = m_flags.testFlag(ThreeDimensional);
4822 const bool isArray = m_flags.testFlag(TextureArray);
4823 const bool is1D = m_flags.testFlag(OneDimensional);
4825 QRHI_RES_RHI(QRhiD3D12);
4827 bool needsOptimizedClearValueSpecified =
false;
4828 UINT resourceFlags = 0;
4829 if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
4831 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4833 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4834 needsOptimizedClearValueSpecified =
true;
4836 if (m_flags.testFlag(UsedWithGenerateMips)) {
4838 qWarning(
"Depth texture cannot have mipmaps generated");
4841 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4843 if (m_flags.testFlag(UsedWithLoadStore))
4844 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4846 D3D12_RESOURCE_DESC resourceDesc = {};
4847 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
4848 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
4849 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
4850 resourceDesc.Width = UINT64(size.width());
4851 resourceDesc.Height = UINT(size.height());
4852 resourceDesc.DepthOrArraySize = isCube ? 6
4853 : (isArray ? UINT(qMax(0, m_arraySize))
4854 : (is3D ? qMax(1, m_depth)
4856 resourceDesc.MipLevels = mipLevelCount;
4857 resourceDesc.Format = dxgiFormat;
4858 resourceDesc.SampleDesc = sampleDesc;
4859 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4860 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
4861 D3D12_CLEAR_VALUE clearValue = {};
4862 clearValue.Format = dxgiFormat;
4864 clearValue.Format = toD3DDepthTextureDSVFormat(m_format);
4865 clearValue.DepthStencil.Depth = 1.0f;
4866 clearValue.DepthStencil.Stencil = 0;
4868 ID3D12Resource *resource =
nullptr;
4869 D3D12MA::Allocation *allocation =
nullptr;
4870 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4872 D3D12_RESOURCE_STATE_COMMON,
4873 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
4875 __uuidof(ID3D12Resource),
4876 reinterpret_cast<
void **>(&resource));
4878 qWarning(
"Failed to create texture: '%s'"
4879 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
4880 qPrintable(QSystemError::windowsComString(hr)),
4881 int(resourceDesc.Dimension),
4882 uint(resourceDesc.Width),
4883 uint(resourceDesc.Height),
4884 uint(resourceDesc.DepthOrArraySize),
4885 uint(resourceDesc.MipLevels),
4886 int(resourceDesc.Format),
4887 int(resourceDesc.SampleDesc.Count));
4891 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON, allocation);
4893 if (!finishCreate())
4896 rhiD->registerResource(
this);
4900bool QD3D12Texture::createFrom(QRhiTexture::NativeTexture src)
4905 if (!prepareCreate())
4908 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *>(src.object);
4909 D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(src.layout);
4911 QRHI_RES_RHI(QRhiD3D12);
4912 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource, state);
4914 if (!finishCreate())
4917 rhiD->registerResource(
this);
4921QRhiTexture::NativeTexture QD3D12Texture::nativeTexture()
4923 QRHI_RES_RHI(QRhiD3D12);
4924 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
4925 return { quint64(res->resource),
int(res->state) };
4930void QD3D12Texture::setNativeLayout(
int layout)
4932 QRHI_RES_RHI(QRhiD3D12);
4933 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
4934 res->state = D3D12_RESOURCE_STATES(layout);
4937QD3D12Sampler::QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
4938 AddressMode u, AddressMode v, AddressMode w)
4939 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
4943QD3D12Sampler::~QD3D12Sampler()
4948void QD3D12Sampler::destroy()
4950 shaderVisibleDescriptor = {};
4952 QRHI_RES_RHI(QRhiD3D12);
4954 rhiD->unregisterResource(
this);
4957static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
4959 if (minFilter == QRhiSampler::Nearest) {
4960 if (magFilter == QRhiSampler::Nearest) {
4961 if (mipFilter == QRhiSampler::Linear)
4962 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
4964 return D3D12_FILTER_MIN_MAG_MIP_POINT;
4966 if (mipFilter == QRhiSampler::Linear)
4967 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
4969 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
4972 if (magFilter == QRhiSampler::Nearest) {
4973 if (mipFilter == QRhiSampler::Linear)
4974 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
4976 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
4978 if (mipFilter == QRhiSampler::Linear)
4979 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
4981 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
4984 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
4987static inline D3D12_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
4990 case QRhiSampler::Repeat:
4991 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
4992 case QRhiSampler::ClampToEdge:
4993 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4994 case QRhiSampler::Mirror:
4995 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
4997 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
5000static inline D3D12_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
5003 case QRhiSampler::Never:
5004 return D3D12_COMPARISON_FUNC_NEVER;
5005 case QRhiSampler::Less:
5006 return D3D12_COMPARISON_FUNC_LESS;
5007 case QRhiSampler::Equal:
5008 return D3D12_COMPARISON_FUNC_EQUAL;
5009 case QRhiSampler::LessOrEqual:
5010 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5011 case QRhiSampler::Greater:
5012 return D3D12_COMPARISON_FUNC_GREATER;
5013 case QRhiSampler::NotEqual:
5014 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5015 case QRhiSampler::GreaterOrEqual:
5016 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5017 case QRhiSampler::Always:
5018 return D3D12_COMPARISON_FUNC_ALWAYS;
5020 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
5023bool QD3D12Sampler::create()
5026 desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
5027 if (m_compareOp != Never)
5028 desc.Filter = D3D12_FILTER(desc.Filter | 0x80);
5029 desc.AddressU = toD3DAddressMode(m_addressU);
5030 desc.AddressV = toD3DAddressMode(m_addressV);
5031 desc.AddressW = toD3DAddressMode(m_addressW);
5032 desc.MaxAnisotropy = 1.0f;
5033 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
5034 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
5036 QRHI_RES_RHI(QRhiD3D12);
5037 rhiD->registerResource(
this,
false);
5041QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
5043 if (!shaderVisibleDescriptor.isValid()) {
5044 QRHI_RES_RHI(QRhiD3D12);
5045 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(desc);
5047 return shaderVisibleDescriptor;
5050QD3D12ShadingRateMap::QD3D12ShadingRateMap(QRhiImplementation *rhi)
5051 : QRhiShadingRateMap(rhi)
5055QD3D12ShadingRateMap::~QD3D12ShadingRateMap()
5060void QD3D12ShadingRateMap::destroy()
5062 if (handle.isNull())
5068bool QD3D12ShadingRateMap::createFrom(QRhiTexture *src)
5070 if (!handle.isNull())
5073 handle = QRHI_RES(QD3D12Texture, src)->handle;
5078QD3D12TextureRenderTarget::QD3D12TextureRenderTarget(QRhiImplementation *rhi,
5079 const QRhiTextureRenderTargetDescription &desc,
5081 : QRhiTextureRenderTarget(rhi, desc, flags),
5086QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
5091void QD3D12TextureRenderTarget::destroy()
5093 if (!rtv[0].isValid() && !dsv.isValid())
5096 QRHI_RES_RHI(QRhiD3D12);
5097 if (dsv.isValid()) {
5098 if (ownsDsv && rhiD)
5099 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
5103 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i) {
5104 if (rtv[i].isValid()) {
5105 if (ownsRtv[i] && rhiD)
5106 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[i], 1);
5112 rhiD->unregisterResource(
this);
5115QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDescriptor()
5119 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
5121 rpD->colorAttachmentCount = 0;
5122 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it) {
5123 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
5124 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
5126 rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
5128 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
5129 rpD->colorAttachmentCount += 1;
5132 rpD->hasDepthStencil =
false;
5133 if (m_desc.depthStencilBuffer()) {
5134 rpD->hasDepthStencil =
true;
5135 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
5136 }
else if (m_desc.depthTexture()) {
5137 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5138 rpD->hasDepthStencil =
true;
5139 rpD->dsFormat = toD3DDepthTextureDSVFormat(depthTexD->format());
5142 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
5144 rpD->updateSerializedFormat();
5146 QRHI_RES_RHI(QRhiD3D12);
5147 rhiD->registerResource(rpD);
5151bool QD3D12TextureRenderTarget::create()
5153 if (rtv[0].isValid() || dsv.isValid())
5156 QRHI_RES_RHI(QRhiD3D12);
5157 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
5158 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
5159 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
5160 d.colorAttCount = 0;
5163 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
5164 d.colorAttCount += 1;
5165 const QRhiColorAttachment &colorAtt(*it);
5166 QRhiTexture *texture = colorAtt.texture();
5167 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
5168 Q_ASSERT(texture || rb);
5170 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, texture);
5171 QD3D12Resource *res = rhiD->resourcePool.lookupRef(texD->handle);
5173 qWarning(
"Could not look up texture handle for render target");
5176 const bool isMultiView = it->multiViewCount() >= 2;
5177 UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
5178 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5179 rtvDesc.Format = texD->rtFormat;
5180 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
5181 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5182 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5183 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5184 rtvDesc.Texture2DArray.ArraySize = layerCount;
5185 }
else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
5186 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5187 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
5188 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
5189 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
5190 rtvDesc.Texture1DArray.ArraySize = layerCount;
5192 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
5193 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
5195 }
else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5196 if (texD->sampleDesc.Count > 1) {
5197 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
5198 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
5199 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
5201 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5202 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5203 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5204 rtvDesc.Texture2DArray.ArraySize = layerCount;
5206 }
else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
5207 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
5208 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
5209 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
5210 rtvDesc.Texture3D.WSize = layerCount;
5212 if (texD->sampleDesc.Count > 1) {
5213 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
5215 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
5216 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
5219 rtv[attIndex] = rhiD->rtvPool.allocate(1);
5220 if (!rtv[attIndex].isValid()) {
5221 qWarning(
"Failed to allocate RTV for texture render target");
5224 rhiD->dev->CreateRenderTargetView(res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
5225 ownsRtv[attIndex] =
true;
5226 if (attIndex == 0) {
5227 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
5228 d.sampleCount =
int(texD->sampleDesc.Count);
5231 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rb);
5232 ownsRtv[attIndex] =
false;
5233 rtv[attIndex] = rbD->rtv;
5234 if (attIndex == 0) {
5235 d.pixelSize = rbD->pixelSize();
5236 d.sampleCount =
int(rbD->sampleDesc.Count);
5243 if (hasDepthStencil) {
5244 if (m_desc.depthTexture()) {
5246 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5247 QD3D12Resource *res = rhiD->resourcePool.lookupRef(depthTexD->handle);
5249 qWarning(
"Could not look up depth texture handle");
5252 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5253 dsvDesc.Format = depthTexD->rtFormat;
5254 dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
5255 : D3D12_DSV_DIMENSION_TEXTURE2D;
5256 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
5257 if (depthTexD->sampleDesc.Count > 1) {
5258 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
5259 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5260 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5261 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5263 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
5264 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5267 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
5268 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5269 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5270 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5272 dsvDesc.Texture2DArray.FirstArraySlice = 0;
5273 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5277 dsv = rhiD->dsvPool.allocate(1);
5278 if (!dsv.isValid()) {
5279 qWarning(
"Failed to allocate DSV for texture render target");
5282 rhiD->dev->CreateDepthStencilView(res->resource, &dsvDesc, dsv.cpuHandle);
5283 if (d.colorAttCount == 0) {
5284 d.pixelSize = depthTexD->pixelSize();
5285 d.sampleCount =
int(depthTexD->sampleDesc.Count);
5289 QD3D12RenderBuffer *depthRbD = QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
5290 dsv = depthRbD->dsv;
5291 if (d.colorAttCount == 0) {
5292 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
5293 d.sampleCount =
int(depthRbD->sampleDesc.Count);
5301 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
5302 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i)
5303 d.rtv[i] = i < d.colorAttCount ? rtv[i].cpuHandle : nullDescHandle;
5304 d.dsv = dsv.cpuHandle;
5305 d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
5307 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &d.currentResIdList);
5309 rhiD->registerResource(
this);
5313QSize QD3D12TextureRenderTarget::pixelSize()
const
5315 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc, d.currentResIdList))
5316 const_cast<QD3D12TextureRenderTarget *>(
this)->create();
5321float QD3D12TextureRenderTarget::devicePixelRatio()
const
5326int QD3D12TextureRenderTarget::sampleCount()
const
5328 return d.sampleCount;
5331QD3D12ShaderResourceBindings::QD3D12ShaderResourceBindings(QRhiImplementation *rhi)
5332 : QRhiShaderResourceBindings(rhi)
5336QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
5341void QD3D12ShaderResourceBindings::destroy()
5343 QRHI_RES_RHI(QRhiD3D12);
5345 rhiD->unregisterResource(
this);
5348bool QD3D12ShaderResourceBindings::create()
5350 QRHI_RES_RHI(QRhiD3D12);
5351 if (!rhiD->sanityCheckShaderResourceBindings(
this))
5354 rhiD->updateLayoutDesc(
this);
5356 hasDynamicOffset =
false;
5357 for (
const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
5358 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
5359 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
5360 hasDynamicOffset =
true;
5374 rhiD->registerResource(
this,
false);
5378void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
5389void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
5390 const QRhiShaderResourceBinding::Data::UniformBufferData &,
5394 D3D12_ROOT_PARAMETER1 rootParam = {};
5395 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
5396 rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
5397 rootParam.Descriptor.ShaderRegister = shaderRegister;
5398 rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
5399 visitorData.cbParams[s].append(rootParam);
5402void QD3D12ShaderResourceBindings::visitTexture(QD3D12Stage s,
5403 const QRhiShaderResourceBinding::TextureAndSampler &,
5406 D3D12_DESCRIPTOR_RANGE1 range = {};
5407 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
5408 range.NumDescriptors = 1;
5409 range.BaseShaderRegister = shaderRegister;
5410 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[s];
5411 visitorData.currentSrvRangeOffset[s] += 1;
5412 visitorData.srvRanges[s].append(range);
5413 if (visitorData.srvRanges[s].count() == 1) {
5414 visitorData.srvTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5415 visitorData.srvTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5419void QD3D12ShaderResourceBindings::visitSampler(QD3D12Stage s,
5420 const QRhiShaderResourceBinding::TextureAndSampler &,
5426 int &rangeStoreIdx(visitorData.samplerRangeHeads[s]);
5427 if (rangeStoreIdx == 16) {
5428 qWarning(
"Sampler count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi", s);
5431 D3D12_DESCRIPTOR_RANGE1 range = {};
5432 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
5433 range.NumDescriptors = 1;
5434 range.BaseShaderRegister = shaderRegister;
5435 visitorData.samplerRanges[s][rangeStoreIdx] = range;
5436 D3D12_ROOT_PARAMETER1 param = {};
5437 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5438 param.ShaderVisibility = qd3d12_stageToVisibility(s);
5439 param.DescriptorTable.NumDescriptorRanges = 1;
5440 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[s][rangeStoreIdx];
5442 visitorData.samplerTables[s].append(param);
5445void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage s,
5446 const QRhiShaderResourceBinding::Data::StorageBufferData &,
5447 QD3D12ShaderResourceVisitor::StorageOp,
5450 D3D12_DESCRIPTOR_RANGE1 range = {};
5451 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5452 range.NumDescriptors = 1;
5453 range.BaseShaderRegister = shaderRegister;
5454 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5455 visitorData.currentUavRangeOffset[s] += 1;
5456 visitorData.uavRanges[s].append(range);
5457 if (visitorData.uavRanges[s].count() == 1) {
5458 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5459 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5463void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage s,
5464 const QRhiShaderResourceBinding::Data::StorageImageData &,
5465 QD3D12ShaderResourceVisitor::StorageOp,
5468 D3D12_DESCRIPTOR_RANGE1 range = {};
5469 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5470 range.NumDescriptors = 1;
5471 range.BaseShaderRegister = shaderRegister;
5472 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5473 visitorData.currentUavRangeOffset[s] += 1;
5474 visitorData.uavRanges[s].append(range);
5475 if (visitorData.uavRanges[s].count() == 1) {
5476 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5477 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5481QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
5484 QRHI_RES_RHI(QRhiD3D12);
5498 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
5502 using namespace std::placeholders;
5503 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
5504 visitor.texture = std::bind(&QD3D12ShaderResourceBindings::visitTexture,
this, _1, _2, _3);
5505 visitor.sampler = std::bind(&QD3D12ShaderResourceBindings::visitSampler,
this, _1, _2, _3);
5506 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
5507 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
5531 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> rootParams;
5532 for (
int s = 0; s < 6; ++s) {
5533 if (!visitorData.cbParams[s].isEmpty())
5534 rootParams.append(visitorData.cbParams[s].constData(), visitorData.cbParams[s].count());
5536 for (
int s = 0; s < 6; ++s) {
5537 if (!visitorData.srvRanges[s].isEmpty()) {
5538 visitorData.srvTables[s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[s].count();
5539 visitorData.srvTables[s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[s].constData();
5540 rootParams.append(visitorData.srvTables[s]);
5543 for (
int s = 0; s < 6; ++s) {
5544 if (!visitorData.samplerTables[s].isEmpty())
5545 rootParams.append(visitorData.samplerTables[s].constData(), visitorData.samplerTables[s].count());
5547 for (
int s = 0; s < 6; ++s) {
5548 if (!visitorData.uavRanges[s].isEmpty()) {
5549 visitorData.uavTables[s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[s].count();
5550 visitorData.uavTables[s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[s].constData();
5551 rootParams.append(visitorData.uavTables[s]);
5555 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
5556 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
5557 if (!rootParams.isEmpty()) {
5558 rsDesc.Desc_1_1.NumParameters = rootParams.count();
5559 rsDesc.Desc_1_1.pParameters = rootParams.constData();
5563 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
5564 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
5565 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
5567 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
5569 ID3DBlob *signature =
nullptr;
5570 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
5572 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5575 ID3D12RootSignature *rootSig =
nullptr;
5576 hr = rhiD->dev->CreateRootSignature(0,
5577 signature->GetBufferPointer(),
5578 signature->GetBufferSize(),
5579 __uuidof(ID3D12RootSignature),
5580 reinterpret_cast<
void **>(&rootSig));
5581 signature->Release();
5583 qWarning(
"Failed to create root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5587 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
5599static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
5601 const int smMajor = version / 10;
5602 const int smMinor = version % 10;
5603 target[0] = stage[0];
5604 target[1] = stage[1];
5606 target[3] =
'0' + smMajor;
5608 target[5] =
'0' + smMinor;
5612enum class HlslCompileFlag
5614 WithDebugInfo = 0x01
5617static QByteArray legacyCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5619 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
5621 qWarning(
"Unable to resolve function D3DCompile()");
5622 return QByteArray();
5625 ID3DBlob *bytecode =
nullptr;
5626 ID3DBlob *errors =
nullptr;
5627 UINT d3dCompileFlags = 0;
5628 if (flags &
int(HlslCompileFlag::WithDebugInfo))
5629 d3dCompileFlags |= D3DCOMPILE_DEBUG;
5631 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
5632 nullptr,
nullptr,
nullptr,
5633 hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
5634 if (FAILED(hr) || !bytecode) {
5635 qWarning(
"HLSL shader compilation failed: 0x%x", uint(hr));
5637 *error = QString::fromUtf8(
static_cast<
const char *>(errors->GetBufferPointer()),
5638 int(errors->GetBufferSize()));
5641 return QByteArray();
5645 result.resize(
int(bytecode->GetBufferSize()));
5646 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
5647 bytecode->Release();
5651#ifdef QRHI_D3D12_HAS_DXC
5654#define DXC_CP_UTF8 65001
5657#ifndef DXC_ARG_DEBUG
5658#define DXC_ARG_DEBUG L"-Zi"
5661static QByteArray dxcCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5663 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
5664 IDxcCompiler *compiler = dxc.first;
5666 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
5667 "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
5668 return QByteArray();
5670 IDxcLibrary *library = dxc.second;
5672 return QByteArray();
5674 IDxcBlobEncoding *sourceBlob =
nullptr;
5675 HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
5676 UINT32(hlslSource.shader().size()),
5680 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
5682 qPrintable(QSystemError::windowsComString(hr)));
5683 return QByteArray();
5686 const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
5687 const QString targetStr = QString::fromLatin1(target);
5689 QVarLengthArray<LPCWSTR, 4> argPtrs;
5691 if (flags &
int(HlslCompileFlag::WithDebugInfo)) {
5692 debugArg = QString::fromUtf16(
reinterpret_cast<
const char16_t *>(DXC_ARG_DEBUG));
5693 argPtrs.append(
reinterpret_cast<LPCWSTR>(debugArg.utf16()));
5696 IDxcOperationResult *result =
nullptr;
5697 hr = compiler->Compile(sourceBlob,
5699 reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
5700 reinterpret_cast<LPCWSTR>(targetStr.utf16()),
5701 argPtrs.data(), argPtrs.count(),
5705 sourceBlob->Release();
5707 result->GetStatus(&hr);
5709 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
5711 qPrintable(QSystemError::windowsComString(hr)));
5713 IDxcBlobEncoding *errorsBlob =
nullptr;
5714 if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
5716 *error = QString::fromUtf8(
static_cast<
const char *>(errorsBlob->GetBufferPointer()),
5717 int(errorsBlob->GetBufferSize()));
5718 errorsBlob->Release();
5722 return QByteArray();
5725 IDxcBlob *bytecode =
nullptr;
5726 if FAILED(result->GetResult(&bytecode)) {
5727 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
5729 qPrintable(QSystemError::windowsComString(hr)));
5730 return QByteArray();
5734 ba.resize(
int(bytecode->GetBufferSize()));
5735 memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
5736 bytecode->Release();
5742static QByteArray compileHlslShaderSource(
const QShader &shader,
5743 QShader::Variant shaderVariant,
5746 QShaderKey *usedShaderKey)
5749 const int shaderModelMax = 67;
5750 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5751 for (QShader::Source type : { QShader::DxilShader, QShader::DxbcShader }) {
5752 QShaderKey key = { type, sm, shaderVariant };
5753 QShaderCode intermediateBytecodeShader = shader.shader(key);
5754 if (!intermediateBytecodeShader.shader().isEmpty()) {
5756 *usedShaderKey = key;
5757 return intermediateBytecodeShader.shader();
5762 QShaderCode hlslSource;
5764 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5765 key = { QShader::HlslShader, sm, shaderVariant };
5766 hlslSource = shader.shader(key);
5767 if (!hlslSource.shader().isEmpty())
5771 if (hlslSource.shader().isEmpty()) {
5772 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" << shader;
5773 return QByteArray();
5777 *usedShaderKey = key;
5780 switch (shader.stage()) {
5781 case QShader::VertexStage:
5782 makeHlslTargetString(target,
"vs", key.sourceVersion().version());
5784 case QShader::TessellationControlStage:
5785 makeHlslTargetString(target,
"hs", key.sourceVersion().version());
5787 case QShader::TessellationEvaluationStage:
5788 makeHlslTargetString(target,
"ds", key.sourceVersion().version());
5790 case QShader::GeometryStage:
5791 makeHlslTargetString(target,
"gs", key.sourceVersion().version());
5793 case QShader::FragmentStage:
5794 makeHlslTargetString(target,
"ps", key.sourceVersion().version());
5796 case QShader::ComputeStage:
5797 makeHlslTargetString(target,
"cs", key.sourceVersion().version());
5801 if (key.sourceVersion().version() >= 60) {
5802#ifdef QRHI_D3D12_HAS_DXC
5803 return dxcCompile(hlslSource, target, flags, error);
5805 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
5806 "but the Qt build has no support for DXC. "
5807 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
5811 return legacyCompile(hlslSource, target, flags, error);
5814static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
5817 if (c.testFlag(QRhiGraphicsPipeline::R))
5818 f |= D3D12_COLOR_WRITE_ENABLE_RED;
5819 if (c.testFlag(QRhiGraphicsPipeline::G))
5820 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
5821 if (c.testFlag(QRhiGraphicsPipeline::B))
5822 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
5823 if (c.testFlag(QRhiGraphicsPipeline::A))
5824 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
5828static inline D3D12_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f,
bool rgb)
5837 case QRhiGraphicsPipeline::Zero:
5838 return D3D12_BLEND_ZERO;
5839 case QRhiGraphicsPipeline::One:
5840 return D3D12_BLEND_ONE;
5841 case QRhiGraphicsPipeline::SrcColor:
5842 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
5843 case QRhiGraphicsPipeline::OneMinusSrcColor:
5844 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
5845 case QRhiGraphicsPipeline::DstColor:
5846 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
5847 case QRhiGraphicsPipeline::OneMinusDstColor:
5848 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
5849 case QRhiGraphicsPipeline::SrcAlpha:
5850 return D3D12_BLEND_SRC_ALPHA;
5851 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
5852 return D3D12_BLEND_INV_SRC_ALPHA;
5853 case QRhiGraphicsPipeline::DstAlpha:
5854 return D3D12_BLEND_DEST_ALPHA;
5855 case QRhiGraphicsPipeline::OneMinusDstAlpha:
5856 return D3D12_BLEND_INV_DEST_ALPHA;
5857 case QRhiGraphicsPipeline::ConstantColor:
5858 case QRhiGraphicsPipeline::ConstantAlpha:
5859 return D3D12_BLEND_BLEND_FACTOR;
5860 case QRhiGraphicsPipeline::OneMinusConstantColor:
5861 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
5862 return D3D12_BLEND_INV_BLEND_FACTOR;
5863 case QRhiGraphicsPipeline::SrcAlphaSaturate:
5864 return D3D12_BLEND_SRC_ALPHA_SAT;
5865 case QRhiGraphicsPipeline::Src1Color:
5866 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
5867 case QRhiGraphicsPipeline::OneMinusSrc1Color:
5868 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
5869 case QRhiGraphicsPipeline::Src1Alpha:
5870 return D3D12_BLEND_SRC1_ALPHA;
5871 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
5872 return D3D12_BLEND_INV_SRC1_ALPHA;
5874 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
5877static inline D3D12_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
5880 case QRhiGraphicsPipeline::Add:
5881 return D3D12_BLEND_OP_ADD;
5882 case QRhiGraphicsPipeline::Subtract:
5883 return D3D12_BLEND_OP_SUBTRACT;
5884 case QRhiGraphicsPipeline::ReverseSubtract:
5885 return D3D12_BLEND_OP_REV_SUBTRACT;
5886 case QRhiGraphicsPipeline::Min:
5887 return D3D12_BLEND_OP_MIN;
5888 case QRhiGraphicsPipeline::Max:
5889 return D3D12_BLEND_OP_MAX;
5891 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
5894static inline D3D12_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
5897 case QRhiGraphicsPipeline::None:
5898 return D3D12_CULL_MODE_NONE;
5899 case QRhiGraphicsPipeline::Front:
5900 return D3D12_CULL_MODE_FRONT;
5901 case QRhiGraphicsPipeline::Back:
5902 return D3D12_CULL_MODE_BACK;
5904 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
5907static inline D3D12_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
5910 case QRhiGraphicsPipeline::Fill:
5911 return D3D12_FILL_MODE_SOLID;
5912 case QRhiGraphicsPipeline::Line:
5913 return D3D12_FILL_MODE_WIREFRAME;
5915 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
5918static inline D3D12_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
5921 case QRhiGraphicsPipeline::Never:
5922 return D3D12_COMPARISON_FUNC_NEVER;
5923 case QRhiGraphicsPipeline::Less:
5924 return D3D12_COMPARISON_FUNC_LESS;
5925 case QRhiGraphicsPipeline::Equal:
5926 return D3D12_COMPARISON_FUNC_EQUAL;
5927 case QRhiGraphicsPipeline::LessOrEqual:
5928 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5929 case QRhiGraphicsPipeline::Greater:
5930 return D3D12_COMPARISON_FUNC_GREATER;
5931 case QRhiGraphicsPipeline::NotEqual:
5932 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5933 case QRhiGraphicsPipeline::GreaterOrEqual:
5934 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5935 case QRhiGraphicsPipeline::Always:
5936 return D3D12_COMPARISON_FUNC_ALWAYS;
5938 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
5941static inline D3D12_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
5944 case QRhiGraphicsPipeline::StencilZero:
5945 return D3D12_STENCIL_OP_ZERO;
5946 case QRhiGraphicsPipeline::Keep:
5947 return D3D12_STENCIL_OP_KEEP;
5948 case QRhiGraphicsPipeline::Replace:
5949 return D3D12_STENCIL_OP_REPLACE;
5950 case QRhiGraphicsPipeline::IncrementAndClamp:
5951 return D3D12_STENCIL_OP_INCR_SAT;
5952 case QRhiGraphicsPipeline::DecrementAndClamp:
5953 return D3D12_STENCIL_OP_DECR_SAT;
5954 case QRhiGraphicsPipeline::Invert:
5955 return D3D12_STENCIL_OP_INVERT;
5956 case QRhiGraphicsPipeline::IncrementAndWrap:
5957 return D3D12_STENCIL_OP_INCR;
5958 case QRhiGraphicsPipeline::DecrementAndWrap:
5959 return D3D12_STENCIL_OP_DECR;
5961 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
5964static inline D3D12_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t,
int patchControlPointCount)
5967 case QRhiGraphicsPipeline::Triangles:
5968 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
5969 case QRhiGraphicsPipeline::TriangleStrip:
5970 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
5971 case QRhiGraphicsPipeline::TriangleFan:
5972 qWarning(
"Triangle fans are not supported with D3D");
5973 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
5974 case QRhiGraphicsPipeline::Lines:
5975 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
5976 case QRhiGraphicsPipeline::LineStrip:
5977 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
5978 case QRhiGraphicsPipeline::Points:
5979 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
5980 case QRhiGraphicsPipeline::Patches:
5981 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
5982 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
5984 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
5987static inline D3D12_PRIMITIVE_TOPOLOGY_TYPE toD3DTopologyType(QRhiGraphicsPipeline::Topology t)
5990 case QRhiGraphicsPipeline::Triangles:
5991 case QRhiGraphicsPipeline::TriangleStrip:
5992 case QRhiGraphicsPipeline::TriangleFan:
5993 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
5994 case QRhiGraphicsPipeline::Lines:
5995 case QRhiGraphicsPipeline::LineStrip:
5996 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
5997 case QRhiGraphicsPipeline::Points:
5998 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
5999 case QRhiGraphicsPipeline::Patches:
6000 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
6002 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
6005static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
6008 case QRhiVertexInputAttribute::Float4:
6009 return DXGI_FORMAT_R32G32B32A32_FLOAT;
6010 case QRhiVertexInputAttribute::Float3:
6011 return DXGI_FORMAT_R32G32B32_FLOAT;
6012 case QRhiVertexInputAttribute::Float2:
6013 return DXGI_FORMAT_R32G32_FLOAT;
6014 case QRhiVertexInputAttribute::Float:
6015 return DXGI_FORMAT_R32_FLOAT;
6016 case QRhiVertexInputAttribute::UNormByte4:
6017 return DXGI_FORMAT_R8G8B8A8_UNORM;
6018 case QRhiVertexInputAttribute::UNormByte2:
6019 return DXGI_FORMAT_R8G8_UNORM;
6020 case QRhiVertexInputAttribute::UNormByte:
6021 return DXGI_FORMAT_R8_UNORM;
6022 case QRhiVertexInputAttribute::UInt4:
6023 return DXGI_FORMAT_R32G32B32A32_UINT;
6024 case QRhiVertexInputAttribute::UInt3:
6025 return DXGI_FORMAT_R32G32B32_UINT;
6026 case QRhiVertexInputAttribute::UInt2:
6027 return DXGI_FORMAT_R32G32_UINT;
6028 case QRhiVertexInputAttribute::UInt:
6029 return DXGI_FORMAT_R32_UINT;
6030 case QRhiVertexInputAttribute::SInt4:
6031 return DXGI_FORMAT_R32G32B32A32_SINT;
6032 case QRhiVertexInputAttribute::SInt3:
6033 return DXGI_FORMAT_R32G32B32_SINT;
6034 case QRhiVertexInputAttribute::SInt2:
6035 return DXGI_FORMAT_R32G32_SINT;
6036 case QRhiVertexInputAttribute::SInt:
6037 return DXGI_FORMAT_R32_SINT;
6038 case QRhiVertexInputAttribute::Half4:
6040 case QRhiVertexInputAttribute::Half3:
6041 return DXGI_FORMAT_R16G16B16A16_FLOAT;
6042 case QRhiVertexInputAttribute::Half2:
6043 return DXGI_FORMAT_R16G16_FLOAT;
6044 case QRhiVertexInputAttribute::Half:
6045 return DXGI_FORMAT_R16_FLOAT;
6046 case QRhiVertexInputAttribute::UShort4:
6048 case QRhiVertexInputAttribute::UShort3:
6049 return DXGI_FORMAT_R16G16B16A16_UINT;
6050 case QRhiVertexInputAttribute::UShort2:
6051 return DXGI_FORMAT_R16G16_UINT;
6052 case QRhiVertexInputAttribute::UShort:
6053 return DXGI_FORMAT_R16_UINT;
6054 case QRhiVertexInputAttribute::SShort4:
6056 case QRhiVertexInputAttribute::SShort3:
6057 return DXGI_FORMAT_R16G16B16A16_SINT;
6058 case QRhiVertexInputAttribute::SShort2:
6059 return DXGI_FORMAT_R16G16_SINT;
6060 case QRhiVertexInputAttribute::SShort:
6061 return DXGI_FORMAT_R16_SINT;
6063 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
6066QD3D12GraphicsPipeline::QD3D12GraphicsPipeline(QRhiImplementation *rhi)
6067 : QRhiGraphicsPipeline(rhi)
6071QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
6076void QD3D12GraphicsPipeline::destroy()
6078 if (handle.isNull())
6081 QRHI_RES_RHI(QRhiD3D12);
6083 rhiD->releaseQueue.deferredReleasePipeline(handle);
6084 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6091 rhiD->unregisterResource(
this);
6094bool QD3D12GraphicsPipeline::create()
6096 if (!handle.isNull())
6099 QRHI_RES_RHI(QRhiD3D12);
6100 if (!rhiD->sanityCheckGraphicsPipeline(
this))
6103 rhiD->pipelineCreationStart();
6105 QByteArray shaderBytecode[5];
6106 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6107 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
6108 stageData[d3dStage].valid =
true;
6109 stageData[d3dStage].stage = d3dStage;
6110 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
6111 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6112 shaderBytecode[d3dStage] = cacheIt->bytecode;
6113 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6116 QShaderKey shaderKey;
6117 int compileFlags = 0;
6118 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6119 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6120 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
6121 shaderStage.shaderVariant(),
6125 if (bytecode.isEmpty()) {
6126 qWarning(
"HLSL graphics shader compilation failed: %s", qPrintable(error));
6130 shaderBytecode[d3dStage] = bytecode;
6131 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
6132 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
6133 { bytecode, stageData[d3dStage].nativeResourceBindingMap });
6137 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6139 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
6140 if (rootSigHandle.isNull()) {
6141 qWarning(
"Failed to create root signature");
6145 ID3D12RootSignature *rootSig =
nullptr;
6146 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6147 rootSig = rs->rootSig;
6149 qWarning(
"Cannot create graphics pipeline state without root signature");
6153 QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6154 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
6155 if (rpD->colorAttachmentCount > 0) {
6156 format = DXGI_FORMAT(rpD->colorFormat[0]);
6157 }
else if (rpD->hasDepthStencil) {
6158 format = DXGI_FORMAT(rpD->dsFormat);
6160 qWarning(
"Cannot create graphics pipeline state without color or depthStencil format");
6163 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
6166 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6167 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
6168 QD3D12PipelineStateSubObject<D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE> primitiveRestartValue;
6169 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
6170 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
6171 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
6172 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
6173 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
6174 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
6175 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
6176 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
6177 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
6178 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
6179 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
6180 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
6181 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
6182 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
6185 stream.rootSig.object = rootSig;
6187 QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
6188 QByteArrayList matrixSliceSemantics;
6189 if (!shaderBytecode[VS].isEmpty()) {
6190 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
6193 D3D12_INPUT_ELEMENT_DESC desc = {};
6198 const int matrixSlice = it->matrixSlice();
6199 if (matrixSlice < 0) {
6200 desc.SemanticName =
"TEXCOORD";
6201 desc.SemanticIndex = UINT(it->location());
6205 std::snprintf(sem.data(), sem.size(),
"TEXCOORD%d_", it->location() - matrixSlice);
6206 matrixSliceSemantics.append(sem);
6207 desc.SemanticName = matrixSliceSemantics.last().constData();
6208 desc.SemanticIndex = UINT(matrixSlice);
6210 desc.Format = toD3DAttributeFormat(it->format());
6211 desc.InputSlot = UINT(it->binding());
6212 desc.AlignedByteOffset = it->offset();
6213 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
6214 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
6215 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
6216 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
6218 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
6220 inputDescs.append(desc);
6224 stream.inputLayout.object.NumElements = inputDescs.count();
6225 stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ?
nullptr : inputDescs.constData();
6227 stream.primitiveRestartValue.object = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
6229 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
6230 topology = toD3DTopology(m_topology, m_patchControlPointCount);
6232 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6233 const int d3dStage = qd3d12_stage(shaderStage.type());
6236 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6237 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6240 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6241 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6244 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6245 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6248 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6249 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6252 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6253 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6261 stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
6262 stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
6263 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
6264 stream.rasterizerState.object.DepthBias = m_depthBias;
6265 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
6266 stream.rasterizerState.object.DepthClipEnable = TRUE;
6267 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
6269 stream.depthStencilState.object.DepthEnable = m_depthTest;
6270 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
6271 stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
6272 stream.depthStencilState.object.StencilEnable = m_stencilTest;
6273 if (m_stencilTest) {
6274 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
6275 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
6276 stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
6277 stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
6278 stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
6279 stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
6280 stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
6281 stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
6282 stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
6283 stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
6286 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
6287 for (
int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
6288 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
6289 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6290 blend.BlendEnable = b.enable;
6291 blend.SrcBlend = toD3DBlendFactor(b.srcColor,
true);
6292 blend.DestBlend = toD3DBlendFactor(b.dstColor,
true);
6293 blend.BlendOp = toD3DBlendOp(b.opColor);
6294 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha,
false);
6295 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha,
false);
6296 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
6297 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
6298 stream.blendState.object.RenderTarget[i] = blend;
6300 if (m_targetBlends.isEmpty()) {
6301 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6302 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
6303 stream.blendState.object.RenderTarget[0] = blend;
6306 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
6307 for (
int i = 0; i < rpD->colorAttachmentCount; ++i)
6308 stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
6310 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
6312 stream.sampleDesc.object = sampleDesc;
6314 stream.sampleMask.object = 0xFFFFFFFF;
6316 viewInstanceMask = 0;
6317 const bool isMultiView = m_multiViewCount >= 2;
6318 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
6319 QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
6321 for (
int i = 0; i < m_multiViewCount; ++i) {
6322 viewInstanceMask |= (1 << i);
6323 viewInstanceLocations.append({ 0, UINT(i) });
6325 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
6328 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6330 ID3D12PipelineState *pso =
nullptr;
6331 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6333 qWarning(
"Failed to create graphics pipeline state: %s",
6334 qPrintable(QSystemError::windowsComString(hr)));
6335 rhiD->rootSignaturePool.remove(rootSigHandle);
6340 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
6342 rhiD->pipelineCreationEnd();
6344 rhiD->registerResource(
this);
6348QD3D12ComputePipeline::QD3D12ComputePipeline(QRhiImplementation *rhi)
6349 : QRhiComputePipeline(rhi)
6353QD3D12ComputePipeline::~QD3D12ComputePipeline()
6358void QD3D12ComputePipeline::destroy()
6360 if (handle.isNull())
6363 QRHI_RES_RHI(QRhiD3D12);
6365 rhiD->releaseQueue.deferredReleasePipeline(handle);
6366 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6373 rhiD->unregisterResource(
this);
6376bool QD3D12ComputePipeline::create()
6378 if (!handle.isNull())
6381 QRHI_RES_RHI(QRhiD3D12);
6382 rhiD->pipelineCreationStart();
6384 stageData.valid =
true;
6385 stageData.stage = CS;
6387 QByteArray shaderBytecode;
6388 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(m_shaderStage);
6389 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6390 shaderBytecode = cacheIt->bytecode;
6391 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6394 QShaderKey shaderKey;
6395 int compileFlags = 0;
6396 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6397 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6398 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
6399 m_shaderStage.shaderVariant(),
6403 if (bytecode.isEmpty()) {
6404 qWarning(
"HLSL compute shader compilation failed: %s", qPrintable(error));
6408 shaderBytecode = bytecode;
6409 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
6410 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
6411 stageData.nativeResourceBindingMap });
6414 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6416 rootSigHandle = srbD->createRootSignature(&stageData, 1);
6417 if (rootSigHandle.isNull()) {
6418 qWarning(
"Failed to create root signature");
6422 ID3D12RootSignature *rootSig =
nullptr;
6423 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6424 rootSig = rs->rootSig;
6426 qWarning(
"Cannot create compute pipeline state without root signature");
6431 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6432 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
6434 stream.rootSig.object = rootSig;
6435 stream.CS.object.pShaderBytecode = shaderBytecode.constData();
6436 stream.CS.object.BytecodeLength = shaderBytecode.size();
6437 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6438 ID3D12PipelineState *pso =
nullptr;
6439 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6441 qWarning(
"Failed to create compute pipeline state: %s",
6442 qPrintable(QSystemError::windowsComString(hr)));
6443 rhiD->rootSignaturePool.remove(rootSigHandle);
6448 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
6450 rhiD->pipelineCreationEnd();
6452 rhiD->registerResource(
this);
6459QD3D12RenderPassDescriptor::QD3D12RenderPassDescriptor(QRhiImplementation *rhi)
6460 : QRhiRenderPassDescriptor(rhi)
6462 serializedFormatData.reserve(16);
6465QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
6470void QD3D12RenderPassDescriptor::destroy()
6472 QRHI_RES_RHI(QRhiD3D12);
6474 rhiD->unregisterResource(
this);
6477bool QD3D12RenderPassDescriptor::isCompatible(
const QRhiRenderPassDescriptor *other)
const
6482 const QD3D12RenderPassDescriptor *o = QRHI_RES(
const QD3D12RenderPassDescriptor, other);
6484 if (colorAttachmentCount != o->colorAttachmentCount)
6487 if (hasDepthStencil != o->hasDepthStencil)
6490 for (
int i = 0; i < colorAttachmentCount; ++i) {
6491 if (colorFormat[i] != o->colorFormat[i])
6495 if (hasDepthStencil) {
6496 if (dsFormat != o->dsFormat)
6500 if (hasShadingRateMap != o->hasShadingRateMap)
6506void QD3D12RenderPassDescriptor::updateSerializedFormat()
6508 serializedFormatData.clear();
6509 auto p = std::back_inserter(serializedFormatData);
6511 *p++ = colorAttachmentCount;
6512 *p++ = hasDepthStencil;
6513 for (
int i = 0; i < colorAttachmentCount; ++i)
6514 *p++ = colorFormat[i];
6515 *p++ = hasDepthStencil ? dsFormat : 0;
6518QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor()
const
6520 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6521 rpD->colorAttachmentCount = colorAttachmentCount;
6522 rpD->hasDepthStencil = hasDepthStencil;
6523 memcpy(rpD->colorFormat, colorFormat,
sizeof(colorFormat));
6524 rpD->dsFormat = dsFormat;
6525 rpD->hasShadingRateMap = hasShadingRateMap;
6527 rpD->updateSerializedFormat();
6529 QRHI_RES_RHI(QRhiD3D12);
6530 rhiD->registerResource(rpD);
6534QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat()
const
6536 return serializedFormatData;
6539QD3D12CommandBuffer::QD3D12CommandBuffer(QRhiImplementation *rhi)
6540 : QRhiCommandBuffer(rhi)
6545QD3D12CommandBuffer::~QD3D12CommandBuffer()
6550void QD3D12CommandBuffer::destroy()
6555const QRhiNativeHandles *QD3D12CommandBuffer::nativeHandles()
6557 nativeHandlesStruct.commandList = cmdList;
6558 return &nativeHandlesStruct;
6561QD3D12SwapChainRenderTarget::QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
6562 : QRhiSwapChainRenderTarget(rhi, swapchain),
6567QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
6572void QD3D12SwapChainRenderTarget::destroy()
6577QSize QD3D12SwapChainRenderTarget::pixelSize()
const
6582float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
6587int QD3D12SwapChainRenderTarget::sampleCount()
const
6589 return d.sampleCount;
6592QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
6593 : QRhiSwapChain(rhi),
6594 rtWrapper(rhi,
this),
6595 rtWrapperRight(rhi,
this),
6600QD3D12SwapChain::~QD3D12SwapChain()
6605void QD3D12SwapChain::destroy()
6612 swapChain->Release();
6613 swapChain =
nullptr;
6614 sourceSwapChain1->Release();
6615 sourceSwapChain1 =
nullptr;
6617 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
6618 FrameResources &fr(frameRes[i]);
6620 fr.fence->Release();
6622 CloseHandle(fr.fenceEvent);
6624 fr.cmdList->Release();
6629 dcompVisual->Release();
6630 dcompVisual =
nullptr;
6634 dcompTarget->Release();
6635 dcompTarget =
nullptr;
6638 if (frameLatencyWaitableObject) {
6639 CloseHandle(frameLatencyWaitableObject);
6640 frameLatencyWaitableObject =
nullptr;
6643 QDxgiVSyncService::instance()->unregisterWindow(window);
6645 QRHI_RES_RHI(QRhiD3D12);
6647 rhiD->swapchains.remove(
this);
6648 rhiD->unregisterResource(
this);
6652void QD3D12SwapChain::releaseBuffers()
6654 QRHI_RES_RHI(QRhiD3D12);
6656 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
6657 rhiD->resourcePool.remove(colorBuffers[i]);
6658 rhiD->rtvPool.release(rtvs[i], 1);
6660 rhiD->rtvPool.release(rtvsRight[i], 1);
6661 if (!msaaBuffers[i].isNull())
6662 rhiD->resourcePool.remove(msaaBuffers[i]);
6663 if (msaaRtvs[i].isValid())
6664 rhiD->rtvPool.release(msaaRtvs[i], 1);
6668void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
6670 FrameResources &fr(frameRes[frameSlot]);
6671 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
6672 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
6673 WaitForSingleObject(fr.fenceEvent, INFINITE);
6677void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
6679 QRHI_RES_RHI(QRhiD3D12);
6680 FrameResources &fr(frameRes[currentFrameSlot]);
6681 fr.fenceCounter += 1u;
6682 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
6685QRhiCommandBuffer *QD3D12SwapChain::currentFrameCommandBuffer()
6690QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
6695QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
6697 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
6700QSize QD3D12SwapChain::surfacePixelSize()
6703 return m_window->size() * m_window->devicePixelRatio();
6706bool QD3D12SwapChain::isFormatSupported(Format f)
6712 qWarning(
"Attempted to call isFormatSupported() without a window set");
6716 QRHI_RES_RHI(QRhiD3D12);
6717 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window))
6718 return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
6723QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
6725 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
6728 QRHI_RES_RHI(QRhiD3D12);
6729 info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window);
6734QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
6739 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6740 rpD->colorAttachmentCount = 1;
6741 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
6742 rpD->colorFormat[0] =
int(srgbAdjustedColorFormat);
6743 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
6745 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
6747 rpD->updateSerializedFormat();
6749 QRHI_RES_RHI(QRhiD3D12);
6750 rhiD->registerResource(rpD);
6754bool QRhiD3D12::ensureDirectCompositionDevice()
6759 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
6760 dcompDevice = QRhiD3D::createDirectCompositionDevice();
6761 return dcompDevice ?
true :
false;
6764static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
6765static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
6767void QD3D12SwapChain::chooseFormats()
6769 colorFormat = DEFAULT_FORMAT;
6770 srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
6771 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
6772 QRHI_RES_RHI(QRhiD3D12);
6773 if (m_format != SDR) {
6774 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) {
6777 case HDRExtendedSrgbLinear:
6778 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
6779 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
6780 srgbAdjustedColorFormat = colorFormat;
6783 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
6784 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
6785 srgbAdjustedColorFormat = colorFormat;
6794 qWarning(
"The output associated with the window is not HDR capable "
6795 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
6798 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
6801bool QD3D12SwapChain::createOrResize()
6807 const bool needsRegistration = !window || window != m_window;
6810 if (window && window != m_window)
6814 m_currentPixelSize = surfacePixelSize();
6815 pixelSize = m_currentPixelSize;
6817 if (pixelSize.isEmpty())
6820 HWND hwnd =
reinterpret_cast<HWND>(window->winId());
6822 QRHI_RES_RHI(QRhiD3D12);
6823 stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
6825 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
6826 if (rhiD->ensureDirectCompositionDevice()) {
6828 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
false, &dcompTarget);
6830 qWarning(
"Failed to create Direct Composition target for the window: %s",
6831 qPrintable(QSystemError::windowsComString(hr)));
6834 if (dcompTarget && !dcompVisual) {
6835 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
6837 qWarning(
"Failed to create DirectComposition visual: %s",
6838 qPrintable(QSystemError::windowsComString(hr)));
6843 if (window->requestedFormat().alphaBufferSize() <= 0)
6844 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
6845 "This may lead to problems.");
6848 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
6850 if (swapInterval == 0 && rhiD->supportsAllowTearing)
6851 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
6855 const bool useFrameLatencyWaitableObject = rhiD->maxFrameLatency != 0
6856 && swapInterval != 0
6857 && rhiD->driverInfoStruct.deviceType != QRhiDriverInfo::CpuDevice;
6858 if (useFrameLatencyWaitableObject)
6859 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
6864 DXGI_SWAP_CHAIN_DESC1 desc = {};
6865 desc.Width = UINT(pixelSize.width());
6866 desc.Height = UINT(pixelSize.height());
6867 desc.Format = colorFormat;
6868 desc.SampleDesc.Count = 1;
6869 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6870 desc.BufferCount = BUFFER_COUNT;
6871 desc.Flags = swapChainFlags;
6872 desc.Scaling = DXGI_SCALING_NONE;
6873 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
6874 desc.Stereo = stereo;
6880 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
6885 desc.Scaling = DXGI_SCALING_STRETCH;
6889 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
6891 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
6896 if (FAILED(hr) && m_format != SDR) {
6897 colorFormat = DEFAULT_FORMAT;
6898 desc.Format = DEFAULT_FORMAT;
6900 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
6902 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
6905 if (SUCCEEDED(hr)) {
6906 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<
void **>(&swapChain)))) {
6907 qWarning(
"IDXGISwapChain3 not available");
6910 if (m_format != SDR) {
6911 hr = swapChain->SetColorSpace1(hdrColorSpace);
6913 qWarning(
"Failed to set color space on swapchain: %s",
6914 qPrintable(QSystemError::windowsComString(hr)));
6917 if (useFrameLatencyWaitableObject) {
6918 swapChain->SetMaximumFrameLatency(rhiD->maxFrameLatency);
6919 frameLatencyWaitableObject = swapChain->GetFrameLatencyWaitableObject();
6922 hr = dcompVisual->SetContent(swapChain);
6923 if (SUCCEEDED(hr)) {
6924 hr = dcompTarget->SetRoot(dcompVisual);
6926 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
6927 qPrintable(QSystemError::windowsComString(hr)));
6930 qWarning(
"Failed to set content for Direct Composition visual: %s",
6931 qPrintable(QSystemError::windowsComString(hr)));
6935 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
6939 qWarning(
"Failed to create D3D12 swapchain: %s"
6940 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
6941 qPrintable(QSystemError::windowsComString(hr)),
6942 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
6943 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
6947 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
6948 hr = rhiD->dev->CreateFence(0,
6949 D3D12_FENCE_FLAG_NONE,
6950 __uuidof(ID3D12Fence),
6951 reinterpret_cast<
void **>(&frameRes[i].fence));
6953 qWarning(
"Failed to create fence for swapchain: %s",
6954 qPrintable(QSystemError::windowsComString(hr)));
6957 frameRes[i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
6959 frameRes[i].fenceCounter = 0;
6963 hr = swapChain->ResizeBuffers(BUFFER_COUNT,
6964 UINT(pixelSize.width()),
6965 UINT(pixelSize.height()),
6968 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
6969 qWarning(
"Device loss detected in ResizeBuffers()");
6970 rhiD->deviceLost =
true;
6972 }
else if (FAILED(hr)) {
6973 qWarning(
"Failed to resize D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
6978 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
6979 ID3D12Resource *colorBuffer;
6980 hr = swapChain->GetBuffer(i, __uuidof(ID3D12Resource),
reinterpret_cast<
void **>(&colorBuffer));
6982 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
6983 i, qPrintable(QSystemError::windowsComString(hr)));
6986 colorBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
6987 rtvs[i] = rhiD->rtvPool.allocate(1);
6988 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6989 rtvDesc.Format = srgbAdjustedColorFormat;
6990 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
6991 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
6994 rtvsRight[i] = rhiD->rtvPool.allocate(1);
6995 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6996 rtvDesc.Format = srgbAdjustedColorFormat;
6997 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
6998 rtvDesc.Texture2DArray.ArraySize = 1;
6999 rtvDesc.Texture2DArray.FirstArraySlice = 1;
7000 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
7004 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
7005 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
7006 m_depthStencil->sampleCount(), m_sampleCount);
7008 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
7009 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
7010 m_depthStencil->setPixelSize(pixelSize);
7011 if (!m_depthStencil->create())
7012 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
7013 pixelSize.width(), pixelSize.height());
7015 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
7016 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
7017 pixelSize.width(), pixelSize.height());
7021 ds = m_depthStencil ? QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
7023 if (sampleDesc.Count > 1) {
7024 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7025 D3D12_RESOURCE_DESC resourceDesc = {};
7026 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
7027 resourceDesc.Width = UINT64(pixelSize.width());
7028 resourceDesc.Height = UINT(pixelSize.height());
7029 resourceDesc.DepthOrArraySize = 1;
7030 resourceDesc.MipLevels = 1;
7031 resourceDesc.Format = srgbAdjustedColorFormat;
7032 resourceDesc.SampleDesc = sampleDesc;
7033 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
7034 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
7035 D3D12_CLEAR_VALUE clearValue = {};
7036 clearValue.Format = colorFormat;
7037 ID3D12Resource *resource =
nullptr;
7038 D3D12MA::Allocation *allocation =
nullptr;
7039 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
7041 D3D12_RESOURCE_STATE_RENDER_TARGET,
7044 __uuidof(ID3D12Resource),
7045 reinterpret_cast<
void **>(&resource));
7047 qWarning(
"Failed to create MSAA color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
7050 msaaBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
7051 msaaRtvs[i] = rhiD->rtvPool.allocate(1);
7052 if (!msaaRtvs[i].isValid())
7054 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7055 rtvDesc.Format = srgbAdjustedColorFormat;
7056 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
7057 : D3D12_RTV_DIMENSION_TEXTURE2D;
7058 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[i].cpuHandle);
7062 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
7063 currentFrameSlot = 0;
7064 lastFrameLatencyWaitSlot = -1;
7066 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
7067 QD3D12SwapChainRenderTarget *rtD = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
7068 rtD->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7069 rtD->d.pixelSize = pixelSize;
7070 rtD->d.dpr =
float(window->devicePixelRatio());
7071 rtD->d.sampleCount =
int(sampleDesc.Count);
7072 rtD->d.colorAttCount = 1;
7073 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
7075 rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
7076 QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
7077 rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7078 rtDr->d.pixelSize = pixelSize;
7079 rtDr->d.dpr =
float(window->devicePixelRatio());
7080 rtDr->d.sampleCount =
int(sampleDesc.Count);
7081 rtDr->d.colorAttCount = 1;
7082 rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
7084 QDxgiVSyncService::instance()->registerWindow(window);
7086 if (needsRegistration || !rhiD->swapchains.contains(
this))
7087 rhiD->swapchains.insert(
this);
7089 rhiD->registerResource(
this);