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()));
3799 size = clampedSubResourceUploadSize(size, dstPos, level, texD->m_pixelSize);
3801 footprint.Width = size.width();
3802 footprint.Height = size.height();
3806 srcBox.right = UINT(size.width());
3807 srcBox.bottom = UINT(size.height());
3811 const uchar *imgPtr = img.constBits();
3812 const quint32 lineBytes = size.width() * bpc;
3813 for (
int y = 0, h = size.height(); y < h; ++y) {
3814 memcpy(stagingAlloc.p + y * footprint.RowPitch,
3815 imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
3818 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
3821 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3823 dstPos.setX(aligned(dstPos.x(), blockDim.width()));
3824 dstPos.setY(aligned(dstPos.y(), blockDim.height()));
3829 srcBox.right = aligned(subresSize.width(), blockDim.width());
3830 srcBox.bottom = aligned(subresSize.height(), blockDim.height());
3835 footprint.Width = aligned(subresSize.width(), blockDim.width());
3836 footprint.Height = aligned(subresSize.height(), blockDim.height());
3838 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
3839 const QByteArray imgData = subresDesc.data();
3840 const char *imgPtr = imgData.constData();
3841 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
3842 for (
int y = 0; y < rowCount; ++y)
3843 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
3844 }
else if (!subresDesc.data().isEmpty()) {
3847 srcBox.right = subresSize.width();
3848 srcBox.bottom = subresSize.height();
3852 footprint.Width = subresSize.width();
3853 footprint.Height = subresSize.height();
3856 if (subresDesc.dataStride())
3857 bpl = subresDesc.dataStride();
3859 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
3861 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
3862 const QByteArray data = subresDesc.data();
3863 const char *imgPtr = data.constData();
3864 for (
int y = 0, h = subresSize.height(); y < h; ++y)
3865 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
3868 src.PlacedFootprint.Footprint = footprint;
3870 cbD->cmdList->CopyTextureRegion(&dst,
3873 is3D ? UINT(layer) : 0u,
3877 if (ownStagingArea.has_value())
3878 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3882 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
3883 Q_ASSERT(u.src && u.dst);
3884 QD3D12Texture *srcD = QRHI_RES(QD3D12Texture, u.src);
3885 QD3D12Texture *dstD = QRHI_RES(QD3D12Texture, u.dst);
3886 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3887 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3888 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
3889 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
3890 if (!srcRes || !dstRes)
3893 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
3894 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
3895 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3897 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
3898 srcIs3D ? 0u : UINT(u.desc.sourceLayer()),
3899 srcD->mipLevelCount);
3900 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
3901 dstIs3D ? 0u : UINT(u.desc.destinationLayer()),
3902 dstD->mipLevelCount);
3903 const QPoint dp = u.desc.destinationTopLeft();
3904 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
3905 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
3906 const QPoint sp = u.desc.sourceTopLeft();
3909 srcBox.left = UINT(sp.x());
3910 srcBox.top = UINT(sp.y());
3911 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
3913 srcBox.right = srcBox.left + UINT(copySize.width());
3914 srcBox.bottom = srcBox.top + UINT(copySize.height());
3915 srcBox.back = srcBox.front + 1;
3917 D3D12_TEXTURE_COPY_LOCATION src;
3918 src.pResource = srcRes->resource;
3919 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3920 src.SubresourceIndex = srcSubresource;
3921 D3D12_TEXTURE_COPY_LOCATION dst;
3922 dst.pResource = dstRes->resource;
3923 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3924 dst.SubresourceIndex = dstSubresource;
3926 cbD->cmdList->CopyTextureRegion(&dst,
3929 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
3932 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
3933 QD3D12Readback readback;
3934 readback.frameSlot = currentFrameSlot;
3935 readback.result = u.result;
3937 QD3D12ObjectHandle srcHandle;
3940 if (u.rb.texture()) {
3941 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.rb.texture());
3942 if (texD->sampleDesc.Count > 1) {
3943 qWarning(
"Multisample texture cannot be read back");
3946 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
3947 if (u.rb.rect().isValid())
3950 rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
3951 readback.format = texD->m_format;
3952 srcHandle = texD->handle;
3954 Q_ASSERT(currentSwapChain);
3955 if (u.rb.rect().isValid())
3958 rect = QRect({0, 0}, currentSwapChain->pixelSize);
3959 readback.format = swapchainReadbackTextureFormat(currentSwapChain->colorFormat,
nullptr);
3960 if (readback.format == QRhiTexture::UnknownFormat)
3962 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
3964 readback.pixelSize = rect.size();
3966 textureFormatInfo(readback.format,
3968 &readback.bytesPerLine,
3972 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
3976 const UINT subresource = calcSubresource(UINT(u.rb.level()),
3977 is3D ? 0u : UINT(u.rb.layer()),
3978 srcRes->desc.MipLevels);
3979 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
3982 UINT64 totalBytes = 0;
3983 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
3984 &layout,
nullptr,
nullptr, &totalBytes);
3985 readback.stagingRowPitch = layout.Footprint.RowPitch;
3987 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT);
3988 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
3989 if (u.result->completed)
3990 u.result->completed();
3993 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
3994 if (!stagingAlloc.isValid()) {
3995 readback.staging.destroy();
3996 if (u.result->completed)
3997 u.result->completed();
4000 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4002 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4003 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4005 D3D12_TEXTURE_COPY_LOCATION dst;
4006 dst.pResource = stagingAlloc.buffer;
4007 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4008 dst.PlacedFootprint.Offset = 0;
4009 dst.PlacedFootprint.Footprint = layout.Footprint;
4011 D3D12_TEXTURE_COPY_LOCATION src;
4012 src.pResource = srcRes->resource;
4013 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4014 src.SubresourceIndex = subresource;
4016 D3D12_BOX srcBox = {};
4017 srcBox.left = UINT(rect.left());
4018 srcBox.top = UINT(rect.top());
4019 srcBox.front = is3D ? UINT(u.rb.layer()) : 0u;
4021 srcBox.right = srcBox.left + UINT(rect.width());
4022 srcBox.bottom = srcBox.top + UINT(rect.height());
4023 srcBox.back = srcBox.front + 1;
4025 cbD->cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &srcBox);
4026 activeReadbacks.append(readback);
4027 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
4028 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4029 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
4030 if (texD->flags().testFlag(QRhiTexture::ThreeDimensional))
4031 mipmapGen3D.generate(cbD, texD->handle);
4033 mipmapGen.generate(cbD, texD->handle);
4040void QRhiD3D12::finishActiveReadbacks(
bool forced)
4042 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4044 for (
int i = activeReadbacks.size() - 1; i >= 0; --i) {
4045 QD3D12Readback &readback(activeReadbacks[i]);
4046 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
4047 readback.result->format = readback.format;
4048 readback.result->pixelSize = readback.pixelSize;
4049 readback.result->data.resize(
int(readback.byteSize));
4051 if (readback.format != QRhiTexture::UnknownFormat) {
4052 quint8 *dstPtr =
reinterpret_cast<quint8 *>(readback.result->data.data());
4053 const quint8 *srcPtr = readback.staging.mem.p;
4054 const quint32 lineSize = qMin(readback.bytesPerLine, readback.stagingRowPitch);
4055 for (
int y = 0, h = readback.pixelSize.height(); y < h; ++y)
4056 memcpy(dstPtr + y * readback.bytesPerLine, srcPtr + y * readback.stagingRowPitch, lineSize);
4058 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
4061 readback.staging.destroy();
4063 if (readback.result->completed)
4064 completedCallbacks.append(readback.result->completed);
4066 activeReadbacks.remove(i);
4070 for (
auto f : completedCallbacks)
4074bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
4075 D3D12_DESCRIPTOR_HEAP_TYPE type,
4077 quint32 neededDescriptorCount,
4085 if (h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
4086 const quint32 newPerFrameSize = qMax(h->perFrameHeapSlice[frameSlot].capacity * 2,
4087 neededDescriptorCount);
4088 QD3D12ShaderVisibleDescriptorHeap newHeap;
4089 if (!newHeap.create(dev, type, newPerFrameSize)) {
4090 qWarning(
"Could not create new shader-visible descriptor heap");
4093 h->destroyWithDeferredRelease(&releaseQueue);
4100void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
4102 ID3D12DescriptorHeap *heaps[] = {
4103 shaderVisibleCbvSrvUavHeap.heap.heap,
4104 samplerMgr.shaderVisibleSamplerHeap.heap.heap
4106 cbD->cmdList->SetDescriptorHeaps(2, heaps);
4109QD3D12Buffer::QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
4110 : QRhiBuffer(rhi, type, usage, size)
4114QD3D12Buffer::~QD3D12Buffer()
4119void QD3D12Buffer::destroy()
4121 if (handles[0].isNull())
4124 QRHI_RES_RHI(QRhiD3D12);
4133 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4135 rhiD->releaseQueue.deferredReleaseResource(handles[i]);
4137 pendingHostWrites[i].clear();
4141 rhiD->unregisterResource(
this);
4144bool QD3D12Buffer::create()
4146 if (!handles[0].isNull())
4149 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
4150 qWarning(
"UniformBuffer must always be Dynamic");
4154 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
4155 qWarning(
"StorageBuffer cannot be combined with Dynamic");
4159 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
4160 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
4162 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
4163 if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
4164 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4166 QRHI_RES_RHI(QRhiD3D12);
4168 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4169 if (i == 0 || m_type == Dynamic) {
4170 D3D12_RESOURCE_DESC resourceDesc = {};
4171 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
4172 resourceDesc.Width = roundedSize;
4173 resourceDesc.Height = 1;
4174 resourceDesc.DepthOrArraySize = 1;
4175 resourceDesc.MipLevels = 1;
4176 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
4177 resourceDesc.SampleDesc = { 1, 0 };
4178 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
4179 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
4180 ID3D12Resource *resource =
nullptr;
4181 D3D12MA::Allocation *allocation =
nullptr;
4183 D3D12_HEAP_TYPE heapType = m_type == Dynamic
4184 ? D3D12_HEAP_TYPE_UPLOAD
4185 : D3D12_HEAP_TYPE_DEFAULT;
4186 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
4187 ? D3D12_RESOURCE_STATE_GENERIC_READ
4188 : D3D12_RESOURCE_STATE_COMMON;
4189 hr = rhiD->vma.createResource(heapType,
4195 reinterpret_cast<
void **>(&resource));
4198 if (!m_objectName.isEmpty()) {
4199 QString decoratedName = QString::fromUtf8(m_objectName);
4200 if (m_type == Dynamic) {
4201 decoratedName += QLatin1Char(
'/');
4202 decoratedName += QString::number(i);
4204 resource->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
4206 void *cpuMemPtr =
nullptr;
4207 if (m_type == Dynamic) {
4209 hr = resource->Map(0,
nullptr, &cpuMemPtr);
4211 qWarning(
"Map() failed to dynamic buffer");
4212 resource->Release();
4214 allocation->Release();
4218 handles[i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
4226 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
4227 qPrintable(QSystemError::windowsComString(hr)),
4230 int(rhiD->vma.isUsingD3D12MA()));
4234 rhiD->registerResource(
this);
4238QRhiBuffer::NativeBuffer QD3D12Buffer::nativeBuffer()
4241 Q_ASSERT(
sizeof(b.objects) /
sizeof(b.objects[0]) >= size_t(QD3D12_FRAMES_IN_FLIGHT));
4242 QRHI_RES_RHI(QRhiD3D12);
4243 if (m_type == Dynamic) {
4244 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4245 executeHostWritesForFrameSlot(i);
4246 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[i]))
4247 b.objects[i] = res->resource;
4249 b.objects[i] =
nullptr;
4251 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
4254 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[0]))
4255 b.objects[0] = res->resource;
4257 b.objects[0] =
nullptr;
4262char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
4270 Q_ASSERT(m_type == Dynamic);
4271 QRHI_RES_RHI(QRhiD3D12);
4272 Q_ASSERT(rhiD->inFrame);
4273 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
4274 return static_cast<
char *>(res->cpuMapPtr);
4279void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
4284void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
4286 if (pendingHostWrites[frameSlot].isEmpty())
4289 Q_ASSERT(m_type == QRhiBuffer::Dynamic);
4290 QRHI_RES_RHI(QRhiD3D12);
4291 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
4292 Q_ASSERT(res->cpuMapPtr);
4293 for (
const QD3D12Buffer::HostWrite &u : std::as_const(pendingHostWrites[frameSlot]))
4294 memcpy(
static_cast<
char *>(res->cpuMapPtr) + u.offset, u.data.constData(), u.data.size());
4296 pendingHostWrites[frameSlot].clear();
4299static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
4301 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
4303 case QRhiTexture::RGBA8:
4304 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
4305 case QRhiTexture::BGRA8:
4306 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
4307 case QRhiTexture::R8:
4308 return DXGI_FORMAT_R8_UNORM;
4309 case QRhiTexture::R8SI:
4310 return DXGI_FORMAT_R8_SINT;
4311 case QRhiTexture::R8UI:
4312 return DXGI_FORMAT_R8_UINT;
4313 case QRhiTexture::RG8:
4314 return DXGI_FORMAT_R8G8_UNORM;
4315 case QRhiTexture::R16:
4316 return DXGI_FORMAT_R16_UNORM;
4317 case QRhiTexture::RG16:
4318 return DXGI_FORMAT_R16G16_UNORM;
4319 case QRhiTexture::RED_OR_ALPHA8:
4320 return DXGI_FORMAT_R8_UNORM;
4322 case QRhiTexture::RGBA16F:
4323 return DXGI_FORMAT_R16G16B16A16_FLOAT;
4324 case QRhiTexture::RGBA32F:
4325 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4326 case QRhiTexture::R16F:
4327 return DXGI_FORMAT_R16_FLOAT;
4328 case QRhiTexture::R32F:
4329 return DXGI_FORMAT_R32_FLOAT;
4331 case QRhiTexture::RGB10A2:
4332 return DXGI_FORMAT_R10G10B10A2_UNORM;
4334 case QRhiTexture::R32SI:
4335 return DXGI_FORMAT_R32_SINT;
4336 case QRhiTexture::R32UI:
4337 return DXGI_FORMAT_R32_UINT;
4338 case QRhiTexture::RG32SI:
4339 return DXGI_FORMAT_R32G32_SINT;
4340 case QRhiTexture::RG32UI:
4341 return DXGI_FORMAT_R32G32_UINT;
4342 case QRhiTexture::RGBA32SI:
4343 return DXGI_FORMAT_R32G32B32A32_SINT;
4344 case QRhiTexture::RGBA32UI:
4345 return DXGI_FORMAT_R32G32B32A32_UINT;
4347 case QRhiTexture::D16:
4348 return DXGI_FORMAT_R16_TYPELESS;
4349 case QRhiTexture::D24:
4350 return DXGI_FORMAT_R24G8_TYPELESS;
4351 case QRhiTexture::D24S8:
4352 return DXGI_FORMAT_R24G8_TYPELESS;
4353 case QRhiTexture::D32F:
4354 return DXGI_FORMAT_R32_TYPELESS;
4355 case QRhiTexture::Format::D32FS8:
4356 return DXGI_FORMAT_R32G8X24_TYPELESS;
4358 case QRhiTexture::BC1:
4359 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
4360 case QRhiTexture::BC2:
4361 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
4362 case QRhiTexture::BC3:
4363 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
4364 case QRhiTexture::BC4:
4365 return DXGI_FORMAT_BC4_UNORM;
4366 case QRhiTexture::BC5:
4367 return DXGI_FORMAT_BC5_UNORM;
4368 case QRhiTexture::BC6H:
4369 return DXGI_FORMAT_BC6H_UF16;
4370 case QRhiTexture::BC7:
4371 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
4373 case QRhiTexture::ETC2_RGB8:
4374 case QRhiTexture::ETC2_RGB8A1:
4375 case QRhiTexture::ETC2_RGBA8:
4376 qWarning(
"QRhiD3D12 does not support ETC2 textures");
4377 return DXGI_FORMAT_R8G8B8A8_UNORM;
4379 case QRhiTexture::ASTC_4x4:
4380 case QRhiTexture::ASTC_5x4:
4381 case QRhiTexture::ASTC_5x5:
4382 case QRhiTexture::ASTC_6x5:
4383 case QRhiTexture::ASTC_6x6:
4384 case QRhiTexture::ASTC_8x5:
4385 case QRhiTexture::ASTC_8x6:
4386 case QRhiTexture::ASTC_8x8:
4387 case QRhiTexture::ASTC_10x5:
4388 case QRhiTexture::ASTC_10x6:
4389 case QRhiTexture::ASTC_10x8:
4390 case QRhiTexture::ASTC_10x10:
4391 case QRhiTexture::ASTC_12x10:
4392 case QRhiTexture::ASTC_12x12:
4393 qWarning(
"QRhiD3D12 does not support ASTC textures");
4394 return DXGI_FORMAT_R8G8B8A8_UNORM;
4399 return DXGI_FORMAT_R8G8B8A8_UNORM;
4402QD3D12RenderBuffer::QD3D12RenderBuffer(QRhiImplementation *rhi,
4404 const QSize &pixelSize,
4407 QRhiTexture::Format backingFormatHint)
4408 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
4412QD3D12RenderBuffer::~QD3D12RenderBuffer()
4417void QD3D12RenderBuffer::destroy()
4419 if (handle.isNull())
4422 QRHI_RES_RHI(QRhiD3D12);
4425 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->rtvPool, rtv, 1);
4426 else if (dsv.isValid())
4427 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->dsvPool, dsv, 1);
4435 rhiD->unregisterResource(
this);
4438bool QD3D12RenderBuffer::create()
4440 if (!handle.isNull())
4443 if (m_pixelSize.isEmpty())
4446 QRHI_RES_RHI(QRhiD3D12);
4449 case QRhiRenderBuffer::Color:
4451 dxgiFormat = toD3DTextureFormat(backingFormat(), {});
4452 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4453 D3D12_RESOURCE_DESC resourceDesc = {};
4454 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4455 resourceDesc.Width = UINT64(m_pixelSize.width());
4456 resourceDesc.Height = UINT(m_pixelSize.height());
4457 resourceDesc.DepthOrArraySize = 1;
4458 resourceDesc.MipLevels = 1;
4459 resourceDesc.Format = dxgiFormat;
4460 resourceDesc.SampleDesc = sampleDesc;
4461 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4462 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4463 D3D12_CLEAR_VALUE clearValue = {};
4464 clearValue.Format = dxgiFormat;
4466 ID3D12Resource *resource =
nullptr;
4467 D3D12MA::Allocation *allocation =
nullptr;
4468 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4470 D3D12_RESOURCE_STATE_RENDER_TARGET,
4473 __uuidof(ID3D12Resource),
4474 reinterpret_cast<
void **>(&resource));
4476 qWarning(
"Failed to create color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4479 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
4480 rtv = rhiD->rtvPool.allocate(1);
4483 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
4484 rtvDesc.Format = dxgiFormat;
4485 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
4486 : D3D12_RTV_DIMENSION_TEXTURE2D;
4487 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
4490 case QRhiRenderBuffer::DepthStencil:
4492 dxgiFormat = DS_FORMAT;
4493 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4494 D3D12_RESOURCE_DESC resourceDesc = {};
4495 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
4496 resourceDesc.Width = UINT64(m_pixelSize.width());
4497 resourceDesc.Height = UINT(m_pixelSize.height());
4498 resourceDesc.DepthOrArraySize = 1;
4499 resourceDesc.MipLevels = 1;
4500 resourceDesc.Format = dxgiFormat;
4501 resourceDesc.SampleDesc = sampleDesc;
4502 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4503 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4504 if (m_flags.testFlag(UsedWithSwapChainOnly))
4505 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
4506 D3D12_CLEAR_VALUE clearValue = {};
4507 clearValue.Format = dxgiFormat;
4508 clearValue.DepthStencil.Depth = 1.0f;
4509 clearValue.DepthStencil.Stencil = 0;
4510 ID3D12Resource *resource =
nullptr;
4511 D3D12MA::Allocation *allocation =
nullptr;
4512 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4514 D3D12_RESOURCE_STATE_DEPTH_WRITE,
4517 __uuidof(ID3D12Resource),
4518 reinterpret_cast<
void **>(&resource));
4520 qWarning(
"Failed to create depth-stencil buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
4523 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE, allocation);
4524 dsv = rhiD->dsvPool.allocate(1);
4527 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
4528 dsvDesc.Format = dxgiFormat;
4529 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
4530 : D3D12_DSV_DIMENSION_TEXTURE2D;
4531 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
4536 if (!m_objectName.isEmpty()) {
4537 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4538 const QString name = QString::fromUtf8(m_objectName);
4539 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4544 rhiD->registerResource(
this);
4548QRhiTexture::Format QD3D12RenderBuffer::backingFormat()
const
4550 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
4551 return m_backingFormatHint;
4553 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
4556QD3D12Texture::QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
4557 int arraySize,
int sampleCount, Flags flags)
4558 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
4562QD3D12Texture::~QD3D12Texture()
4567void QD3D12Texture::destroy()
4569 if (handle.isNull())
4572 QRHI_RES_RHI(QRhiD3D12);
4574 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->cbvSrvUavPool, srv, 1);
4580 rhiD->unregisterResource(
this);
4583static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
4586 case QRhiTexture::Format::D16:
4587 return DXGI_FORMAT_R16_FLOAT;
4588 case QRhiTexture::Format::D24:
4589 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4590 case QRhiTexture::Format::D24S8:
4591 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
4592 case QRhiTexture::Format::D32F:
4593 return DXGI_FORMAT_R32_FLOAT;
4594 case QRhiTexture::Format::D32FS8:
4595 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
4599 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
4602static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
4606 case QRhiTexture::Format::D16:
4607 return DXGI_FORMAT_D16_UNORM;
4608 case QRhiTexture::Format::D24:
4609 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4610 case QRhiTexture::Format::D24S8:
4611 return DXGI_FORMAT_D24_UNORM_S8_UINT;
4612 case QRhiTexture::Format::D32F:
4613 return DXGI_FORMAT_D32_FLOAT;
4614 case QRhiTexture::Format::D32FS8:
4615 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
4619 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
4622static inline bool isDepthTextureFormat(QRhiTexture::Format format)
4625 case QRhiTexture::Format::D16:
4626 case QRhiTexture::Format::D24:
4627 case QRhiTexture::Format::D24S8:
4628 case QRhiTexture::Format::D32F:
4629 case QRhiTexture::Format::D32FS8:
4636bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
4638 if (!handle.isNull())
4641 QRHI_RES_RHI(QRhiD3D12);
4642 if (!rhiD->isTextureFormatSupported(m_format, m_flags))
4645 const bool isDepth = isDepthTextureFormat(m_format);
4646 const bool isCube = m_flags.testFlag(CubeMap);
4647 const bool is3D = m_flags.testFlag(ThreeDimensional);
4648 const bool isArray = m_flags.testFlag(TextureArray);
4649 const bool hasMipMaps = m_flags.testFlag(MipMapped);
4650 const bool is1D = m_flags.testFlag(OneDimensional);
4652 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
4653 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
4655 dxgiFormat = toD3DTextureFormat(m_format, m_flags);
4657 srvFormat = toD3DDepthTextureSRVFormat(m_format);
4658 rtFormat = toD3DDepthTextureDSVFormat(m_format);
4660 srvFormat = dxgiFormat;
4661 rtFormat = dxgiFormat;
4663 if (m_writeViewFormat.format != UnknownFormat) {
4665 rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
4667 rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
4669 if (m_readViewFormat.format != UnknownFormat) {
4671 srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
4673 srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
4676 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
4677 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
4678 if (sampleDesc.Count > 1) {
4680 qWarning(
"Cubemap texture cannot be multisample");
4684 qWarning(
"3D texture cannot be multisample");
4688 qWarning(
"Multisample texture cannot have mipmaps");
4692 if (isDepth && hasMipMaps) {
4693 qWarning(
"Depth texture cannot have mipmaps");
4696 if (isCube && is3D) {
4697 qWarning(
"Texture cannot be both cube and 3D");
4700 if (isArray && is3D) {
4701 qWarning(
"Texture cannot be both array and 3D");
4704 if (isCube && is1D) {
4705 qWarning(
"Texture cannot be both cube and 1D");
4709 qWarning(
"Texture cannot be both 1D and 3D");
4712 if (m_depth > 1 && !is3D) {
4713 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
4716 if (m_arraySize > 0 && !isArray) {
4717 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
4720 if (m_arraySize < 1 && isArray) {
4721 qWarning(
"Texture is an array but array size is %d", m_arraySize);
4726 *adjustedSize = size;
4731bool QD3D12Texture::finishCreate()
4733 QRHI_RES_RHI(QRhiD3D12);
4734 const bool isCube = m_flags.testFlag(CubeMap);
4735 const bool is3D = m_flags.testFlag(ThreeDimensional);
4736 const bool isArray = m_flags.testFlag(TextureArray);
4737 const bool is1D = m_flags.testFlag(OneDimensional);
4739 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4740 srvDesc.Format = srvFormat;
4741 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4744 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
4745 srvDesc.TextureCube.MipLevels = mipLevelCount;
4749 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
4750 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
4751 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4752 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4753 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
4755 srvDesc.Texture1DArray.FirstArraySlice = 0;
4756 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
4759 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
4760 srvDesc.Texture1D.MipLevels = mipLevelCount;
4762 }
else if (isArray) {
4763 if (sampleDesc.Count > 1) {
4764 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
4765 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4766 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
4767 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
4769 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
4770 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
4773 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
4774 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
4775 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4776 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4777 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
4779 srvDesc.Texture2DArray.FirstArraySlice = 0;
4780 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
4784 if (sampleDesc.Count > 1) {
4785 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
4787 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4788 srvDesc.Texture3D.MipLevels = mipLevelCount;
4790 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
4791 srvDesc.Texture2D.MipLevels = mipLevelCount;
4796 srv = rhiD->cbvSrvUavPool.allocate(1);
4800 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
4801 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4802 if (!m_objectName.isEmpty()) {
4803 const QString name = QString::fromUtf8(m_objectName);
4804 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
4814bool QD3D12Texture::create()
4817 if (!prepareCreate(&size))
4820 const bool isDepth = isDepthTextureFormat(m_format);
4821 const bool isCube = m_flags.testFlag(CubeMap);
4822 const bool is3D = m_flags.testFlag(ThreeDimensional);
4823 const bool isArray = m_flags.testFlag(TextureArray);
4824 const bool is1D = m_flags.testFlag(OneDimensional);
4826 QRHI_RES_RHI(QRhiD3D12);
4828 bool needsOptimizedClearValueSpecified =
false;
4829 UINT resourceFlags = 0;
4830 if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
4832 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4834 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4835 needsOptimizedClearValueSpecified =
true;
4837 if (m_flags.testFlag(UsedWithGenerateMips)) {
4839 qWarning(
"Depth texture cannot have mipmaps generated");
4842 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4844 if (m_flags.testFlag(UsedWithLoadStore))
4845 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4847 D3D12_RESOURCE_DESC resourceDesc = {};
4848 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
4849 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
4850 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
4851 resourceDesc.Width = UINT64(size.width());
4852 resourceDesc.Height = UINT(size.height());
4853 resourceDesc.DepthOrArraySize = isCube ? 6
4854 : (isArray ? UINT(qMax(0, m_arraySize))
4855 : (is3D ? qMax(1, m_depth)
4857 resourceDesc.MipLevels = mipLevelCount;
4858 resourceDesc.Format = dxgiFormat;
4859 resourceDesc.SampleDesc = sampleDesc;
4860 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4861 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
4862 D3D12_CLEAR_VALUE clearValue = {};
4863 clearValue.Format = dxgiFormat;
4865 clearValue.Format = toD3DDepthTextureDSVFormat(m_format);
4866 clearValue.DepthStencil.Depth = 1.0f;
4867 clearValue.DepthStencil.Stencil = 0;
4869 ID3D12Resource *resource =
nullptr;
4870 D3D12MA::Allocation *allocation =
nullptr;
4871 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4873 D3D12_RESOURCE_STATE_COMMON,
4874 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
4876 __uuidof(ID3D12Resource),
4877 reinterpret_cast<
void **>(&resource));
4879 qWarning(
"Failed to create texture: '%s'"
4880 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
4881 qPrintable(QSystemError::windowsComString(hr)),
4882 int(resourceDesc.Dimension),
4883 uint(resourceDesc.Width),
4884 uint(resourceDesc.Height),
4885 uint(resourceDesc.DepthOrArraySize),
4886 uint(resourceDesc.MipLevels),
4887 int(resourceDesc.Format),
4888 int(resourceDesc.SampleDesc.Count));
4892 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON, allocation);
4894 if (!finishCreate())
4897 rhiD->registerResource(
this);
4901bool QD3D12Texture::createFrom(QRhiTexture::NativeTexture src)
4906 if (!prepareCreate())
4909 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *>(src.object);
4910 D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(src.layout);
4912 QRHI_RES_RHI(QRhiD3D12);
4913 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource, state);
4915 if (!finishCreate())
4918 rhiD->registerResource(
this);
4922QRhiTexture::NativeTexture QD3D12Texture::nativeTexture()
4924 QRHI_RES_RHI(QRhiD3D12);
4925 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
4926 return { quint64(res->resource),
int(res->state) };
4931void QD3D12Texture::setNativeLayout(
int layout)
4933 QRHI_RES_RHI(QRhiD3D12);
4934 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
4935 res->state = D3D12_RESOURCE_STATES(layout);
4938QD3D12Sampler::QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
4939 AddressMode u, AddressMode v, AddressMode w)
4940 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
4944QD3D12Sampler::~QD3D12Sampler()
4949void QD3D12Sampler::destroy()
4951 shaderVisibleDescriptor = {};
4953 QRHI_RES_RHI(QRhiD3D12);
4955 rhiD->unregisterResource(
this);
4958static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
4960 if (minFilter == QRhiSampler::Nearest) {
4961 if (magFilter == QRhiSampler::Nearest) {
4962 if (mipFilter == QRhiSampler::Linear)
4963 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
4965 return D3D12_FILTER_MIN_MAG_MIP_POINT;
4967 if (mipFilter == QRhiSampler::Linear)
4968 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
4970 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
4973 if (magFilter == QRhiSampler::Nearest) {
4974 if (mipFilter == QRhiSampler::Linear)
4975 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
4977 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
4979 if (mipFilter == QRhiSampler::Linear)
4980 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
4982 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
4985 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
4988static inline D3D12_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
4991 case QRhiSampler::Repeat:
4992 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
4993 case QRhiSampler::ClampToEdge:
4994 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4995 case QRhiSampler::Mirror:
4996 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
4998 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
5001static inline D3D12_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
5004 case QRhiSampler::Never:
5005 return D3D12_COMPARISON_FUNC_NEVER;
5006 case QRhiSampler::Less:
5007 return D3D12_COMPARISON_FUNC_LESS;
5008 case QRhiSampler::Equal:
5009 return D3D12_COMPARISON_FUNC_EQUAL;
5010 case QRhiSampler::LessOrEqual:
5011 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5012 case QRhiSampler::Greater:
5013 return D3D12_COMPARISON_FUNC_GREATER;
5014 case QRhiSampler::NotEqual:
5015 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5016 case QRhiSampler::GreaterOrEqual:
5017 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5018 case QRhiSampler::Always:
5019 return D3D12_COMPARISON_FUNC_ALWAYS;
5021 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
5024bool QD3D12Sampler::create()
5027 desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
5028 if (m_compareOp != Never)
5029 desc.Filter = D3D12_FILTER(desc.Filter | 0x80);
5030 desc.AddressU = toD3DAddressMode(m_addressU);
5031 desc.AddressV = toD3DAddressMode(m_addressV);
5032 desc.AddressW = toD3DAddressMode(m_addressW);
5033 desc.MaxAnisotropy = 1.0f;
5034 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
5035 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
5037 QRHI_RES_RHI(QRhiD3D12);
5038 rhiD->registerResource(
this,
false);
5042QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
5044 if (!shaderVisibleDescriptor.isValid()) {
5045 QRHI_RES_RHI(QRhiD3D12);
5046 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(desc);
5048 return shaderVisibleDescriptor;
5051QD3D12ShadingRateMap::QD3D12ShadingRateMap(QRhiImplementation *rhi)
5052 : QRhiShadingRateMap(rhi)
5056QD3D12ShadingRateMap::~QD3D12ShadingRateMap()
5061void QD3D12ShadingRateMap::destroy()
5063 if (handle.isNull())
5069bool QD3D12ShadingRateMap::createFrom(QRhiTexture *src)
5071 if (!handle.isNull())
5074 handle = QRHI_RES(QD3D12Texture, src)->handle;
5079QD3D12TextureRenderTarget::QD3D12TextureRenderTarget(QRhiImplementation *rhi,
5080 const QRhiTextureRenderTargetDescription &desc,
5082 : QRhiTextureRenderTarget(rhi, desc, flags),
5087QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
5092void QD3D12TextureRenderTarget::destroy()
5094 if (!rtv[0].isValid() && !dsv.isValid())
5097 QRHI_RES_RHI(QRhiD3D12);
5098 if (dsv.isValid()) {
5099 if (ownsDsv && rhiD)
5100 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
5104 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i) {
5105 if (rtv[i].isValid()) {
5106 if (ownsRtv[i] && rhiD)
5107 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[i], 1);
5113 rhiD->unregisterResource(
this);
5116QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDescriptor()
5120 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
5122 rpD->colorAttachmentCount = 0;
5123 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it) {
5124 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
5125 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
5127 rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
5129 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
5130 rpD->colorAttachmentCount += 1;
5133 rpD->hasDepthStencil =
false;
5134 if (m_desc.depthStencilBuffer()) {
5135 rpD->hasDepthStencil =
true;
5136 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
5137 }
else if (m_desc.depthTexture()) {
5138 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5139 rpD->hasDepthStencil =
true;
5140 rpD->dsFormat = toD3DDepthTextureDSVFormat(depthTexD->format());
5143 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
5145 rpD->updateSerializedFormat();
5147 QRHI_RES_RHI(QRhiD3D12);
5148 rhiD->registerResource(rpD);
5152bool QD3D12TextureRenderTarget::create()
5154 if (rtv[0].isValid() || dsv.isValid())
5157 QRHI_RES_RHI(QRhiD3D12);
5158 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
5159 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
5160 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
5161 d.colorAttCount = 0;
5164 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
5165 d.colorAttCount += 1;
5166 const QRhiColorAttachment &colorAtt(*it);
5167 QRhiTexture *texture = colorAtt.texture();
5168 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
5169 Q_ASSERT(texture || rb);
5171 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, texture);
5172 QD3D12Resource *res = rhiD->resourcePool.lookupRef(texD->handle);
5174 qWarning(
"Could not look up texture handle for render target");
5177 const bool isMultiView = it->multiViewCount() >= 2;
5178 UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
5179 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5180 rtvDesc.Format = texD->rtFormat;
5181 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
5182 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5183 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5184 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5185 rtvDesc.Texture2DArray.ArraySize = layerCount;
5186 }
else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
5187 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5188 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
5189 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
5190 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
5191 rtvDesc.Texture1DArray.ArraySize = layerCount;
5193 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
5194 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
5196 }
else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5197 if (texD->sampleDesc.Count > 1) {
5198 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
5199 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
5200 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
5202 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5203 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5204 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5205 rtvDesc.Texture2DArray.ArraySize = layerCount;
5207 }
else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
5208 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
5209 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
5210 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
5211 rtvDesc.Texture3D.WSize = layerCount;
5213 if (texD->sampleDesc.Count > 1) {
5214 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
5216 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
5217 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
5220 rtv[attIndex] = rhiD->rtvPool.allocate(1);
5221 if (!rtv[attIndex].isValid()) {
5222 qWarning(
"Failed to allocate RTV for texture render target");
5225 rhiD->dev->CreateRenderTargetView(res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
5226 ownsRtv[attIndex] =
true;
5227 if (attIndex == 0) {
5228 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
5229 d.sampleCount =
int(texD->sampleDesc.Count);
5232 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rb);
5233 ownsRtv[attIndex] =
false;
5234 rtv[attIndex] = rbD->rtv;
5235 if (attIndex == 0) {
5236 d.pixelSize = rbD->pixelSize();
5237 d.sampleCount =
int(rbD->sampleDesc.Count);
5244 if (hasDepthStencil) {
5245 if (m_desc.depthTexture()) {
5247 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5248 QD3D12Resource *res = rhiD->resourcePool.lookupRef(depthTexD->handle);
5250 qWarning(
"Could not look up depth texture handle");
5253 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5254 dsvDesc.Format = depthTexD->rtFormat;
5255 dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
5256 : D3D12_DSV_DIMENSION_TEXTURE2D;
5257 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
5258 if (depthTexD->sampleDesc.Count > 1) {
5259 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
5260 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5261 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5262 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5264 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
5265 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5268 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
5269 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5270 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5271 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5273 dsvDesc.Texture2DArray.FirstArraySlice = 0;
5274 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
5278 dsv = rhiD->dsvPool.allocate(1);
5279 if (!dsv.isValid()) {
5280 qWarning(
"Failed to allocate DSV for texture render target");
5283 rhiD->dev->CreateDepthStencilView(res->resource, &dsvDesc, dsv.cpuHandle);
5284 if (d.colorAttCount == 0) {
5285 d.pixelSize = depthTexD->pixelSize();
5286 d.sampleCount =
int(depthTexD->sampleDesc.Count);
5290 QD3D12RenderBuffer *depthRbD = QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
5291 dsv = depthRbD->dsv;
5292 if (d.colorAttCount == 0) {
5293 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
5294 d.sampleCount =
int(depthRbD->sampleDesc.Count);
5302 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
5303 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i)
5304 d.rtv[i] = i < d.colorAttCount ? rtv[i].cpuHandle : nullDescHandle;
5305 d.dsv = dsv.cpuHandle;
5306 d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
5308 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &d.currentResIdList);
5310 rhiD->registerResource(
this);
5314QSize QD3D12TextureRenderTarget::pixelSize()
const
5316 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc, d.currentResIdList))
5317 const_cast<QD3D12TextureRenderTarget *>(
this)->create();
5322float QD3D12TextureRenderTarget::devicePixelRatio()
const
5327int QD3D12TextureRenderTarget::sampleCount()
const
5329 return d.sampleCount;
5332QD3D12ShaderResourceBindings::QD3D12ShaderResourceBindings(QRhiImplementation *rhi)
5333 : QRhiShaderResourceBindings(rhi)
5337QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
5342void QD3D12ShaderResourceBindings::destroy()
5344 QRHI_RES_RHI(QRhiD3D12);
5346 rhiD->unregisterResource(
this);
5349bool QD3D12ShaderResourceBindings::create()
5351 QRHI_RES_RHI(QRhiD3D12);
5352 if (!rhiD->sanityCheckShaderResourceBindings(
this))
5355 rhiD->updateLayoutDesc(
this);
5357 hasDynamicOffset =
false;
5358 for (
const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
5359 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
5360 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
5361 hasDynamicOffset =
true;
5375 rhiD->registerResource(
this,
false);
5379void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
5390void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
5391 const QRhiShaderResourceBinding::Data::UniformBufferData &,
5395 D3D12_ROOT_PARAMETER1 rootParam = {};
5396 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
5397 rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
5398 rootParam.Descriptor.ShaderRegister = shaderRegister;
5399 rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
5400 visitorData.cbParams[s].append(rootParam);
5403void QD3D12ShaderResourceBindings::visitTexture(QD3D12Stage s,
5404 const QRhiShaderResourceBinding::TextureAndSampler &,
5407 D3D12_DESCRIPTOR_RANGE1 range = {};
5408 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
5409 range.NumDescriptors = 1;
5410 range.BaseShaderRegister = shaderRegister;
5411 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[s];
5412 visitorData.currentSrvRangeOffset[s] += 1;
5413 visitorData.srvRanges[s].append(range);
5414 if (visitorData.srvRanges[s].count() == 1) {
5415 visitorData.srvTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5416 visitorData.srvTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5420void QD3D12ShaderResourceBindings::visitSampler(QD3D12Stage s,
5421 const QRhiShaderResourceBinding::TextureAndSampler &,
5427 int &rangeStoreIdx(visitorData.samplerRangeHeads[s]);
5428 if (rangeStoreIdx == 16) {
5429 qWarning(
"Sampler count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi", s);
5432 D3D12_DESCRIPTOR_RANGE1 range = {};
5433 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
5434 range.NumDescriptors = 1;
5435 range.BaseShaderRegister = shaderRegister;
5436 visitorData.samplerRanges[s][rangeStoreIdx] = range;
5437 D3D12_ROOT_PARAMETER1 param = {};
5438 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5439 param.ShaderVisibility = qd3d12_stageToVisibility(s);
5440 param.DescriptorTable.NumDescriptorRanges = 1;
5441 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[s][rangeStoreIdx];
5443 visitorData.samplerTables[s].append(param);
5446void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage s,
5447 const QRhiShaderResourceBinding::Data::StorageBufferData &,
5448 QD3D12ShaderResourceVisitor::StorageOp,
5451 D3D12_DESCRIPTOR_RANGE1 range = {};
5452 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5453 range.NumDescriptors = 1;
5454 range.BaseShaderRegister = shaderRegister;
5455 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5456 visitorData.currentUavRangeOffset[s] += 1;
5457 visitorData.uavRanges[s].append(range);
5458 if (visitorData.uavRanges[s].count() == 1) {
5459 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5460 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5464void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage s,
5465 const QRhiShaderResourceBinding::Data::StorageImageData &,
5466 QD3D12ShaderResourceVisitor::StorageOp,
5469 D3D12_DESCRIPTOR_RANGE1 range = {};
5470 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
5471 range.NumDescriptors = 1;
5472 range.BaseShaderRegister = shaderRegister;
5473 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
5474 visitorData.currentUavRangeOffset[s] += 1;
5475 visitorData.uavRanges[s].append(range);
5476 if (visitorData.uavRanges[s].count() == 1) {
5477 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
5478 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
5482QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
5485 QRHI_RES_RHI(QRhiD3D12);
5499 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
5503 using namespace std::placeholders;
5504 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
5505 visitor.texture = std::bind(&QD3D12ShaderResourceBindings::visitTexture,
this, _1, _2, _3);
5506 visitor.sampler = std::bind(&QD3D12ShaderResourceBindings::visitSampler,
this, _1, _2, _3);
5507 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
5508 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
5532 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> rootParams;
5533 for (
int s = 0; s < 6; ++s) {
5534 if (!visitorData.cbParams[s].isEmpty())
5535 rootParams.append(visitorData.cbParams[s].constData(), visitorData.cbParams[s].count());
5537 for (
int s = 0; s < 6; ++s) {
5538 if (!visitorData.srvRanges[s].isEmpty()) {
5539 visitorData.srvTables[s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[s].count();
5540 visitorData.srvTables[s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[s].constData();
5541 rootParams.append(visitorData.srvTables[s]);
5544 for (
int s = 0; s < 6; ++s) {
5545 if (!visitorData.samplerTables[s].isEmpty())
5546 rootParams.append(visitorData.samplerTables[s].constData(), visitorData.samplerTables[s].count());
5548 for (
int s = 0; s < 6; ++s) {
5549 if (!visitorData.uavRanges[s].isEmpty()) {
5550 visitorData.uavTables[s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[s].count();
5551 visitorData.uavTables[s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[s].constData();
5552 rootParams.append(visitorData.uavTables[s]);
5556 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
5557 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
5558 if (!rootParams.isEmpty()) {
5559 rsDesc.Desc_1_1.NumParameters = rootParams.count();
5560 rsDesc.Desc_1_1.pParameters = rootParams.constData();
5564 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
5565 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
5566 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
5568 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
5570 ID3DBlob *signature =
nullptr;
5571 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
5573 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5576 ID3D12RootSignature *rootSig =
nullptr;
5577 hr = rhiD->dev->CreateRootSignature(0,
5578 signature->GetBufferPointer(),
5579 signature->GetBufferSize(),
5580 __uuidof(ID3D12RootSignature),
5581 reinterpret_cast<
void **>(&rootSig));
5582 signature->Release();
5584 qWarning(
"Failed to create root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
5588 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
5600static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
5602 const int smMajor = version / 10;
5603 const int smMinor = version % 10;
5604 target[0] = stage[0];
5605 target[1] = stage[1];
5607 target[3] =
'0' + smMajor;
5609 target[5] =
'0' + smMinor;
5613enum class HlslCompileFlag
5615 WithDebugInfo = 0x01
5618static QByteArray legacyCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5620 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
5622 qWarning(
"Unable to resolve function D3DCompile()");
5623 return QByteArray();
5626 ID3DBlob *bytecode =
nullptr;
5627 ID3DBlob *errors =
nullptr;
5628 UINT d3dCompileFlags = 0;
5629 if (flags &
int(HlslCompileFlag::WithDebugInfo))
5630 d3dCompileFlags |= D3DCOMPILE_DEBUG;
5632 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
5633 nullptr,
nullptr,
nullptr,
5634 hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
5635 if (FAILED(hr) || !bytecode) {
5636 qWarning(
"HLSL shader compilation failed: 0x%x", uint(hr));
5638 *error = QString::fromUtf8(
static_cast<
const char *>(errors->GetBufferPointer()),
5639 int(errors->GetBufferSize()));
5642 return QByteArray();
5646 result.resize(
int(bytecode->GetBufferSize()));
5647 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
5648 bytecode->Release();
5652#ifdef QRHI_D3D12_HAS_DXC
5655#define DXC_CP_UTF8 65001
5658#ifndef DXC_ARG_DEBUG
5659#define DXC_ARG_DEBUG L"-Zi"
5662static QByteArray dxcCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
5664 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
5665 IDxcCompiler *compiler = dxc.first;
5667 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
5668 "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
5669 return QByteArray();
5671 IDxcLibrary *library = dxc.second;
5673 return QByteArray();
5675 IDxcBlobEncoding *sourceBlob =
nullptr;
5676 HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
5677 UINT32(hlslSource.shader().size()),
5681 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
5683 qPrintable(QSystemError::windowsComString(hr)));
5684 return QByteArray();
5687 const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
5688 const QString targetStr = QString::fromLatin1(target);
5690 QVarLengthArray<LPCWSTR, 4> argPtrs;
5692 if (flags &
int(HlslCompileFlag::WithDebugInfo)) {
5693 debugArg = QString::fromUtf16(
reinterpret_cast<
const char16_t *>(DXC_ARG_DEBUG));
5694 argPtrs.append(
reinterpret_cast<LPCWSTR>(debugArg.utf16()));
5697 IDxcOperationResult *result =
nullptr;
5698 hr = compiler->Compile(sourceBlob,
5700 reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
5701 reinterpret_cast<LPCWSTR>(targetStr.utf16()),
5702 argPtrs.data(), argPtrs.count(),
5706 sourceBlob->Release();
5708 result->GetStatus(&hr);
5710 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
5712 qPrintable(QSystemError::windowsComString(hr)));
5714 IDxcBlobEncoding *errorsBlob =
nullptr;
5715 if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
5717 *error = QString::fromUtf8(
static_cast<
const char *>(errorsBlob->GetBufferPointer()),
5718 int(errorsBlob->GetBufferSize()));
5719 errorsBlob->Release();
5723 return QByteArray();
5726 IDxcBlob *bytecode =
nullptr;
5727 if FAILED(result->GetResult(&bytecode)) {
5728 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
5730 qPrintable(QSystemError::windowsComString(hr)));
5731 return QByteArray();
5735 ba.resize(
int(bytecode->GetBufferSize()));
5736 memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
5737 bytecode->Release();
5743static QByteArray compileHlslShaderSource(
const QShader &shader,
5744 QShader::Variant shaderVariant,
5747 QShaderKey *usedShaderKey)
5750 const int shaderModelMax = 67;
5751 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5752 for (QShader::Source type : { QShader::DxilShader, QShader::DxbcShader }) {
5753 QShaderKey key = { type, sm, shaderVariant };
5754 QShaderCode intermediateBytecodeShader = shader.shader(key);
5755 if (!intermediateBytecodeShader.shader().isEmpty()) {
5757 *usedShaderKey = key;
5758 return intermediateBytecodeShader.shader();
5763 QShaderCode hlslSource;
5765 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5766 key = { QShader::HlslShader, sm, shaderVariant };
5767 hlslSource = shader.shader(key);
5768 if (!hlslSource.shader().isEmpty())
5772 if (hlslSource.shader().isEmpty()) {
5773 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" << shader;
5774 return QByteArray();
5778 *usedShaderKey = key;
5781 switch (shader.stage()) {
5782 case QShader::VertexStage:
5783 makeHlslTargetString(target,
"vs", key.sourceVersion().version());
5785 case QShader::TessellationControlStage:
5786 makeHlslTargetString(target,
"hs", key.sourceVersion().version());
5788 case QShader::TessellationEvaluationStage:
5789 makeHlslTargetString(target,
"ds", key.sourceVersion().version());
5791 case QShader::GeometryStage:
5792 makeHlslTargetString(target,
"gs", key.sourceVersion().version());
5794 case QShader::FragmentStage:
5795 makeHlslTargetString(target,
"ps", key.sourceVersion().version());
5797 case QShader::ComputeStage:
5798 makeHlslTargetString(target,
"cs", key.sourceVersion().version());
5802 if (key.sourceVersion().version() >= 60) {
5803#ifdef QRHI_D3D12_HAS_DXC
5804 return dxcCompile(hlslSource, target, flags, error);
5806 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
5807 "but the Qt build has no support for DXC. "
5808 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
5812 return legacyCompile(hlslSource, target, flags, error);
5815static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
5818 if (c.testFlag(QRhiGraphicsPipeline::R))
5819 f |= D3D12_COLOR_WRITE_ENABLE_RED;
5820 if (c.testFlag(QRhiGraphicsPipeline::G))
5821 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
5822 if (c.testFlag(QRhiGraphicsPipeline::B))
5823 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
5824 if (c.testFlag(QRhiGraphicsPipeline::A))
5825 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
5829static inline D3D12_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f,
bool rgb)
5838 case QRhiGraphicsPipeline::Zero:
5839 return D3D12_BLEND_ZERO;
5840 case QRhiGraphicsPipeline::One:
5841 return D3D12_BLEND_ONE;
5842 case QRhiGraphicsPipeline::SrcColor:
5843 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
5844 case QRhiGraphicsPipeline::OneMinusSrcColor:
5845 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
5846 case QRhiGraphicsPipeline::DstColor:
5847 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
5848 case QRhiGraphicsPipeline::OneMinusDstColor:
5849 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
5850 case QRhiGraphicsPipeline::SrcAlpha:
5851 return D3D12_BLEND_SRC_ALPHA;
5852 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
5853 return D3D12_BLEND_INV_SRC_ALPHA;
5854 case QRhiGraphicsPipeline::DstAlpha:
5855 return D3D12_BLEND_DEST_ALPHA;
5856 case QRhiGraphicsPipeline::OneMinusDstAlpha:
5857 return D3D12_BLEND_INV_DEST_ALPHA;
5858 case QRhiGraphicsPipeline::ConstantColor:
5859 case QRhiGraphicsPipeline::ConstantAlpha:
5860 return D3D12_BLEND_BLEND_FACTOR;
5861 case QRhiGraphicsPipeline::OneMinusConstantColor:
5862 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
5863 return D3D12_BLEND_INV_BLEND_FACTOR;
5864 case QRhiGraphicsPipeline::SrcAlphaSaturate:
5865 return D3D12_BLEND_SRC_ALPHA_SAT;
5866 case QRhiGraphicsPipeline::Src1Color:
5867 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
5868 case QRhiGraphicsPipeline::OneMinusSrc1Color:
5869 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
5870 case QRhiGraphicsPipeline::Src1Alpha:
5871 return D3D12_BLEND_SRC1_ALPHA;
5872 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
5873 return D3D12_BLEND_INV_SRC1_ALPHA;
5875 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
5878static inline D3D12_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
5881 case QRhiGraphicsPipeline::Add:
5882 return D3D12_BLEND_OP_ADD;
5883 case QRhiGraphicsPipeline::Subtract:
5884 return D3D12_BLEND_OP_SUBTRACT;
5885 case QRhiGraphicsPipeline::ReverseSubtract:
5886 return D3D12_BLEND_OP_REV_SUBTRACT;
5887 case QRhiGraphicsPipeline::Min:
5888 return D3D12_BLEND_OP_MIN;
5889 case QRhiGraphicsPipeline::Max:
5890 return D3D12_BLEND_OP_MAX;
5892 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
5895static inline D3D12_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
5898 case QRhiGraphicsPipeline::None:
5899 return D3D12_CULL_MODE_NONE;
5900 case QRhiGraphicsPipeline::Front:
5901 return D3D12_CULL_MODE_FRONT;
5902 case QRhiGraphicsPipeline::Back:
5903 return D3D12_CULL_MODE_BACK;
5905 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
5908static inline D3D12_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
5911 case QRhiGraphicsPipeline::Fill:
5912 return D3D12_FILL_MODE_SOLID;
5913 case QRhiGraphicsPipeline::Line:
5914 return D3D12_FILL_MODE_WIREFRAME;
5916 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
5919static inline D3D12_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
5922 case QRhiGraphicsPipeline::Never:
5923 return D3D12_COMPARISON_FUNC_NEVER;
5924 case QRhiGraphicsPipeline::Less:
5925 return D3D12_COMPARISON_FUNC_LESS;
5926 case QRhiGraphicsPipeline::Equal:
5927 return D3D12_COMPARISON_FUNC_EQUAL;
5928 case QRhiGraphicsPipeline::LessOrEqual:
5929 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5930 case QRhiGraphicsPipeline::Greater:
5931 return D3D12_COMPARISON_FUNC_GREATER;
5932 case QRhiGraphicsPipeline::NotEqual:
5933 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5934 case QRhiGraphicsPipeline::GreaterOrEqual:
5935 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5936 case QRhiGraphicsPipeline::Always:
5937 return D3D12_COMPARISON_FUNC_ALWAYS;
5939 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
5942static inline D3D12_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
5945 case QRhiGraphicsPipeline::StencilZero:
5946 return D3D12_STENCIL_OP_ZERO;
5947 case QRhiGraphicsPipeline::Keep:
5948 return D3D12_STENCIL_OP_KEEP;
5949 case QRhiGraphicsPipeline::Replace:
5950 return D3D12_STENCIL_OP_REPLACE;
5951 case QRhiGraphicsPipeline::IncrementAndClamp:
5952 return D3D12_STENCIL_OP_INCR_SAT;
5953 case QRhiGraphicsPipeline::DecrementAndClamp:
5954 return D3D12_STENCIL_OP_DECR_SAT;
5955 case QRhiGraphicsPipeline::Invert:
5956 return D3D12_STENCIL_OP_INVERT;
5957 case QRhiGraphicsPipeline::IncrementAndWrap:
5958 return D3D12_STENCIL_OP_INCR;
5959 case QRhiGraphicsPipeline::DecrementAndWrap:
5960 return D3D12_STENCIL_OP_DECR;
5962 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
5965static inline D3D12_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t,
int patchControlPointCount)
5968 case QRhiGraphicsPipeline::Triangles:
5969 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
5970 case QRhiGraphicsPipeline::TriangleStrip:
5971 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
5972 case QRhiGraphicsPipeline::TriangleFan:
5973 qWarning(
"Triangle fans are not supported with D3D");
5974 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
5975 case QRhiGraphicsPipeline::Lines:
5976 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
5977 case QRhiGraphicsPipeline::LineStrip:
5978 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
5979 case QRhiGraphicsPipeline::Points:
5980 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
5981 case QRhiGraphicsPipeline::Patches:
5982 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
5983 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
5985 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
5988static inline D3D12_PRIMITIVE_TOPOLOGY_TYPE toD3DTopologyType(QRhiGraphicsPipeline::Topology t)
5991 case QRhiGraphicsPipeline::Triangles:
5992 case QRhiGraphicsPipeline::TriangleStrip:
5993 case QRhiGraphicsPipeline::TriangleFan:
5994 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
5995 case QRhiGraphicsPipeline::Lines:
5996 case QRhiGraphicsPipeline::LineStrip:
5997 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
5998 case QRhiGraphicsPipeline::Points:
5999 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
6000 case QRhiGraphicsPipeline::Patches:
6001 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
6003 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
6006static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
6009 case QRhiVertexInputAttribute::Float4:
6010 return DXGI_FORMAT_R32G32B32A32_FLOAT;
6011 case QRhiVertexInputAttribute::Float3:
6012 return DXGI_FORMAT_R32G32B32_FLOAT;
6013 case QRhiVertexInputAttribute::Float2:
6014 return DXGI_FORMAT_R32G32_FLOAT;
6015 case QRhiVertexInputAttribute::Float:
6016 return DXGI_FORMAT_R32_FLOAT;
6017 case QRhiVertexInputAttribute::UNormByte4:
6018 return DXGI_FORMAT_R8G8B8A8_UNORM;
6019 case QRhiVertexInputAttribute::UNormByte2:
6020 return DXGI_FORMAT_R8G8_UNORM;
6021 case QRhiVertexInputAttribute::UNormByte:
6022 return DXGI_FORMAT_R8_UNORM;
6023 case QRhiVertexInputAttribute::UInt4:
6024 return DXGI_FORMAT_R32G32B32A32_UINT;
6025 case QRhiVertexInputAttribute::UInt3:
6026 return DXGI_FORMAT_R32G32B32_UINT;
6027 case QRhiVertexInputAttribute::UInt2:
6028 return DXGI_FORMAT_R32G32_UINT;
6029 case QRhiVertexInputAttribute::UInt:
6030 return DXGI_FORMAT_R32_UINT;
6031 case QRhiVertexInputAttribute::SInt4:
6032 return DXGI_FORMAT_R32G32B32A32_SINT;
6033 case QRhiVertexInputAttribute::SInt3:
6034 return DXGI_FORMAT_R32G32B32_SINT;
6035 case QRhiVertexInputAttribute::SInt2:
6036 return DXGI_FORMAT_R32G32_SINT;
6037 case QRhiVertexInputAttribute::SInt:
6038 return DXGI_FORMAT_R32_SINT;
6039 case QRhiVertexInputAttribute::Half4:
6041 case QRhiVertexInputAttribute::Half3:
6042 return DXGI_FORMAT_R16G16B16A16_FLOAT;
6043 case QRhiVertexInputAttribute::Half2:
6044 return DXGI_FORMAT_R16G16_FLOAT;
6045 case QRhiVertexInputAttribute::Half:
6046 return DXGI_FORMAT_R16_FLOAT;
6047 case QRhiVertexInputAttribute::UShort4:
6049 case QRhiVertexInputAttribute::UShort3:
6050 return DXGI_FORMAT_R16G16B16A16_UINT;
6051 case QRhiVertexInputAttribute::UShort2:
6052 return DXGI_FORMAT_R16G16_UINT;
6053 case QRhiVertexInputAttribute::UShort:
6054 return DXGI_FORMAT_R16_UINT;
6055 case QRhiVertexInputAttribute::SShort4:
6057 case QRhiVertexInputAttribute::SShort3:
6058 return DXGI_FORMAT_R16G16B16A16_SINT;
6059 case QRhiVertexInputAttribute::SShort2:
6060 return DXGI_FORMAT_R16G16_SINT;
6061 case QRhiVertexInputAttribute::SShort:
6062 return DXGI_FORMAT_R16_SINT;
6064 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
6067QD3D12GraphicsPipeline::QD3D12GraphicsPipeline(QRhiImplementation *rhi)
6068 : QRhiGraphicsPipeline(rhi)
6072QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
6077void QD3D12GraphicsPipeline::destroy()
6079 if (handle.isNull())
6082 QRHI_RES_RHI(QRhiD3D12);
6084 rhiD->releaseQueue.deferredReleasePipeline(handle);
6085 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6092 rhiD->unregisterResource(
this);
6095bool QD3D12GraphicsPipeline::create()
6097 if (!handle.isNull())
6100 QRHI_RES_RHI(QRhiD3D12);
6101 if (!rhiD->sanityCheckGraphicsPipeline(
this))
6104 rhiD->pipelineCreationStart();
6106 QByteArray shaderBytecode[5];
6107 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6108 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
6109 stageData[d3dStage].valid =
true;
6110 stageData[d3dStage].stage = d3dStage;
6111 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
6112 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6113 shaderBytecode[d3dStage] = cacheIt->bytecode;
6114 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6117 QShaderKey shaderKey;
6118 int compileFlags = 0;
6119 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6120 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6121 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
6122 shaderStage.shaderVariant(),
6126 if (bytecode.isEmpty()) {
6127 qWarning(
"HLSL graphics shader compilation failed: %s", qPrintable(error));
6131 shaderBytecode[d3dStage] = bytecode;
6132 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
6133 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
6134 { bytecode, stageData[d3dStage].nativeResourceBindingMap });
6138 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6140 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
6141 if (rootSigHandle.isNull()) {
6142 qWarning(
"Failed to create root signature");
6146 ID3D12RootSignature *rootSig =
nullptr;
6147 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6148 rootSig = rs->rootSig;
6150 qWarning(
"Cannot create graphics pipeline state without root signature");
6154 QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6155 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
6156 if (rpD->colorAttachmentCount > 0) {
6157 format = DXGI_FORMAT(rpD->colorFormat[0]);
6158 }
else if (rpD->hasDepthStencil) {
6159 format = DXGI_FORMAT(rpD->dsFormat);
6161 qWarning(
"Cannot create graphics pipeline state without color or depthStencil format");
6164 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
6167 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6168 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
6169 QD3D12PipelineStateSubObject<D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE> primitiveRestartValue;
6170 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
6171 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
6172 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
6173 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
6174 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
6175 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
6176 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
6177 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
6178 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
6179 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
6180 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
6181 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
6182 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
6183 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
6186 stream.rootSig.object = rootSig;
6188 QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
6189 QByteArrayList matrixSliceSemantics;
6190 if (!shaderBytecode[VS].isEmpty()) {
6191 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
6194 D3D12_INPUT_ELEMENT_DESC desc = {};
6199 const int matrixSlice = it->matrixSlice();
6200 if (matrixSlice < 0) {
6201 desc.SemanticName =
"TEXCOORD";
6202 desc.SemanticIndex = UINT(it->location());
6206 std::snprintf(sem.data(), sem.size(),
"TEXCOORD%d_", it->location() - matrixSlice);
6207 matrixSliceSemantics.append(sem);
6208 desc.SemanticName = matrixSliceSemantics.last().constData();
6209 desc.SemanticIndex = UINT(matrixSlice);
6211 desc.Format = toD3DAttributeFormat(it->format());
6212 desc.InputSlot = UINT(it->binding());
6213 desc.AlignedByteOffset = it->offset();
6214 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
6215 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
6216 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
6217 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
6219 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
6221 inputDescs.append(desc);
6225 stream.inputLayout.object.NumElements = inputDescs.count();
6226 stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ?
nullptr : inputDescs.constData();
6228 stream.primitiveRestartValue.object = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
6230 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
6231 topology = toD3DTopology(m_topology, m_patchControlPointCount);
6233 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6234 const int d3dStage = qd3d12_stage(shaderStage.type());
6237 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6238 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6241 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6242 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6245 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6246 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6249 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6250 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6253 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
6254 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
6262 stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
6263 stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
6264 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
6265 stream.rasterizerState.object.DepthBias = m_depthBias;
6266 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
6267 stream.rasterizerState.object.DepthClipEnable = m_depthClamp ? FALSE : TRUE;
6268 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
6270 stream.depthStencilState.object.DepthEnable = m_depthTest;
6271 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
6272 stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
6273 stream.depthStencilState.object.StencilEnable = m_stencilTest;
6274 if (m_stencilTest) {
6275 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
6276 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
6277 stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
6278 stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
6279 stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
6280 stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
6281 stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
6282 stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
6283 stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
6284 stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
6287 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
6288 for (
int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
6289 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
6290 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6291 blend.BlendEnable = b.enable;
6292 blend.SrcBlend = toD3DBlendFactor(b.srcColor,
true);
6293 blend.DestBlend = toD3DBlendFactor(b.dstColor,
true);
6294 blend.BlendOp = toD3DBlendOp(b.opColor);
6295 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha,
false);
6296 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha,
false);
6297 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
6298 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
6299 stream.blendState.object.RenderTarget[i] = blend;
6301 if (m_targetBlends.isEmpty()) {
6302 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
6303 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
6304 stream.blendState.object.RenderTarget[0] = blend;
6307 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
6308 for (
int i = 0; i < rpD->colorAttachmentCount; ++i)
6309 stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
6311 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
6313 stream.sampleDesc.object = sampleDesc;
6315 stream.sampleMask.object = 0xFFFFFFFF;
6317 viewInstanceMask = 0;
6318 const bool isMultiView = m_multiViewCount >= 2;
6319 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
6320 QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
6322 for (
int i = 0; i < m_multiViewCount; ++i) {
6323 viewInstanceMask |= (1 << i);
6324 viewInstanceLocations.append({ 0, UINT(i) });
6326 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
6329 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6331 ID3D12PipelineState *pso =
nullptr;
6332 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6334 qWarning(
"Failed to create graphics pipeline state: %s",
6335 qPrintable(QSystemError::windowsComString(hr)));
6336 rhiD->rootSignaturePool.remove(rootSigHandle);
6341 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
6343 rhiD->pipelineCreationEnd();
6345 rhiD->registerResource(
this);
6349QD3D12ComputePipeline::QD3D12ComputePipeline(QRhiImplementation *rhi)
6350 : QRhiComputePipeline(rhi)
6354QD3D12ComputePipeline::~QD3D12ComputePipeline()
6359void QD3D12ComputePipeline::destroy()
6361 if (handle.isNull())
6364 QRHI_RES_RHI(QRhiD3D12);
6366 rhiD->releaseQueue.deferredReleasePipeline(handle);
6367 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6374 rhiD->unregisterResource(
this);
6377bool QD3D12ComputePipeline::create()
6379 if (!handle.isNull())
6382 QRHI_RES_RHI(QRhiD3D12);
6383 rhiD->pipelineCreationStart();
6385 stageData.valid =
true;
6386 stageData.stage = CS;
6388 QByteArray shaderBytecode;
6389 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(m_shaderStage);
6390 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6391 shaderBytecode = cacheIt->bytecode;
6392 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6395 QShaderKey shaderKey;
6396 int compileFlags = 0;
6397 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6398 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6399 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
6400 m_shaderStage.shaderVariant(),
6404 if (bytecode.isEmpty()) {
6405 qWarning(
"HLSL compute shader compilation failed: %s", qPrintable(error));
6409 shaderBytecode = bytecode;
6410 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
6411 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
6412 stageData.nativeResourceBindingMap });
6415 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6417 rootSigHandle = srbD->createRootSignature(&stageData, 1);
6418 if (rootSigHandle.isNull()) {
6419 qWarning(
"Failed to create root signature");
6423 ID3D12RootSignature *rootSig =
nullptr;
6424 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6425 rootSig = rs->rootSig;
6427 qWarning(
"Cannot create compute pipeline state without root signature");
6432 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6433 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
6435 stream.rootSig.object = rootSig;
6436 stream.CS.object.pShaderBytecode = shaderBytecode.constData();
6437 stream.CS.object.BytecodeLength = shaderBytecode.size();
6438 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
6439 ID3D12PipelineState *pso =
nullptr;
6440 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<
void **>(&pso));
6442 qWarning(
"Failed to create compute pipeline state: %s",
6443 qPrintable(QSystemError::windowsComString(hr)));
6444 rhiD->rootSignaturePool.remove(rootSigHandle);
6449 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
6451 rhiD->pipelineCreationEnd();
6453 rhiD->registerResource(
this);
6460QD3D12RenderPassDescriptor::QD3D12RenderPassDescriptor(QRhiImplementation *rhi)
6461 : QRhiRenderPassDescriptor(rhi)
6463 serializedFormatData.reserve(16);
6466QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
6471void QD3D12RenderPassDescriptor::destroy()
6473 QRHI_RES_RHI(QRhiD3D12);
6475 rhiD->unregisterResource(
this);
6478bool QD3D12RenderPassDescriptor::isCompatible(
const QRhiRenderPassDescriptor *other)
const
6483 const QD3D12RenderPassDescriptor *o = QRHI_RES(
const QD3D12RenderPassDescriptor, other);
6485 if (colorAttachmentCount != o->colorAttachmentCount)
6488 if (hasDepthStencil != o->hasDepthStencil)
6491 for (
int i = 0; i < colorAttachmentCount; ++i) {
6492 if (colorFormat[i] != o->colorFormat[i])
6496 if (hasDepthStencil) {
6497 if (dsFormat != o->dsFormat)
6501 if (hasShadingRateMap != o->hasShadingRateMap)
6507void QD3D12RenderPassDescriptor::updateSerializedFormat()
6509 serializedFormatData.clear();
6510 auto p = std::back_inserter(serializedFormatData);
6512 *p++ = colorAttachmentCount;
6513 *p++ = hasDepthStencil;
6514 for (
int i = 0; i < colorAttachmentCount; ++i)
6515 *p++ = colorFormat[i];
6516 *p++ = hasDepthStencil ? dsFormat : 0;
6519QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor()
const
6521 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6522 rpD->colorAttachmentCount = colorAttachmentCount;
6523 rpD->hasDepthStencil = hasDepthStencil;
6524 memcpy(rpD->colorFormat, colorFormat,
sizeof(colorFormat));
6525 rpD->dsFormat = dsFormat;
6526 rpD->hasShadingRateMap = hasShadingRateMap;
6528 rpD->updateSerializedFormat();
6530 QRHI_RES_RHI(QRhiD3D12);
6531 rhiD->registerResource(rpD);
6535QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat()
const
6537 return serializedFormatData;
6540QD3D12CommandBuffer::QD3D12CommandBuffer(QRhiImplementation *rhi)
6541 : QRhiCommandBuffer(rhi)
6546QD3D12CommandBuffer::~QD3D12CommandBuffer()
6551void QD3D12CommandBuffer::destroy()
6556const QRhiNativeHandles *QD3D12CommandBuffer::nativeHandles()
6558 nativeHandlesStruct.commandList = cmdList;
6559 return &nativeHandlesStruct;
6562QD3D12SwapChainRenderTarget::QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
6563 : QRhiSwapChainRenderTarget(rhi, swapchain),
6568QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
6573void QD3D12SwapChainRenderTarget::destroy()
6578QSize QD3D12SwapChainRenderTarget::pixelSize()
const
6583float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
6588int QD3D12SwapChainRenderTarget::sampleCount()
const
6590 return d.sampleCount;
6593QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
6594 : QRhiSwapChain(rhi),
6595 rtWrapper(rhi,
this),
6596 rtWrapperRight(rhi,
this),
6601QD3D12SwapChain::~QD3D12SwapChain()
6606void QD3D12SwapChain::destroy()
6613 swapChain->Release();
6614 swapChain =
nullptr;
6615 sourceSwapChain1->Release();
6616 sourceSwapChain1 =
nullptr;
6618 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
6619 FrameResources &fr(frameRes[i]);
6621 fr.fence->Release();
6623 CloseHandle(fr.fenceEvent);
6625 fr.cmdList->Release();
6630 dcompVisual->Release();
6631 dcompVisual =
nullptr;
6635 dcompTarget->Release();
6636 dcompTarget =
nullptr;
6639 if (frameLatencyWaitableObject) {
6640 CloseHandle(frameLatencyWaitableObject);
6641 frameLatencyWaitableObject =
nullptr;
6644 QDxgiVSyncService::instance()->unregisterWindow(window);
6646 QRHI_RES_RHI(QRhiD3D12);
6648 rhiD->swapchains.remove(
this);
6649 rhiD->unregisterResource(
this);
6653void QD3D12SwapChain::releaseBuffers()
6655 QRHI_RES_RHI(QRhiD3D12);
6657 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
6658 rhiD->resourcePool.remove(colorBuffers[i]);
6659 rhiD->rtvPool.release(rtvs[i], 1);
6661 rhiD->rtvPool.release(rtvsRight[i], 1);
6662 if (!msaaBuffers[i].isNull())
6663 rhiD->resourcePool.remove(msaaBuffers[i]);
6664 if (msaaRtvs[i].isValid())
6665 rhiD->rtvPool.release(msaaRtvs[i], 1);
6669void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
6671 FrameResources &fr(frameRes[frameSlot]);
6672 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
6673 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
6674 WaitForSingleObject(fr.fenceEvent, INFINITE);
6678void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
6680 QRHI_RES_RHI(QRhiD3D12);
6681 FrameResources &fr(frameRes[currentFrameSlot]);
6682 fr.fenceCounter += 1u;
6683 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
6686QRhiCommandBuffer *QD3D12SwapChain::currentFrameCommandBuffer()
6691QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
6696QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
6698 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
6701QSize QD3D12SwapChain::surfacePixelSize()
6704 return m_window->size() * m_window->devicePixelRatio();
6707bool QD3D12SwapChain::isFormatSupported(Format f)
6713 qWarning(
"Attempted to call isFormatSupported() without a window set");
6717 QRHI_RES_RHI(QRhiD3D12);
6718 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window))
6719 return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
6724QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
6726 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
6729 QRHI_RES_RHI(QRhiD3D12);
6730 info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window);
6735QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
6740 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6741 rpD->colorAttachmentCount = 1;
6742 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
6743 rpD->colorFormat[0] =
int(srgbAdjustedColorFormat);
6744 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
6746 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
6748 rpD->updateSerializedFormat();
6750 QRHI_RES_RHI(QRhiD3D12);
6751 rhiD->registerResource(rpD);
6755bool QRhiD3D12::ensureDirectCompositionDevice()
6760 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
6761 dcompDevice = QRhiD3D::createDirectCompositionDevice();
6762 return dcompDevice ?
true :
false;
6765static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
6766static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
6768void QD3D12SwapChain::chooseFormats()
6770 colorFormat = DEFAULT_FORMAT;
6771 srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
6772 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
6773 QRHI_RES_RHI(QRhiD3D12);
6774 if (m_format != SDR) {
6775 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) {
6778 case HDRExtendedSrgbLinear:
6779 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
6780 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
6781 srgbAdjustedColorFormat = colorFormat;
6784 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
6785 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
6786 srgbAdjustedColorFormat = colorFormat;
6795 qWarning(
"The output associated with the window is not HDR capable "
6796 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
6799 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
6802bool QD3D12SwapChain::createOrResize()
6808 const bool needsRegistration = !window || window != m_window;
6811 if (window && window != m_window)
6815 m_currentPixelSize = surfacePixelSize();
6816 pixelSize = m_currentPixelSize;
6818 if (pixelSize.isEmpty())
6821 HWND hwnd =
reinterpret_cast<HWND>(window->winId());
6823 QRHI_RES_RHI(QRhiD3D12);
6824 stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
6826 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
6827 if (rhiD->ensureDirectCompositionDevice()) {
6829 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
false, &dcompTarget);
6831 qWarning(
"Failed to create Direct Composition target for the window: %s",
6832 qPrintable(QSystemError::windowsComString(hr)));
6835 if (dcompTarget && !dcompVisual) {
6836 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
6838 qWarning(
"Failed to create DirectComposition visual: %s",
6839 qPrintable(QSystemError::windowsComString(hr)));
6844 if (window->requestedFormat().alphaBufferSize() <= 0)
6845 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
6846 "This may lead to problems.");
6849 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
6851 if (swapInterval == 0 && rhiD->supportsAllowTearing)
6852 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
6856 const bool useFrameLatencyWaitableObject = rhiD->maxFrameLatency != 0
6857 && swapInterval != 0
6858 && rhiD->driverInfoStruct.deviceType != QRhiDriverInfo::CpuDevice;
6859 if (useFrameLatencyWaitableObject)
6860 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
6865 DXGI_SWAP_CHAIN_DESC1 desc = {};
6866 desc.Width = UINT(pixelSize.width());
6867 desc.Height = UINT(pixelSize.height());
6868 desc.Format = colorFormat;
6869 desc.SampleDesc.Count = 1;
6870 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6871 desc.BufferCount = BUFFER_COUNT;
6872 desc.Flags = swapChainFlags;
6873 desc.Scaling = DXGI_SCALING_NONE;
6874 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
6875 desc.Stereo = stereo;
6881 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
6886 desc.Scaling = DXGI_SCALING_STRETCH;
6890 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
6892 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
6897 if (FAILED(hr) && m_format != SDR) {
6898 colorFormat = DEFAULT_FORMAT;
6899 desc.Format = DEFAULT_FORMAT;
6901 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
6903 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
6906 if (SUCCEEDED(hr)) {
6907 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<
void **>(&swapChain)))) {
6908 qWarning(
"IDXGISwapChain3 not available");
6911 if (m_format != SDR) {
6912 hr = swapChain->SetColorSpace1(hdrColorSpace);
6914 qWarning(
"Failed to set color space on swapchain: %s",
6915 qPrintable(QSystemError::windowsComString(hr)));
6918 if (useFrameLatencyWaitableObject) {
6919 swapChain->SetMaximumFrameLatency(rhiD->maxFrameLatency);
6920 frameLatencyWaitableObject = swapChain->GetFrameLatencyWaitableObject();
6923 hr = dcompVisual->SetContent(swapChain);
6924 if (SUCCEEDED(hr)) {
6925 hr = dcompTarget->SetRoot(dcompVisual);
6927 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
6928 qPrintable(QSystemError::windowsComString(hr)));
6931 qWarning(
"Failed to set content for Direct Composition visual: %s",
6932 qPrintable(QSystemError::windowsComString(hr)));
6936 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
6940 qWarning(
"Failed to create D3D12 swapchain: %s"
6941 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
6942 qPrintable(QSystemError::windowsComString(hr)),
6943 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
6944 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
6948 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
6949 hr = rhiD->dev->CreateFence(0,
6950 D3D12_FENCE_FLAG_NONE,
6951 __uuidof(ID3D12Fence),
6952 reinterpret_cast<
void **>(&frameRes[i].fence));
6954 qWarning(
"Failed to create fence for swapchain: %s",
6955 qPrintable(QSystemError::windowsComString(hr)));
6958 frameRes[i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
6960 frameRes[i].fenceCounter = 0;
6964 hr = swapChain->ResizeBuffers(BUFFER_COUNT,
6965 UINT(pixelSize.width()),
6966 UINT(pixelSize.height()),
6969 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
6970 qWarning(
"Device loss detected in ResizeBuffers()");
6971 rhiD->deviceLost =
true;
6973 }
else if (FAILED(hr)) {
6974 qWarning(
"Failed to resize D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
6979 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
6980 ID3D12Resource *colorBuffer;
6981 hr = swapChain->GetBuffer(i, __uuidof(ID3D12Resource),
reinterpret_cast<
void **>(&colorBuffer));
6983 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
6984 i, qPrintable(QSystemError::windowsComString(hr)));
6987 colorBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
6988 rtvs[i] = rhiD->rtvPool.allocate(1);
6989 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6990 rtvDesc.Format = srgbAdjustedColorFormat;
6991 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
6992 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
6995 rtvsRight[i] = rhiD->rtvPool.allocate(1);
6996 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6997 rtvDesc.Format = srgbAdjustedColorFormat;
6998 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
6999 rtvDesc.Texture2DArray.ArraySize = 1;
7000 rtvDesc.Texture2DArray.FirstArraySlice = 1;
7001 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
7005 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
7006 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
7007 m_depthStencil->sampleCount(), m_sampleCount);
7009 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
7010 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
7011 m_depthStencil->setPixelSize(pixelSize);
7012 if (!m_depthStencil->create())
7013 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
7014 pixelSize.width(), pixelSize.height());
7016 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
7017 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
7018 pixelSize.width(), pixelSize.height());
7022 ds = m_depthStencil ? QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
7024 if (sampleDesc.Count > 1) {
7025 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7026 D3D12_RESOURCE_DESC resourceDesc = {};
7027 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
7028 resourceDesc.Width = UINT64(pixelSize.width());
7029 resourceDesc.Height = UINT(pixelSize.height());
7030 resourceDesc.DepthOrArraySize = 1;
7031 resourceDesc.MipLevels = 1;
7032 resourceDesc.Format = srgbAdjustedColorFormat;
7033 resourceDesc.SampleDesc = sampleDesc;
7034 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
7035 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
7036 D3D12_CLEAR_VALUE clearValue = {};
7037 clearValue.Format = colorFormat;
7038 ID3D12Resource *resource =
nullptr;
7039 D3D12MA::Allocation *allocation =
nullptr;
7040 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
7042 D3D12_RESOURCE_STATE_RENDER_TARGET,
7045 __uuidof(ID3D12Resource),
7046 reinterpret_cast<
void **>(&resource));
7048 qWarning(
"Failed to create MSAA color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
7051 msaaBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
7052 msaaRtvs[i] = rhiD->rtvPool.allocate(1);
7053 if (!msaaRtvs[i].isValid())
7055 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7056 rtvDesc.Format = srgbAdjustedColorFormat;
7057 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
7058 : D3D12_RTV_DIMENSION_TEXTURE2D;
7059 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[i].cpuHandle);
7063 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
7064 currentFrameSlot = 0;
7065 lastFrameLatencyWaitSlot = -1;
7067 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
7068 QD3D12SwapChainRenderTarget *rtD = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
7069 rtD->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7070 rtD->d.pixelSize = pixelSize;
7071 rtD->d.dpr =
float(window->devicePixelRatio());
7072 rtD->d.sampleCount =
int(sampleDesc.Count);
7073 rtD->d.colorAttCount = 1;
7074 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
7076 rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
7077 QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
7078 rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7079 rtDr->d.pixelSize = pixelSize;
7080 rtDr->d.dpr =
float(window->devicePixelRatio());
7081 rtDr->d.sampleCount =
int(sampleDesc.Count);
7082 rtDr->d.colorAttCount = 1;
7083 rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
7085 QDxgiVSyncService::instance()->registerWindow(window);
7087 if (needsRegistration || !rhiD->swapchains.contains(
this))
7088 rhiD->swapchains.insert(
this);
7090 rhiD->registerResource(
this);