7#include <QtCore/private/qsystemerror_p.h>
8#include <QtCore/qcryptographichash.h>
16#define QRHI_D3D12_HAS_OLD_PIX
19#ifdef __ID3D12Device2_INTERFACE_DEFINED__
24
25
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
69
70
71
72
73
74
75
76
77
80
81
82
83
84
85
86
87
88
89
90
91
94
95
96
97
98
99
102
103
104
105
106
107
108
109
110
111
112
115
116
117
118
119
120
123
124
125
126
127
128
131
132
133
134
135
136
137
140
141
142
143
144
145
146
147
148
149
150
151
152
153
156
157
160static const D3D_FEATURE_LEVEL MIN_FEATURE_LEVEL = D3D_FEATURE_LEVEL_11_0;
162QRhiD3D12::QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importParams)
164 debugLayer = params->enableDebugLayer;
166 if (importParams->dev) {
167 ID3D12Device *d3d12Device =
reinterpret_cast<ID3D12Device *>(importParams->dev);
168 if (SUCCEEDED(d3d12Device->QueryInterface(__uuidof(ID3D12Device2),
reinterpret_cast<
void **>(&dev)))) {
170 d3d12Device->Release();
171 importedDevice =
true;
173 qWarning(
"ID3D12Device2 not supported, cannot import device");
176 if (importParams->commandQueue) {
177 cmdQueue =
reinterpret_cast<ID3D12CommandQueue *>(importParams->commandQueue);
178 importedCommandQueue =
true;
180 minimumFeatureLevel = D3D_FEATURE_LEVEL(importParams->minimumFeatureLevel);
181 adapterLuid.LowPart = importParams->adapterLuidLow;
182 adapterLuid.HighPart = importParams->adapterLuidHigh;
187inline Int aligned(Int v, Int byteAlign)
189 return (v + byteAlign - 1) & ~(byteAlign - 1);
192static inline UINT calcSubresource(UINT mipSlice, UINT arraySlice, UINT mipLevels)
194 return mipSlice + arraySlice * mipLevels;
197static inline QD3D12RenderTargetData *rtData(QRhiRenderTarget *rt)
199 switch (rt->resourceType()) {
200 case QRhiResource::SwapChainRenderTarget:
201 return &QRHI_RES(QD3D12SwapChainRenderTarget, rt)->d;
202 case QRhiResource::TextureRenderTarget:
203 return &QRHI_RES(QD3D12TextureRenderTarget, rt)->d;
208 Q_UNREACHABLE_RETURN(
nullptr);
211#ifdef QRHI_D3D12_INFOQUEUE1_AVAILABLE
212static void __stdcall qd3d12_message_callback(D3D12_MESSAGE_CATEGORY category,
213 D3D12_MESSAGE_SEVERITY severity,
223 if (severity == D3D12_MESSAGE_SEVERITY_INFO)
225 if (id == D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE
226 || id == D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE)
233 qDebug(
"D3D12: %s", description);
237bool QRhiD3D12::create(QRhi::Flags flags)
241 UINT factoryFlags = 0;
243 factoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
244 HRESULT hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
248 qCDebug(QRHI_LOG_INFO,
"Debug layer was requested but is not available. "
249 "Attempting to create DXGIFactory2 without it.");
250 factoryFlags &= ~DXGI_CREATE_FACTORY_DEBUG;
251 hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgiFactory));
256 qWarning(
"CreateDXGIFactory2() failed to create DXGI factory: %s",
257 qPrintable(QSystemError::windowsComString(hr)));
262 if (qEnvironmentVariableIsSet(
"QT_D3D_MAX_FRAME_LATENCY"))
263 maxFrameLatency = UINT(qMax(0, qEnvironmentVariableIntValue(
"QT_D3D_MAX_FRAME_LATENCY")));
264 if (maxFrameLatency != 0)
265 qCDebug(QRHI_LOG_INFO,
"Using frame latency waitable object with max frame latency %u", maxFrameLatency);
267 supportsAllowTearing =
false;
268 IDXGIFactory5 *factory5 =
nullptr;
269 if (SUCCEEDED(dxgiFactory->QueryInterface(__uuidof(IDXGIFactory5),
reinterpret_cast<
void **>(&factory5)))) {
270 BOOL allowTearing =
false;
271 if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing,
sizeof(allowTearing))))
272 supportsAllowTearing = allowTearing;
277 ID3D12Debug1 *debug =
nullptr;
278 if (SUCCEEDED(D3D12GetDebugInterface(__uuidof(ID3D12Debug1),
reinterpret_cast<
void **>(&debug)))) {
279 qCDebug(QRHI_LOG_INFO,
"Enabling D3D12 debug layer");
280 debug->EnableDebugLayer();
285 activeAdapter =
nullptr;
287 if (!importedDevice) {
288 IDXGIAdapter1 *adapter;
289 int requestedAdapterIndex = -1;
290 if (qEnvironmentVariableIsSet(
"QT_D3D_ADAPTER_INDEX"))
291 requestedAdapterIndex = qEnvironmentVariableIntValue(
"QT_D3D_ADAPTER_INDEX");
293 if (requestedRhiAdapter)
294 adapterLuid =
static_cast<QD3D12Adapter *>(requestedRhiAdapter)->luid;
297 if (requestedAdapterIndex < 0 && (adapterLuid.LowPart || adapterLuid.HighPart)) {
298 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
299 DXGI_ADAPTER_DESC1 desc;
300 adapter->GetDesc1(&desc);
302 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
303 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
305 requestedAdapterIndex = adapterIndex;
311 if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
312 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
313 DXGI_ADAPTER_DESC1 desc;
314 adapter->GetDesc1(&desc);
316 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
317 requestedAdapterIndex = adapterIndex;
323 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
324 DXGI_ADAPTER_DESC1 desc;
325 adapter->GetDesc1(&desc);
326 const QString name = QString::fromUtf16(
reinterpret_cast<
char16_t *>(desc.Description));
327 qCDebug(QRHI_LOG_INFO,
"Adapter %d: '%s' (vendor 0x%X device 0x%X flags 0x%X)",
333 if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
334 activeAdapter = adapter;
335 adapterLuid = desc.AdapterLuid;
336 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
337 qCDebug(QRHI_LOG_INFO,
" using this adapter");
342 if (!activeAdapter) {
343 qWarning(
"No adapter");
347 if (minimumFeatureLevel == 0)
348 minimumFeatureLevel = MIN_FEATURE_LEVEL;
350 hr = D3D12CreateDevice(activeAdapter,
352 __uuidof(ID3D12Device2),
353 reinterpret_cast<
void **>(&dev));
355 qWarning(
"Failed to create D3D12 device: %s", qPrintable(QSystemError::windowsComString(hr)));
361 adapterLuid = dev->GetAdapterLuid();
362 IDXGIAdapter1 *adapter;
363 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
364 DXGI_ADAPTER_DESC1 desc;
365 adapter->GetDesc1(&desc);
366 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
367 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
369 activeAdapter = adapter;
370 QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
376 if (!activeAdapter) {
377 qWarning(
"No adapter");
380 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
383 QDxgiVSyncService::instance()->refAdapter(adapterLuid);
386 ID3D12InfoQueue *infoQueue;
387 if (SUCCEEDED(dev->QueryInterface(__uuidof(ID3D12InfoQueue),
reinterpret_cast<
void **>(&infoQueue)))) {
388 if (qEnvironmentVariableIntValue(
"QT_D3D_DEBUG_BREAK")) {
389 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION,
true);
390 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR,
true);
391 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING,
true);
393 D3D12_INFO_QUEUE_FILTER filter = {};
394 D3D12_MESSAGE_ID suppressedMessages[2] = {
396 D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
398 D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE
400 filter.DenyList.NumIDs = 2;
401 filter.DenyList.pIDList = suppressedMessages;
404 D3D12_MESSAGE_SEVERITY infoSev = D3D12_MESSAGE_SEVERITY_INFO;
405 filter.DenyList.NumSeverities = 1;
406 filter.DenyList.pSeverityList = &infoSev;
407 infoQueue->PushStorageFilter(&filter);
408#ifdef QRHI_D3D12_INFOQUEUE1_AVAILABLE
413 if (SUCCEEDED(infoQueue->QueryInterface(__uuidof(ID3D12InfoQueue1),
reinterpret_cast<
void **>(&infoQueue1)))) {
418 if (SUCCEEDED(infoQueue1->RegisterMessageCallback(qd3d12_message_callback,
419 D3D12_MESSAGE_CALLBACK_IGNORE_FILTERS,
421 &infoQueueCallbackCookie)))
425 infoQueue1->SetMuteDebugOutput(
true);
427 infoQueue1->Release();
428 infoQueue1 =
nullptr;
432 infoQueue->Release();
436 if (!importedCommandQueue) {
437 D3D12_COMMAND_QUEUE_DESC queueDesc = {};
438 queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
439 queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
440 hr = dev->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue),
reinterpret_cast<
void **>(&cmdQueue));
442 qWarning(
"Failed to create command queue: %s", qPrintable(QSystemError::windowsComString(hr)));
447 hr = dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence),
reinterpret_cast<
void **>(&fullFence));
449 qWarning(
"Failed to create fence: %s", qPrintable(QSystemError::windowsComString(hr)));
452 fullFenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
453 fullFenceCounter = 0;
455 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
456 hr = dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
457 __uuidof(ID3D12CommandAllocator),
458 reinterpret_cast<
void **>(&cmdAllocators[i]));
460 qWarning(
"Failed to create command allocator: %s", qPrintable(QSystemError::windowsComString(hr)));
465 if (!vma.create(dev, activeAdapter)) {
466 qWarning(
"Failed to initialize graphics memory suballocator");
470 if (!rtvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
"main RTV pool")) {
471 qWarning(
"Could not create RTV pool");
475 if (!dsvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
"main DSV pool")) {
476 qWarning(
"Could not create DSV pool");
480 if (!cbvSrvUavPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
"main CBV-SRV-UAV pool")) {
481 qWarning(
"Could not create CBV-SRV-UAV pool");
485 resourcePool.create(
"main resource pool");
486 pipelinePool.create(
"main pipeline pool");
487 rootSignaturePool.create(
"main root signature pool");
488 releaseQueue.create(&resourcePool, &pipelinePool, &rootSignaturePool);
489 barrierGen.create(&resourcePool);
491 if (!samplerMgr.create(dev)) {
492 qWarning(
"Could not create sampler pool and shader-visible sampler heap");
496 mipmapGen.create(
this);
497 mipmapGen3D.create(
this);
499 const qint32 smallStagingSize = aligned(SMALL_STAGING_AREA_BYTES_PER_FRAME_START, QD3D12StagingArea::ALIGNMENT);
500 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
501 if (!smallStagingAreas[i].create(
this, smallStagingSize, D3D12_HEAP_TYPE_UPLOAD)) {
502 qWarning(
"Could not create host-visible staging area");
505 QString decoratedName = QLatin1String(
"Small staging area buffer/");
506 decoratedName += QString::number(i);
507 smallStagingAreas[i].mem.buffer->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
510 if (!shaderVisibleCbvSrvUavHeap.create(dev,
511 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
512 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE))
514 qWarning(
"Could not create first shader-visible CBV/SRV/UAV heap");
518 if (flags.testFlag(QRhi::EnableTimestamps)) {
519 static bool wantsStablePowerState = qEnvironmentVariableIntValue(
"QT_D3D_STABLE_POWER_STATE");
535 if (wantsStablePowerState)
536 dev->SetStablePowerState(TRUE);
538 hr = cmdQueue->GetTimestampFrequency(×tampTicksPerSecond);
540 qWarning(
"Failed to query timestamp frequency: %s",
541 qPrintable(QSystemError::windowsComString(hr)));
544 if (!timestampQueryHeap.create(dev, QD3D12_FRAMES_IN_FLIGHT * 2, D3D12_QUERY_HEAP_TYPE_TIMESTAMP)) {
545 qWarning(
"Failed to create timestamp query pool");
548 const quint32 readbackBufSize = QD3D12_FRAMES_IN_FLIGHT * 2 *
sizeof(quint64);
549 if (!timestampReadbackArea.create(
this, readbackBufSize, D3D12_HEAP_TYPE_READBACK)) {
550 qWarning(
"Failed to create timestamp readback buffer");
553 timestampReadbackArea.mem.buffer->SetName(L"Timestamp readback buffer");
554 memset(timestampReadbackArea.mem.p, 0, readbackBufSize);
558 D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
559 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3,
sizeof(options3)))) {
560 caps.multiView = options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
562 caps.textureViewFormat = options3.CastingFullyTypedFormatSupported;
565#ifdef QRHI_D3D12_CL5_AVAILABLE
566 D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {};
567 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6,
sizeof(options6)))) {
568 caps.vrs = options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED;
569 caps.vrsMap = options6.VariableShadingRateTier == D3D12_VARIABLE_SHADING_RATE_TIER_2;
570 caps.vrsAdditionalRates = options6.AdditionalShadingRatesSupported;
571 shadingRateImageTileSize = options6.ShadingRateImageTileSize;
576 caps.vrsAdditionalRates =
false;
580 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
581 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
583 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
584 sigDesc.ByteStride =
sizeof(D3D12_DRAW_ARGUMENTS);
585 sigDesc.NumArgumentDescs = 1;
586 sigDesc.pArgumentDescs = &arg;
588 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&drawCommandSignature));
590 qWarning(
"Failed to create draw command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
596 D3D12_INDIRECT_ARGUMENT_DESC arg = {};
597 arg.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
599 D3D12_COMMAND_SIGNATURE_DESC sigDesc = {};
600 sigDesc.ByteStride =
sizeof(D3D12_DRAW_INDEXED_ARGUMENTS);
601 sigDesc.NumArgumentDescs = 1;
602 sigDesc.pArgumentDescs = &arg;
604 hr = dev->CreateCommandSignature(&sigDesc,
nullptr, IID_PPV_ARGS(&drawIndexedCommandSignature));
606 qWarning(
"Failed to create draw indexed command signature: %s", qPrintable(QSystemError::windowsComString(hr)));
612 offscreenActive =
false;
614 nativeHandlesStruct.dev = dev;
615 nativeHandlesStruct.minimumFeatureLevel = minimumFeatureLevel;
616 nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
617 nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
618 nativeHandlesStruct.commandQueue = cmdQueue;
623void QRhiD3D12::destroy()
625 if (!deviceLost && fullFence && fullFenceEvent)
628 releaseQueue.releaseAll();
630 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
631 if (offscreenCb[i]) {
632 if (offscreenCb[i]->cmdList)
633 offscreenCb[i]->cmdList->Release();
634 delete offscreenCb[i];
635 offscreenCb[i] =
nullptr;
639 timestampQueryHeap.destroy();
640 timestampReadbackArea.destroy();
642 shaderVisibleCbvSrvUavHeap.destroy();
644 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i)
645 smallStagingAreas[i].destroy();
648 mipmapGen3D.destroy();
649 samplerMgr.destroy();
650 resourcePool.destroy();
651 pipelinePool.destroy();
652 rootSignaturePool.destroy();
655 cbvSrvUavPool.destroy();
657 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
658 if (cmdAllocators[i]) {
659 cmdAllocators[i]->Release();
660 cmdAllocators[i] =
nullptr;
664 if (fullFenceEvent) {
665 CloseHandle(fullFenceEvent);
666 fullFenceEvent =
nullptr;
670 fullFence->Release();
674 if (!importedCommandQueue) {
683#ifdef QRHI_D3D12_INFOQUEUE1_AVAILABLE
685 infoQueue1->UnregisterMessageCallback(infoQueueCallbackCookie);
686 infoQueue1->Release();
687 infoQueue1 =
nullptr;
688 infoQueueCallbackCookie = 0;
692 if (!importedDevice) {
700 dcompDevice->Release();
701 dcompDevice =
nullptr;
705 activeAdapter->Release();
706 activeAdapter =
nullptr;
710 dxgiFactory->Release();
711 dxgiFactory =
nullptr;
714 QDxgiVSyncService::instance()->derefAdapter(adapterLuid);
717 importedDevice =
false;
718 importedCommandQueue =
false;
720 if (drawCommandSignature) {
721 drawCommandSignature->Release();
722 drawCommandSignature =
nullptr;
725 if (drawIndexedCommandSignature) {
726 drawIndexedCommandSignature->Release();
727 drawIndexedCommandSignature =
nullptr;
730 destroyPipelineLibrary();
733QRhi::AdapterList QRhiD3D12::enumerateAdaptersBeforeCreate(QRhiNativeHandles *nativeHandles)
const
735 LUID requestedLuid = {};
737 QRhiD3D12NativeHandles *h =
static_cast<QRhiD3D12NativeHandles *>(nativeHandles);
738 const LUID adapterLuid = { h->adapterLuidLow, h->adapterLuidHigh };
739 if (adapterLuid.LowPart || adapterLuid.HighPart)
740 requestedLuid = adapterLuid;
743 IDXGIFactory2 *dxgi =
nullptr;
744 if (FAILED(CreateDXGIFactory2(0, __uuidof(IDXGIFactory2),
reinterpret_cast<
void **>(&dxgi))))
747 QRhi::AdapterList list;
748 IDXGIAdapter1 *adapter;
749 for (
int adapterIndex = 0; dxgi->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
750 DXGI_ADAPTER_DESC1 desc;
751 adapter->GetDesc1(&desc);
753 if (requestedLuid.LowPart || requestedLuid.HighPart) {
754 if (desc.AdapterLuid.LowPart != requestedLuid.LowPart
755 || desc.AdapterLuid.HighPart != requestedLuid.HighPart)
760 QD3D12Adapter *a =
new QD3D12Adapter;
761 a->luid = desc.AdapterLuid;
762 QRhiD3D::fillDriverInfo(&a->adapterInfo, desc);
770QRhiDriverInfo QD3D12Adapter::info()
const
775QList<
int> QRhiD3D12::supportedSampleCounts()
const
777 return { 1, 2, 4, 8 };
780QList<QSize> QRhiD3D12::supportedShadingRates(
int sampleCount)
const
783 switch (sampleCount) {
786 if (caps.vrsAdditionalRates) {
787 sizes.append(QSize(4, 4));
788 sizes.append(QSize(4, 2));
789 sizes.append(QSize(2, 4));
791 sizes.append(QSize(2, 2));
792 sizes.append(QSize(2, 1));
793 sizes.append(QSize(1, 2));
796 if (caps.vrsAdditionalRates)
797 sizes.append(QSize(2, 4));
798 sizes.append(QSize(2, 2));
799 sizes.append(QSize(2, 1));
800 sizes.append(QSize(1, 2));
803 sizes.append(QSize(2, 2));
804 sizes.append(QSize(2, 1));
805 sizes.append(QSize(1, 2));
810 sizes.append(QSize(1, 1));
814QRhiSwapChain *QRhiD3D12::createSwapChain()
816 return new QD3D12SwapChain(
this);
819QRhiBuffer *QRhiD3D12::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
821 return new QD3D12Buffer(
this, type, usage, size);
824int QRhiD3D12::ubufAlignment()
const
826 return D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
829bool QRhiD3D12::isYUpInFramebuffer()
const
834bool QRhiD3D12::isYUpInNDC()
const
839bool QRhiD3D12::isClipDepthZeroToOne()
const
844QMatrix4x4 QRhiD3D12::clipSpaceCorrMatrix()
const
849 static constexpr QMatrix4x4 m(1.0f, 0.0f, 0.0f, 0.0f,
850 0.0f, 1.0f, 0.0f, 0.0f,
851 0.0f, 0.0f, 0.5f, 0.5f,
852 0.0f, 0.0f, 0.0f, 1.0f);
856bool QRhiD3D12::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags)
const
860 if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ASTC_12x12)
866bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature)
const
869 case QRhi::MultisampleTexture:
871 case QRhi::MultisampleRenderBuffer:
873 case QRhi::DebugMarkers:
874#ifdef QRHI_D3D12_HAS_OLD_PIX
879 case QRhi::Timestamps:
881 case QRhi::Instancing:
883 case QRhi::CustomInstanceStepRate:
885 case QRhi::PrimitiveRestart:
887 case QRhi::NonDynamicUniformBuffers:
889 case QRhi::NonFourAlignedEffectiveIndexBufferOffset:
891 case QRhi::NPOTTextureRepeat:
893 case QRhi::RedOrAlpha8IsRed:
895 case QRhi::ElementIndexUint:
899 case QRhi::WideLines:
901 case QRhi::VertexShaderPointSize:
903 case QRhi::BaseVertex:
905 case QRhi::BaseInstance:
907 case QRhi::TriangleFanTopology:
909 case QRhi::ReadBackNonUniformBuffer:
911 case QRhi::ReadBackNonBaseMipLevel:
913 case QRhi::TexelFetch:
915 case QRhi::RenderToNonBaseMipLevel:
917 case QRhi::IntAttributes:
919 case QRhi::ScreenSpaceDerivatives:
921 case QRhi::ReadBackAnyTextureFormat:
923 case QRhi::PipelineCacheDataLoadSave:
924#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
929 case QRhi::ImageDataStride:
931 case QRhi::RenderBufferImport:
933 case QRhi::ThreeDimensionalTextures:
935 case QRhi::RenderTo3DTextureSlice:
937 case QRhi::TextureArrays:
939 case QRhi::Tessellation:
941 case QRhi::GeometryShader:
943 case QRhi::TextureArrayRange:
945 case QRhi::NonFillPolygonMode:
947 case QRhi::OneDimensionalTextures:
949 case QRhi::OneDimensionalTextureMipmaps:
951 case QRhi::HalfAttributes:
953 case QRhi::RenderToOneDimensionalTexture:
955 case QRhi::ThreeDimensionalTextureMipmaps:
957 case QRhi::MultiView:
958 return caps.multiView;
959 case QRhi::TextureViewFormat:
960 return caps.textureViewFormat;
961 case QRhi::ResolveDepthStencil:
965 case QRhi::VariableRateShading:
967 case QRhi::VariableRateShadingMap:
968 case QRhi::VariableRateShadingMapWithTexture:
970 case QRhi::PerRenderTargetBlending:
971 case QRhi::SampleVariables:
973 case QRhi::InstanceIndexIncludesBaseInstance:
975 case QRhi::DepthClamp:
977 case QRhi::DrawIndirect:
978 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
979 case QRhi::DrawIndirectMulti:
980 return drawCommandSignature !=
nullptr && drawIndexedCommandSignature !=
nullptr;
981 case QRhi::ShaderDrawParameters:
987int QRhiD3D12::resourceLimit(QRhi::ResourceLimit limit)
const
990 case QRhi::TextureSizeMin:
992 case QRhi::TextureSizeMax:
994 case QRhi::MaxColorAttachments:
996 case QRhi::FramesInFlight:
997 return QD3D12_FRAMES_IN_FLIGHT;
998 case QRhi::MaxAsyncReadbackFrames:
999 return QD3D12_FRAMES_IN_FLIGHT;
1000 case QRhi::MaxThreadGroupsPerDimension:
1002 case QRhi::MaxThreadsPerThreadGroup:
1004 case QRhi::MaxThreadGroupX:
1006 case QRhi::MaxThreadGroupY:
1008 case QRhi::MaxThreadGroupZ:
1010 case QRhi::TextureArraySizeMax:
1012 case QRhi::MaxUniformBufferRange:
1014 case QRhi::MaxVertexInputs:
1016 case QRhi::MaxVertexOutputs:
1018 case QRhi::ShadingRateImageTileSize:
1019 return shadingRateImageTileSize;
1024const QRhiNativeHandles *QRhiD3D12::nativeHandles()
1026 return &nativeHandlesStruct;
1029QRhiDriverInfo QRhiD3D12::driverInfo()
const
1031 return driverInfoStruct;
1034QRhiStats QRhiD3D12::statistics()
1037 result.totalPipelineCreationTime = totalPipelineCreationTime();
1039 D3D12MA::Budget budgets[2];
1040 vma.getBudget(&budgets[0], &budgets[1]);
1041 for (
int i = 0; i < 2; ++i) {
1042 const D3D12MA::Statistics &stats(budgets[i].Stats);
1043 result.blockCount += stats.BlockCount;
1044 result.allocCount += stats.AllocationCount;
1045 result.usedBytes += stats.AllocationBytes;
1046 result.unusedBytes += stats.BlockBytes - stats.AllocationBytes;
1047 result.totalUsageBytes += budgets[i].UsageBytes;
1053bool QRhiD3D12::makeThreadLocalNativeContextCurrent()
1059void QRhiD3D12::setQueueSubmitParams(QRhiNativeHandles *)
1064void QRhiD3D12::releaseCachedResources()
1066 shaderBytecodeCache.data.clear();
1075static inline void addToKey(QCryptographicHash *h,
const void *p, size_t size)
1077 h->addData(QByteArrayView(
static_cast<
const char *>(p), qsizetype(size)));
1081static inline void addToKey(QCryptographicHash *h,
const T &v)
1083 addToKey(h, &v,
sizeof(T));
1086static inline void addToKey(QCryptographicHash *h,
const QByteArray &b)
1088 const quint32 size = quint32(b.size());
1093static inline void addToKey(QCryptographicHash *h,
const QVector<quint32> &v)
1095 const quint32 count = quint32(v.count());
1097 addToKey(h, v.constData(), v.count() *
sizeof(quint32));
1100bool QRhiD3D12::createPipelineLibrary(
const QByteArray &blob)
1102#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1103 destroyPipelineLibrary();
1105 pipelineLibraryBlob = blob;
1106 HRESULT hr = dev->CreatePipelineLibrary(pipelineLibraryBlob.isEmpty() ?
nullptr
1107 : pipelineLibraryBlob.constData(),
1108 SIZE_T(pipelineLibraryBlob.size()),
1109 __uuidof(ID3D12PipelineLibrary1),
1110 reinterpret_cast<
void **>(&pipelineLibrary));
1116 qCDebug(QRHI_LOG_INFO,
"Failed to create pipeline library: %s",
1117 qPrintable(QSystemError::windowsComString(hr)));
1118 pipelineLibrary =
nullptr;
1119 pipelineLibraryBlob.clear();
1129bool QRhiD3D12::ensurePipelineLibrary()
1131#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1132 if (pipelineLibrary)
1134 if (!rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
1136 return createPipelineLibrary(QByteArray());
1142void QRhiD3D12::destroyPipelineLibrary()
1144#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1145 if (pipelineLibrary) {
1146 pipelineLibrary->Release();
1147 pipelineLibrary =
nullptr;
1149 pipelineLibraryBlob.clear();
1150 pipelineLibraryNames.clear();
1154ID3D12PipelineState *QRhiD3D12::loadOrCreatePipelineState(
const D3D12_PIPELINE_STATE_STREAM_DESC *streamDesc,
1155 const QByteArray &cacheKey,
1158 ID3D12PipelineState *pso =
nullptr;
1160#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1161 QVarLengthArray<
wchar_t, 64> name;
1162 if (ensurePipelineLibrary() && !cacheKey.isEmpty()) {
1163 name.resize(cacheKey.size() + 1);
1164 for (qsizetype i = 0; i < cacheKey.size(); ++i)
1165 name[i] =
wchar_t(cacheKey.at(i));
1166 name[cacheKey.size()] = 0;
1167 HRESULT hr = pipelineLibrary->LoadPipeline(name.constData(),
1169 __uuidof(ID3D12PipelineState),
1170 reinterpret_cast<
void **>(&pso));
1176 HRESULT hr = dev->CreatePipelineState(streamDesc,
1177 __uuidof(ID3D12PipelineState),
1178 reinterpret_cast<
void **>(&pso));
1180 qWarning(
"Failed to create %s pipeline state: %s",
1181 what, qPrintable(QSystemError::windowsComString(hr)));
1185#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1186 if (pipelineLibrary && !name.isEmpty() && !pipelineLibraryNames.contains(cacheKey)) {
1187 if (SUCCEEDED(pipelineLibrary->StorePipeline(name.constData(), pso)))
1188 pipelineLibraryNames.insert(cacheKey);
1195struct QD3D12PipelineCacheDataHeader
1203 quint64 adapterLuid;
1206QByteArray QRhiD3D12::pipelineCacheData()
1208 static_assert(
sizeof(QD3D12PipelineCacheDataHeader) == 32);
1211#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1212 if (!pipelineLibrary || !rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
1215 const SIZE_T dataSize = pipelineLibrary->GetSerializedSize();
1219 const size_t headerSize =
sizeof(QD3D12PipelineCacheDataHeader);
1220 data.resize(qsizetype(headerSize + dataSize));
1221 HRESULT hr = pipelineLibrary->Serialize(data.data() + headerSize, dataSize);
1223 qCDebug(QRHI_LOG_INFO,
"Failed to serialize pipeline library: %s",
1224 qPrintable(QSystemError::windowsComString(hr)));
1225 return QByteArray();
1228 QD3D12PipelineCacheDataHeader header = {};
1229 header.rhiId = pipelineCacheRhiId();
1230 header.arch = quint32(
sizeof(
void *));
1231 header.dataSize = quint32(dataSize);
1232 header.vendorId = quint32(driverInfoStruct.vendorId);
1233 header.deviceId = quint32(driverInfoStruct.deviceId);
1234 header.adapterLuid = (quint64(quint32(adapterLuid.HighPart)) << 32) | quint64(adapterLuid.LowPart);
1235 memcpy(data.data(), &header, headerSize);
1240void QRhiD3D12::setPipelineCacheData(
const QByteArray &data)
1242#ifdef QRHI_D3D12_PIPELINE_LIBRARY_AVAILABLE
1246 const size_t headerSize =
sizeof(QD3D12PipelineCacheDataHeader);
1247 if (data.size() < qsizetype(headerSize)) {
1248 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob size");
1251 QD3D12PipelineCacheDataHeader header;
1252 memcpy(&header, data.constData(), headerSize);
1254 const quint32 rhiId = pipelineCacheRhiId();
1255 if (header.rhiId != rhiId) {
1256 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
1257 rhiId, header.rhiId);
1260 const quint32 arch = quint32(
sizeof(
void *));
1261 if (header.arch != arch) {
1262 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Architecture does not match (%u, %u)",
1266 if (header.vendorId != quint32(driverInfoStruct.vendorId)) {
1267 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: vendorId does not match (%u, %u)",
1268 quint32(driverInfoStruct.vendorId), header.vendorId);
1271 if (header.deviceId != quint32(driverInfoStruct.deviceId)) {
1272 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: deviceId does not match (%u, %u)",
1273 quint32(driverInfoStruct.deviceId), header.deviceId);
1276 const quint64 luid = (quint64(quint32(adapterLuid.HighPart)) << 32) | quint64(adapterLuid.LowPart);
1277 if (header.adapterLuid != luid) {
1278 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: adapter LUID does not match");
1281 if (quint64(data.size()) < quint64(headerSize) + header.dataSize) {
1282 qCDebug(QRHI_LOG_INFO,
"setPipelineCacheData: Invalid blob, data missing");
1289 if (createPipelineLibrary(data.mid(qsizetype(headerSize)))) {
1290 qCDebug(QRHI_LOG_INFO,
"Created pipeline library with initial data of %u bytes",
1298bool QRhiD3D12::isDeviceLost()
const
1303QRhiRenderBuffer *QRhiD3D12::createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
1304 int sampleCount, QRhiRenderBuffer::Flags flags,
1305 QRhiTexture::Format backingFormatHint)
1307 return new QD3D12RenderBuffer(
this, type, pixelSize, sampleCount, flags, backingFormatHint);
1310QRhiTexture *QRhiD3D12::createTexture(QRhiTexture::Format format,
1311 const QSize &pixelSize,
int depth,
int arraySize,
1312 int sampleCount, QRhiTexture::Flags flags)
1314 return new QD3D12Texture(
this, format, pixelSize, depth, arraySize, sampleCount, flags);
1317QRhiSampler *QRhiD3D12::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
1318 QRhiSampler::Filter mipmapMode,
1319 QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
1321 return new QD3D12Sampler(
this, magFilter, minFilter, mipmapMode, u, v, w);
1324QRhiTextureRenderTarget *QRhiD3D12::createTextureRenderTarget(
const QRhiTextureRenderTargetDescription &desc,
1325 QRhiTextureRenderTarget::Flags flags)
1327 return new QD3D12TextureRenderTarget(
this, desc, flags);
1330QRhiShadingRateMap *QRhiD3D12::createShadingRateMap()
1332 return new QD3D12ShadingRateMap(
this);
1335QRhiGraphicsPipeline *QRhiD3D12::createGraphicsPipeline()
1337 return new QD3D12GraphicsPipeline(
this);
1340QRhiComputePipeline *QRhiD3D12::createComputePipeline()
1342 return new QD3D12ComputePipeline(
this);
1345QRhiShaderResourceBindings *QRhiD3D12::createShaderResourceBindings()
1347 return new QD3D12ShaderResourceBindings(
this);
1350void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
1352 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1353 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1354 QD3D12GraphicsPipeline *psD = QRHI_RES(QD3D12GraphicsPipeline, ps);
1355 const bool pipelineChanged = cbD->currentGraphicsPipeline != psD || cbD->currentPipelineGeneration != psD->generation;
1357 if (pipelineChanged) {
1358 cbD->currentGraphicsPipeline = psD;
1359 cbD->currentComputePipeline =
nullptr;
1360 cbD->currentPipelineGeneration = psD->generation;
1362 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
1363 Q_ASSERT(pipeline->type == QD3D12Pipeline::Graphics);
1364 cbD->cmdList->SetPipelineState(pipeline->pso);
1365 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
1366 cbD->cmdList->SetGraphicsRootSignature(rs->rootSig);
1369 cbD->cmdList->IASetPrimitiveTopology(psD->topology);
1371 if (psD->viewInstanceMask)
1372 cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
1374 if (cbD->hasCustomScissorSet && !psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor))
1375 setDefaultScissor(cbD);
1379void QD3D12ShaderResourceBindings::cacheUniformBuffer(QD3D12Stage s,
1380 const QRhiShaderResourceBinding::Data::UniformBufferData &d,
1387 bindingCache.cbufs[s].append({ QRHI_RES(QD3D12Buffer, d.buf), d.offset, binding });
1390void QD3D12ShaderResourceBindings::cacheTextures(QD3D12Stage s,
1391 const QRhiShaderResourceBinding::TextureAndSampler *d,
1395 for (
int i = 0; i < count; ++i) {
1396 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d[i].tex);
1397 bindingCache.srvs[s].append(texD->srv.cpuHandle);
1401void QD3D12ShaderResourceBindings::cacheSamplers(QD3D12Stage s,
1402 const QRhiShaderResourceBinding::TextureAndSampler *d,
1407 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, d[0].sampler);
1408 bindingCache.samplers[s].append(samplerD->lookupOrCreateShaderVisibleDescriptor().gpuHandle);
1416 QRHI_RES_RHI(QRhiD3D12);
1417 QVarLengthArray<Q_D3D12_SAMPLER_DESC, 8> descs;
1418 for (
int i = 0; i < count; ++i)
1419 descs.append({ QRHI_RES(QD3D12Sampler, d[i].sampler)->desc });
1420 bindingCache.samplers[s].append(rhiD->samplerMgr.getShaderVisibleDescriptors(descs).gpuHandle);
1423void QD3D12ShaderResourceBindings::cacheStorageBuffer(QD3D12Stage s,
1424 const QRhiShaderResourceBinding::Data::StorageBufferData &d,
1425 QD3D12ShaderResourceVisitor::StorageOp,
1428 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
1430 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1431 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1432 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
1433 uavDesc.Buffer.FirstElement = d.offset / 4;
1434 uavDesc.Buffer.NumElements = aligned(bufD->m_size - d.offset, 4u) / 4;
1435 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
1436 bindingCache.uavs[s].append({ bufD->handles[0], uavDesc });
1439void QD3D12ShaderResourceBindings::cacheStorageImage(QD3D12Stage s,
1440 const QRhiShaderResourceBinding::Data::StorageImageData &d,
1441 QD3D12ShaderResourceVisitor::StorageOp,
1444 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
1445 const bool isCube = texD->m_flags.testFlag(QRhiTexture::CubeMap);
1446 const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
1447 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1448 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
1449 uavDesc.Format = texD->rtFormat;
1451 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1452 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1453 uavDesc.Texture2DArray.FirstArraySlice = 0;
1454 uavDesc.Texture2DArray.ArraySize = 6;
1455 }
else if (isArray) {
1456 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1457 uavDesc.Texture2DArray.MipSlice = UINT(d.level);
1458 uavDesc.Texture2DArray.FirstArraySlice = 0;
1459 uavDesc.Texture2DArray.ArraySize = UINT(qMax(0, texD->m_arraySize));
1461 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1462 uavDesc.Texture3D.MipSlice = UINT(d.level);
1463 uavDesc.Texture3D.WSize = UINT(-1);
1465 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
1466 uavDesc.Texture2D.MipSlice = UINT(d.level);
1468 bindingCache.uavs[s].append({ texD->handle, uavDesc });
1471void QD3D12ShaderResourceBindings::rebuildBindingCache(
const QD3D12ShaderStageData *stageData,
1474 bindingCache.reset();
1476 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
1478 using namespace std::placeholders;
1479 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::cacheUniformBuffer,
this, _1, _2, _3, _4);
1480 visitor.textures = std::bind(&QD3D12ShaderResourceBindings::cacheTextures,
this, _1, _2, _3, _4);
1481 visitor.samplers = std::bind(&QD3D12ShaderResourceBindings::cacheSamplers,
this, _1, _2, _3, _4);
1482 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::cacheStorageBuffer,
this, _1, _2, _3, _4);
1483 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::cacheStorageImage,
this, _1, _2, _3, _4);
1488 for (
int s = 0; s < 6; ++s) {
1489 bindingCache.srvUavCount += bindingCache.srvs[s].count();
1490 bindingCache.srvUavCount += bindingCache.uavs[s].count();
1493 bindingCacheValid =
true;
1494 bindingCacheGeneration = generation;
1497void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
1498 int dynamicOffsetCount,
1499 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
1501 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1502 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
1503 QD3D12GraphicsPipeline *gfxPsD = QRHI_RES(QD3D12GraphicsPipeline, cbD->currentGraphicsPipeline);
1504 QD3D12ComputePipeline *compPsD = QRHI_RES(QD3D12ComputePipeline, cbD->currentComputePipeline);
1508 srb = gfxPsD->m_shaderResourceBindings;
1510 srb = compPsD->m_shaderResourceBindings;
1513 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, srb);
1515 bool pipelineChanged =
false;
1517 pipelineChanged = srbD->lastUsedGraphicsPipeline != gfxPsD
1518 || srbD->lastUsedPipelineGeneration != gfxPsD->generation;
1519 srbD->lastUsedGraphicsPipeline = gfxPsD;
1520 srbD->lastUsedComputePipeline =
nullptr;
1521 srbD->lastUsedPipelineGeneration = gfxPsD->generation;
1523 pipelineChanged = srbD->lastUsedComputePipeline != compPsD
1524 || srbD->lastUsedPipelineGeneration != compPsD->generation;
1525 srbD->lastUsedGraphicsPipeline =
nullptr;
1526 srbD->lastUsedComputePipeline = compPsD;
1527 srbD->lastUsedPipelineGeneration = compPsD->generation;
1530 bool srbUpdate =
false;
1532 for (
int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
1533 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings[i]);
1534 QD3D12ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
1536 case QRhiShaderResourceBinding::UniformBuffer:
1538 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.ubuf.buf);
1539 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
1540 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1541 sanityCheckResourceOwnership(bufD);
1542 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1543 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
1545 bd.ubuf.id = bufD->m_id;
1546 bd.ubuf.generation = bufD->generation;
1550 case QRhiShaderResourceBinding::SampledTexture:
1551 case QRhiShaderResourceBinding::Texture:
1552 case QRhiShaderResourceBinding::Sampler:
1554 const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
1555 if (bd.stex.count != data->count) {
1556 bd.stex.count = data->count;
1559 for (
int elem = 0; elem < data->count; ++elem) {
1560 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, data->texSamplers[elem].tex);
1561 QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, data->texSamplers[elem].sampler);
1565 Q_ASSERT(texD || samplerD);
1566 sanityCheckResourceOwnership(texD);
1567 sanityCheckResourceOwnership(samplerD);
1568 const quint64 texId = texD ? texD->m_id : 0;
1569 const uint texGen = texD ? texD->generation : 0;
1570 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
1571 const uint samplerGen = samplerD ? samplerD->generation : 0;
1572 if (texId != bd.stex.d[elem].texId || texGen != bd.stex.d[elem].texGeneration
1573 || samplerId != bd.stex.d[elem].samplerId
1574 || samplerGen != bd.stex.d[elem].samplerGeneration)
1577 bd.stex.d[elem].texId = texId;
1578 bd.stex.d[elem].texGeneration = texGen;
1579 bd.stex.d[elem].samplerId = samplerId;
1580 bd.stex.d[elem].samplerGeneration = samplerGen;
1584 if (b->stage == QRhiShaderResourceBinding::FragmentStage) {
1585 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1586 }
else if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
1587 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1589 state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
1591 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATES(state));
1596 case QRhiShaderResourceBinding::ImageLoad:
1597 case QRhiShaderResourceBinding::ImageStore:
1598 case QRhiShaderResourceBinding::ImageLoadStore:
1600 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, b->u.simage.tex);
1601 sanityCheckResourceOwnership(texD);
1602 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
1604 bd.simage.id = texD->m_id;
1605 bd.simage.generation = texD->generation;
1607 if (QD3D12Resource *res = resourcePool.lookupRef(texD->handle)) {
1608 if (res->uavUsage) {
1609 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1611 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1613 if (b->type == QRhiShaderResourceBinding::ImageStore
1614 || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1617 barrierGen.enqueueUavBarrier(cbD, texD->handle);
1622 if (b->type == QRhiShaderResourceBinding::ImageLoad || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1623 res->uavUsage |= QD3D12Resource::UavUsageRead;
1624 if (b->type == QRhiShaderResourceBinding::ImageStore || b->type == QRhiShaderResourceBinding::ImageLoadStore)
1625 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1626 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1630 case QRhiShaderResourceBinding::BufferLoad:
1631 case QRhiShaderResourceBinding::BufferStore:
1632 case QRhiShaderResourceBinding::BufferLoadStore:
1634 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.sbuf.buf);
1635 sanityCheckResourceOwnership(bufD);
1636 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
1637 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1638 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
1640 bd.sbuf.id = bufD->m_id;
1641 bd.sbuf.generation = bufD->generation;
1643 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
1644 if (res->uavUsage) {
1645 if (res->uavUsage & QD3D12Resource::UavUsageWrite) {
1647 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1649 if (b->type == QRhiShaderResourceBinding::BufferStore
1650 || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1653 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1658 if (b->type == QRhiShaderResourceBinding::BufferLoad || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1659 res->uavUsage |= QD3D12Resource::UavUsageRead;
1660 if (b->type == QRhiShaderResourceBinding::BufferStore || b->type == QRhiShaderResourceBinding::BufferLoadStore)
1661 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1662 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1669 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1670 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1678 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1684 if (pipelineChanged || srbUpdate || !srbD->bindingCacheValid
1685 || srbD->bindingCacheGeneration != srbD->generation)
1687 const QD3D12ShaderStageData *stageData = gfxPsD ? gfxPsD->stageData.data() : &compPsD->stageData;
1688 srbD->rebuildBindingCache(stageData, gfxPsD ? 5 : 1);
1691 if (pipelineChanged || srbChanged || srbRebuilt || srbUpdate || srbD->hasDynamicOffset) {
1696 const QD3D12ShaderResourceBindings::BindingCache &cache(srbD->bindingCache);
1698 bool gotNewHeap =
false;
1699 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
1700 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1708 qCDebug(QRHI_LOG_INFO,
"Created new shader-visible CBV/SRV/UAV descriptor heap,"
1709 " per-frame slice size is now %u,"
1710 " if this happens frequently then that's not great.",
1711 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[0].capacity);
1712 bindShaderVisibleHeaps(cbD);
1715 int rootParamIndex = 0;
1716 for (
int s = 0; s < 6; ++s) {
1717 for (
const QD3D12ShaderResourceBindings::BindingCache::CBuf &cbuf : cache.cbufs[s]) {
1718 if (QD3D12Resource *res = resourcePool.lookupRef(cbuf.buf->handles[currentFrameSlot])) {
1719 quint32 offset = cbuf.offset;
1720 if (srbD->hasDynamicOffset) {
1721 for (
int i = 0; i < dynamicOffsetCount; ++i) {
1722 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1723 if (dynOfs.first == cbuf.binding) {
1724 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1725 offset += dynOfs.second;
1729 const D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = res->resource->GetGPUVirtualAddress() + offset;
1731 cbD->cmdList->SetGraphicsRootConstantBufferView(rootParamIndex, gpuAddr);
1733 cbD->cmdList->SetComputeRootConstantBufferView(rootParamIndex, gpuAddr);
1735 rootParamIndex += 1;
1738 for (
int s = 0; s < 6; ++s) {
1739 if (!cache.srvs[s].isEmpty()) {
1740 QD3D12DescriptorHeap &gpuSrvHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1741 const UINT count = UINT(cache.srvs[s].count());
1742 const QD3D12Descriptor startDesc = gpuSrvHeap.get(count);
1745 dev->CopyDescriptors(1, &startDesc.cpuHandle, &count,
1746 count, cache.srvs[s].constData(),
nullptr,
1747 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1750 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1752 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1754 rootParamIndex += 1;
1757 for (
int s = 0; s < 6; ++s) {
1760 for (D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor : cache.samplers[s]) {
1762 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerDescriptor);
1764 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, samplerDescriptor);
1766 rootParamIndex += 1;
1769 for (
int s = 0; s < 6; ++s) {
1770 if (!cache.uavs[s].isEmpty()) {
1771 QD3D12DescriptorHeap &gpuUavHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1772 const int count = cache.uavs[s].count();
1773 const QD3D12Descriptor startDesc = gpuUavHeap.get(count);
1774 for (
int i = 0; i < count; ++i) {
1775 const QD3D12ShaderResourceBindings::BindingCache::Uav &uav(cache.uavs[s][i]);
1776 if (QD3D12Resource *res = resourcePool.lookupRef(uav.handle)) {
1777 dev->CreateUnorderedAccessView(res->resource,
nullptr, &uav.desc,
1778 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1780 dev->CreateUnorderedAccessView(
nullptr,
nullptr,
nullptr,
1781 gpuUavHeap.incremented(startDesc, i).cpuHandle);
1786 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1788 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1790 rootParamIndex += 1;
1795 cbD->currentGraphicsSrb = srb;
1796 cbD->currentComputeSrb =
nullptr;
1798 cbD->currentGraphicsSrb =
nullptr;
1799 cbD->currentComputeSrb = srb;
1801 cbD->currentSrbGeneration = srbD->generation;
1805void QRhiD3D12::setVertexInput(QRhiCommandBuffer *cb,
1806 int startBinding,
int bindingCount,
const QRhiCommandBuffer::VertexInput *bindings,
1807 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1809 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1810 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1812 bool needsBindVBuf =
false;
1813 for (
int i = 0; i < bindingCount; ++i) {
1814 const int inputSlot = startBinding + i;
1815 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1816 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1817 const bool isDynamic = bufD->m_type == QRhiBuffer::Dynamic;
1819 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1821 if (cbD->currentVertexBuffers[inputSlot] != bufD->handles[isDynamic ? currentFrameSlot : 0]
1822 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1824 needsBindVBuf =
true;
1825 cbD->currentVertexBuffers[inputSlot] = bufD->handles[isDynamic ? currentFrameSlot : 0];
1826 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1830 if (needsBindVBuf) {
1831 QVarLengthArray<D3D12_VERTEX_BUFFER_VIEW, 4> vbv;
1832 vbv.reserve(bindingCount);
1834 QD3D12GraphicsPipeline *psD = cbD->currentGraphicsPipeline;
1835 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1836 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1838 for (
int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1839 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, bindings[i].first);
1840 const QD3D12ObjectHandle handle = bufD->handles[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
1841 const quint32 offset = bindings[i].second;
1842 const quint32 stride = inputLayout.bindingAt(i)->stride();
1844 if (bufD->m_type != QRhiBuffer::Dynamic) {
1845 barrierGen.addTransitionBarrier(handle, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
1846 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1849 if (QD3D12Resource *res = resourcePool.lookupRef(handle)) {
1851 res->resource->GetGPUVirtualAddress() + offset,
1852 UINT(res->desc.Width - offset),
1858 cbD->cmdList->IASetVertexBuffers(UINT(startBinding), vbv.count(), vbv.constData());
1862 QD3D12Buffer *ibufD = QRHI_RES(QD3D12Buffer, indexBuf);
1863 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1864 const bool isDynamic = ibufD->m_type == QRhiBuffer::Dynamic;
1866 ibufD->executeHostWritesForFrameSlot(currentFrameSlot);
1868 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1869 : DXGI_FORMAT_R32_UINT;
1870 if (cbD->currentIndexBuffer != ibufD->handles[isDynamic ? currentFrameSlot : 0]
1871 || cbD->currentIndexOffset != indexOffset
1872 || cbD->currentIndexFormat != dxgiFormat)
1874 cbD->currentIndexBuffer = ibufD->handles[isDynamic ? currentFrameSlot : 0];
1875 cbD->currentIndexOffset = indexOffset;
1876 cbD->currentIndexFormat = dxgiFormat;
1878 if (ibufD->m_type != QRhiBuffer::Dynamic) {
1879 barrierGen.addTransitionBarrier(cbD->currentIndexBuffer, D3D12_RESOURCE_STATE_INDEX_BUFFER);
1880 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1883 if (QD3D12Resource *res = resourcePool.lookupRef(cbD->currentIndexBuffer)) {
1884 const D3D12_INDEX_BUFFER_VIEW ibv = {
1885 res->resource->GetGPUVirtualAddress() + indexOffset,
1886 UINT(res->desc.Width - indexOffset),
1889 cbD->cmdList->IASetIndexBuffer(&ibv);
1895void QRhiD3D12::setDefaultScissor(QD3D12CommandBuffer *cbD)
1897 cbD->hasCustomScissorSet =
false;
1899 const QSize outputSize = cbD->currentTarget->pixelSize();
1900 std::array<
float, 4> vp = cbD->currentViewport.viewport();
1901 float x = 0, y = 0, w = 0, h = 0;
1903 if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) {
1906 w = outputSize.width();
1907 h = outputSize.height();
1910 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, vp, &x, &y, &w, &h);
1919 cbD->cmdList->RSSetScissorRects(1, &r);
1922void QRhiD3D12::setViewport(QRhiCommandBuffer *cb,
const QRhiViewport &viewport)
1924 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1925 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1926 Q_ASSERT(cbD->currentTarget);
1927 const QSize outputSize = cbD->currentTarget->pixelSize();
1931 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1939 v.MinDepth = viewport.minDepth();
1940 v.MaxDepth = viewport.maxDepth();
1941 cbD->cmdList->RSSetViewports(1, &v);
1943 cbD->currentViewport = viewport;
1944 if (cbD->currentGraphicsPipeline
1945 && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor))
1947 setDefaultScissor(cbD);
1951void QRhiD3D12::setScissor(QRhiCommandBuffer *cb,
const QRhiScissor &scissor)
1953 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1954 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1955 Q_ASSERT(cbD->currentTarget);
1956 const QSize outputSize = cbD->currentTarget->pixelSize();
1960 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
1969 cbD->cmdList->RSSetScissorRects(1, &r);
1971 cbD->hasCustomScissorSet =
true;
1974void QRhiD3D12::setBlendConstants(QRhiCommandBuffer *cb,
const QColor &c)
1976 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1977 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1978 float v[4] = { c.redF(), c.greenF(), c.blueF(), c.alphaF() };
1979 cbD->cmdList->OMSetBlendFactor(v);
1982void QRhiD3D12::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
1984 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
1985 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1986 cbD->cmdList->OMSetStencilRef(refValue);
1989static inline D3D12_SHADING_RATE toD3DShadingRate(
const QSize &coarsePixelSize)
1991 if (coarsePixelSize == QSize(1, 2))
1992 return D3D12_SHADING_RATE_1X2;
1993 if (coarsePixelSize == QSize(2, 1))
1994 return D3D12_SHADING_RATE_2X1;
1995 if (coarsePixelSize == QSize(2, 2))
1996 return D3D12_SHADING_RATE_2X2;
1997 if (coarsePixelSize == QSize(2, 4))
1998 return D3D12_SHADING_RATE_2X4;
1999 if (coarsePixelSize == QSize(4, 2))
2000 return D3D12_SHADING_RATE_4X2;
2001 if (coarsePixelSize == QSize(4, 4))
2002 return D3D12_SHADING_RATE_4X4;
2003 return D3D12_SHADING_RATE_1X1;
2006void QRhiD3D12::setShadingRate(QRhiCommandBuffer *cb,
const QSize &coarsePixelSize)
2008 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2009 cbD->hasShadingRateSet =
false;
2011#ifdef QRHI_D3D12_CL5_AVAILABLE
2015 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2016 const D3D12_SHADING_RATE_COMBINER combiners[] = { D3D12_SHADING_RATE_COMBINER_MAX, D3D12_SHADING_RATE_COMBINER_MAX };
2017 cbD->cmdList->RSSetShadingRate(toD3DShadingRate(coarsePixelSize), combiners);
2018 if (coarsePixelSize.width() != 1 || coarsePixelSize.height() != 1)
2019 cbD->hasShadingRateSet =
true;
2022 Q_UNUSED(coarsePixelSize);
2023 qWarning(
"Attempted to set ShadingRate without building Qt against a sufficiently new Windows SDK and d3d12.h. This cannot work.");
2027void QRhiD3D12::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
2028 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
2030 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2031 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2032 cbD->cmdList->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
2035void QRhiD3D12::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
2036 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
2038 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2039 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2040 cbD->cmdList->DrawIndexedInstanced(indexCount, instanceCount,
2041 firstIndex, vertexOffset,
2045void QRhiD3D12::drawIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
2046 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
2048 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2049 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2051 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2052 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2053 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
2055 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2057 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2058 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2060 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
2063 ID3D12Resource *indirectBufferRes = indirectRes->resource;
2065 const bool canUseMulti = (stride ==
sizeof(QRhiIndirectDrawCommand) && drawCommandSignature);
2067 if (canUseMulti && drawCount > 1) {
2068 cbD->cmdList->ExecuteIndirect(drawCommandSignature, drawCount,
2069 indirectBufferRes, indirectBufferOffset,
2072 UINT offset = indirectBufferOffset;
2073 for (quint32 i = 0; i < drawCount; ++i) {
2074 cbD->cmdList->ExecuteIndirect(drawCommandSignature, 1,
2075 indirectBufferRes, offset,
2082void QRhiD3D12::drawIndexedIndirect(QRhiCommandBuffer *cb, QRhiBuffer *indirectBuffer,
2083 quint32 indirectBufferOffset, quint32 drawCount, quint32 stride)
2085 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2086 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2088 QD3D12Buffer *indirectBufferD = QRHI_RES(QD3D12Buffer, indirectBuffer);
2089 const bool isDynamic = indirectBufferD->m_type == QRhiBuffer::Dynamic;
2090 const QD3D12ObjectHandle indirectBufferHandle = indirectBufferD->handles[isDynamic ? currentFrameSlot : 0];
2092 indirectBufferD->executeHostWritesForFrameSlot(currentFrameSlot);
2094 barrierGen.addTransitionBarrier(indirectBufferHandle, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
2095 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2097 QD3D12Resource *indirectRes = resourcePool.lookupRef(indirectBufferHandle);
2100 ID3D12Resource *indirectBufferRes = indirectRes->resource;
2102 const bool canUseMulti = (stride ==
sizeof(QRhiIndexedIndirectDrawCommand) && drawIndexedCommandSignature);
2104 if (canUseMulti && drawCount > 1) {
2105 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, drawCount,
2106 indirectBufferRes, indirectBufferOffset,
2109 UINT offset = indirectBufferOffset;
2110 for (quint32 i = 0; i < drawCount; ++i) {
2111 cbD->cmdList->ExecuteIndirect(drawIndexedCommandSignature, 1,
2112 indirectBufferRes, offset,
2119void QRhiD3D12::debugMarkBegin(QRhiCommandBuffer *cb,
const QByteArray &name)
2124 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2125#ifdef QRHI_D3D12_HAS_OLD_PIX
2126 PIXBeginEvent(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(name).utf16()));
2133void QRhiD3D12::debugMarkEnd(QRhiCommandBuffer *cb)
2138 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2139#ifdef QRHI_D3D12_HAS_OLD_PIX
2140 PIXEndEvent(cbD->cmdList);
2146void QRhiD3D12::debugMarkMsg(QRhiCommandBuffer *cb,
const QByteArray &msg)
2151 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2152#ifdef QRHI_D3D12_HAS_OLD_PIX
2153 PIXSetMarker(cbD->cmdList, PIX_COLOR_DEFAULT,
reinterpret_cast<LPCWSTR>(QString::fromLatin1(msg).utf16()));
2160const QRhiNativeHandles *QRhiD3D12::nativeHandles(QRhiCommandBuffer *cb)
2162 return QRHI_RES(QD3D12CommandBuffer, cb)->nativeHandles();
2165void QRhiD3D12::beginExternal(QRhiCommandBuffer *cb)
2170void QRhiD3D12::endExternal(QRhiCommandBuffer *cb)
2172 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2173 cbD->resetPerPassState();
2174 bindShaderVisibleHeaps(cbD);
2175 if (cbD->currentTarget) {
2176 QD3D12RenderTargetData *rtD = rtData(cbD->currentTarget);
2177 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2180 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2184double QRhiD3D12::lastCompletedGpuTime(QRhiCommandBuffer *cb)
2186 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2187 return cbD->lastGpuTime;
2190static void calculateGpuTime(QD3D12CommandBuffer *cbD,
2191 int timestampPairStartIndex,
2192 const quint8 *readbackBufPtr,
2193 quint64 timestampTicksPerSecond)
2195 const size_t byteOffset = timestampPairStartIndex *
sizeof(quint64);
2196 const quint64 *p =
reinterpret_cast<
const quint64 *>(readbackBufPtr + byteOffset);
2197 const quint64 startTime = *p++;
2198 const quint64 endTime = *p;
2199 if (startTime < endTime) {
2200 const quint64 ticks = endTime - startTime;
2201 const double timeSec = ticks /
double(timestampTicksPerSecond);
2202 cbD->lastGpuTime = timeSec;
2206QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
2216 return QRhi::FrameOpDeviceLost;
2218 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
2219 currentSwapChain = swapChainD;
2220 currentFrameSlot = swapChainD->currentFrameSlot;
2221 QD3D12SwapChain::FrameResources &fr(swapChainD->frameRes[currentFrameSlot]);
2234 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2235 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2237 if (swapChainD->frameLatencyWaitableObject) {
2239 if (swapChainD->lastFrameLatencyWaitSlot != currentFrameSlot) {
2240 WaitForSingleObjectEx(swapChainD->frameLatencyWaitableObject, 1000,
true);
2241 swapChainD->lastFrameLatencyWaitSlot = currentFrameSlot;
2245 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2247 qWarning(
"Failed to reset command allocator: %s",
2248 qPrintable(QSystemError::windowsComString(hr)));
2249 return QRhi::FrameOpError;
2252 if (!startCommandListForCurrentFrameSlot(&fr.cmdList))
2253 return QRhi::FrameOpError;
2255 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
2256 cbD->cmdList = fr.cmdList;
2258 swapChainD->rtWrapper.d.rtv[0] = swapChainD->sampleDesc.Count > 1
2259 ? swapChainD->msaaRtvs[currentFrameSlot].cpuHandle
2260 : swapChainD->rtvs[swapChainD->currentBackBufferIndex].cpuHandle;
2262 swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
2263 : D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
2265 if (swapChainD->stereo) {
2266 swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
2267 ? swapChainD->msaaRtvs[currentFrameSlot].cpuHandle
2268 : swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
2270 swapChainD->rtWrapperRight.d.dsv =
2271 swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
2278 releaseQueue.executeDeferredReleases(currentFrameSlot);
2284 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2287 resetAndResizeSmallStagingArea(currentFrameSlot);
2289 bindShaderVisibleHeaps(cbD);
2291 finishActiveReadbacks();
2293 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2296 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2297 calculateGpuTime(cbD,
2298 timestampPairStartIndex,
2299 timestampReadbackArea.mem.p,
2300 timestampTicksPerSecond);
2302 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2303 D3D12_QUERY_TYPE_TIMESTAMP,
2304 timestampPairStartIndex);
2307 QDxgiVSyncService::instance()->beginFrame(adapterLuid);
2309 return QRhi::FrameOpSuccess;
2312QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
2314 QD3D12SwapChain *swapChainD = QRHI_RES(QD3D12SwapChain, swapChain);
2315 Q_ASSERT(currentSwapChain == swapChainD);
2316 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
2318 QD3D12ObjectHandle backBufferResourceHandle = swapChainD->colorBuffers[swapChainD->currentBackBufferIndex];
2319 if (swapChainD->sampleDesc.Count > 1) {
2320 QD3D12ObjectHandle msaaBackBufferResourceHandle = swapChainD->msaaBuffers[currentFrameSlot];
2321 barrierGen.addTransitionBarrier(msaaBackBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2322 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2323 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2324 const QD3D12Resource *src = resourcePool.lookupRef(msaaBackBufferResourceHandle);
2325 const QD3D12Resource *dst = resourcePool.lookupRef(backBufferResourceHandle);
2327 cbD->cmdList->ResolveSubresource(dst->resource, 0, src->resource, 0, swapChainD->colorFormat);
2330 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
2331 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2333 if (timestampQueryHeap.isValid()) {
2334 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2335 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2336 D3D12_QUERY_TYPE_TIMESTAMP,
2337 timestampPairStartIndex + 1);
2338 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2339 D3D12_QUERY_TYPE_TIMESTAMP,
2340 timestampPairStartIndex,
2342 timestampReadbackArea.mem.buffer,
2343 timestampPairStartIndex *
sizeof(quint64));
2346 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2347 HRESULT hr = cmdList->Close();
2349 qWarning(
"Failed to close command list: %s",
2350 qPrintable(QSystemError::windowsComString(hr)));
2351 return QRhi::FrameOpError;
2354 ID3D12CommandList *execList[] = { cmdList };
2355 cmdQueue->ExecuteCommandLists(1, execList);
2357 if (!flags.testFlag(QRhi::SkipPresent)) {
2358 UINT presentFlags = 0;
2359 if (swapChainD->swapInterval == 0
2360 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
2362 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
2364 if (!swapChainD->swapChain) {
2365 qWarning(
"Failed to present, no swapchain");
2366 return QRhi::FrameOpError;
2368 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
2369 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
2370 qWarning(
"Device loss detected in Present()");
2372 return QRhi::FrameOpDeviceLost;
2373 }
else if (FAILED(hr)) {
2374 qWarning(
"Failed to present: %s", qPrintable(QSystemError::windowsComString(hr)));
2375 return QRhi::FrameOpError;
2378 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
2379 dcompDevice->Commit();
2382 swapChainD->addCommandCompletionSignalForCurrentFrameSlot();
2389 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2391 if (!flags.testFlag(QRhi::SkipPresent)) {
2395 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2396 swapChainD->currentBackBufferIndex = swapChainD->swapChain->GetCurrentBackBufferIndex();
2399 currentSwapChain =
nullptr;
2400 return QRhi::FrameOpSuccess;
2403QRhi::FrameOpResult QRhiD3D12::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags)
2416 currentFrameSlot = (currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
2418 for (QD3D12SwapChain *sc : std::as_const(swapchains))
2419 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
2421 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2423 qWarning(
"Failed to reset command allocator: %s",
2424 qPrintable(QSystemError::windowsComString(hr)));
2425 return QRhi::FrameOpError;
2428 if (!offscreenCb[currentFrameSlot])
2429 offscreenCb[currentFrameSlot] =
new QD3D12CommandBuffer(
this);
2430 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2431 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2432 return QRhi::FrameOpError;
2434 releaseQueue.executeDeferredReleases(currentFrameSlot);
2436 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2437 resetAndResizeSmallStagingArea(currentFrameSlot);
2439 bindShaderVisibleHeaps(cbD);
2441 if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
2442 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2443 D3D12_QUERY_TYPE_TIMESTAMP,
2444 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT);
2447 offscreenActive =
true;
2450 return QRhi::FrameOpSuccess;
2453QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
2456 Q_ASSERT(offscreenActive);
2457 offscreenActive =
false;
2459 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
2460 if (timestampQueryHeap.isValid()) {
2461 const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
2462 cbD->cmdList->EndQuery(timestampQueryHeap.heap,
2463 D3D12_QUERY_TYPE_TIMESTAMP,
2464 timestampPairStartIndex + 1);
2465 cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
2466 D3D12_QUERY_TYPE_TIMESTAMP,
2467 timestampPairStartIndex,
2469 timestampReadbackArea.mem.buffer,
2470 timestampPairStartIndex *
sizeof(quint64));
2473 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2474 HRESULT hr = cmdList->Close();
2476 qWarning(
"Failed to close command list: %s",
2477 qPrintable(QSystemError::windowsComString(hr)));
2478 return QRhi::FrameOpError;
2481 ID3D12CommandList *execList[] = { cmdList };
2482 cmdQueue->ExecuteCommandLists(1, execList);
2484 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2491 finishActiveReadbacks(
true);
2494 if (timestampQueryHeap.isValid()) {
2495 calculateGpuTime(cbD,
2496 currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT,
2497 timestampReadbackArea.mem.p,
2498 timestampTicksPerSecond);
2501 return QRhi::FrameOpSuccess;
2504QRhi::FrameOpResult QRhiD3D12::finish()
2506 QD3D12CommandBuffer *cbD =
nullptr;
2508 if (offscreenActive) {
2509 Q_ASSERT(!currentSwapChain);
2510 cbD = offscreenCb[currentFrameSlot];
2512 Q_ASSERT(currentSwapChain);
2513 cbD = ¤tSwapChain->cbWrapper;
2516 return QRhi::FrameOpError;
2518 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2520 D3D12GraphicsCommandList *cmdList = cbD->cmdList;
2521 HRESULT hr = cmdList->Close();
2523 qWarning(
"Failed to close command list: %s",
2524 qPrintable(QSystemError::windowsComString(hr)));
2525 return QRhi::FrameOpError;
2528 ID3D12CommandList *execList[] = { cmdList };
2529 cmdQueue->ExecuteCommandLists(1, execList);
2531 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
2538 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
2540 qWarning(
"Failed to reset command allocator: %s",
2541 qPrintable(QSystemError::windowsComString(hr)));
2542 return QRhi::FrameOpError;
2545 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
2546 return QRhi::FrameOpError;
2550 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
2551 smallStagingAreas[currentFrameSlot].head = 0;
2553 bindShaderVisibleHeaps(cbD);
2556 releaseQueue.releaseAll();
2557 finishActiveReadbacks(
true);
2559 return QRhi::FrameOpSuccess;
2562void QRhiD3D12::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2564 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2565 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2566 enqueueResourceUpdates(cbD, resourceUpdates);
2569void QRhiD3D12::beginPass(QRhiCommandBuffer *cb,
2570 QRhiRenderTarget *rt,
2571 const QColor &colorClearValue,
2572 const QRhiDepthStencilClearValue &depthStencilClearValue,
2573 QRhiResourceUpdateBatch *resourceUpdates,
2574 QRhiCommandBuffer::BeginPassFlags)
2576 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2577 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2579 if (resourceUpdates)
2580 enqueueResourceUpdates(cbD, resourceUpdates);
2582 QD3D12RenderTargetData *rtD = rtData(rt);
2583 bool wantsColorClear =
true;
2584 bool wantsDsClear =
true;
2585 if (rt->resourceType() == QRhiRenderTarget::TextureRenderTarget) {
2586 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, rt);
2587 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2588 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2589 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2592 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments(); it != itEnd; ++it) {
2593 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
2594 QD3D12Texture *resolveTexD = QRHI_RES(QD3D12Texture, it->resolveTexture());
2595 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
2597 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2599 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2601 barrierGen.addTransitionBarrier(resolveTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2603 if (rtTex->m_desc.depthStencilBuffer()) {
2604 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rtTex->m_desc.depthStencilBuffer());
2605 Q_ASSERT(rbD->m_type == QRhiRenderBuffer::DepthStencil);
2606 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2607 }
else if (rtTex->m_desc.depthTexture()) {
2608 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, rtTex->m_desc.depthTexture());
2609 barrierGen.addTransitionBarrier(depthTexD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
2611 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2613 Q_ASSERT(currentSwapChain);
2614 barrierGen.addTransitionBarrier(currentSwapChain->sampleDesc.Count > 1
2615 ? currentSwapChain->msaaBuffers[currentFrameSlot]
2616 : currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex],
2617 D3D12_RESOURCE_STATE_RENDER_TARGET);
2618 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2621 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
2624 rtD->dsAttCount ? &rtD->dsv :
nullptr);
2626 if (rtD->colorAttCount && wantsColorClear) {
2627 float clearColor[4] = {
2628 colorClearValue.redF(),
2629 colorClearValue.greenF(),
2630 colorClearValue.blueF(),
2631 colorClearValue.alphaF()
2633 for (
int i = 0; i < rtD->colorAttCount; ++i)
2634 cbD->cmdList->ClearRenderTargetView(rtD->rtv[i], clearColor, 0,
nullptr);
2636 if (rtD->dsAttCount && wantsDsClear) {
2637 cbD->cmdList->ClearDepthStencilView(rtD->dsv,
2638 D3D12_CLEAR_FLAGS(D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL),
2639 depthStencilClearValue.depthClearValue(),
2640 UINT8(depthStencilClearValue.stencilClearValue()),
2645 cbD->recordingPass = QD3D12CommandBuffer::RenderPass;
2646 cbD->currentTarget = rt;
2648 bool hasShadingRateMapSet =
false;
2649#ifdef QRHI_D3D12_CL5_AVAILABLE
2650 if (rtD->rp->hasShadingRateMap) {
2651 cbD->setShadingRate(QSize(1, 1));
2652 QD3D12ShadingRateMap *rateMapD = rt->resourceType() == QRhiRenderTarget::TextureRenderTarget
2653 ? QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12TextureRenderTarget, rt)->m_desc.shadingRateMap())
2654 : QRHI_RES(QD3D12ShadingRateMap, QRHI_RES(QD3D12SwapChainRenderTarget, rt)->swapChain()->shadingRateMap());
2655 if (QD3D12Resource *res = resourcePool.lookupRef(rateMapD->handle)) {
2656 barrierGen.addTransitionBarrier(rateMapD->handle, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
2657 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2658 cbD->cmdList->RSSetShadingRateImage(res->resource);
2659 hasShadingRateMapSet =
true;
2661 }
else if (cbD->hasShadingRateMapSet) {
2662 cbD->cmdList->RSSetShadingRateImage(
nullptr);
2663 cbD->setShadingRate(QSize(1, 1));
2664 }
else if (cbD->hasShadingRateSet) {
2665 cbD->setShadingRate(QSize(1, 1));
2669 cbD->resetPerPassState();
2672 cbD->hasShadingRateMapSet = hasShadingRateMapSet;
2675void QRhiD3D12::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2677 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2678 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
2680 if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
2681 QD3D12TextureRenderTarget *rtTex = QRHI_RES(QD3D12TextureRenderTarget, cbD->currentTarget);
2682 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2685 const QRhiColorAttachment &colorAtt(*it);
2686 if (!colorAtt.resolveTexture())
2689 QD3D12Texture *dstTexD = QRHI_RES(QD3D12Texture, colorAtt.resolveTexture());
2690 QD3D12Resource *dstRes = resourcePool.lookupRef(dstTexD->handle);
2694 QD3D12Texture *srcTexD = QRHI_RES(QD3D12Texture, colorAtt.texture());
2695 QD3D12RenderBuffer *srcRbD = QRHI_RES(QD3D12RenderBuffer, colorAtt.renderBuffer());
2696 Q_ASSERT(srcTexD || srcRbD);
2697 QD3D12Resource *srcRes = resourcePool.lookupRef(srcTexD ? srcTexD->handle : srcRbD->handle);
2702 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2703 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2704 int(srcTexD->dxgiFormat),
int(dstTexD->dxgiFormat));
2707 if (srcTexD->sampleDesc.Count <= 1) {
2708 qWarning(
"Cannot resolve a non-multisample texture");
2711 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2712 qWarning(
"Resolve source and destination sizes do not match");
2716 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2717 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
2718 int(srcRbD->dxgiFormat),
int(dstTexD->dxgiFormat));
2721 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2722 qWarning(
"Resolve source and destination sizes do not match");
2733 const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
2734 QBitArray &initialized(dstTexD->resolveDestInitialized);
2735 QVarLengthArray<UINT, 4> dstSubresources;
2736 QVarLengthArray<UINT, 4> subresourcesToDiscard;
2737 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2738 const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
2739 UINT(colorAtt.resolveLayer()) + resolveIdx,
2740 dstTexD->mipLevelCount);
2741 dstSubresources.append(dstSubresource);
2742 if (
int(dstSubresource) >= initialized.size())
2743 initialized.resize(
int(dstSubresource) + 1);
2744 if (!initialized.testBit(
int(dstSubresource))) {
2745 initialized.setBit(
int(dstSubresource));
2746 subresourcesToDiscard.append(dstSubresource);
2750 barrierGen.addTransitionBarrier(srcTexD ? srcTexD->handle : srcRbD->handle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
2753 if (!subresourcesToDiscard.isEmpty()) {
2754 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
2755 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2756 for (UINT dstSubresource : subresourcesToDiscard) {
2757 D3D12_DISCARD_REGION region = {};
2758 region.FirstSubresource = dstSubresource;
2759 region.NumSubresources = 1;
2760 cbD->cmdList->DiscardResource(dstRes->resource, ®ion);
2764 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
2765 barrierGen.enqueueBufferedTransitionBarriers(cbD);
2767 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
2768 const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
2769 cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresources[resolveIdx],
2770 srcRes->resource, srcSubresource,
2771 dstTexD->dxgiFormat);
2774 if (rtTex->m_desc.depthResolveTexture())
2775 qWarning(
"Resolving multisample depth-stencil buffers is not supported with D3D");
2778 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2779 cbD->currentTarget =
nullptr;
2781 if (resourceUpdates)
2782 enqueueResourceUpdates(cbD, resourceUpdates);
2785void QRhiD3D12::beginComputePass(QRhiCommandBuffer *cb,
2786 QRhiResourceUpdateBatch *resourceUpdates,
2787 QRhiCommandBuffer::BeginPassFlags)
2789 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2790 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
2792 if (resourceUpdates)
2793 enqueueResourceUpdates(cbD, resourceUpdates);
2795 cbD->recordingPass = QD3D12CommandBuffer::ComputePass;
2797 cbD->resetPerPassState();
2800void QRhiD3D12::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
2802 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2803 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2805 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
2807 if (resourceUpdates)
2808 enqueueResourceUpdates(cbD, resourceUpdates);
2811void QRhiD3D12::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
2813 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2814 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2815 QD3D12ComputePipeline *psD = QRHI_RES(QD3D12ComputePipeline, ps);
2816 const bool pipelineChanged = cbD->currentComputePipeline != psD || cbD->currentPipelineGeneration != psD->generation;
2818 if (pipelineChanged) {
2819 cbD->currentGraphicsPipeline =
nullptr;
2820 cbD->currentComputePipeline = psD;
2821 cbD->currentPipelineGeneration = psD->generation;
2823 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
2824 Q_ASSERT(pipeline->type == QD3D12Pipeline::Compute);
2825 cbD->cmdList->SetPipelineState(pipeline->pso);
2826 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
2827 cbD->cmdList->SetComputeRootSignature(rs->rootSig);
2832void QRhiD3D12::dispatch(QRhiCommandBuffer *cb,
int x,
int y,
int z)
2834 QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
2835 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
2836 cbD->cmdList->Dispatch(UINT(x), UINT(y), UINT(z));
2839bool QD3D12DescriptorHeap::create(ID3D12Device *device,
2840 quint32 descriptorCount,
2841 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
2842 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags)
2845 capacity = descriptorCount;
2846 this->heapType = heapType;
2847 this->heapFlags = heapFlags;
2849 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
2850 heapDesc.Type = heapType;
2851 heapDesc.NumDescriptors = capacity;
2852 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS(heapFlags);
2854 HRESULT hr = device->CreateDescriptorHeap(&heapDesc, __uuidof(ID3D12DescriptorHeap),
reinterpret_cast<
void **>(&heap));
2856 qWarning(
"Failed to create descriptor heap: %s", qPrintable(QSystemError::windowsComString(hr)));
2858 capacity = descriptorByteSize = 0;
2862 descriptorByteSize = device->GetDescriptorHandleIncrementSize(heapType);
2863 heapStart.cpuHandle = heap->GetCPUDescriptorHandleForHeapStart();
2864 if (heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
2865 heapStart.gpuHandle = heap->GetGPUDescriptorHandleForHeapStart();
2870void QD3D12DescriptorHeap::createWithExisting(
const QD3D12DescriptorHeap &other,
2871 quint32 offsetInDescriptors,
2872 quint32 descriptorCount)
2876 capacity = descriptorCount;
2877 heapType = other.heapType;
2878 heapFlags = other.heapFlags;
2879 descriptorByteSize = other.descriptorByteSize;
2880 heapStart = incremented(other.heapStart, offsetInDescriptors);
2883void QD3D12DescriptorHeap::destroy()
2892void QD3D12DescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2895 releaseQueue->deferredReleaseDescriptorHeap(heap);
2901QD3D12Descriptor QD3D12DescriptorHeap::get(quint32 count)
2903 Q_ASSERT(count > 0);
2904 if (head + count > capacity) {
2905 qWarning(
"Cannot get %u descriptors as that would exceed capacity %u", count, capacity);
2909 return at(head - count);
2912QD3D12Descriptor QD3D12DescriptorHeap::at(quint32 index)
const
2914 const quint32 startOffset = index * descriptorByteSize;
2915 QD3D12Descriptor result;
2916 result.cpuHandle.ptr = heapStart.cpuHandle.ptr + startOffset;
2917 if (heapStart.gpuHandle.ptr != 0)
2918 result.gpuHandle.ptr = heapStart.gpuHandle.ptr + startOffset;
2922bool QD3D12CpuDescriptorPool::create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName)
2924 QD3D12DescriptorHeap firstHeap;
2925 if (!firstHeap.create(device, DESCRIPTORS_PER_HEAP, heapType, D3D12_DESCRIPTOR_HEAP_FLAG_NONE))
2927 heaps.append(HeapWithMap::init(firstHeap, DESCRIPTORS_PER_HEAP));
2928 descriptorByteSize = heaps[0].heap.descriptorByteSize;
2929 this->device = device;
2930 this->debugName = debugName;
2934void QD3D12CpuDescriptorPool::destroy()
2938 static bool leakCheck =
true;
2941 static bool leakCheck = qEnvironmentVariableIntValue(
"QT_RHI_LEAK_CHECK");
2944 for (
const HeapWithMap &heap : std::as_const(heaps)) {
2945 const int leakedDescriptorCount = heap.map.count(
true);
2946 if (leakedDescriptorCount > 0) {
2947 qWarning(
"QD3D12CpuDescriptorPool::destroy(): "
2948 "Heap %p for descriptor pool %p '%s' has %d unreleased descriptors",
2949 &heap.heap,
this, debugName, leakedDescriptorCount);
2953 for (HeapWithMap &heap : heaps)
2954 heap.heap.destroy();
2958QD3D12Descriptor QD3D12CpuDescriptorPool::allocate(quint32 count)
2960 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
2962 HeapWithMap &last(heaps.last());
2963 if (last.heap.head + count <= last.heap.capacity) {
2964 quint32 firstIndex = last.heap.head;
2965 for (quint32 i = 0; i < count; ++i)
2966 last.map.setBit(firstIndex + i);
2967 return last.heap.get(count);
2970 for (HeapWithMap &heap : heaps) {
2971 quint32 freeCount = 0;
2972 for (quint32 i = 0; i < DESCRIPTORS_PER_HEAP; ++i) {
2973 if (heap.map.testBit(i)) {
2977 if (freeCount == count) {
2978 const quint32 firstIndex = i - (freeCount - 1);
2979 for (quint32 j = 0; j < count; ++j)
2980 heap.map.setBit(firstIndex + j);
2984 if (firstIndex + count > heap.heap.head)
2985 heap.heap.head = firstIndex + count;
2986 return heap.heap.at(firstIndex);
2992 QD3D12DescriptorHeap newHeap;
2993 if (!newHeap.create(device, DESCRIPTORS_PER_HEAP, last.heap.heapType, last.heap.heapFlags))
2996 heaps.append(HeapWithMap::init(newHeap, DESCRIPTORS_PER_HEAP));
2998 for (quint32 i = 0; i < count; ++i)
2999 heaps.last().map.setBit(i);
3001 return heaps.last().heap.get(count);
3004void QD3D12CpuDescriptorPool::release(
const QD3D12Descriptor &descriptor, quint32 count)
3006 Q_ASSERT(count > 0 && count <= DESCRIPTORS_PER_HEAP);
3007 if (!descriptor.isValid())
3010 const SIZE_T addr = descriptor.cpuHandle.ptr;
3011 for (HeapWithMap &heap : heaps) {
3012 const SIZE_T begin = heap.heap.heapStart.cpuHandle.ptr;
3013 const SIZE_T end = begin + heap.heap.descriptorByteSize * heap.heap.capacity;
3014 if (addr >= begin && addr < end) {
3015 quint32 firstIndex = (addr - begin) / heap.heap.descriptorByteSize;
3016 for (quint32 i = 0; i < count; ++i)
3017 heap.map.setBit(firstIndex + i,
false);
3022 qWarning(
"QD3D12CpuDescriptorPool::release: Descriptor with address %llu is not in any heap",
3023 quint64(descriptor.cpuHandle.ptr));
3026bool QD3D12QueryHeap::create(ID3D12Device *device,
3028 D3D12_QUERY_HEAP_TYPE heapType)
3030 capacity = queryCount;
3032 D3D12_QUERY_HEAP_DESC heapDesc = {};
3033 heapDesc.Type = heapType;
3034 heapDesc.Count = capacity;
3036 HRESULT hr = device->CreateQueryHeap(&heapDesc, __uuidof(ID3D12QueryHeap),
reinterpret_cast<
void **>(&heap));
3038 qWarning(
"Failed to create query heap: %s", qPrintable(QSystemError::windowsComString(hr)));
3047void QD3D12QueryHeap::destroy()
3056bool QD3D12StagingArea::create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType)
3058 Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
3059 D3D12_RESOURCE_DESC resourceDesc = {};
3060 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
3061 resourceDesc.Width = capacity;
3062 resourceDesc.Height = 1;
3063 resourceDesc.DepthOrArraySize = 1;
3064 resourceDesc.MipLevels = 1;
3065 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
3066 resourceDesc.SampleDesc = { 1, 0 };
3067 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
3068 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
3069 UINT state = heapType == D3D12_HEAP_TYPE_UPLOAD ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
3070 HRESULT hr = rhi->vma.createResource(heapType,
3072 D3D12_RESOURCE_STATES(state),
3075 __uuidof(ID3D12Resource),
3076 reinterpret_cast<
void **>(&resource));
3078 qWarning(
"Failed to create buffer for staging area: %s",
3079 qPrintable(QSystemError::windowsComString(hr)));
3083 hr = resource->Map(0,
nullptr, &p);
3085 qWarning(
"Failed to map buffer for staging area: %s",
3086 qPrintable(QSystemError::windowsComString(hr)));
3091 mem.p =
static_cast<quint8 *>(p);
3092 mem.gpuAddr = resource->GetGPUVirtualAddress();
3093 mem.buffer = resource;
3094 mem.bufferOffset = 0;
3096 this->capacity = capacity;
3102void QD3D12StagingArea::destroy()
3105 resource->Release();
3109 allocation->Release();
3110 allocation =
nullptr;
3115void QD3D12StagingArea::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3118 releaseQueue->deferredReleaseResourceAndAllocation(resource, allocation);
3122QD3D12StagingArea::Allocation QD3D12StagingArea::get(quint32 byteSize)
3124 const quint32 allocSize = aligned(byteSize, ALIGNMENT);
3125 if (head + allocSize > capacity) {
3126 qWarning(
"Failed to allocate %u (%u) bytes from staging area of size %u with %u bytes left",
3127 allocSize, byteSize, capacity, remainingCapacity());
3130 const quint32 offset = head;
3134 mem.gpuAddr + offset,
3143void QD3D12ReleaseQueue::deferredReleaseResource(
const QD3D12ObjectHandle &handle)
3145 DeferredReleaseEntry e;
3150void QD3D12ReleaseQueue::deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &handle,
3151 QD3D12CpuDescriptorPool *pool,
3152 const QD3D12Descriptor &viewsStart,
3155 DeferredReleaseEntry e;
3156 e.type = DeferredReleaseEntry::Resource;
3158 e.poolForViews = pool;
3159 e.viewsStart = viewsStart;
3160 e.viewCount = viewCount;
3164void QD3D12ReleaseQueue::deferredReleasePipeline(
const QD3D12ObjectHandle &handle)
3166 DeferredReleaseEntry e;
3167 e.type = DeferredReleaseEntry::Pipeline;
3172void QD3D12ReleaseQueue::deferredReleaseRootSignature(
const QD3D12ObjectHandle &handle)
3174 DeferredReleaseEntry e;
3175 e.type = DeferredReleaseEntry::RootSignature;
3180void QD3D12ReleaseQueue::deferredReleaseCallback(std::function<
void(
void*)> callback,
void *userData)
3182 DeferredReleaseEntry e;
3183 e.type = DeferredReleaseEntry::Callback;
3184 e.callback = callback;
3185 e.callbackUserData = userData;
3189void QD3D12ReleaseQueue::deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
3190 D3D12MA::Allocation *allocation)
3192 DeferredReleaseEntry e;
3193 e.type = DeferredReleaseEntry::ResourceAndAllocation;
3194 e.resourceAndAllocation = { resource, allocation };
3198void QD3D12ReleaseQueue::deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap)
3200 DeferredReleaseEntry e;
3201 e.type = DeferredReleaseEntry::DescriptorHeap;
3202 e.descriptorHeap = heap;
3206void QD3D12ReleaseQueue::deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
3207 const QD3D12Descriptor &viewsStart,
3210 DeferredReleaseEntry e;
3211 e.type = DeferredReleaseEntry::Views;
3212 e.poolForViews = pool;
3213 e.viewsStart = viewsStart;
3214 e.viewCount = viewCount;
3218void QD3D12ReleaseQueue::activatePendingDeferredReleaseRequests(
int frameSlot)
3220 for (DeferredReleaseEntry &e : queue) {
3221 if (!e.frameSlotToBeReleasedIn.has_value())
3222 e.frameSlotToBeReleasedIn = frameSlot;
3226void QD3D12ReleaseQueue::executeDeferredReleases(
int frameSlot,
bool forced)
3228 for (
int i = queue.count() - 1; i >= 0; --i) {
3229 const DeferredReleaseEntry &e(queue[i]);
3230 if (forced || (e.frameSlotToBeReleasedIn.has_value() && e.frameSlotToBeReleasedIn.value() == frameSlot)) {
3232 case DeferredReleaseEntry::Resource:
3233 resourcePool->remove(e.handle);
3234 if (e.poolForViews && e.viewsStart.isValid() && e.viewCount > 0)
3235 e.poolForViews->release(e.viewsStart, e.viewCount);
3237 case DeferredReleaseEntry::Pipeline:
3238 pipelinePool->remove(e.handle);
3240 case DeferredReleaseEntry::RootSignature:
3241 rootSignaturePool->remove(e.handle);
3243 case DeferredReleaseEntry::Callback:
3244 e.callback(e.callbackUserData);
3246 case DeferredReleaseEntry::ResourceAndAllocation:
3249 e.resourceAndAllocation.first->Release();
3250 if (e.resourceAndAllocation.second)
3251 e.resourceAndAllocation.second->Release();
3253 case DeferredReleaseEntry::DescriptorHeap:
3254 e.descriptorHeap->Release();
3256 case DeferredReleaseEntry::Views:
3257 e.poolForViews->release(e.viewsStart, e.viewCount);
3265void QD3D12ReleaseQueue::releaseAll()
3267 executeDeferredReleases(0,
true);
3270void QD3D12ResourceBarrierGenerator::addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle,
3271 D3D12_RESOURCE_STATES stateAfter)
3273 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3274 if (stateAfter != res->state) {
3275 transitionResourceBarriers.append({ resourceHandle, res->state, stateAfter });
3276 res->state = stateAfter;
3281void QD3D12ResourceBarrierGenerator::enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD)
3283 QVarLengthArray<D3D12_RESOURCE_BARRIER, PREALLOC> barriers;
3284 for (
const TransitionResourceBarrier &trb : transitionResourceBarriers) {
3285 if (QD3D12Resource *res = resourcePool->lookupRef(trb.resourceHandle)) {
3286 D3D12_RESOURCE_BARRIER barrier = {};
3287 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
3288 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3289 barrier.Transition.pResource = res->resource;
3290 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
3291 barrier.Transition.StateBefore = trb.stateBefore;
3292 barrier.Transition.StateAfter = trb.stateAfter;
3293 barriers.append(barrier);
3296 transitionResourceBarriers.clear();
3297 if (!barriers.isEmpty())
3298 cbD->cmdList->ResourceBarrier(barriers.count(), barriers.constData());
3301void QD3D12ResourceBarrierGenerator::enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
3302 const QD3D12ObjectHandle &resourceHandle,
3304 D3D12_RESOURCE_STATES stateBefore,
3305 D3D12_RESOURCE_STATES stateAfter)
3307 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3308 D3D12_RESOURCE_BARRIER barrier = {};
3309 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
3310 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3311 barrier.Transition.pResource = res->resource;
3312 barrier.Transition.Subresource = subresource;
3313 barrier.Transition.StateBefore = stateBefore;
3314 barrier.Transition.StateAfter = stateAfter;
3315 cbD->cmdList->ResourceBarrier(1, &barrier);
3319void QD3D12ResourceBarrierGenerator::enqueueUavBarrier(QD3D12CommandBuffer *cbD,
3320 const QD3D12ObjectHandle &resourceHandle)
3322 if (QD3D12Resource *res = resourcePool->lookupRef(resourceHandle)) {
3323 D3D12_RESOURCE_BARRIER barrier = {};
3324 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
3325 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
3326 barrier.UAV.pResource = res->resource;
3327 cbD->cmdList->ResourceBarrier(1, &barrier);
3331void QD3D12ShaderBytecodeCache::insertWithCapacityLimit(
const QRhiShaderStage &key,
const Shader &s)
3333 if (data.count() >= QRhiD3D12::MAX_SHADER_CACHE_ENTRIES)
3335 data.insert(key, s);
3338bool QD3D12ShaderVisibleDescriptorHeap::create(ID3D12Device *device,
3339 D3D12_DESCRIPTOR_HEAP_TYPE type,
3340 quint32 perFrameDescriptorCount)
3342 Q_ASSERT(type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
3344 quint32 size = perFrameDescriptorCount * QD3D12_FRAMES_IN_FLIGHT;
3347 const quint32 CBV_SRV_UAV_MAX = 1000000;
3348 const quint32 SAMPLER_MAX = 2048;
3349 if (type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
3350 size = qMin(size, CBV_SRV_UAV_MAX);
3351 else if (type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
3352 size = qMin(size, SAMPLER_MAX);
3354 if (!heap.create(device, size, type, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
3355 qWarning(
"Failed to create shader-visible descriptor heap of size %u", size);
3359 perFrameDescriptorCount = size / QD3D12_FRAMES_IN_FLIGHT;
3360 quint32 currentOffsetInDescriptors = 0;
3361 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
3362 perFrameHeapSlice[i].createWithExisting(heap, currentOffsetInDescriptors, perFrameDescriptorCount);
3363 currentOffsetInDescriptors += perFrameDescriptorCount;
3369void QD3D12ShaderVisibleDescriptorHeap::destroy()
3374void QD3D12ShaderVisibleDescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
3376 heap.destroyWithDeferredRelease(releaseQueue);
3379static inline std::pair<
int,
int> mapBinding(
int binding,
const QShader::NativeResourceBindingMap &map)
3382 return { binding, binding };
3384 auto it = map.constFind(binding);
3385 if (it != map.cend())
3394void QD3D12ShaderResourceVisitor::visit()
3396 for (
int bindingIdx = 0, bindingCount = srb->m_bindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
3397 const QRhiShaderResourceBinding &b(srb->m_bindings[bindingIdx]);
3398 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
3400 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
3401 const QD3D12ShaderStageData *sd = &stageData[stageIdx];
3405 if (!bd->stage.testFlag(qd3d12_stageToSrb(sd->stage)))
3409 case QRhiShaderResourceBinding::UniformBuffer:
3411 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3412 if (shaderRegister >= 0 && uniformBuffer)
3413 uniformBuffer(sd->stage, bd->u.ubuf, shaderRegister, bd->binding);
3416 case QRhiShaderResourceBinding::SampledTexture:
3418 Q_ASSERT(bd->u.stex.count > 0);
3419 const int textureBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3420 const int samplerBaseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).second;
3421 if (textureBaseShaderRegister >= 0 && textures)
3422 textures(sd->stage, bd->u.stex.texSamplers, bd->u.stex.count, textureBaseShaderRegister);
3423 if (samplerBaseShaderRegister >= 0 && samplers)
3424 samplers(sd->stage, bd->u.stex.texSamplers, bd->u.stex.count, samplerBaseShaderRegister);
3427 case QRhiShaderResourceBinding::Texture:
3429 Q_ASSERT(bd->u.stex.count > 0);
3430 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3431 if (baseShaderRegister >= 0 && textures)
3432 textures(sd->stage, bd->u.stex.texSamplers, bd->u.stex.count, baseShaderRegister);
3435 case QRhiShaderResourceBinding::Sampler:
3437 Q_ASSERT(bd->u.stex.count > 0);
3438 const int baseShaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3439 if (baseShaderRegister >= 0 && samplers)
3440 samplers(sd->stage, bd->u.stex.texSamplers, bd->u.stex.count, baseShaderRegister);
3443 case QRhiShaderResourceBinding::ImageLoad:
3445 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3446 if (shaderRegister >= 0 && storageImage)
3447 storageImage(sd->stage, bd->u.simage, Load, shaderRegister);
3450 case QRhiShaderResourceBinding::ImageStore:
3452 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3453 if (shaderRegister >= 0 && storageImage)
3454 storageImage(sd->stage, bd->u.simage, Store, shaderRegister);
3457 case QRhiShaderResourceBinding::ImageLoadStore:
3459 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3460 if (shaderRegister >= 0 && storageImage)
3461 storageImage(sd->stage, bd->u.simage, LoadStore, shaderRegister);
3464 case QRhiShaderResourceBinding::BufferLoad:
3466 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3467 if (shaderRegister >= 0 && storageBuffer)
3468 storageBuffer(sd->stage, bd->u.sbuf, Load, shaderRegister);
3471 case QRhiShaderResourceBinding::BufferStore:
3473 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3474 if (shaderRegister >= 0 && storageBuffer)
3475 storageBuffer(sd->stage, bd->u.sbuf, Store, shaderRegister);
3478 case QRhiShaderResourceBinding::BufferLoadStore:
3480 const int shaderRegister = mapBinding(bd->binding, sd->nativeResourceBindingMap).first;
3481 if (shaderRegister >= 0 && storageBuffer)
3482 storageBuffer(sd->stage, bd->u.sbuf, LoadStore, shaderRegister);
3490bool QD3D12SamplerManager::create(ID3D12Device *device)
3493 if (!shaderVisibleSamplerHeap.create(device,
3494 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
3495 MAX_SAMPLERS / QD3D12_FRAMES_IN_FLIGHT))
3497 qWarning(
"Could not create shader-visible SAMPLER heap");
3501 this->device = device;
3505void QD3D12SamplerManager::destroy()
3508 shaderVisibleSamplerHeap.destroy();
3513QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &desc)
3515 auto it = gpuMap.constFind({desc});
3516 if (it != gpuMap.cend())
3519 QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
3520 if (descriptor.isValid()) {
3521 device->CreateSampler(&desc, descriptor.cpuHandle);
3522 gpuMap.insert({desc}, descriptor);
3524 qWarning(
"Out of shader-visible SAMPLER descriptor heap space,"
3525 " this should not happen, maximum number of unique samplers is %u",
3526 shaderVisibleSamplerHeap.heap.capacity);
3532QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptors(
const QVarLengthArray<Q_D3D12_SAMPLER_DESC, 8> &descs)
3538 auto it = gpuArrayMap.constFind({ descs });
3539 if (it != gpuArrayMap.cend())
3542 const quint32 count = quint32(descs.count());
3543 QD3D12Descriptor startDescriptor = shaderVisibleSamplerHeap.heap.get(count);
3544 if (startDescriptor.isValid()) {
3545 for (quint32 i = 0; i < count; ++i) {
3546 device->CreateSampler(&descs[
int(i)].desc,
3547 shaderVisibleSamplerHeap.heap.incremented(startDescriptor, i).cpuHandle);
3549 gpuArrayMap.insert({ descs }, startDescriptor);
3556 qWarning(
"Out of shader-visible SAMPLER descriptor heap space when reserving"
3557 " %u consecutive descriptors for a sampler array, maximum number of"
3558 " sampler descriptors is %u",
3559 count, shaderVisibleSamplerHeap.heap.capacity);
3562 return startDescriptor;
3565void QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
3570bool QD3D12MipmapGenerator::ensureCreated()
3572 if (!pipelineHandle.isNull())
3578 if (!buildPipeline()) {
3579 createFailed =
true;
3586bool QD3D12MipmapGenerator::buildPipeline()
3588 qCDebug(QRHI_LOG_INFO,
"Building mipmap generator compute pipeline on first use");
3590 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3591 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3594 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3595 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3596 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3599 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3600 descriptorRanges[0].NumDescriptors = 1;
3601 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3602 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3603 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3604 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3605 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3608 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3609 descriptorRanges[1].NumDescriptors = 4;
3610 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3611 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3612 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3613 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3616 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3617 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3618 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3619 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3620 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3621 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3623 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3624 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3625 rsDesc.Desc_1_1.NumParameters = 3;
3626 rsDesc.Desc_1_1.pParameters = rootParams;
3627 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3628 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3630 ID3DBlob *signature =
nullptr;
3631 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3633 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3636 ID3D12RootSignature *rootSig =
nullptr;
3637 hr = rhiD->dev->CreateRootSignature(0,
3638 signature->GetBufferPointer(),
3639 signature->GetBufferSize(),
3640 __uuidof(ID3D12RootSignature),
3641 reinterpret_cast<
void **>(&rootSig));
3642 signature->Release();
3644 qWarning(
"Failed to create root signature: %s",
3645 qPrintable(QSystemError::windowsComString(hr)));
3649 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3651 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3652 psoDesc.pRootSignature = rootSig;
3653 psoDesc.CS.pShaderBytecode = g_csMipmap;
3654 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap);
3655 ID3D12PipelineState *pso =
nullptr;
3656 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3657 __uuidof(ID3D12PipelineState),
3658 reinterpret_cast<
void **>(&pso));
3660 qWarning(
"Failed to create compute pipeline state: %s",
3661 qPrintable(QSystemError::windowsComString(hr)));
3662 rhiD->rootSignaturePool.remove(rootSigHandle);
3667 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3672void QD3D12MipmapGenerator::destroy()
3679 rhiD->pipelinePool.remove(pipelineHandle);
3680 pipelineHandle = {};
3681 rhiD->rootSignaturePool.remove(rootSigHandle);
3683 createFailed =
false;
3686void QD3D12MipmapGenerator::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3688 if (!ensureCreated())
3691 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3694 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3697 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3701 const quint32 mipLevelCount = res->desc.MipLevels;
3702 if (mipLevelCount < 2)
3705 if (res->desc.SampleDesc.Count > 1) {
3706 qWarning(
"Cannot generate mipmaps for MSAA texture");
3710 const bool is1D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D;
3712 qWarning(
"Cannot generate mipmaps for 1D texture");
3716 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3717 const bool isCubeOrArray = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
3718 && res->desc.DepthOrArraySize > 1;
3719 const quint32 layerCount = isCubeOrArray ? res->desc.DepthOrArraySize : 1;
3722 qWarning(
"2D mipmap generator invoked for 3D texture, this should not happen");
3726 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3727 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3729 cbD->cmdList->SetPipelineState(pipeline->pso);
3730 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3732 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
3735 quint32 srcMipLevel;
3736 quint32 numMipLevels;
3741 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount * layerCount);
3742 std::optional<QD3D12StagingArea> ownStagingArea;
3743 rhiD->recordSmallStagingAreaDemand(allocSize);
3744 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
3745 ownStagingArea = QD3D12StagingArea();
3746 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
3747 qWarning(
"Could not create staging area for mipmap generation");
3751 QD3D12StagingArea *workArea = ownStagingArea.has_value()
3752 ? &ownStagingArea.value()
3753 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
3755 bool gotNewHeap =
false;
3756 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
3757 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
3758 rhiD->currentFrameSlot,
3759 (1 + 4) * mipLevelCount * layerCount,
3762 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
3766 rhiD->bindShaderVisibleHeaps(cbD);
3768 for (quint32 layer = 0; layer < layerCount; ++layer) {
3769 for (quint32 level = 0; level < mipLevelCount ;) {
3770 UINT subresource = calcSubresource(level, layer, res->desc.MipLevels);
3771 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3772 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
3773 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
3775 quint32 levelPlusOneMipWidth = res->desc.Width >> (level + 1);
3776 quint32 levelPlusOneMipHeight = res->desc.Height >> (level + 1);
3777 const quint32 dw = levelPlusOneMipWidth == 1 ? levelPlusOneMipHeight : levelPlusOneMipWidth;
3778 const quint32 dh = levelPlusOneMipHeight == 1 ? levelPlusOneMipWidth : levelPlusOneMipHeight;
3780 const quint32 additionalMips = qCountTrailingZeroBits(dw | dh);
3781 const quint32 numGenMips = qMin(1u + qMin(3u, additionalMips), res->desc.MipLevels - level);
3782 levelPlusOneMipWidth = qMax(1u, levelPlusOneMipWidth);
3783 levelPlusOneMipHeight = qMax(1u, levelPlusOneMipHeight);
3785 CBufData cbufData = {
3788 1.0f /
float(levelPlusOneMipWidth),
3789 1.0f /
float(levelPlusOneMipHeight)
3792 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
3793 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
3794 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
3796 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
3797 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3798 srvDesc.Format = res->desc.Format;
3799 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3800 if (isCubeOrArray) {
3801 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
3802 srvDesc.Texture2DArray.MipLevels = res->desc.MipLevels;
3803 srvDesc.Texture2DArray.FirstArraySlice = layer;
3804 srvDesc.Texture2DArray.ArraySize = 1;
3806 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
3807 srvDesc.Texture2D.MipLevels = res->desc.MipLevels;
3809 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
3810 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
3812 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(4);
3813 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
3815 for (quint32 uavIdx = 0; uavIdx < 4; ++uavIdx) {
3816 const quint32 uavMipLevel = qMin(level + 1u + uavIdx, res->desc.MipLevels - 1u);
3817 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
3818 uavDesc.Format = res->desc.Format;
3819 if (isCubeOrArray) {
3820 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
3821 uavDesc.Texture2DArray.MipSlice = uavMipLevel;
3822 uavDesc.Texture2DArray.FirstArraySlice = layer;
3823 uavDesc.Texture2DArray.ArraySize = 1;
3825 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
3826 uavDesc.Texture2D.MipSlice = uavMipLevel;
3828 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
3829 uavCpuHandle.ptr += descriptorByteSize;
3831 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
3833 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, 1);
3835 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
3836 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
3837 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
3838 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3840 level += numGenMips;
3844 if (ownStagingArea.has_value())
3845 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
3848void QD3D12MipmapGenerator3D::create(QRhiD3D12 *rhiD)
3853bool QD3D12MipmapGenerator3D::ensureCreated()
3855 if (!pipelineHandle.isNull())
3861 if (!buildPipeline()) {
3862 createFailed =
true;
3869bool QD3D12MipmapGenerator3D::buildPipeline()
3871 qCDebug(QRHI_LOG_INFO,
"Building 3D texture mipmap generator compute pipeline on first use");
3873 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
3874 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
3877 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
3878 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3879 rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
3882 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
3883 descriptorRanges[0].NumDescriptors = 1;
3884 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
3885 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3886 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3887 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
3888 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
3891 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
3892 descriptorRanges[1].NumDescriptors = 1;
3893 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
3894 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3895 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
3896 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
3899 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
3900 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3901 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3902 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3903 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3904 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
3906 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
3907 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
3908 rsDesc.Desc_1_1.NumParameters = 3;
3909 rsDesc.Desc_1_1.pParameters = rootParams;
3910 rsDesc.Desc_1_1.NumStaticSamplers = 1;
3911 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
3913 ID3DBlob *signature =
nullptr;
3914 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
3916 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
3919 ID3D12RootSignature *rootSig =
nullptr;
3920 hr = rhiD->dev->CreateRootSignature(0,
3921 signature->GetBufferPointer(),
3922 signature->GetBufferSize(),
3923 __uuidof(ID3D12RootSignature),
3924 reinterpret_cast<
void **>(&rootSig));
3925 signature->Release();
3927 qWarning(
"Failed to create root signature: %s",
3928 qPrintable(QSystemError::windowsComString(hr)));
3932 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
3934 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
3935 psoDesc.pRootSignature = rootSig;
3936 psoDesc.CS.pShaderBytecode = g_csMipmap3D;
3937 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap3D);
3938 ID3D12PipelineState *pso =
nullptr;
3939 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
3940 __uuidof(ID3D12PipelineState),
3941 reinterpret_cast<
void **>(&pso));
3943 qWarning(
"Failed to create compute pipeline state: %s",
3944 qPrintable(QSystemError::windowsComString(hr)));
3945 rhiD->rootSignaturePool.remove(rootSigHandle);
3950 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
3955void QD3D12MipmapGenerator3D::destroy()
3960 rhiD->pipelinePool.remove(pipelineHandle);
3961 pipelineHandle = {};
3962 rhiD->rootSignaturePool.remove(rootSigHandle);
3964 createFailed =
false;
3967void QD3D12MipmapGenerator3D::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
3969 if (!ensureCreated())
3972 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
3975 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
3978 QD3D12Resource *res = rhiD->resourcePool.lookupRef(textureHandle);
3982 const quint32 mipLevelCount = res->desc.MipLevels;
3983 if (mipLevelCount < 2)
3986 const bool is3D = res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
3988 qWarning(
"3D mipmap generator invoked for non-3D texture, this should not happen");
3992 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3993 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
3995 cbD->cmdList->SetPipelineState(pipeline->pso);
3996 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
3998 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
4004 quint32 srcMipLevel;
4007 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount);
4008 std::optional<QD3D12StagingArea> ownStagingArea;
4009 rhiD->recordSmallStagingAreaDemand(allocSize);
4010 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
4011 ownStagingArea = QD3D12StagingArea();
4012 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
4013 qWarning(
"Could not create staging area for mipmap generation");
4017 QD3D12StagingArea *workArea = ownStagingArea.has_value()
4018 ? &ownStagingArea.value()
4019 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
4021 bool gotNewHeap =
false;
4022 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
4023 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
4024 rhiD->currentFrameSlot,
4025 (1 + 1) * mipLevelCount,
4028 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
4032 rhiD->bindShaderVisibleHeaps(cbD);
4034 for (quint32 level = 0; level < mipLevelCount; ++level) {
4035 UINT subresource = calcSubresource(level, 0u, res->desc.MipLevels);
4036 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4037 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
4038 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
4040 quint32 levelPlusOneMipWidth = qMax<quint32>(1, res->desc.Width >> (level + 1));
4041 quint32 levelPlusOneMipHeight = qMax<quint32>(1, res->desc.Height >> (level + 1));
4042 quint32 levelPlusOneMipDepth = qMax<quint32>(1, res->desc.DepthOrArraySize >> (level + 1));
4044 CBufData cbufData = {
4045 1.0f /
float(levelPlusOneMipWidth),
4046 1.0f /
float(levelPlusOneMipHeight),
4047 1.0f /
float(levelPlusOneMipDepth),
4051 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
4052 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
4053 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
4055 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4056 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4057 srvDesc.Format = res->desc.Format;
4058 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4059 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4060 srvDesc.Texture3D.MipLevels = res->desc.MipLevels;
4062 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
4063 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
4065 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
4066 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
4067 const quint32 uavMipLevel = qMin(level + 1u, res->desc.MipLevels - 1u);
4068 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
4069 uavDesc.Format = res->desc.Format;
4070 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
4071 uavDesc.Texture3D.MipSlice = uavMipLevel;
4072 uavDesc.Texture3D.WSize = UINT(-1);
4073 rhiD->dev->CreateUnorderedAccessView(res->resource,
nullptr, &uavDesc, uavCpuHandle);
4074 uavCpuHandle.ptr += descriptorByteSize;
4075 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
4077 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, levelPlusOneMipDepth);
4079 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
4080 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
4081 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
4082 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
4085 if (ownStagingArea.has_value())
4086 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
4089bool QD3D12MemoryAllocator::create(ID3D12Device *device, IDXGIAdapter1 *adapter)
4091 this->device = device;
4098 static bool disableMA = qEnvironmentVariableIntValue(
"QT_D3D_NO_SUBALLOC");
4102 DXGI_ADAPTER_DESC1 desc;
4103 adapter->GetDesc1(&desc);
4104 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
4107 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
4108 allocatorDesc.pDevice = device;
4109 allocatorDesc.pAdapter = adapter;
4112 allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED;
4113 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
4115 qWarning(
"Failed to initialize D3D12 Memory Allocator: %s",
4116 qPrintable(QSystemError::windowsComString(hr)));
4122void QD3D12MemoryAllocator::destroy()
4125 allocator->Release();
4126 allocator =
nullptr;
4130HRESULT QD3D12MemoryAllocator::createResource(D3D12_HEAP_TYPE heapType,
4131 const D3D12_RESOURCE_DESC *resourceDesc,
4132 D3D12_RESOURCE_STATES initialState,
4133 const D3D12_CLEAR_VALUE *optimizedClearValue,
4134 D3D12MA::Allocation **maybeAllocation,
4135 REFIID riidResource,
4139 D3D12MA::ALLOCATION_DESC allocDesc = {};
4140 allocDesc.HeapType = heapType;
4141 return allocator->CreateResource(&allocDesc,
4144 optimizedClearValue,
4149 *maybeAllocation =
nullptr;
4150 D3D12_HEAP_PROPERTIES heapProps = {};
4151 heapProps.Type = heapType;
4152 return device->CreateCommittedResource(&heapProps,
4153 D3D12_HEAP_FLAG_NONE,
4156 optimizedClearValue,
4162void QD3D12MemoryAllocator::getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget)
4165 allocator->GetBudget(localBudget, nonLocalBudget);
4168 *nonLocalBudget = {};
4172void QRhiD3D12::waitGpu()
4174 fullFenceCounter += 1u;
4175 if (SUCCEEDED(cmdQueue->Signal(fullFence, fullFenceCounter))) {
4176 if (SUCCEEDED(fullFence->SetEventOnCompletion(fullFenceCounter, fullFenceEvent)))
4177 WaitForSingleObject(fullFenceEvent, INFINITE);
4181DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleDesc(
int sampleCount, DXGI_FORMAT format)
const
4183 DXGI_SAMPLE_DESC desc;
4187 const int s = effectiveSampleCount(sampleCount);
4190 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
4191 msaaInfo.Format = format;
4192 msaaInfo.SampleCount = UINT(s);
4193 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo,
sizeof(msaaInfo)))) {
4194 if (msaaInfo.NumQualityLevels > 0) {
4195 desc.Count = UINT(s);
4196 desc.Quality = msaaInfo.NumQualityLevels - 1;
4198 qWarning(
"No quality levels for multisampling with sample count %d", s);
4206bool QRhiD3D12::startCommandListForCurrentFrameSlot(D3D12GraphicsCommandList **cmdList)
4208 ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
4210 HRESULT hr = dev->CreateCommandList(0,
4211 D3D12_COMMAND_LIST_TYPE_DIRECT,
4214 __uuidof(D3D12GraphicsCommandList),
4215 reinterpret_cast<
void **>(cmdList));
4217 qWarning(
"Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
4221 HRESULT hr = (*cmdList)->Reset(cmdAlloc,
nullptr);
4223 qWarning(
"Failed to reset command list: %s", qPrintable(QSystemError::windowsComString(hr)));
4230static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
4233 case DXGI_FORMAT_R8G8B8A8_UNORM:
4234 return QRhiTexture::RGBA8;
4235 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
4237 (*flags) |= QRhiTexture::sRGB;
4238 return QRhiTexture::RGBA8;
4239 case DXGI_FORMAT_B8G8R8A8_UNORM:
4240 return QRhiTexture::BGRA8;
4241 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
4243 (*flags) |= QRhiTexture::sRGB;
4244 return QRhiTexture::BGRA8;
4245 case DXGI_FORMAT_R16G16B16A16_FLOAT:
4246 return QRhiTexture::RGBA16F;
4247 case DXGI_FORMAT_R32G32B32A32_FLOAT:
4248 return QRhiTexture::RGBA32F;
4249 case DXGI_FORMAT_R10G10B10A2_UNORM:
4250 return QRhiTexture::RGB10A2;
4252 qWarning(
"DXGI_FORMAT %d cannot be read back", format);
4255 return QRhiTexture::UnknownFormat;
4258void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
4260 QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
4262 for (
int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
4263 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
4264 if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
4265 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4266 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
4267 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4268 if (u.offset == 0 && u.data.size() == bufD->m_size)
4269 bufD->pendingHostWrites[i].clear();
4270 bufD->pendingHostWrites[i].append({ u.offset, u.data });
4272 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
4273 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4274 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
4275 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
4283 QD3D12StagingArea::Allocation stagingAlloc;
4284 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(bufD->m_size, 1);
4285 recordSmallStagingAreaDemand(allocSize);
4286 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
4287 stagingAlloc = smallStagingAreas[currentFrameSlot].get(bufD->m_size);
4289 std::optional<QD3D12StagingArea> ownStagingArea;
4290 if (!stagingAlloc.isValid()) {
4291 ownStagingArea = QD3D12StagingArea();
4292 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
4294 stagingAlloc = ownStagingArea->get(allocSize);
4295 if (!stagingAlloc.isValid()) {
4296 ownStagingArea->destroy();
4301 memcpy(stagingAlloc.p + u.offset, u.data.constData(), u.data.size());
4303 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
4304 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4306 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
4307 cbD->cmdList->CopyBufferRegion(res->resource,
4309 stagingAlloc.buffer,
4310 stagingAlloc.bufferOffset + u.offset,
4314 if (ownStagingArea.has_value())
4315 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4316 }
else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
4317 QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, u.buf);
4318 if (bufD->m_type == QRhiBuffer::Dynamic) {
4319 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
4320 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[currentFrameSlot])) {
4321 Q_ASSERT(res->cpuMapPtr);
4322 u.result->data.resize(u.readSize);
4323 memcpy(u.result->data.data(),
reinterpret_cast<
char *>(res->cpuMapPtr) + u.offset, u.readSize);
4325 if (u.result->completed)
4326 u.result->completed();
4328 QD3D12Readback readback;
4329 readback.frameSlot = currentFrameSlot;
4330 readback.result = u.result;
4331 readback.byteSize = u.readSize;
4332 const quint32 allocSize = aligned(u.readSize, QD3D12StagingArea::ALIGNMENT);
4333 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
4334 if (u.result->completed)
4335 u.result->completed();
4338 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(u.readSize);
4339 if (!stagingAlloc.isValid()) {
4340 readback.staging.destroy();
4341 if (u.result->completed)
4342 u.result->completed();
4345 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4346 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
4347 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4348 if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) {
4349 cbD->cmdList->CopyBufferRegion(stagingAlloc.buffer, 0, res->resource, u.offset, u.readSize);
4350 activeReadbacks.append(readback);
4352 readback.staging.destroy();
4353 if (u.result->completed)
4354 u.result->completed();
4360 for (
int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
4361 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
4362 if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
4363 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4364 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4365 QD3D12Resource *res = resourcePool.lookupRef(texD->handle);
4368 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4369 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4370 for (
int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
4371 for (
int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
4372 for (
const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level])) {
4373 D3D12_SUBRESOURCE_FOOTPRINT footprint = {};
4374 footprint.Format = res->desc.Format;
4375 footprint.Depth = 1;
4376 quint32 totalBytes = 0;
4378 QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
4379 : subresDesc.sourceSize();
4380 const QPoint srcPos = subresDesc.sourceTopLeft();
4381 QPoint dstPos = subresDesc.destinationTopLeft();
4383 if (subresDesc.image().isNull()
4384 && !subresDesc.data().isEmpty()
4385 && !isCompressedFormat(texD->m_format))
4387 subresSize = clampedSubResourceUploadSize(subresSize, dstPos, level, texD->m_pixelSize);
4388 quint32 bytesPerPixel = 0;
4389 textureFormatInfo(texD->m_format, subresSize,
nullptr,
nullptr, &bytesPerPixel);
4390 subresSize = clampedSubResourceUploadSizeForSourceData(subresSize,
4391 subresDesc.dataStride(),
4393 subresDesc.data().size());
4394 if (subresSize.isEmpty())
4398 if (!subresDesc.image().isNull()) {
4399 const QImage img = subresDesc.image();
4400 const int bpl = img.bytesPerLine();
4401 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4402 totalBytes = footprint.RowPitch * img.height();
4403 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
4406 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
4407 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4408 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
4409 totalBytes = footprint.RowPitch * rowCount;
4410 }
else if (!subresDesc.data().isEmpty()) {
4412 if (subresDesc.dataStride())
4413 bpl = subresDesc.dataStride();
4415 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4416 footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
4417 totalBytes = footprint.RowPitch * subresSize.height();
4419 qWarning(
"Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
4423 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(totalBytes, 1);
4424 QD3D12StagingArea::Allocation stagingAlloc;
4425 recordSmallStagingAreaDemand(allocSize);
4426 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
4427 stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
4429 std::optional<QD3D12StagingArea> ownStagingArea;
4430 if (!stagingAlloc.isValid()) {
4431 ownStagingArea = QD3D12StagingArea();
4432 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
4434 stagingAlloc = ownStagingArea->get(allocSize);
4435 if (!stagingAlloc.isValid()) {
4436 ownStagingArea->destroy();
4441 D3D12_TEXTURE_COPY_LOCATION dst;
4442 dst.pResource = res->resource;
4443 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4444 dst.SubresourceIndex = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
4445 D3D12_TEXTURE_COPY_LOCATION src;
4446 src.pResource = stagingAlloc.buffer;
4447 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4448 src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
4452 if (!subresDesc.image().isNull()) {
4453 const QImage img = subresDesc.image();
4454 const int bpc = qMax(1, img.depth() / 8);
4455 const int bpl = img.bytesPerLine();
4457 QSize size = subresDesc.sourceSize().isEmpty() ? img.size() : subresDesc.sourceSize();
4458 size.setWidth(qMin(size.width(), img.width() - srcPos.x()));
4459 size.setHeight(qMin(size.height(), img.height() - srcPos.y()));
4460 size = clampedSubResourceUploadSize(size, dstPos, level, texD->m_pixelSize);
4462 footprint.Width = size.width();
4463 footprint.Height = size.height();
4467 srcBox.right = UINT(size.width());
4468 srcBox.bottom = UINT(size.height());
4472 const uchar *imgPtr = img.constBits();
4473 const quint32 lineBytes = size.width() * bpc;
4474 for (
int y = 0, h = size.height(); y < h; ++y) {
4475 memcpy(stagingAlloc.p + y * footprint.RowPitch,
4476 imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
4479 }
else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
4482 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
4484 dstPos.setX(aligned(dstPos.x(), blockDim.width()));
4485 dstPos.setY(aligned(dstPos.y(), blockDim.height()));
4490 srcBox.right = aligned(subresSize.width(), blockDim.width());
4491 srcBox.bottom = aligned(subresSize.height(), blockDim.height());
4496 footprint.Width = aligned(subresSize.width(), blockDim.width());
4497 footprint.Height = aligned(subresSize.height(), blockDim.height());
4499 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4500 const QByteArray imgData = subresDesc.data();
4501 const char *imgPtr = imgData.constData();
4502 const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
4503 for (
int y = 0; y < rowCount; ++y) {
4504 const quint64 srcOffset = quint64(y) * bpl;
4505 if (srcOffset >= quint64(imgData.size()))
4507 const quint32 n = quint32(qMin(quint64(copyBytes),
4508 quint64(imgData.size()) - srcOffset));
4509 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + srcOffset, n);
4511 }
else if (!subresDesc.data().isEmpty()) {
4514 srcBox.right = subresSize.width();
4515 srcBox.bottom = subresSize.height();
4519 footprint.Width = subresSize.width();
4520 footprint.Height = subresSize.height();
4523 if (subresDesc.dataStride())
4524 bpl = subresDesc.dataStride();
4526 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
4528 const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
4529 const QByteArray data = subresDesc.data();
4530 const char *imgPtr = data.constData();
4531 for (
int y = 0, h = subresSize.height(); y < h; ++y) {
4536 const quint64 srcOffset = quint64(y) * bpl;
4537 if (srcOffset >= quint64(data.size()))
4539 const quint32 n = quint32(qMin(quint64(copyBytes),
4540 quint64(data.size()) - srcOffset));
4541 memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + srcOffset, n);
4545 src.PlacedFootprint.Footprint = footprint;
4547 cbD->cmdList->CopyTextureRegion(&dst,
4550 is3D ? UINT(layer) : 0u,
4554 if (ownStagingArea.has_value())
4555 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
4559 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
4560 Q_ASSERT(u.src && u.dst);
4561 QD3D12Texture *srcD = QRHI_RES(QD3D12Texture, u.src);
4562 QD3D12Texture *dstD = QRHI_RES(QD3D12Texture, u.dst);
4563 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4564 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4565 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
4566 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
4567 if (!srcRes || !dstRes)
4570 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4571 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
4572 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4574 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
4575 srcIs3D ? 0u : UINT(u.desc.sourceLayer()),
4576 srcD->mipLevelCount);
4577 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
4578 dstIs3D ? 0u : UINT(u.desc.destinationLayer()),
4579 dstD->mipLevelCount);
4580 const QPoint dp = u.desc.destinationTopLeft();
4581 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
4582 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
4583 const QPoint sp = u.desc.sourceTopLeft();
4586 srcBox.left = UINT(sp.x());
4587 srcBox.top = UINT(sp.y());
4588 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
4590 srcBox.right = srcBox.left + UINT(copySize.width());
4591 srcBox.bottom = srcBox.top + UINT(copySize.height());
4592 srcBox.back = srcBox.front + 1;
4594 D3D12_TEXTURE_COPY_LOCATION src;
4595 src.pResource = srcRes->resource;
4596 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4597 src.SubresourceIndex = srcSubresource;
4598 D3D12_TEXTURE_COPY_LOCATION dst;
4599 dst.pResource = dstRes->resource;
4600 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4601 dst.SubresourceIndex = dstSubresource;
4603 cbD->cmdList->CopyTextureRegion(&dst,
4606 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
4609 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
4610 QD3D12Readback readback;
4611 readback.frameSlot = currentFrameSlot;
4612 readback.result = u.result;
4614 QD3D12ObjectHandle srcHandle;
4617 if (u.rb.texture()) {
4618 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.rb.texture());
4619 if (texD->sampleDesc.Count > 1) {
4620 qWarning(
"Multisample texture cannot be read back");
4623 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
4624 if (u.rb.rect().isValid())
4627 rect = QRect({0, 0}, q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize));
4628 readback.format = texD->m_format;
4629 srcHandle = texD->handle;
4631 Q_ASSERT(currentSwapChain);
4632 if (u.rb.rect().isValid())
4635 rect = QRect({0, 0}, currentSwapChain->pixelSize);
4636 readback.format = swapchainReadbackTextureFormat(currentSwapChain->colorFormat,
nullptr);
4637 if (readback.format == QRhiTexture::UnknownFormat)
4639 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
4641 readback.pixelSize = rect.size();
4643 textureFormatInfo(readback.format,
4645 &readback.bytesPerLine,
4649 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
4653 const UINT subresource = calcSubresource(UINT(u.rb.level()),
4654 is3D ? 0u : UINT(u.rb.layer()),
4655 srcRes->desc.MipLevels);
4656 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
4659 UINT64 totalBytes = 0;
4660 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
4661 &layout,
nullptr,
nullptr, &totalBytes);
4662 readback.stagingRowPitch = layout.Footprint.RowPitch;
4664 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT);
4665 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
4666 if (u.result->completed)
4667 u.result->completed();
4670 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
4671 if (!stagingAlloc.isValid()) {
4672 readback.staging.destroy();
4673 if (u.result->completed)
4674 u.result->completed();
4677 Q_ASSERT(stagingAlloc.bufferOffset == 0);
4679 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
4680 barrierGen.enqueueBufferedTransitionBarriers(cbD);
4682 D3D12_TEXTURE_COPY_LOCATION dst;
4683 dst.pResource = stagingAlloc.buffer;
4684 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
4685 dst.PlacedFootprint.Offset = 0;
4686 dst.PlacedFootprint.Footprint = layout.Footprint;
4688 D3D12_TEXTURE_COPY_LOCATION src;
4689 src.pResource = srcRes->resource;
4690 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
4691 src.SubresourceIndex = subresource;
4693 D3D12_BOX srcBox = {};
4694 srcBox.left = UINT(rect.left());
4695 srcBox.top = UINT(rect.top());
4696 srcBox.front = is3D ? UINT(u.rb.layer()) : 0u;
4698 srcBox.right = srcBox.left + UINT(rect.width());
4699 srcBox.bottom = srcBox.top + UINT(rect.height());
4700 srcBox.back = srcBox.front + 1;
4702 cbD->cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, &srcBox);
4703 activeReadbacks.append(readback);
4704 }
else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
4705 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, u.dst);
4706 Q_ASSERT(texD->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
4707 if (texD->flags().testFlag(QRhiTexture::ThreeDimensional))
4708 mipmapGen3D.generate(cbD, texD->handle);
4710 mipmapGen.generate(cbD, texD->handle);
4717void QRhiD3D12::finishActiveReadbacks(
bool forced)
4719 QVarLengthArray<std::function<
void()>, 4> completedCallbacks;
4721 for (
int i = activeReadbacks.size() - 1; i >= 0; --i) {
4722 QD3D12Readback &readback(activeReadbacks[i]);
4723 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
4724 readback.result->format = readback.format;
4725 readback.result->pixelSize = readback.pixelSize;
4726 readback.result->data.resize(
int(readback.byteSize));
4728 if (readback.format != QRhiTexture::UnknownFormat) {
4729 quint8 *dstPtr =
reinterpret_cast<quint8 *>(readback.result->data.data());
4730 const quint8 *srcPtr = readback.staging.mem.p;
4731 const quint32 lineSize = qMin(readback.bytesPerLine, readback.stagingRowPitch);
4732 for (
int y = 0, h = readback.pixelSize.height(); y < h; ++y)
4733 memcpy(dstPtr + y * readback.bytesPerLine, srcPtr + y * readback.stagingRowPitch, lineSize);
4735 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
4738 readback.staging.destroy();
4740 if (readback.result->completed)
4741 completedCallbacks.append(readback.result->completed);
4743 activeReadbacks.remove(i);
4747 for (
auto f : completedCallbacks)
4751bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
4752 D3D12_DESCRIPTOR_HEAP_TYPE type,
4754 quint32 neededDescriptorCount,
4762 if (h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
4763 const quint32 newPerFrameSize = qMax(h->perFrameHeapSlice[frameSlot].capacity * 2,
4764 neededDescriptorCount);
4765 QD3D12ShaderVisibleDescriptorHeap newHeap;
4766 if (!newHeap.create(dev, type, newPerFrameSize)) {
4767 qWarning(
"Could not create new shader-visible descriptor heap");
4770 h->destroyWithDeferredRelease(&releaseQueue);
4777void QRhiD3D12::resetAndResizeSmallStagingArea(
int frameSlot)
4779 QD3D12StagingArea &area(smallStagingAreas[frameSlot]);
4785 const quint32 needed = smallStagingAreaBytesNeeded[frameSlot];
4786 smallStagingAreaBytesNeeded[frameSlot] = 0;
4788 quint32 newCapacity = 0;
4789 if (needed > area.capacity) {
4792 smallStagingAreaLowDemandFrames[frameSlot] = 0;
4793 newCapacity = qMin(qNextPowerOfTwo(needed), SMALL_STAGING_AREA_BYTES_PER_FRAME_MAX);
4794 }
else if (needed <= area.capacity / 4 && area.capacity > SMALL_STAGING_AREA_BYTES_PER_FRAME_START) {
4795 if (++smallStagingAreaLowDemandFrames[frameSlot] >= SMALL_STAGING_AREA_LOW_DEMAND_FRAMES) {
4796 smallStagingAreaLowDemandFrames[frameSlot] = 0;
4797 newCapacity = qMax(area.capacity / 2, SMALL_STAGING_AREA_BYTES_PER_FRAME_START);
4800 smallStagingAreaLowDemandFrames[frameSlot] = 0;
4803 if (newCapacity && newCapacity != area.capacity) {
4804 QD3D12StagingArea newArea;
4805 if (newArea.create(
this, aligned(newCapacity, QD3D12StagingArea::ALIGNMENT), D3D12_HEAP_TYPE_UPLOAD)) {
4806 area.destroyWithDeferredRelease(&releaseQueue);
4808 QString decoratedName = QLatin1String(
"Small staging area buffer/");
4809 decoratedName += QString::number(frameSlot);
4810 area.mem.buffer->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
4819void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
4821 ID3D12DescriptorHeap *heaps[] = {
4822 shaderVisibleCbvSrvUavHeap.heap.heap,
4823 samplerMgr.shaderVisibleSamplerHeap.heap.heap
4825 cbD->cmdList->SetDescriptorHeaps(2, heaps);
4828QD3D12Buffer::QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
4829 : QRhiBuffer(rhi, type, usage, size)
4833QD3D12Buffer::~QD3D12Buffer()
4838void QD3D12Buffer::destroy()
4840 if (handles[0].isNull())
4843 QRHI_RES_RHI(QRhiD3D12);
4852 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4854 rhiD->releaseQueue.deferredReleaseResource(handles[i]);
4856 pendingHostWrites[i].clear();
4860 rhiD->unregisterResource(
this);
4863bool QD3D12Buffer::create()
4865 if (!handles[0].isNull())
4868 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
4869 qWarning(
"UniformBuffer must always be Dynamic");
4873 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
4874 qWarning(
"StorageBuffer cannot be combined with Dynamic");
4878 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
4879 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
4881 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
4882 if (m_usage.testFlag(QRhiBuffer::StorageBuffer))
4883 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4885 QRHI_RES_RHI(QRhiD3D12);
4887 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4888 if (i == 0 || m_type == Dynamic) {
4889 D3D12_RESOURCE_DESC resourceDesc = {};
4890 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
4891 resourceDesc.Width = roundedSize;
4892 resourceDesc.Height = 1;
4893 resourceDesc.DepthOrArraySize = 1;
4894 resourceDesc.MipLevels = 1;
4895 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
4896 resourceDesc.SampleDesc = { 1, 0 };
4897 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
4898 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
4899 ID3D12Resource *resource =
nullptr;
4900 D3D12MA::Allocation *allocation =
nullptr;
4902 D3D12_HEAP_TYPE heapType = m_type == Dynamic
4903 ? D3D12_HEAP_TYPE_UPLOAD
4904 : D3D12_HEAP_TYPE_DEFAULT;
4905 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
4906 ? D3D12_RESOURCE_STATE_GENERIC_READ
4907 : D3D12_RESOURCE_STATE_COMMON;
4908 hr = rhiD->vma.createResource(heapType,
4914 reinterpret_cast<
void **>(&resource));
4917 if (!m_objectName.isEmpty()) {
4918 QString decoratedName = QString::fromUtf8(m_objectName);
4919 if (m_type == Dynamic) {
4920 decoratedName += QLatin1Char(
'/');
4921 decoratedName += QString::number(i);
4923 resource->SetName(
reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
4925 void *cpuMemPtr =
nullptr;
4926 if (m_type == Dynamic) {
4928 hr = resource->Map(0,
nullptr, &cpuMemPtr);
4930 qWarning(
"Map() failed to dynamic buffer");
4931 resource->Release();
4933 allocation->Release();
4937 handles[i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
4945 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
4946 qPrintable(QSystemError::windowsComString(hr)),
4949 int(rhiD->vma.isUsingD3D12MA()));
4954 rhiD->registerResource(
this);
4958QRhiBuffer::NativeBuffer QD3D12Buffer::nativeBuffer()
4961 Q_ASSERT(
sizeof(b.objects) /
sizeof(b.objects[0]) >= size_t(QD3D12_FRAMES_IN_FLIGHT));
4962 QRHI_RES_RHI(QRhiD3D12);
4963 if (m_type == Dynamic) {
4964 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
4965 executeHostWritesForFrameSlot(i);
4966 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[i]))
4967 b.objects[i] = res->resource;
4969 b.objects[i] =
nullptr;
4971 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
4974 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[0]))
4975 b.objects[0] = res->resource;
4977 b.objects[0] =
nullptr;
4982char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
4990 Q_ASSERT(m_type == Dynamic);
4991 QRHI_RES_RHI(QRhiD3D12);
4992 Q_ASSERT(rhiD->inFrame);
4993 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
4994 return static_cast<
char *>(res->cpuMapPtr);
4999void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
5004void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
5006 if (pendingHostWrites[frameSlot].isEmpty())
5009 Q_ASSERT(m_type == QRhiBuffer::Dynamic);
5010 QRHI_RES_RHI(QRhiD3D12);
5011 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
5012 Q_ASSERT(res->cpuMapPtr);
5013 for (
const QD3D12Buffer::HostWrite &u : std::as_const(pendingHostWrites[frameSlot]))
5014 memcpy(
static_cast<
char *>(res->cpuMapPtr) + u.offset, u.data.constData(), u.data.size());
5016 pendingHostWrites[frameSlot].clear();
5019static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
5021 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
5023 case QRhiTexture::RGBA8:
5024 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
5025 case QRhiTexture::BGRA8:
5026 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
5027 case QRhiTexture::R8:
5028 return DXGI_FORMAT_R8_UNORM;
5029 case QRhiTexture::R8SI:
5030 return DXGI_FORMAT_R8_SINT;
5031 case QRhiTexture::R8UI:
5032 return DXGI_FORMAT_R8_UINT;
5033 case QRhiTexture::RG8:
5034 return DXGI_FORMAT_R8G8_UNORM;
5035 case QRhiTexture::R16:
5036 return DXGI_FORMAT_R16_UNORM;
5037 case QRhiTexture::RG16:
5038 return DXGI_FORMAT_R16G16_UNORM;
5039 case QRhiTexture::RED_OR_ALPHA8:
5040 return DXGI_FORMAT_R8_UNORM;
5042 case QRhiTexture::RGBA16F:
5043 return DXGI_FORMAT_R16G16B16A16_FLOAT;
5044 case QRhiTexture::RGBA32F:
5045 return DXGI_FORMAT_R32G32B32A32_FLOAT;
5046 case QRhiTexture::R16F:
5047 return DXGI_FORMAT_R16_FLOAT;
5048 case QRhiTexture::R32F:
5049 return DXGI_FORMAT_R32_FLOAT;
5051 case QRhiTexture::RGB10A2:
5052 return DXGI_FORMAT_R10G10B10A2_UNORM;
5054 case QRhiTexture::R32SI:
5055 return DXGI_FORMAT_R32_SINT;
5056 case QRhiTexture::R32UI:
5057 return DXGI_FORMAT_R32_UINT;
5058 case QRhiTexture::RG32SI:
5059 return DXGI_FORMAT_R32G32_SINT;
5060 case QRhiTexture::RG32UI:
5061 return DXGI_FORMAT_R32G32_UINT;
5062 case QRhiTexture::RGBA32SI:
5063 return DXGI_FORMAT_R32G32B32A32_SINT;
5064 case QRhiTexture::RGBA32UI:
5065 return DXGI_FORMAT_R32G32B32A32_UINT;
5067 case QRhiTexture::D16:
5068 return DXGI_FORMAT_R16_TYPELESS;
5069 case QRhiTexture::D24:
5070 return DXGI_FORMAT_R24G8_TYPELESS;
5071 case QRhiTexture::D24S8:
5072 return DXGI_FORMAT_R24G8_TYPELESS;
5073 case QRhiTexture::D32F:
5074 return DXGI_FORMAT_R32_TYPELESS;
5075 case QRhiTexture::Format::D32FS8:
5076 return DXGI_FORMAT_R32G8X24_TYPELESS;
5078 case QRhiTexture::BC1:
5079 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
5080 case QRhiTexture::BC2:
5081 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
5082 case QRhiTexture::BC3:
5083 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
5084 case QRhiTexture::BC4:
5085 return DXGI_FORMAT_BC4_UNORM;
5086 case QRhiTexture::BC5:
5087 return DXGI_FORMAT_BC5_UNORM;
5088 case QRhiTexture::BC6H:
5089 return DXGI_FORMAT_BC6H_UF16;
5090 case QRhiTexture::BC7:
5091 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
5093 case QRhiTexture::ETC2_RGB8:
5094 case QRhiTexture::ETC2_RGB8A1:
5095 case QRhiTexture::ETC2_RGBA8:
5096 qWarning(
"QRhiD3D12 does not support ETC2 textures");
5097 return DXGI_FORMAT_R8G8B8A8_UNORM;
5099 case QRhiTexture::ASTC_4x4:
5100 case QRhiTexture::ASTC_5x4:
5101 case QRhiTexture::ASTC_5x5:
5102 case QRhiTexture::ASTC_6x5:
5103 case QRhiTexture::ASTC_6x6:
5104 case QRhiTexture::ASTC_8x5:
5105 case QRhiTexture::ASTC_8x6:
5106 case QRhiTexture::ASTC_8x8:
5107 case QRhiTexture::ASTC_10x5:
5108 case QRhiTexture::ASTC_10x6:
5109 case QRhiTexture::ASTC_10x8:
5110 case QRhiTexture::ASTC_10x10:
5111 case QRhiTexture::ASTC_12x10:
5112 case QRhiTexture::ASTC_12x12:
5113 qWarning(
"QRhiD3D12 does not support ASTC textures");
5114 return DXGI_FORMAT_R8G8B8A8_UNORM;
5119 return DXGI_FORMAT_R8G8B8A8_UNORM;
5122QD3D12RenderBuffer::QD3D12RenderBuffer(QRhiImplementation *rhi,
5124 const QSize &pixelSize,
5127 QRhiTexture::Format backingFormatHint)
5128 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
5132QD3D12RenderBuffer::~QD3D12RenderBuffer()
5137void QD3D12RenderBuffer::destroy()
5139 if (handle.isNull())
5142 QRHI_RES_RHI(QRhiD3D12);
5145 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->rtvPool, rtv, 1);
5146 else if (dsv.isValid())
5147 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->dsvPool, dsv, 1);
5155 rhiD->unregisterResource(
this);
5158bool QD3D12RenderBuffer::create()
5160 if (!handle.isNull())
5163 if (m_pixelSize.isEmpty())
5166 QRHI_RES_RHI(QRhiD3D12);
5169 case QRhiRenderBuffer::Color:
5171 dxgiFormat = toD3DTextureFormat(backingFormat(), {});
5172 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5173 D3D12_RESOURCE_DESC resourceDesc = {};
5174 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
5175 resourceDesc.Width = UINT64(m_pixelSize.width());
5176 resourceDesc.Height = UINT(m_pixelSize.height());
5177 resourceDesc.DepthOrArraySize = 1;
5178 resourceDesc.MipLevels = 1;
5179 resourceDesc.Format = dxgiFormat;
5180 resourceDesc.SampleDesc = sampleDesc;
5181 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5182 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
5183 D3D12_CLEAR_VALUE clearValue = {};
5184 clearValue.Format = dxgiFormat;
5186 ID3D12Resource *resource =
nullptr;
5187 D3D12MA::Allocation *allocation =
nullptr;
5188 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5190 D3D12_RESOURCE_STATE_RENDER_TARGET,
5193 __uuidof(ID3D12Resource),
5194 reinterpret_cast<
void **>(&resource));
5196 qWarning(
"Failed to create color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
5199 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
5200 rtv = rhiD->rtvPool.allocate(1);
5203 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5204 rtvDesc.Format = dxgiFormat;
5205 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
5206 : D3D12_RTV_DIMENSION_TEXTURE2D;
5207 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
5210 case QRhiRenderBuffer::DepthStencil:
5212 dxgiFormat = DS_FORMAT;
5213 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5214 D3D12_RESOURCE_DESC resourceDesc = {};
5215 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
5216 resourceDesc.Width = UINT64(m_pixelSize.width());
5217 resourceDesc.Height = UINT(m_pixelSize.height());
5218 resourceDesc.DepthOrArraySize = 1;
5219 resourceDesc.MipLevels = 1;
5220 resourceDesc.Format = dxgiFormat;
5221 resourceDesc.SampleDesc = sampleDesc;
5222 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5223 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
5224 if (m_flags.testFlag(UsedWithSwapChainOnly))
5225 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
5226 D3D12_CLEAR_VALUE clearValue = {};
5227 clearValue.Format = dxgiFormat;
5228 clearValue.DepthStencil.Depth = 1.0f;
5229 clearValue.DepthStencil.Stencil = 0;
5230 ID3D12Resource *resource =
nullptr;
5231 D3D12MA::Allocation *allocation =
nullptr;
5232 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5234 D3D12_RESOURCE_STATE_DEPTH_WRITE,
5237 __uuidof(ID3D12Resource),
5238 reinterpret_cast<
void **>(&resource));
5240 qWarning(
"Failed to create depth-stencil buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
5243 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE, allocation);
5244 dsv = rhiD->dsvPool.allocate(1);
5247 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5248 dsvDesc.Format = dxgiFormat;
5249 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
5250 : D3D12_DSV_DIMENSION_TEXTURE2D;
5251 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
5256 if (!m_objectName.isEmpty()) {
5257 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
5258 const QString name = QString::fromUtf8(m_objectName);
5259 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
5264 rhiD->registerResource(
this);
5268QRhiTexture::Format QD3D12RenderBuffer::backingFormat()
const
5270 if (m_backingFormatHint != QRhiTexture::UnknownFormat)
5271 return m_backingFormatHint;
5273 return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat;
5276QD3D12Texture::QD3D12Texture(QRhiImplementation *rhi, Format format,
const QSize &pixelSize,
int depth,
5277 int arraySize,
int sampleCount, Flags flags)
5278 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
5282QD3D12Texture::~QD3D12Texture()
5287void QD3D12Texture::destroy()
5289 if (handle.isNull())
5292 QRHI_RES_RHI(QRhiD3D12);
5294 rhiD->releaseQueue.deferredReleaseResourceWithViews(handle, &rhiD->cbvSrvUavPool, srv, 1);
5298 resolveDestInitialized.clear();
5301 rhiD->unregisterResource(
this);
5304static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
5307 case QRhiTexture::Format::D16:
5308 return DXGI_FORMAT_R16_FLOAT;
5309 case QRhiTexture::Format::D24:
5310 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
5311 case QRhiTexture::Format::D24S8:
5312 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
5313 case QRhiTexture::Format::D32F:
5314 return DXGI_FORMAT_R32_FLOAT;
5315 case QRhiTexture::Format::D32FS8:
5316 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
5320 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
5323static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
5327 case QRhiTexture::Format::D16:
5328 return DXGI_FORMAT_D16_UNORM;
5329 case QRhiTexture::Format::D24:
5330 return DXGI_FORMAT_D24_UNORM_S8_UINT;
5331 case QRhiTexture::Format::D24S8:
5332 return DXGI_FORMAT_D24_UNORM_S8_UINT;
5333 case QRhiTexture::Format::D32F:
5334 return DXGI_FORMAT_D32_FLOAT;
5335 case QRhiTexture::Format::D32FS8:
5336 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
5340 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
5343static inline bool isDepthTextureFormat(QRhiTexture::Format format)
5346 case QRhiTexture::Format::D16:
5347 case QRhiTexture::Format::D24:
5348 case QRhiTexture::Format::D24S8:
5349 case QRhiTexture::Format::D32F:
5350 case QRhiTexture::Format::D32FS8:
5357bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
5359 if (!handle.isNull())
5362 QRHI_RES_RHI(QRhiD3D12);
5363 if (!rhiD->isTextureFormatSupported(m_format, m_flags))
5366 const bool isDepth = isDepthTextureFormat(m_format);
5367 const bool isCube = m_flags.testFlag(CubeMap);
5368 const bool is3D = m_flags.testFlag(ThreeDimensional);
5369 const bool isArray = m_flags.testFlag(TextureArray);
5370 const bool hasMipMaps = m_flags.testFlag(MipMapped);
5371 const bool is1D = m_flags.testFlag(OneDimensional);
5373 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
5374 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
5376 dxgiFormat = toD3DTextureFormat(m_format, m_flags);
5378 srvFormat = toD3DDepthTextureSRVFormat(m_format);
5379 rtFormat = toD3DDepthTextureDSVFormat(m_format);
5381 srvFormat = dxgiFormat;
5382 rtFormat = dxgiFormat;
5384 if (m_writeViewFormat.format != UnknownFormat) {
5386 rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
5388 rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
5390 if (m_readViewFormat.format != UnknownFormat) {
5392 srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
5394 srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
5397 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
5398 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
5399 if (sampleDesc.Count > 1) {
5401 qWarning(
"Cubemap texture cannot be multisample");
5405 qWarning(
"3D texture cannot be multisample");
5409 qWarning(
"Multisample texture cannot have mipmaps");
5413 if (isDepth && hasMipMaps) {
5414 qWarning(
"Depth texture cannot have mipmaps");
5417 if (isCube && is3D) {
5418 qWarning(
"Texture cannot be both cube and 3D");
5421 if (isArray && is3D) {
5422 qWarning(
"Texture cannot be both array and 3D");
5425 if (isCube && is1D) {
5426 qWarning(
"Texture cannot be both cube and 1D");
5430 qWarning(
"Texture cannot be both 1D and 3D");
5433 if (m_depth > 1 && !is3D) {
5434 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
5437 if (m_arraySize > 0 && !isArray) {
5438 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
5441 if (m_arraySize < 1 && isArray) {
5442 qWarning(
"Texture is an array but array size is %d", m_arraySize);
5446 if (!rhiD->textureFormatInfo(m_format, size,
nullptr,
nullptr,
nullptr))
5450 *adjustedSize = size;
5455bool QD3D12Texture::finishCreate()
5457 QRHI_RES_RHI(QRhiD3D12);
5458 const bool isCube = m_flags.testFlag(CubeMap);
5459 const bool is3D = m_flags.testFlag(ThreeDimensional);
5460 const bool isArray = m_flags.testFlag(TextureArray);
5461 const bool is1D = m_flags.testFlag(OneDimensional);
5463 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
5464 srvDesc.Format = srvFormat;
5465 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
5468 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
5469 srvDesc.TextureCube.MipLevels = mipLevelCount;
5473 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
5474 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
5475 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5476 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
5477 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
5479 srvDesc.Texture1DArray.FirstArraySlice = 0;
5480 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
5483 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
5484 srvDesc.Texture1D.MipLevels = mipLevelCount;
5486 }
else if (isArray) {
5487 if (sampleDesc.Count > 1) {
5488 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
5489 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5490 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
5491 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
5493 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
5494 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
5497 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
5498 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
5499 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
5500 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
5501 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
5503 srvDesc.Texture2DArray.FirstArraySlice = 0;
5504 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
5508 if (sampleDesc.Count > 1) {
5509 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
5511 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
5512 srvDesc.Texture3D.MipLevels = mipLevelCount;
5514 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
5515 srvDesc.Texture2D.MipLevels = mipLevelCount;
5520 srv = rhiD->cbvSrvUavPool.allocate(1);
5524 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle)) {
5525 rhiD->dev->CreateShaderResourceView(res->resource, &srvDesc, srv.cpuHandle);
5526 if (!m_objectName.isEmpty()) {
5527 const QString name = QString::fromUtf8(m_objectName);
5528 res->resource->SetName(
reinterpret_cast<LPCWSTR>(name.utf16()));
5538bool QD3D12Texture::create()
5541 if (!prepareCreate(&size))
5544 const bool isDepth = isDepthTextureFormat(m_format);
5545 const bool isCube = m_flags.testFlag(CubeMap);
5546 const bool is3D = m_flags.testFlag(ThreeDimensional);
5547 const bool isArray = m_flags.testFlag(TextureArray);
5548 const bool is1D = m_flags.testFlag(OneDimensional);
5550 QRHI_RES_RHI(QRhiD3D12);
5552 bool needsOptimizedClearValueSpecified =
false;
5553 UINT resourceFlags = 0;
5554 if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
5556 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
5558 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
5559 needsOptimizedClearValueSpecified =
true;
5561 if (m_flags.testFlag(UsedWithGenerateMips)) {
5563 qWarning(
"Depth texture cannot have mipmaps generated");
5566 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5568 if (m_flags.testFlag(UsedWithLoadStore))
5569 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
5571 D3D12_RESOURCE_DESC resourceDesc = {};
5572 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
5573 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
5574 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
5575 resourceDesc.Width = UINT64(size.width());
5576 resourceDesc.Height = UINT(size.height());
5577 resourceDesc.DepthOrArraySize = isCube ? 6
5578 : (isArray ? UINT(qMax(0, m_arraySize))
5579 : (is3D ? qMax(1, m_depth)
5581 resourceDesc.MipLevels = mipLevelCount;
5582 resourceDesc.Format = dxgiFormat;
5583 resourceDesc.SampleDesc = sampleDesc;
5584 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
5585 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
5586 D3D12_CLEAR_VALUE clearValue = {};
5587 clearValue.Format = dxgiFormat;
5589 clearValue.Format = toD3DDepthTextureDSVFormat(m_format);
5590 clearValue.DepthStencil.Depth = 1.0f;
5591 clearValue.DepthStencil.Stencil = 0;
5593 ID3D12Resource *resource =
nullptr;
5594 D3D12MA::Allocation *allocation =
nullptr;
5595 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
5597 D3D12_RESOURCE_STATE_COMMON,
5598 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
5600 __uuidof(ID3D12Resource),
5601 reinterpret_cast<
void **>(&resource));
5603 qWarning(
"Failed to create texture: '%s'"
5604 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
5605 qPrintable(QSystemError::windowsComString(hr)),
5606 int(resourceDesc.Dimension),
5607 uint(resourceDesc.Width),
5608 uint(resourceDesc.Height),
5609 uint(resourceDesc.DepthOrArraySize),
5610 uint(resourceDesc.MipLevels),
5611 int(resourceDesc.Format),
5612 int(resourceDesc.SampleDesc.Count));
5613 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
5614 rhiD->deviceLost =
true;
5618 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON, allocation);
5620 if (!finishCreate())
5623 rhiD->registerResource(
this);
5627bool QD3D12Texture::createFrom(QRhiTexture::NativeTexture src)
5632 if (!prepareCreate())
5635 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *>(src.object);
5636 D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATES(src.layout);
5638 QRHI_RES_RHI(QRhiD3D12);
5639 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource, state);
5641 if (!finishCreate())
5644 rhiD->registerResource(
this);
5648QRhiTexture::NativeTexture QD3D12Texture::nativeTexture()
5650 QRHI_RES_RHI(QRhiD3D12);
5651 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
5652 return { quint64(res->resource),
int(res->state) };
5657void QD3D12Texture::setNativeLayout(
int layout)
5659 QRHI_RES_RHI(QRhiD3D12);
5660 if (QD3D12Resource *res = rhiD->resourcePool.lookupRef(handle))
5661 res->state = D3D12_RESOURCE_STATES(layout);
5664QD3D12Sampler::QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
5665 AddressMode u, AddressMode v, AddressMode w)
5666 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
5670QD3D12Sampler::~QD3D12Sampler()
5675void QD3D12Sampler::destroy()
5677 shaderVisibleDescriptor = {};
5679 QRHI_RES_RHI(QRhiD3D12);
5681 rhiD->unregisterResource(
this);
5684static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
5686 if (minFilter == QRhiSampler::Nearest) {
5687 if (magFilter == QRhiSampler::Nearest) {
5688 if (mipFilter == QRhiSampler::Linear)
5689 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
5691 return D3D12_FILTER_MIN_MAG_MIP_POINT;
5693 if (mipFilter == QRhiSampler::Linear)
5694 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
5696 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
5699 if (magFilter == QRhiSampler::Nearest) {
5700 if (mipFilter == QRhiSampler::Linear)
5701 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
5703 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
5705 if (mipFilter == QRhiSampler::Linear)
5706 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
5708 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
5711 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
5714static inline D3D12_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
5717 case QRhiSampler::Repeat:
5718 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
5719 case QRhiSampler::ClampToEdge:
5720 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
5721 case QRhiSampler::Mirror:
5722 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
5724 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
5727static inline D3D12_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
5730 case QRhiSampler::Never:
5731 return D3D12_COMPARISON_FUNC_NEVER;
5732 case QRhiSampler::Less:
5733 return D3D12_COMPARISON_FUNC_LESS;
5734 case QRhiSampler::Equal:
5735 return D3D12_COMPARISON_FUNC_EQUAL;
5736 case QRhiSampler::LessOrEqual:
5737 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5738 case QRhiSampler::Greater:
5739 return D3D12_COMPARISON_FUNC_GREATER;
5740 case QRhiSampler::NotEqual:
5741 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5742 case QRhiSampler::GreaterOrEqual:
5743 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5744 case QRhiSampler::Always:
5745 return D3D12_COMPARISON_FUNC_ALWAYS;
5747 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
5750bool QD3D12Sampler::create()
5753 desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
5754 if (m_compareOp != Never)
5755 desc.Filter = D3D12_FILTER(desc.Filter | 0x80);
5756 desc.AddressU = toD3DAddressMode(m_addressU);
5757 desc.AddressV = toD3DAddressMode(m_addressV);
5758 desc.AddressW = toD3DAddressMode(m_addressW);
5759 desc.MaxAnisotropy = 1.0f;
5760 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
5761 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
5765 shaderVisibleDescriptor = {};
5769 QRHI_RES_RHI(QRhiD3D12);
5770 rhiD->registerResource(
this,
false);
5774QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
5776 if (!shaderVisibleDescriptor.isValid()) {
5777 QRHI_RES_RHI(QRhiD3D12);
5778 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(desc);
5780 return shaderVisibleDescriptor;
5783QD3D12ShadingRateMap::QD3D12ShadingRateMap(QRhiImplementation *rhi)
5784 : QRhiShadingRateMap(rhi)
5788QD3D12ShadingRateMap::~QD3D12ShadingRateMap()
5793void QD3D12ShadingRateMap::destroy()
5795 if (handle.isNull())
5801bool QD3D12ShadingRateMap::createFrom(QRhiTexture *src)
5803 if (!handle.isNull())
5806 handle = QRHI_RES(QD3D12Texture, src)->handle;
5811QD3D12TextureRenderTarget::QD3D12TextureRenderTarget(QRhiImplementation *rhi,
5812 const QRhiTextureRenderTargetDescription &desc,
5814 : QRhiTextureRenderTarget(rhi, desc, flags),
5819QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
5824void QD3D12TextureRenderTarget::destroy()
5826 if (!rtv[0].isValid() && !dsv.isValid())
5829 QRHI_RES_RHI(QRhiD3D12);
5830 if (dsv.isValid()) {
5831 if (ownsDsv && rhiD)
5832 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
5836 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i) {
5837 if (rtv[i].isValid()) {
5838 if (ownsRtv[i] && rhiD)
5839 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[i], 1);
5845 rhiD->unregisterResource(
this);
5848QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDescriptor()
5852 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
5854 rpD->colorAttachmentCount = 0;
5855 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it) {
5856 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
5857 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
5859 rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
5861 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
5862 rpD->colorAttachmentCount += 1;
5865 rpD->hasDepthStencil =
false;
5866 if (m_desc.depthStencilBuffer()) {
5867 rpD->hasDepthStencil =
true;
5868 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
5869 }
else if (m_desc.depthTexture()) {
5870 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5871 rpD->hasDepthStencil =
true;
5872 rpD->dsFormat = toD3DDepthTextureDSVFormat(depthTexD->format());
5875 rpD->hasShadingRateMap = m_desc.shadingRateMap() !=
nullptr;
5877 rpD->updateSerializedFormat();
5879 QRHI_RES_RHI(QRhiD3D12);
5880 rhiD->registerResource(rpD);
5884bool QD3D12TextureRenderTarget::create()
5886 if (rtv[0].isValid() || dsv.isValid())
5889 QRHI_RES_RHI(QRhiD3D12);
5890 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
5891 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
5892 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
5893 d.colorAttCount = 0;
5896 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
5897 d.colorAttCount += 1;
5898 const QRhiColorAttachment &colorAtt(*it);
5899 QRhiTexture *texture = colorAtt.texture();
5900 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
5901 Q_ASSERT(texture || rb);
5903 QD3D12Texture *texD = QRHI_RES(QD3D12Texture, texture);
5904 QD3D12Resource *res = rhiD->resourcePool.lookupRef(texD->handle);
5906 qWarning(
"Could not look up texture handle for render target");
5909 const bool isMultiView = it->multiViewCount() >= 2;
5910 UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
5911 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5912 rtvDesc.Format = texD->rtFormat;
5913 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
5914 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5915 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5916 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5917 rtvDesc.Texture2DArray.ArraySize = layerCount;
5918 }
else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
5919 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5920 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
5921 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
5922 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
5923 rtvDesc.Texture1DArray.ArraySize = layerCount;
5925 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
5926 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
5928 }
else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
5929 if (texD->sampleDesc.Count > 1) {
5930 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
5931 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
5932 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
5934 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
5935 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
5936 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
5937 rtvDesc.Texture2DArray.ArraySize = layerCount;
5939 }
else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
5940 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
5941 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
5942 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
5943 rtvDesc.Texture3D.WSize = layerCount;
5945 if (texD->sampleDesc.Count > 1) {
5946 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
5948 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
5949 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
5952 rtv[attIndex] = rhiD->rtvPool.allocate(1);
5953 if (!rtv[attIndex].isValid()) {
5954 qWarning(
"Failed to allocate RTV for texture render target");
5957 rhiD->dev->CreateRenderTargetView(res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
5958 ownsRtv[attIndex] =
true;
5959 if (attIndex == 0) {
5960 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
5961 d.sampleCount =
int(texD->sampleDesc.Count);
5964 QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, rb);
5965 ownsRtv[attIndex] =
false;
5966 rtv[attIndex] = rbD->rtv;
5967 if (attIndex == 0) {
5968 d.pixelSize = rbD->pixelSize();
5969 d.sampleCount =
int(rbD->sampleDesc.Count);
5976 if (hasDepthStencil) {
5977 if (m_desc.depthTexture()) {
5979 QD3D12Texture *depthTexD = QRHI_RES(QD3D12Texture, m_desc.depthTexture());
5980 QD3D12Resource *res = rhiD->resourcePool.lookupRef(depthTexD->handle);
5982 qWarning(
"Could not look up depth texture handle");
5985 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
5986 dsvDesc.Format = depthTexD->rtFormat;
5987 const bool isMultisample = depthTexD->sampleDesc.Count > 1;
5988 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
5989 if (isMultisample) {
5990 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
5991 if (m_desc.depthLayer() >= 0) {
5992 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_desc.depthLayer());
5993 dsvDesc.Texture2DMSArray.ArraySize = 1;
5994 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
5995 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
5996 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
5998 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
5999 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
6002 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
6003 if (m_desc.depthLayer() >= 0) {
6004 dsvDesc.Texture2DArray.FirstArraySlice = UINT(m_desc.depthLayer());
6005 dsvDesc.Texture2DArray.ArraySize = 1;
6006 }
else if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
6007 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
6008 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
6010 dsvDesc.Texture2DArray.FirstArraySlice = 0;
6011 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
6016 dsvDesc.ViewDimension = isMultisample ? D3D12_DSV_DIMENSION_TEXTURE2DMS
6017 : D3D12_DSV_DIMENSION_TEXTURE2D;
6019 dsv = rhiD->dsvPool.allocate(1);
6020 if (!dsv.isValid()) {
6021 qWarning(
"Failed to allocate DSV for texture render target");
6024 rhiD->dev->CreateDepthStencilView(res->resource, &dsvDesc, dsv.cpuHandle);
6025 if (d.colorAttCount == 0) {
6026 d.pixelSize = depthTexD->pixelSize();
6027 d.sampleCount =
int(depthTexD->sampleDesc.Count);
6031 QD3D12RenderBuffer *depthRbD = QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
6032 dsv = depthRbD->dsv;
6033 if (d.colorAttCount == 0) {
6034 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
6035 d.sampleCount =
int(depthRbD->sampleDesc.Count);
6043 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
6044 for (
int i = 0; i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++i)
6045 d.rtv[i] = i < d.colorAttCount ? rtv[i].cpuHandle : nullDescHandle;
6046 d.dsv = dsv.cpuHandle;
6047 d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6049 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &d.currentResIdList);
6051 rhiD->registerResource(
this);
6055QSize QD3D12TextureRenderTarget::pixelSize()
const
6057 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc, d.currentResIdList))
6058 const_cast<QD3D12TextureRenderTarget *>(
this)->create();
6063float QD3D12TextureRenderTarget::devicePixelRatio()
const
6068int QD3D12TextureRenderTarget::sampleCount()
const
6070 return d.sampleCount;
6073QD3D12ShaderResourceBindings::QD3D12ShaderResourceBindings(QRhiImplementation *rhi)
6074 : QRhiShaderResourceBindings(rhi)
6078QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
6083void QD3D12ShaderResourceBindings::destroy()
6085 bindingCache.reset();
6086 bindingCacheValid =
false;
6087 boundResourceData.clear();
6089 QRHI_RES_RHI(QRhiD3D12);
6091 rhiD->unregisterResource(
this);
6094bool QD3D12ShaderResourceBindings::create()
6096 QRHI_RES_RHI(QRhiD3D12);
6097 if (!rhiD->sanityCheckShaderResourceBindings(
this))
6100 rhiD->updateLayoutDesc(
this);
6102 boundResourceData.resize(m_bindings.count());
6103 for (BoundResourceData &bd : boundResourceData)
6104 memset(&bd, 0,
sizeof(BoundResourceData));
6106 bindingCache.reset();
6107 bindingCacheValid =
false;
6109 hasDynamicOffset =
false;
6110 for (
const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
6111 const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
6112 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
6113 hasDynamicOffset =
true;
6127 rhiD->registerResource(
this,
false);
6131void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
6135 Q_ASSERT(boundResourceData.count() == m_bindings.count());
6136 for (BoundResourceData &bd : boundResourceData)
6137 memset(&bd, 0,
sizeof(BoundResourceData));
6139 bindingCache.reset();
6140 bindingCacheValid =
false;
6150void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
6151 const QRhiShaderResourceBinding::Data::UniformBufferData &,
6155 D3D12_ROOT_PARAMETER1 rootParam = {};
6156 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
6157 rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
6158 rootParam.Descriptor.ShaderRegister = shaderRegister;
6159 rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
6160 visitorData.cbParams[s].append(rootParam);
6163void QD3D12ShaderResourceBindings::visitTextures(QD3D12Stage s,
6164 const QRhiShaderResourceBinding::TextureAndSampler *,
6166 int baseShaderRegister)
6171 D3D12_DESCRIPTOR_RANGE1 range = {};
6172 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
6173 range.NumDescriptors = UINT(count);
6174 range.BaseShaderRegister = baseShaderRegister;
6175 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[s];
6176 visitorData.currentSrvRangeOffset[s] += UINT(count);
6177 visitorData.srvRanges[s].append(range);
6178 if (visitorData.srvRanges[s].count() == 1) {
6179 visitorData.srvTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6180 visitorData.srvTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6184void QD3D12ShaderResourceBindings::visitSamplers(QD3D12Stage s,
6185 const QRhiShaderResourceBinding::TextureAndSampler *,
6187 int baseShaderRegister)
6195 int &rangeStoreIdx(visitorData.samplerRangeHeads[s]);
6196 if (rangeStoreIdx == 16) {
6197 qWarning(
"Sampler binding count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi", s);
6200 D3D12_DESCRIPTOR_RANGE1 range = {};
6201 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
6202 range.NumDescriptors = UINT(count);
6203 range.BaseShaderRegister = baseShaderRegister;
6204 visitorData.samplerRanges[s][rangeStoreIdx] = range;
6205 D3D12_ROOT_PARAMETER1 param = {};
6206 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6207 param.ShaderVisibility = qd3d12_stageToVisibility(s);
6208 param.DescriptorTable.NumDescriptorRanges = 1;
6209 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[s][rangeStoreIdx];
6211 visitorData.samplerTables[s].append(param);
6214void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage s,
6215 const QRhiShaderResourceBinding::Data::StorageBufferData &,
6216 QD3D12ShaderResourceVisitor::StorageOp,
6219 D3D12_DESCRIPTOR_RANGE1 range = {};
6220 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
6221 range.NumDescriptors = 1;
6222 range.BaseShaderRegister = shaderRegister;
6223 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
6224 visitorData.currentUavRangeOffset[s] += 1;
6225 visitorData.uavRanges[s].append(range);
6226 if (visitorData.uavRanges[s].count() == 1) {
6227 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6228 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6232void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage s,
6233 const QRhiShaderResourceBinding::Data::StorageImageData &,
6234 QD3D12ShaderResourceVisitor::StorageOp,
6237 D3D12_DESCRIPTOR_RANGE1 range = {};
6238 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
6239 range.NumDescriptors = 1;
6240 range.BaseShaderRegister = shaderRegister;
6241 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[s];
6242 visitorData.currentUavRangeOffset[s] += 1;
6243 visitorData.uavRanges[s].append(range);
6244 if (visitorData.uavRanges[s].count() == 1) {
6245 visitorData.uavTables[s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
6246 visitorData.uavTables[s].ShaderVisibility = qd3d12_stageToVisibility(s);
6250QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
6253 QRHI_RES_RHI(QRhiD3D12);
6267 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
6271 using namespace std::placeholders;
6272 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
6273 visitor.textures = std::bind(&QD3D12ShaderResourceBindings::visitTextures,
this, _1, _2, _3, _4);
6274 visitor.samplers = std::bind(&QD3D12ShaderResourceBindings::visitSamplers,
this, _1, _2, _3, _4);
6275 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
6276 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
6300 QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> rootParams;
6301 for (
int s = 0; s < 6; ++s) {
6302 if (!visitorData.cbParams[s].isEmpty())
6303 rootParams.append(visitorData.cbParams[s].constData(), visitorData.cbParams[s].count());
6305 for (
int s = 0; s < 6; ++s) {
6306 if (!visitorData.srvRanges[s].isEmpty()) {
6307 visitorData.srvTables[s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[s].count();
6308 visitorData.srvTables[s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[s].constData();
6309 rootParams.append(visitorData.srvTables[s]);
6312 for (
int s = 0; s < 6; ++s) {
6313 if (!visitorData.samplerTables[s].isEmpty())
6314 rootParams.append(visitorData.samplerTables[s].constData(), visitorData.samplerTables[s].count());
6316 for (
int s = 0; s < 6; ++s) {
6317 if (!visitorData.uavRanges[s].isEmpty()) {
6318 visitorData.uavTables[s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[s].count();
6319 visitorData.uavTables[s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[s].constData();
6320 rootParams.append(visitorData.uavTables[s]);
6324 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
6325 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
6326 if (!rootParams.isEmpty()) {
6327 rsDesc.Desc_1_1.NumParameters = rootParams.count();
6328 rsDesc.Desc_1_1.pParameters = rootParams.constData();
6332 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
6333 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
6334 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
6336 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
6338 ID3DBlob *signature =
nullptr;
6339 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
6341 qWarning(
"Failed to serialize root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
6344 ID3D12RootSignature *rootSig =
nullptr;
6345 hr = rhiD->dev->CreateRootSignature(0,
6346 signature->GetBufferPointer(),
6347 signature->GetBufferSize(),
6348 __uuidof(ID3D12RootSignature),
6349 reinterpret_cast<
void **>(&rootSig));
6350 signature->Release();
6352 qWarning(
"Failed to create root signature: %s", qPrintable(QSystemError::windowsComString(hr)));
6356 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
6368static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
6370 const int smMajor = version / 10;
6371 const int smMinor = version % 10;
6372 target[0] = stage[0];
6373 target[1] = stage[1];
6375 target[3] =
'0' + smMajor;
6377 target[5] =
'0' + smMinor;
6381enum class HlslCompileFlag
6383 WithDebugInfo = 0x01
6386static QByteArray legacyCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
6388 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
6390 qWarning(
"Unable to resolve function D3DCompile()");
6391 return QByteArray();
6394 ID3DBlob *bytecode =
nullptr;
6395 ID3DBlob *errors =
nullptr;
6396 UINT d3dCompileFlags = 0;
6397 if (flags &
int(HlslCompileFlag::WithDebugInfo))
6398 d3dCompileFlags |= D3DCOMPILE_DEBUG;
6400 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
6401 nullptr,
nullptr,
nullptr,
6402 hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
6403 if (FAILED(hr) || !bytecode) {
6404 qWarning(
"HLSL shader compilation failed: 0x%x", uint(hr));
6406 *error = QString::fromUtf8(
static_cast<
const char *>(errors->GetBufferPointer()),
6407 int(errors->GetBufferSize()));
6410 return QByteArray();
6414 result.resize(
int(bytecode->GetBufferSize()));
6415 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
6416 bytecode->Release();
6420#ifdef QRHI_D3D12_HAS_DXC
6423#define DXC_CP_UTF8 65001
6426#ifndef DXC_ARG_DEBUG
6427#define DXC_ARG_DEBUG L"-Zi"
6430static QByteArray dxcCompile(
const QShaderCode &hlslSource,
const char *target,
int flags, QString *error)
6432 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
6433 IDxcCompiler *compiler = dxc.first;
6435 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
6436 "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
6437 return QByteArray();
6439 IDxcLibrary *library = dxc.second;
6441 return QByteArray();
6443 IDxcBlobEncoding *sourceBlob =
nullptr;
6444 HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
6445 UINT32(hlslSource.shader().size()),
6449 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
6451 qPrintable(QSystemError::windowsComString(hr)));
6452 return QByteArray();
6455 const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
6456 const QString targetStr = QString::fromLatin1(target);
6458 QVarLengthArray<LPCWSTR, 4> argPtrs;
6460 if (flags &
int(HlslCompileFlag::WithDebugInfo)) {
6461 debugArg = QString::fromUtf16(
reinterpret_cast<
const char16_t *>(DXC_ARG_DEBUG));
6462 argPtrs.append(
reinterpret_cast<LPCWSTR>(debugArg.utf16()));
6465 IDxcOperationResult *result =
nullptr;
6466 hr = compiler->Compile(sourceBlob,
6468 reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
6469 reinterpret_cast<LPCWSTR>(targetStr.utf16()),
6470 argPtrs.data(), argPtrs.count(),
6474 sourceBlob->Release();
6476 result->GetStatus(&hr);
6478 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
6480 qPrintable(QSystemError::windowsComString(hr)));
6482 IDxcBlobEncoding *errorsBlob =
nullptr;
6483 if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
6485 *error = QString::fromUtf8(
static_cast<
const char *>(errorsBlob->GetBufferPointer()),
6486 int(errorsBlob->GetBufferSize()));
6487 errorsBlob->Release();
6491 return QByteArray();
6494 IDxcBlob *bytecode =
nullptr;
6495 if FAILED(result->GetResult(&bytecode)) {
6496 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
6498 qPrintable(QSystemError::windowsComString(hr)));
6499 return QByteArray();
6503 ba.resize(
int(bytecode->GetBufferSize()));
6504 memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
6505 bytecode->Release();
6511static QByteArray compileHlslShaderSource(
const QShader &shader,
6512 QShader::Variant shaderVariant,
6515 QShaderKey *usedShaderKey)
6518 const int shaderModelMax = 67;
6519 for (
int sm = shaderModelMax; sm >= 50; --sm) {
6520 for (QShader::Source type : { QShader::DxilShader, QShader::DxbcShader }) {
6521 QShaderKey key = { type, sm, shaderVariant };
6522 QShaderCode intermediateBytecodeShader = shader.shader(key);
6523 if (!intermediateBytecodeShader.shader().isEmpty()) {
6525 *usedShaderKey = key;
6526 return intermediateBytecodeShader.shader();
6531 QShaderCode hlslSource;
6533 for (
int sm = shaderModelMax; sm >= 50; --sm) {
6534 key = { QShader::HlslShader, sm, shaderVariant };
6535 hlslSource = shader.shader(key);
6536 if (!hlslSource.shader().isEmpty())
6540 if (hlslSource.shader().isEmpty()) {
6541 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" << shader;
6542 return QByteArray();
6546 *usedShaderKey = key;
6549 switch (shader.stage()) {
6550 case QShader::VertexStage:
6551 makeHlslTargetString(target,
"vs", key.sourceVersion().version());
6553 case QShader::TessellationControlStage:
6554 makeHlslTargetString(target,
"hs", key.sourceVersion().version());
6556 case QShader::TessellationEvaluationStage:
6557 makeHlslTargetString(target,
"ds", key.sourceVersion().version());
6559 case QShader::GeometryStage:
6560 makeHlslTargetString(target,
"gs", key.sourceVersion().version());
6562 case QShader::FragmentStage:
6563 makeHlslTargetString(target,
"ps", key.sourceVersion().version());
6565 case QShader::ComputeStage:
6566 makeHlslTargetString(target,
"cs", key.sourceVersion().version());
6569 qWarning(
"compileHlslShaderSource: Unknown stage (%d)",
int(shader.stage()));
6570 return QByteArray();
6573 if (key.sourceVersion().version() >= 60) {
6574#ifdef QRHI_D3D12_HAS_DXC
6575 return dxcCompile(hlslSource, target, flags, error);
6577 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
6578 "but the Qt build has no support for DXC. "
6579 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
6583 return legacyCompile(hlslSource, target, flags, error);
6586static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
6589 if (c.testFlag(QRhiGraphicsPipeline::R))
6590 f |= D3D12_COLOR_WRITE_ENABLE_RED;
6591 if (c.testFlag(QRhiGraphicsPipeline::G))
6592 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
6593 if (c.testFlag(QRhiGraphicsPipeline::B))
6594 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
6595 if (c.testFlag(QRhiGraphicsPipeline::A))
6596 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
6600static inline D3D12_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f,
bool rgb)
6609 case QRhiGraphicsPipeline::Zero:
6610 return D3D12_BLEND_ZERO;
6611 case QRhiGraphicsPipeline::One:
6612 return D3D12_BLEND_ONE;
6613 case QRhiGraphicsPipeline::SrcColor:
6614 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
6615 case QRhiGraphicsPipeline::OneMinusSrcColor:
6616 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
6617 case QRhiGraphicsPipeline::DstColor:
6618 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
6619 case QRhiGraphicsPipeline::OneMinusDstColor:
6620 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
6621 case QRhiGraphicsPipeline::SrcAlpha:
6622 return D3D12_BLEND_SRC_ALPHA;
6623 case QRhiGraphicsPipeline::OneMinusSrcAlpha:
6624 return D3D12_BLEND_INV_SRC_ALPHA;
6625 case QRhiGraphicsPipeline::DstAlpha:
6626 return D3D12_BLEND_DEST_ALPHA;
6627 case QRhiGraphicsPipeline::OneMinusDstAlpha:
6628 return D3D12_BLEND_INV_DEST_ALPHA;
6629 case QRhiGraphicsPipeline::ConstantColor:
6630 case QRhiGraphicsPipeline::ConstantAlpha:
6631 return D3D12_BLEND_BLEND_FACTOR;
6632 case QRhiGraphicsPipeline::OneMinusConstantColor:
6633 case QRhiGraphicsPipeline::OneMinusConstantAlpha:
6634 return D3D12_BLEND_INV_BLEND_FACTOR;
6635 case QRhiGraphicsPipeline::SrcAlphaSaturate:
6636 return D3D12_BLEND_SRC_ALPHA_SAT;
6637 case QRhiGraphicsPipeline::Src1Color:
6638 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
6639 case QRhiGraphicsPipeline::OneMinusSrc1Color:
6640 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
6641 case QRhiGraphicsPipeline::Src1Alpha:
6642 return D3D12_BLEND_SRC1_ALPHA;
6643 case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
6644 return D3D12_BLEND_INV_SRC1_ALPHA;
6646 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
6649static inline D3D12_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
6652 case QRhiGraphicsPipeline::Add:
6653 return D3D12_BLEND_OP_ADD;
6654 case QRhiGraphicsPipeline::Subtract:
6655 return D3D12_BLEND_OP_SUBTRACT;
6656 case QRhiGraphicsPipeline::ReverseSubtract:
6657 return D3D12_BLEND_OP_REV_SUBTRACT;
6658 case QRhiGraphicsPipeline::Min:
6659 return D3D12_BLEND_OP_MIN;
6660 case QRhiGraphicsPipeline::Max:
6661 return D3D12_BLEND_OP_MAX;
6663 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
6666static inline D3D12_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
6669 case QRhiGraphicsPipeline::None:
6670 return D3D12_CULL_MODE_NONE;
6671 case QRhiGraphicsPipeline::Front:
6672 return D3D12_CULL_MODE_FRONT;
6673 case QRhiGraphicsPipeline::Back:
6674 return D3D12_CULL_MODE_BACK;
6676 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
6679static inline D3D12_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
6682 case QRhiGraphicsPipeline::Fill:
6683 return D3D12_FILL_MODE_SOLID;
6684 case QRhiGraphicsPipeline::Line:
6685 return D3D12_FILL_MODE_WIREFRAME;
6687 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
6690static inline D3D12_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
6693 case QRhiGraphicsPipeline::Never:
6694 return D3D12_COMPARISON_FUNC_NEVER;
6695 case QRhiGraphicsPipeline::Less:
6696 return D3D12_COMPARISON_FUNC_LESS;
6697 case QRhiGraphicsPipeline::Equal:
6698 return D3D12_COMPARISON_FUNC_EQUAL;
6699 case QRhiGraphicsPipeline::LessOrEqual:
6700 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
6701 case QRhiGraphicsPipeline::Greater:
6702 return D3D12_COMPARISON_FUNC_GREATER;
6703 case QRhiGraphicsPipeline::NotEqual:
6704 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
6705 case QRhiGraphicsPipeline::GreaterOrEqual:
6706 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
6707 case QRhiGraphicsPipeline::Always:
6708 return D3D12_COMPARISON_FUNC_ALWAYS;
6710 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
6713static inline D3D12_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
6716 case QRhiGraphicsPipeline::StencilZero:
6717 return D3D12_STENCIL_OP_ZERO;
6718 case QRhiGraphicsPipeline::Keep:
6719 return D3D12_STENCIL_OP_KEEP;
6720 case QRhiGraphicsPipeline::Replace:
6721 return D3D12_STENCIL_OP_REPLACE;
6722 case QRhiGraphicsPipeline::IncrementAndClamp:
6723 return D3D12_STENCIL_OP_INCR_SAT;
6724 case QRhiGraphicsPipeline::DecrementAndClamp:
6725 return D3D12_STENCIL_OP_DECR_SAT;
6726 case QRhiGraphicsPipeline::Invert:
6727 return D3D12_STENCIL_OP_INVERT;
6728 case QRhiGraphicsPipeline::IncrementAndWrap:
6729 return D3D12_STENCIL_OP_INCR;
6730 case QRhiGraphicsPipeline::DecrementAndWrap:
6731 return D3D12_STENCIL_OP_DECR;
6733 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
6736static inline D3D12_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t,
int patchControlPointCount)
6739 case QRhiGraphicsPipeline::Triangles:
6740 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
6741 case QRhiGraphicsPipeline::TriangleStrip:
6742 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
6743 case QRhiGraphicsPipeline::TriangleFan:
6744 qWarning(
"Triangle fans are not supported with D3D");
6745 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
6746 case QRhiGraphicsPipeline::Lines:
6747 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
6748 case QRhiGraphicsPipeline::LineStrip:
6749 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
6750 case QRhiGraphicsPipeline::Points:
6751 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
6752 case QRhiGraphicsPipeline::Patches:
6753 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
6754 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
6756 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
6759static inline D3D12_PRIMITIVE_TOPOLOGY_TYPE toD3DTopologyType(QRhiGraphicsPipeline::Topology t)
6762 case QRhiGraphicsPipeline::Triangles:
6763 case QRhiGraphicsPipeline::TriangleStrip:
6764 case QRhiGraphicsPipeline::TriangleFan:
6765 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
6766 case QRhiGraphicsPipeline::Lines:
6767 case QRhiGraphicsPipeline::LineStrip:
6768 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
6769 case QRhiGraphicsPipeline::Points:
6770 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
6771 case QRhiGraphicsPipeline::Patches:
6772 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
6774 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
6777static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
6780 case QRhiVertexInputAttribute::Float4:
6781 return DXGI_FORMAT_R32G32B32A32_FLOAT;
6782 case QRhiVertexInputAttribute::Float3:
6783 return DXGI_FORMAT_R32G32B32_FLOAT;
6784 case QRhiVertexInputAttribute::Float2:
6785 return DXGI_FORMAT_R32G32_FLOAT;
6786 case QRhiVertexInputAttribute::Float:
6787 return DXGI_FORMAT_R32_FLOAT;
6788 case QRhiVertexInputAttribute::UNormByte4:
6789 return DXGI_FORMAT_R8G8B8A8_UNORM;
6790 case QRhiVertexInputAttribute::UNormByte2:
6791 return DXGI_FORMAT_R8G8_UNORM;
6792 case QRhiVertexInputAttribute::UNormByte:
6793 return DXGI_FORMAT_R8_UNORM;
6794 case QRhiVertexInputAttribute::UInt4:
6795 return DXGI_FORMAT_R32G32B32A32_UINT;
6796 case QRhiVertexInputAttribute::UInt3:
6797 return DXGI_FORMAT_R32G32B32_UINT;
6798 case QRhiVertexInputAttribute::UInt2:
6799 return DXGI_FORMAT_R32G32_UINT;
6800 case QRhiVertexInputAttribute::UInt:
6801 return DXGI_FORMAT_R32_UINT;
6802 case QRhiVertexInputAttribute::SInt4:
6803 return DXGI_FORMAT_R32G32B32A32_SINT;
6804 case QRhiVertexInputAttribute::SInt3:
6805 return DXGI_FORMAT_R32G32B32_SINT;
6806 case QRhiVertexInputAttribute::SInt2:
6807 return DXGI_FORMAT_R32G32_SINT;
6808 case QRhiVertexInputAttribute::SInt:
6809 return DXGI_FORMAT_R32_SINT;
6810 case QRhiVertexInputAttribute::Half4:
6812 case QRhiVertexInputAttribute::Half3:
6813 return DXGI_FORMAT_R16G16B16A16_FLOAT;
6814 case QRhiVertexInputAttribute::Half2:
6815 return DXGI_FORMAT_R16G16_FLOAT;
6816 case QRhiVertexInputAttribute::Half:
6817 return DXGI_FORMAT_R16_FLOAT;
6818 case QRhiVertexInputAttribute::UShort4:
6820 case QRhiVertexInputAttribute::UShort3:
6821 return DXGI_FORMAT_R16G16B16A16_UINT;
6822 case QRhiVertexInputAttribute::UShort2:
6823 return DXGI_FORMAT_R16G16_UINT;
6824 case QRhiVertexInputAttribute::UShort:
6825 return DXGI_FORMAT_R16_UINT;
6826 case QRhiVertexInputAttribute::SShort4:
6828 case QRhiVertexInputAttribute::SShort3:
6829 return DXGI_FORMAT_R16G16B16A16_SINT;
6830 case QRhiVertexInputAttribute::SShort2:
6831 return DXGI_FORMAT_R16G16_SINT;
6832 case QRhiVertexInputAttribute::SShort:
6833 return DXGI_FORMAT_R16_SINT;
6835 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
6838QD3D12GraphicsPipeline::QD3D12GraphicsPipeline(QRhiImplementation *rhi)
6839 : QRhiGraphicsPipeline(rhi)
6843QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
6848void QD3D12GraphicsPipeline::destroy()
6850 if (handle.isNull())
6853 QRHI_RES_RHI(QRhiD3D12);
6855 rhiD->releaseQueue.deferredReleasePipeline(handle);
6856 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
6863 rhiD->unregisterResource(
this);
6866bool QD3D12GraphicsPipeline::create()
6868 if (!handle.isNull())
6871 QRHI_RES_RHI(QRhiD3D12);
6872 if (!rhiD->sanityCheckGraphicsPipeline(
this))
6875 rhiD->pipelineCreationStart();
6877 QByteArray shaderBytecode[5];
6878 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
6879 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
6880 stageData[d3dStage].valid =
true;
6881 stageData[d3dStage].stage = d3dStage;
6882 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
6883 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
6884 shaderBytecode[d3dStage] = cacheIt->bytecode;
6885 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
6888 QShaderKey shaderKey;
6889 int compileFlags = 0;
6890 if (m_flags.testFlag(CompileShadersWithDebugInfo))
6891 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
6892 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
6893 shaderStage.shaderVariant(),
6897 if (bytecode.isEmpty()) {
6898 qWarning(
"HLSL graphics shader compilation failed: %s", qPrintable(error));
6902 shaderBytecode[d3dStage] = bytecode;
6903 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
6904 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
6905 { bytecode, stageData[d3dStage].nativeResourceBindingMap });
6909 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
6911 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
6912 if (rootSigHandle.isNull()) {
6913 qWarning(
"Failed to create root signature");
6917 ID3D12RootSignature *rootSig =
nullptr;
6918 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
6919 rootSig = rs->rootSig;
6921 qWarning(
"Cannot create graphics pipeline state without root signature");
6925 QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6926 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
6927 if (rpD->colorAttachmentCount > 0) {
6928 format = DXGI_FORMAT(rpD->colorFormat[0]);
6929 }
else if (rpD->hasDepthStencil) {
6930 format = DXGI_FORMAT(rpD->dsFormat);
6932 qWarning(
"Cannot create graphics pipeline state without color or depthStencil format");
6935 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, format);
6938 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
6939 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
6940 QD3D12PipelineStateSubObject<D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE> primitiveRestartValue;
6941 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
6942 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
6943 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
6944 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
6945 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
6946 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
6947 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
6948 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
6949 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
6950 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
6951 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
6952 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
6953 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
6954 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
6957 stream.rootSig.object = rootSig;
6959 QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
6960 QByteArrayList matrixSliceSemantics;
6961 if (!shaderBytecode[VS].isEmpty()) {
6962 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
6965 D3D12_INPUT_ELEMENT_DESC desc = {};
6970 const int matrixSlice = it->matrixSlice();
6971 if (matrixSlice < 0) {
6972 desc.SemanticName =
"TEXCOORD";
6973 desc.SemanticIndex = UINT(it->location());
6977 std::snprintf(sem.data(), sem.size(),
"TEXCOORD%d_", it->location() - matrixSlice);
6978 matrixSliceSemantics.append(sem);
6979 desc.SemanticName = matrixSliceSemantics.last().constData();
6980 desc.SemanticIndex = UINT(matrixSlice);
6982 desc.Format = toD3DAttributeFormat(it->format());
6983 desc.InputSlot = UINT(it->binding());
6984 desc.AlignedByteOffset = it->offset();
6985 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
6986 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
6987 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
6988 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
6990 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
6992 inputDescs.append(desc);
6996 stream.inputLayout.object.NumElements = inputDescs.count();
6997 stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ?
nullptr : inputDescs.constData();
6999 stream.primitiveRestartValue.object = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
7001 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
7002 topology = toD3DTopology(m_topology, m_patchControlPointCount);
7004 for (
const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
7005 const int d3dStage = qd3d12_stage(shaderStage.type());
7008 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7009 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7012 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7013 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7016 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7017 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7020 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7021 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7024 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
7025 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
7033 stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
7034 stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
7035 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
7036 stream.rasterizerState.object.DepthBias = m_depthBias;
7037 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
7038 stream.rasterizerState.object.DepthClipEnable = m_depthClamp ? FALSE : TRUE;
7039 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
7041 stream.depthStencilState.object.DepthEnable = m_depthTest;
7042 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
7043 stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
7044 stream.depthStencilState.object.StencilEnable = m_stencilTest;
7045 if (m_stencilTest) {
7046 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
7047 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
7048 stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
7049 stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
7050 stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
7051 stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
7052 stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
7053 stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
7054 stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
7055 stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
7058 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
7059 for (
int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
7060 const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
7061 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
7062 blend.BlendEnable = b.enable;
7063 blend.SrcBlend = toD3DBlendFactor(b.srcColor,
true);
7064 blend.DestBlend = toD3DBlendFactor(b.dstColor,
true);
7065 blend.BlendOp = toD3DBlendOp(b.opColor);
7066 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha,
false);
7067 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha,
false);
7068 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
7069 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
7070 stream.blendState.object.RenderTarget[i] = blend;
7072 if (m_targetBlends.isEmpty()) {
7073 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
7074 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
7075 stream.blendState.object.RenderTarget[0] = blend;
7078 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
7079 for (
int i = 0; i < rpD->colorAttachmentCount; ++i)
7080 stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
7082 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
7084 stream.sampleDesc.object = sampleDesc;
7086 stream.sampleMask.object = 0xFFFFFFFF;
7088 viewInstanceMask = 0;
7089 const bool isMultiView = m_multiViewCount >= 2;
7090 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
7091 QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
7093 for (
int i = 0; i < m_multiViewCount; ++i) {
7094 viewInstanceMask |= (1 << i);
7095 viewInstanceLocations.append({ 0, UINT(i) });
7097 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
7100 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
7102 QCryptographicHash keyHash(QCryptographicHash::Sha1);
7103 for (
const QByteArray &bytecode : shaderBytecode)
7104 addToKey(&keyHash, bytecode);
7105 for (
const D3D12_INPUT_ELEMENT_DESC &desc : inputDescs) {
7106 keyHash.addData(QByteArrayView(desc.SemanticName));
7107 addToKey(&keyHash, desc.SemanticIndex);
7108 addToKey(&keyHash, desc.Format);
7109 addToKey(&keyHash, desc.InputSlot);
7110 addToKey(&keyHash, desc.AlignedByteOffset);
7111 addToKey(&keyHash, desc.InputSlotClass);
7112 addToKey(&keyHash, desc.InstanceDataStepRate);
7114 addToKey(&keyHash, stream.primitiveRestartValue.object);
7115 addToKey(&keyHash, stream.primitiveTopology.object);
7116 addToKey(&keyHash, stream.rasterizerState.object);
7117 addToKey(&keyHash, stream.depthStencilState.object);
7118 addToKey(&keyHash, stream.blendState.object);
7119 addToKey(&keyHash, stream.rtFormats.object);
7120 addToKey(&keyHash, stream.dsFormat.object);
7121 addToKey(&keyHash, stream.sampleDesc.object);
7122 addToKey(&keyHash, stream.sampleMask.object);
7123 addToKey(&keyHash, stream.viewInstancingDesc.object.ViewInstanceCount);
7124 addToKey(&keyHash, stream.viewInstancingDesc.object.Flags);
7125 addToKey(&keyHash, viewInstanceLocations.constData(),
7126 viewInstanceLocations.count() *
sizeof(D3D12_VIEW_INSTANCE_LOCATION));
7129 addToKey(&keyHash, srbD->serializedLayoutDescription());
7131 ID3D12PipelineState *pso = rhiD->loadOrCreatePipelineState(&streamDesc, keyHash.result().toHex(),
"graphics");
7133 rhiD->rootSignaturePool.remove(rootSigHandle);
7138 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
7140 rhiD->pipelineCreationEnd();
7142 rhiD->registerResource(
this);
7146QD3D12ComputePipeline::QD3D12ComputePipeline(QRhiImplementation *rhi)
7147 : QRhiComputePipeline(rhi)
7151QD3D12ComputePipeline::~QD3D12ComputePipeline()
7156void QD3D12ComputePipeline::destroy()
7158 if (handle.isNull())
7161 QRHI_RES_RHI(QRhiD3D12);
7163 rhiD->releaseQueue.deferredReleasePipeline(handle);
7164 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
7171 rhiD->unregisterResource(
this);
7174bool QD3D12ComputePipeline::create()
7176 if (!handle.isNull())
7179 QRHI_RES_RHI(QRhiD3D12);
7180 rhiD->pipelineCreationStart();
7182 stageData.valid =
true;
7183 stageData.stage = CS;
7185 QByteArray shaderBytecode;
7186 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(m_shaderStage);
7187 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
7188 shaderBytecode = cacheIt->bytecode;
7189 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
7192 QShaderKey shaderKey;
7193 int compileFlags = 0;
7194 if (m_flags.testFlag(CompileShadersWithDebugInfo))
7195 compileFlags |=
int(HlslCompileFlag::WithDebugInfo);
7196 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
7197 m_shaderStage.shaderVariant(),
7201 if (bytecode.isEmpty()) {
7202 qWarning(
"HLSL compute shader compilation failed: %s", qPrintable(error));
7206 shaderBytecode = bytecode;
7207 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
7208 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
7209 stageData.nativeResourceBindingMap });
7212 QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
7214 rootSigHandle = srbD->createRootSignature(&stageData, 1);
7215 if (rootSigHandle.isNull()) {
7216 qWarning(
"Failed to create root signature");
7220 ID3D12RootSignature *rootSig =
nullptr;
7221 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
7222 rootSig = rs->rootSig;
7224 qWarning(
"Cannot create compute pipeline state without root signature");
7229 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
7230 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
7232 stream.rootSig.object = rootSig;
7233 stream.CS.object.pShaderBytecode = shaderBytecode.constData();
7234 stream.CS.object.BytecodeLength = shaderBytecode.size();
7235 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(stream), &stream };
7237 QCryptographicHash keyHash(QCryptographicHash::Sha1);
7238 addToKey(&keyHash, shaderBytecode);
7239 addToKey(&keyHash, srbD->serializedLayoutDescription());
7241 ID3D12PipelineState *pso = rhiD->loadOrCreatePipelineState(&streamDesc, keyHash.result().toHex(),
"compute");
7243 rhiD->rootSignaturePool.remove(rootSigHandle);
7248 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
7250 rhiD->pipelineCreationEnd();
7252 rhiD->registerResource(
this);
7259QD3D12RenderPassDescriptor::QD3D12RenderPassDescriptor(QRhiImplementation *rhi)
7260 : QRhiRenderPassDescriptor(rhi)
7262 serializedFormatData.reserve(16);
7265QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
7270void QD3D12RenderPassDescriptor::destroy()
7272 QRHI_RES_RHI(QRhiD3D12);
7274 rhiD->unregisterResource(
this);
7277bool QD3D12RenderPassDescriptor::isCompatible(
const QRhiRenderPassDescriptor *other)
const
7282 const QD3D12RenderPassDescriptor *o = QRHI_RES(
const QD3D12RenderPassDescriptor, other);
7284 if (colorAttachmentCount != o->colorAttachmentCount)
7287 if (hasDepthStencil != o->hasDepthStencil)
7290 for (
int i = 0; i < colorAttachmentCount; ++i) {
7291 if (colorFormat[i] != o->colorFormat[i])
7295 if (hasDepthStencil) {
7296 if (dsFormat != o->dsFormat)
7300 if (hasShadingRateMap != o->hasShadingRateMap)
7306void QD3D12RenderPassDescriptor::updateSerializedFormat()
7308 serializedFormatData.clear();
7309 auto p = std::back_inserter(serializedFormatData);
7311 *p++ = colorAttachmentCount;
7312 *p++ = hasDepthStencil;
7313 for (
int i = 0; i < colorAttachmentCount; ++i)
7314 *p++ = colorFormat[i];
7315 *p++ = hasDepthStencil ? dsFormat : 0;
7318QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor()
const
7320 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
7321 rpD->colorAttachmentCount = colorAttachmentCount;
7322 rpD->hasDepthStencil = hasDepthStencil;
7323 memcpy(rpD->colorFormat, colorFormat,
sizeof(colorFormat));
7324 rpD->dsFormat = dsFormat;
7325 rpD->hasShadingRateMap = hasShadingRateMap;
7327 rpD->updateSerializedFormat();
7329 QRHI_RES_RHI(QRhiD3D12);
7330 rhiD->registerResource(rpD);
7334QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat()
const
7336 return serializedFormatData;
7339QD3D12CommandBuffer::QD3D12CommandBuffer(QRhiImplementation *rhi)
7340 : QRhiCommandBuffer(rhi)
7345QD3D12CommandBuffer::~QD3D12CommandBuffer()
7350void QD3D12CommandBuffer::destroy()
7355const QRhiNativeHandles *QD3D12CommandBuffer::nativeHandles()
7357 nativeHandlesStruct.commandList = cmdList;
7358 return &nativeHandlesStruct;
7361QD3D12SwapChainRenderTarget::QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
7362 : QRhiSwapChainRenderTarget(rhi, swapchain),
7367QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
7372void QD3D12SwapChainRenderTarget::destroy()
7377QSize QD3D12SwapChainRenderTarget::pixelSize()
const
7382float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
7387int QD3D12SwapChainRenderTarget::sampleCount()
const
7389 return d.sampleCount;
7392QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
7393 : QRhiSwapChain(rhi),
7394 rtWrapper(rhi,
this),
7395 rtWrapperRight(rhi,
this),
7400QD3D12SwapChain::~QD3D12SwapChain()
7405void QD3D12SwapChain::destroy()
7412 swapChain->Release();
7413 swapChain =
nullptr;
7414 sourceSwapChain1->Release();
7415 sourceSwapChain1 =
nullptr;
7417 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7418 FrameResources &fr(frameRes[i]);
7420 fr.fence->Release();
7422 CloseHandle(fr.fenceEvent);
7424 fr.cmdList->Release();
7429 dcompVisual->Release();
7430 dcompVisual =
nullptr;
7434 dcompTarget->Release();
7435 dcompTarget =
nullptr;
7438 if (frameLatencyWaitableObject) {
7439 CloseHandle(frameLatencyWaitableObject);
7440 frameLatencyWaitableObject =
nullptr;
7443 QDxgiVSyncService::instance()->unregisterWindow(window);
7445 QRHI_RES_RHI(QRhiD3D12);
7447 rhiD->swapchains.remove(
this);
7448 rhiD->unregisterResource(
this);
7452void QD3D12SwapChain::releaseBuffers()
7454 QRHI_RES_RHI(QRhiD3D12);
7456 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7457 rhiD->resourcePool.remove(colorBuffers[i]);
7458 rhiD->rtvPool.release(rtvs[i], 1);
7460 rhiD->rtvPool.release(rtvsRight[i], 1);
7462 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7463 if (!msaaBuffers[i].isNull())
7464 rhiD->resourcePool.remove(msaaBuffers[i]);
7465 if (msaaRtvs[i].isValid())
7466 rhiD->rtvPool.release(msaaRtvs[i], 1);
7470void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
7472 FrameResources &fr(frameRes[frameSlot]);
7473 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
7474 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
7475 WaitForSingleObject(fr.fenceEvent, INFINITE);
7479void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
7481 QRHI_RES_RHI(QRhiD3D12);
7482 FrameResources &fr(frameRes[currentFrameSlot]);
7483 fr.fenceCounter += 1u;
7484 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
7487QRhiCommandBuffer *QD3D12SwapChain::currentFrameCommandBuffer()
7492QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
7497QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
7499 return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
7502QSize QD3D12SwapChain::surfacePixelSize()
7505 return m_window->size() * m_window->devicePixelRatio();
7508bool QD3D12SwapChain::isFormatSupported(Format f)
7514 qWarning(
"Attempted to call isFormatSupported() without a window set");
7518 QRHI_RES_RHI(QRhiD3D12);
7519 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window))
7520 return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
7525QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
7527 QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
7530 QRHI_RES_RHI(QRhiD3D12);
7531 info = QDxgiHdrInfo(rhiD->activeAdapter).queryHdrInfo(m_window);
7536QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
7541 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
7542 rpD->colorAttachmentCount = 1;
7543 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
7544 rpD->colorFormat[0] =
int(srgbAdjustedColorFormat);
7545 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
7547 rpD->hasShadingRateMap = m_shadingRateMap !=
nullptr;
7549 rpD->updateSerializedFormat();
7551 QRHI_RES_RHI(QRhiD3D12);
7552 rhiD->registerResource(rpD);
7556bool QRhiD3D12::ensureDirectCompositionDevice()
7561 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
7562 dcompDevice = QRhiD3D::createDirectCompositionDevice();
7563 return dcompDevice ?
true :
false;
7566static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
7567static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
7569void QD3D12SwapChain::chooseFormats()
7571 colorFormat = DEFAULT_FORMAT;
7572 srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
7573 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
7574 QRHI_RES_RHI(QRhiD3D12);
7575 if (m_format != SDR) {
7576 if (QDxgiHdrInfo(rhiD->activeAdapter).isHdrCapable(m_window)) {
7579 case HDRExtendedSrgbLinear:
7580 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
7581 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
7582 srgbAdjustedColorFormat = colorFormat;
7585 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
7586 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
7587 srgbAdjustedColorFormat = colorFormat;
7596 qWarning(
"The output associated with the window is not HDR capable "
7597 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
7600 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
7603bool QD3D12SwapChain::createOrResize()
7609 const bool needsRegistration = !window || window != m_window;
7612 if (window && window != m_window)
7616 m_currentPixelSize = surfacePixelSize();
7617 pixelSize = m_currentPixelSize;
7619 if (pixelSize.isEmpty())
7622 HWND hwnd =
reinterpret_cast<HWND>(window->winId());
7624 QRHI_RES_RHI(QRhiD3D12);
7625 stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
7627 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
7628 if (rhiD->ensureDirectCompositionDevice()) {
7630 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
false, &dcompTarget);
7632 qWarning(
"Failed to create Direct Composition target for the window: %s",
7633 qPrintable(QSystemError::windowsComString(hr)));
7636 if (dcompTarget && !dcompVisual) {
7637 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
7639 qWarning(
"Failed to create DirectComposition visual: %s",
7640 qPrintable(QSystemError::windowsComString(hr)));
7645 if (window->requestedFormat().alphaBufferSize() <= 0)
7646 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
7647 "This may lead to problems.");
7650 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
7652 if (swapInterval == 0 && rhiD->supportsAllowTearing)
7653 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
7657 const bool useFrameLatencyWaitableObject = rhiD->maxFrameLatency != 0
7658 && swapInterval != 0
7659 && rhiD->driverInfoStruct.deviceType != QRhiDriverInfo::CpuDevice;
7660 if (useFrameLatencyWaitableObject)
7661 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
7666 DXGI_SWAP_CHAIN_DESC1 desc = {};
7667 desc.Width = UINT(pixelSize.width());
7668 desc.Height = UINT(pixelSize.height());
7669 desc.Format = colorFormat;
7670 desc.SampleDesc.Count = 1;
7671 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
7672 desc.BufferCount = BUFFER_COUNT;
7673 desc.Flags = swapChainFlags;
7674 desc.Scaling = DXGI_SCALING_NONE;
7675 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
7676 desc.Stereo = stereo;
7682 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
7687 desc.Scaling = DXGI_SCALING_STRETCH;
7691 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
7693 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
7698 if (FAILED(hr) && m_format != SDR) {
7699 colorFormat = DEFAULT_FORMAT;
7700 desc.Format = DEFAULT_FORMAT;
7702 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &desc,
nullptr, &sourceSwapChain1);
7704 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &desc,
nullptr,
nullptr, &sourceSwapChain1);
7707 if (SUCCEEDED(hr)) {
7708 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<
void **>(&swapChain)))) {
7709 qWarning(
"IDXGISwapChain3 not available");
7712 if (m_format != SDR) {
7713 hr = swapChain->SetColorSpace1(hdrColorSpace);
7715 qWarning(
"Failed to set color space on swapchain: %s",
7716 qPrintable(QSystemError::windowsComString(hr)));
7719 if (useFrameLatencyWaitableObject) {
7720 swapChain->SetMaximumFrameLatency(rhiD->maxFrameLatency);
7721 frameLatencyWaitableObject = swapChain->GetFrameLatencyWaitableObject();
7724 hr = dcompVisual->SetContent(swapChain);
7725 if (SUCCEEDED(hr)) {
7726 hr = dcompTarget->SetRoot(dcompVisual);
7728 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
7729 qPrintable(QSystemError::windowsComString(hr)));
7732 qWarning(
"Failed to set content for Direct Composition visual: %s",
7733 qPrintable(QSystemError::windowsComString(hr)));
7737 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
7740 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
7741 qWarning(
"Device loss detected during swapchain creation");
7742 rhiD->deviceLost =
true;
7744 }
else if (FAILED(hr)) {
7745 qWarning(
"Failed to create D3D12 swapchain: %s"
7746 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
7747 qPrintable(QSystemError::windowsComString(hr)),
7748 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
7749 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
7753 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7754 hr = rhiD->dev->CreateFence(0,
7755 D3D12_FENCE_FLAG_NONE,
7756 __uuidof(ID3D12Fence),
7757 reinterpret_cast<
void **>(&frameRes[i].fence));
7759 qWarning(
"Failed to create fence for swapchain: %s",
7760 qPrintable(QSystemError::windowsComString(hr)));
7763 frameRes[i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
7765 frameRes[i].fenceCounter = 0;
7769 hr = swapChain->ResizeBuffers(BUFFER_COUNT,
7770 UINT(pixelSize.width()),
7771 UINT(pixelSize.height()),
7774 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
7775 qWarning(
"Device loss detected in ResizeBuffers()");
7776 rhiD->deviceLost =
true;
7778 }
else if (FAILED(hr)) {
7779 qWarning(
"Failed to resize D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
7784 for (UINT i = 0; i < BUFFER_COUNT; ++i) {
7785 ID3D12Resource *colorBuffer;
7786 hr = swapChain->GetBuffer(i, __uuidof(ID3D12Resource),
reinterpret_cast<
void **>(&colorBuffer));
7788 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
7789 i, qPrintable(QSystemError::windowsComString(hr)));
7792 colorBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
7793 rtvs[i] = rhiD->rtvPool.allocate(1);
7794 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7795 rtvDesc.Format = srgbAdjustedColorFormat;
7796 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
7797 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
7800 rtvsRight[i] = rhiD->rtvPool.allocate(1);
7801 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7802 rtvDesc.Format = srgbAdjustedColorFormat;
7803 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
7804 rtvDesc.Texture2DArray.ArraySize = 1;
7805 rtvDesc.Texture2DArray.FirstArraySlice = 1;
7806 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
7810 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
7811 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
7812 m_depthStencil->sampleCount(), m_sampleCount);
7814 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
7815 if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
7816 m_depthStencil->setPixelSize(pixelSize);
7817 if (!m_depthStencil->create())
7818 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
7819 pixelSize.width(), pixelSize.height());
7821 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
7822 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
7823 pixelSize.width(), pixelSize.height());
7827 ds = m_depthStencil ? QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
7829 if (sampleDesc.Count > 1) {
7830 for (
int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
7831 D3D12_RESOURCE_DESC resourceDesc = {};
7832 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
7833 resourceDesc.Width = UINT64(pixelSize.width());
7834 resourceDesc.Height = UINT(pixelSize.height());
7835 resourceDesc.DepthOrArraySize = 1;
7836 resourceDesc.MipLevels = 1;
7837 resourceDesc.Format = srgbAdjustedColorFormat;
7838 resourceDesc.SampleDesc = sampleDesc;
7839 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
7840 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
7841 D3D12_CLEAR_VALUE clearValue = {};
7842 clearValue.Format = colorFormat;
7843 ID3D12Resource *resource =
nullptr;
7844 D3D12MA::Allocation *allocation =
nullptr;
7845 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
7847 D3D12_RESOURCE_STATE_RENDER_TARGET,
7850 __uuidof(ID3D12Resource),
7851 reinterpret_cast<
void **>(&resource));
7853 qWarning(
"Failed to create MSAA color buffer: %s", qPrintable(QSystemError::windowsComString(hr)));
7856 msaaBuffers[i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, allocation);
7857 msaaRtvs[i] = rhiD->rtvPool.allocate(1);
7858 if (!msaaRtvs[i].isValid())
7860 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
7861 rtvDesc.Format = srgbAdjustedColorFormat;
7862 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
7863 : D3D12_RTV_DIMENSION_TEXTURE2D;
7864 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[i].cpuHandle);
7868 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
7869 currentFrameSlot = 0;
7870 lastFrameLatencyWaitSlot = -1;
7872 rtWrapper.setRenderPassDescriptor(m_renderPassDesc);
7873 QD3D12SwapChainRenderTarget *rtD = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
7874 rtD->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7875 rtD->d.pixelSize = pixelSize;
7876 rtD->d.dpr =
float(window->devicePixelRatio());
7877 rtD->d.sampleCount =
int(sampleDesc.Count);
7878 rtD->d.colorAttCount = 1;
7879 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
7881 rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
7882 QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
7883 rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
7884 rtDr->d.pixelSize = pixelSize;
7885 rtDr->d.dpr =
float(window->devicePixelRatio());
7886 rtDr->d.sampleCount =
int(sampleDesc.Count);
7887 rtDr->d.colorAttCount = 1;
7888 rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
7890 QDxgiVSyncService::instance()->registerWindow(window);
7892 if (needsRegistration || !rhiD->swapchains.contains(
this))
7893 rhiD->swapchains.insert(
this);
7895 rhiD->registerResource(
this);