8#include <QtCore/qcryptographichash.h>
9#include <QtCore/private/qsystemerror_p.h>
14#if __has_include(<pix.h>)
16#define QRHI_D3D12_HAS_OLD_PIX
19#ifdef __ID3D12Device2_INTERFACE_DEFINED__
127static const D3D_FEATURE_LEVEL MIN_FEATURE_LEVEL = D3D_FEATURE_LEVEL_11_0;
129QRhiD3D12::QRhiD3D12(QRhiD3D12InitParams *
params, QRhiD3D12NativeHandles *importParams)
131 debugLayer =
params->enableDebugLayer;
133 if (importParams->dev) {
134 ID3D12Device *d3d12Device =
reinterpret_cast<ID3D12Device *
>(importParams->dev);
135 if (SUCCEEDED(d3d12Device->QueryInterface(__uuidof(ID3D12Device2),
reinterpret_cast<void **
>(&dev)))) {
137 d3d12Device->Release();
138 importedDevice =
true;
140 qWarning(
"ID3D12Device2 not supported, cannot import device");
143 if (importParams->commandQueue) {
144 cmdQueue =
reinterpret_cast<ID3D12CommandQueue *
>(importParams->commandQueue);
145 importedCommandQueue =
true;
147 minimumFeatureLevel = D3D_FEATURE_LEVEL(importParams->minimumFeatureLevel);
148 adapterLuid.LowPart = importParams->adapterLuidLow;
149 adapterLuid.HighPart = importParams->adapterLuidHigh;
156 return (
v + byteAlign - 1) & ~(byteAlign - 1);
159static inline UINT calcSubresource(UINT mipSlice, UINT arraySlice, UINT mipLevels)
161 return mipSlice + arraySlice * mipLevels;
168 return &
QRHI_RES(QD3D12SwapChainRenderTarget, rt)->d;
170 return &
QRHI_RES(QD3D12TextureRenderTarget, rt)->d;
175 Q_UNREACHABLE_RETURN(
nullptr);
178bool QRhiD3D12::create(QRhi::Flags
flags)
182 UINT factoryFlags = 0;
184 factoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
185 HRESULT hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2),
reinterpret_cast<void **
>(&dxgiFactory));
187 qWarning(
"CreateDXGIFactory2() failed to create DXGI factory: %s",
188 qPrintable(QSystemError::windowsComString(hr)));
192 supportsAllowTearing =
false;
193 IDXGIFactory5 *factory5 =
nullptr;
194 if (SUCCEEDED(dxgiFactory->QueryInterface(__uuidof(IDXGIFactory5),
reinterpret_cast<void **
>(&factory5)))) {
195 BOOL allowTearing =
false;
196 if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing,
sizeof(allowTearing))))
197 supportsAllowTearing = allowTearing;
202 ID3D12Debug1 *
debug =
nullptr;
203 if (SUCCEEDED(D3D12GetDebugInterface(__uuidof(ID3D12Debug1),
reinterpret_cast<void **
>(&
debug)))) {
204 qCDebug(QRHI_LOG_INFO,
"Enabling D3D12 debug layer");
205 debug->EnableDebugLayer();
210 if (!importedDevice) {
211 IDXGIAdapter1 *adapter;
212 int requestedAdapterIndex = -1;
217 if (requestedAdapterIndex < 0 && (adapterLuid.LowPart || adapterLuid.HighPart)) {
218 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
219 DXGI_ADAPTER_DESC1
desc;
220 adapter->GetDesc1(&
desc);
222 if (
desc.AdapterLuid.LowPart == adapterLuid.LowPart
223 &&
desc.AdapterLuid.HighPart == adapterLuid.HighPart)
225 requestedAdapterIndex = adapterIndex;
232 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
233 DXGI_ADAPTER_DESC1
desc;
234 adapter->GetDesc1(&
desc);
237 requestedAdapterIndex = adapterIndex;
243 activeAdapter =
nullptr;
244 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
245 DXGI_ADAPTER_DESC1
desc;
246 adapter->GetDesc1(&
desc);
248 qCDebug(QRHI_LOG_INFO,
"Adapter %d: '%s' (vendor 0x%X device 0x%X flags 0x%X)",
254 if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
255 activeAdapter = adapter;
256 adapterLuid =
desc.AdapterLuid;
257 driverInfoStruct.deviceName =
name.toUtf8();
258 driverInfoStruct.deviceId =
desc.DeviceId;
259 driverInfoStruct.vendorId =
desc.VendorId;
260 qCDebug(QRHI_LOG_INFO,
" using this adapter");
265 if (!activeAdapter) {
270 if (minimumFeatureLevel == 0)
271 minimumFeatureLevel = MIN_FEATURE_LEVEL;
273 hr = D3D12CreateDevice(activeAdapter,
275 __uuidof(ID3D12Device2),
276 reinterpret_cast<void **
>(&dev));
278 qWarning(
"Failed to create D3D12 device: %s",
qPrintable(QSystemError::windowsComString(hr)));
284 adapterLuid = dev->GetAdapterLuid();
285 IDXGIAdapter1 *adapter;
286 for (
int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
287 DXGI_ADAPTER_DESC1
desc;
288 adapter->GetDesc1(&
desc);
290 if (
desc.AdapterLuid.LowPart == adapterLuid.LowPart
291 &&
desc.AdapterLuid.HighPart == adapterLuid.HighPart)
294 driverInfoStruct.deviceId =
desc.DeviceId;
295 driverInfoStruct.vendorId =
desc.VendorId;
299 qCDebug(QRHI_LOG_INFO,
"Using imported device %p", dev);
303 ID3D12InfoQueue *infoQueue;
304 if (SUCCEEDED(dev->QueryInterface(__uuidof(ID3D12InfoQueue),
reinterpret_cast<void **
>(&infoQueue)))) {
306 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION,
true);
307 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR,
true);
308 infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING,
true);
310 D3D12_INFO_QUEUE_FILTER
filter = {};
311 D3D12_MESSAGE_ID suppressedMessages[2] = {
313 D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
315 D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE
317 filter.DenyList.NumIDs = 2;
318 filter.DenyList.pIDList = suppressedMessages;
321 D3D12_MESSAGE_SEVERITY infoSev = D3D12_MESSAGE_SEVERITY_INFO;
322 filter.DenyList.NumSeverities = 1;
323 filter.DenyList.pSeverityList = &infoSev;
324 infoQueue->PushStorageFilter(&
filter);
325 infoQueue->Release();
329 if (!importedCommandQueue) {
330 D3D12_COMMAND_QUEUE_DESC queueDesc = {};
331 queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
332 queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
333 hr = dev->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue),
reinterpret_cast<void **
>(&cmdQueue));
335 qWarning(
"Failed to create command queue: %s",
qPrintable(QSystemError::windowsComString(hr)));
340 hr = dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence),
reinterpret_cast<void **
>(&fullFence));
342 qWarning(
"Failed to create fence: %s",
qPrintable(QSystemError::windowsComString(hr)));
345 fullFenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
346 fullFenceCounter = 0;
348 for (
int i = 0;
i < QD3D12_FRAMES_IN_FLIGHT; ++
i) {
349 hr = dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
350 __uuidof(ID3D12CommandAllocator),
351 reinterpret_cast<void **
>(&cmdAllocators[
i]));
353 qWarning(
"Failed to create command allocator: %s",
qPrintable(QSystemError::windowsComString(hr)));
358 if (!vma.create(dev, activeAdapter)) {
359 qWarning(
"Failed to initialize graphics memory suballocator");
363 if (!rtvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
"main RTV pool")) {
364 qWarning(
"Could not create RTV pool");
368 if (!dsvPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
"main DSV pool")) {
369 qWarning(
"Could not create DSV pool");
373 if (!cbvSrvUavPool.create(dev, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
"main CBV-SRV-UAV pool")) {
374 qWarning(
"Could not create CBV-SRV-UAV pool");
378 resourcePool.create(
"main resource pool");
379 pipelinePool.create(
"main pipeline pool");
380 rootSignaturePool.create(
"main root signature pool");
381 releaseQueue.create(&resourcePool, &pipelinePool, &rootSignaturePool);
382 barrierGen.create(&resourcePool);
384 if (!samplerMgr.create(dev)) {
385 qWarning(
"Could not create sampler pool and shader-visible sampler heap");
389 if (!mipmapGen.create(
this)) {
390 qWarning(
"Could not initialize mipmap generator");
394 const qint32 smallStagingSize =
aligned(SMALL_STAGING_AREA_BYTES_PER_FRAME, QD3D12StagingArea::ALIGNMENT);
395 for (
int i = 0;
i < QD3D12_FRAMES_IN_FLIGHT; ++
i) {
396 if (!smallStagingAreas[
i].
create(
this, smallStagingSize, D3D12_HEAP_TYPE_UPLOAD)) {
397 qWarning(
"Could not create host-visible staging area");
402 if (!shaderVisibleCbvSrvUavHeap.create(dev,
403 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
404 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE))
406 qWarning(
"Could not create first shader-visible CBV/SRV/UAV heap");
410 D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
411 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3,
sizeof(options3))))
412 caps.multiView = options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
415 offscreenActive =
false;
417 nativeHandlesStruct.dev = dev;
418 nativeHandlesStruct.minimumFeatureLevel = minimumFeatureLevel;
419 nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
420 nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
421 nativeHandlesStruct.commandQueue = cmdQueue;
426void QRhiD3D12::destroy()
428 if (!deviceLost && fullFence && fullFenceEvent)
431 releaseQueue.releaseAll();
433 for (
int i = 0;
i < QD3D12_FRAMES_IN_FLIGHT; ++
i) {
434 if (offscreenCb[
i]) {
435 if (offscreenCb[
i]->cmdList)
436 offscreenCb[
i]->cmdList->Release();
437 delete offscreenCb[
i];
438 offscreenCb[
i] =
nullptr;
442 shaderVisibleCbvSrvUavHeap.destroy();
444 for (
int i = 0;
i < QD3D12_FRAMES_IN_FLIGHT; ++
i)
445 smallStagingAreas[
i].destroy();
448 samplerMgr.destroy();
449 resourcePool.destroy();
450 pipelinePool.destroy();
451 rootSignaturePool.destroy();
454 cbvSrvUavPool.destroy();
456 for (
int i = 0;
i < QD3D12_FRAMES_IN_FLIGHT; ++
i) {
457 cmdAllocators[
i]->Release();
458 cmdAllocators[
i] =
nullptr;
461 if (fullFenceEvent) {
462 CloseHandle(fullFenceEvent);
463 fullFenceEvent =
nullptr;
467 fullFence->Release();
471 if (!importedCommandQueue) {
480 if (!importedDevice) {
488 dcompDevice->Release();
489 dcompDevice =
nullptr;
493 activeAdapter->Release();
494 activeAdapter =
nullptr;
498 dxgiFactory->Release();
499 dxgiFactory =
nullptr;
503QList<int> QRhiD3D12::supportedSampleCounts()
const
505 return { 1, 2, 4, 8 };
510 return new QD3D12SwapChain(
this);
518int QRhiD3D12::ubufAlignment()
const
520 return D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
523bool QRhiD3D12::isYUpInFramebuffer()
const
528bool QRhiD3D12::isYUpInNDC()
const
533bool QRhiD3D12::isClipDepthZeroToOne()
const
538QMatrix4x4 QRhiD3D12::clipSpaceCorrMatrix()
const
543 if (
m.isIdentity()) {
546 0.0f, 1.0f, 0.0f, 0.0f,
547 0.0f, 0.0f, 0.5f, 0.5f,
548 0.0f, 0.0f, 0.0f, 1.0f);
563bool QRhiD3D12::isFeatureSupported(
QRhi::Feature feature)
const
571#ifdef QRHI_D3D12_HAS_OLD_PIX
651 return caps.multiView;
666 return QD3D12_FRAMES_IN_FLIGHT;
668 return QD3D12_FRAMES_IN_FLIGHT;
693 return &nativeHandlesStruct;
698 return driverInfoStruct;
704 result.totalPipelineCreationTime = totalPipelineCreationTime();
706 D3D12MA::Budget budgets[2];
707 vma.getBudget(&budgets[0], &budgets[1]);
708 for (
int i = 0;
i < 2; ++
i) {
709 const D3D12MA::Statistics &stats(budgets[
i].Stats);
710 result.blockCount += stats.BlockCount;
711 result.allocCount += stats.AllocationCount;
712 result.usedBytes += stats.AllocationBytes;
713 result.unusedBytes += stats.BlockBytes - stats.AllocationBytes;
714 result.totalUsageBytes += budgets[
i].UsageBytes;
720bool QRhiD3D12::makeThreadLocalNativeContextCurrent()
726void QRhiD3D12::releaseCachedResources()
728 shaderBytecodeCache.data.clear();
731bool QRhiD3D12::isDeviceLost()
const
747 int sampleCount, QRhiRenderBuffer::Flags
flags,
750 return new QD3D12RenderBuffer(
this,
type, pixelSize, sampleCount,
flags, backingFormatHint);
754 const QSize &pixelSize,
int depth,
int arraySize,
755 int sampleCount, QRhiTexture::Flags
flags)
757 return new QD3D12Texture(
this,
format, pixelSize,
depth, arraySize, sampleCount,
flags);
764 return new QD3D12Sampler(
this, magFilter, minFilter, mipmapMode, u,
v,
w);
768 QRhiTextureRenderTarget::Flags
flags)
770 return new QD3D12TextureRenderTarget(
this,
desc,
flags);
775 return new QD3D12GraphicsPipeline(
this);
780 return new QD3D12ComputePipeline(
this);
785 return new QD3D12ShaderResourceBindings(
this);
790 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
791 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
792 QD3D12GraphicsPipeline *psD =
QRHI_RES(QD3D12GraphicsPipeline, ps);
793 const bool pipelineChanged = cbD->currentGraphicsPipeline != psD || cbD->currentPipelineGeneration != psD->generation;
795 if (pipelineChanged) {
796 cbD->currentGraphicsPipeline = psD;
797 cbD->currentComputePipeline =
nullptr;
798 cbD->currentPipelineGeneration = psD->generation;
800 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
801 Q_ASSERT(pipeline->type == QD3D12Pipeline::Graphics);
802 cbD->cmdList->SetPipelineState(pipeline->pso);
803 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
804 cbD->cmdList->SetGraphicsRootSignature(rs->rootSig);
807 cbD->cmdList->IASetPrimitiveTopology(psD->topology);
809 if (psD->viewInstanceMask)
810 cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
814void QRhiD3D12::visitUniformBuffer(QD3D12Stage
s,
818 int dynamicOffsetCount,
821 QD3D12Buffer *bufD =
QRHI_RES(QD3D12Buffer,
d.buf);
823 if (
d.hasDynamicOffset) {
824 for (
int i = 0;
i < dynamicOffsetCount; ++
i) {
826 if (dynOfs.first == binding) {
832 visitorData.cbufs[
s].append({ bufD->handles[currentFrameSlot],
offset });
835void QRhiD3D12::visitTexture(QD3D12Stage
s,
839 QD3D12Texture *texD =
QRHI_RES(QD3D12Texture,
d.tex);
840 visitorData.srvs[
s].append(texD->srv);
843void QRhiD3D12::visitSampler(QD3D12Stage
s,
847 QD3D12Sampler *samplerD =
QRHI_RES(QD3D12Sampler,
d.sampler);
848 visitorData.samplers[
s].append(samplerD->lookupOrCreateShaderVisibleDescriptor());
851void QRhiD3D12::visitStorageBuffer(QD3D12Stage
s,
853 QD3D12ShaderResourceVisitor::StorageOp,
856 QD3D12Buffer *bufD =
QRHI_RES(QD3D12Buffer,
d.buf);
858 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
859 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
860 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
861 uavDesc.Buffer.FirstElement =
d.offset / 4;
862 uavDesc.Buffer.NumElements =
aligned(bufD->m_size -
d.offset, 4u) / 4;
863 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
864 visitorData.uavs[
s].append({ bufD->handles[0], uavDesc });
867void QRhiD3D12::visitStorageImage(QD3D12Stage
s,
869 QD3D12ShaderResourceVisitor::StorageOp,
872 QD3D12Texture *texD =
QRHI_RES(QD3D12Texture,
d.tex);
876 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
877 uavDesc.Format = texD->dxgiFormat;
879 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
880 uavDesc.Texture2DArray.MipSlice = UINT(
d.level);
881 uavDesc.Texture2DArray.FirstArraySlice = 0;
882 uavDesc.Texture2DArray.ArraySize = 6;
883 }
else if (isArray) {
884 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
885 uavDesc.Texture2DArray.MipSlice = UINT(
d.level);
886 uavDesc.Texture2DArray.FirstArraySlice = 0;
887 uavDesc.Texture2DArray.ArraySize = UINT(
qMax(0, texD->m_arraySize));
889 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
890 uavDesc.Texture3D.MipSlice = UINT(
d.level);
892 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
893 uavDesc.Texture2D.MipSlice = UINT(
d.level);
895 visitorData.uavs[
s].append({ texD->handle, uavDesc });
899 int dynamicOffsetCount,
902 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
903 Q_ASSERT(cbD->recordingPass != QD3D12CommandBuffer::NoPass);
904 QD3D12GraphicsPipeline *gfxPsD =
QRHI_RES(QD3D12GraphicsPipeline, cbD->currentGraphicsPipeline);
905 QD3D12ComputePipeline *compPsD =
QRHI_RES(QD3D12ComputePipeline, cbD->currentComputePipeline);
909 srb = gfxPsD->m_shaderResourceBindings;
911 srb = compPsD->m_shaderResourceBindings;
914 QD3D12ShaderResourceBindings *srbD =
QRHI_RES(QD3D12ShaderResourceBindings, srb);
916 for (
int i = 0, ie = srbD->sortedBindings.size();
i != ie; ++
i) {
921 QD3D12Buffer *bufD =
QRHI_RES(QD3D12Buffer,
b->u.ubuf.buf);
924 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
932 for (
int elem = 0; elem <
data->count; ++elem) {
933 QD3D12Texture *texD =
QRHI_RES(QD3D12Texture,
data->texSamplers[elem].tex);
934 QD3D12Sampler *samplerD =
QRHI_RES(QD3D12Sampler,
data->texSamplers[elem].sampler);
942 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
944 state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
946 state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
948 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATES(
state));
949 barrierGen.enqueueBufferedTransitionBarriers(cbD);
958 QD3D12Texture *texD =
QRHI_RES(QD3D12Texture,
b->u.simage.tex);
959 if (QD3D12Resource *
res = resourcePool.lookupRef(texD->handle)) {
961 if (
res->uavUsage & QD3D12Resource::UavUsageWrite) {
963 barrierGen.enqueueUavBarrier(cbD, texD->handle);
969 barrierGen.enqueueUavBarrier(cbD, texD->handle);
975 res->uavUsage |= QD3D12Resource::UavUsageRead;
977 res->uavUsage |= QD3D12Resource::UavUsageWrite;
978 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
979 barrierGen.enqueueBufferedTransitionBarriers(cbD);
987 QD3D12Buffer *bufD =
QRHI_RES(QD3D12Buffer,
b->u.sbuf.buf);
990 if (QD3D12Resource *
res = resourcePool.lookupRef(bufD->handles[0])) {
992 if (
res->uavUsage & QD3D12Resource::UavUsageWrite) {
994 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1000 barrierGen.enqueueUavBarrier(cbD, bufD->handles[0]);
1006 res->uavUsage |= QD3D12Resource::UavUsageRead;
1008 res->uavUsage |= QD3D12Resource::UavUsageWrite;
1009 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1010 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1017 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1018 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1020 if (srbChanged || srbRebuilt || srbD->hasDynamicOffset) {
1021 const QD3D12ShaderStageData *stageData = gfxPsD ? gfxPsD->stageData.data() : &compPsD->stageData;
1027 QD3D12ShaderResourceVisitor visitor(srbD, stageData, gfxPsD ? 5 : 1);
1031 using namespace std::placeholders;
1032 visitor.uniformBuffer = std::bind(&QRhiD3D12::visitUniformBuffer,
this, _1, _2, _3, _4, dynamicOffsetCount, dynamicOffsets);
1033 visitor.texture = std::bind(&QRhiD3D12::visitTexture,
this, _1, _2, _3);
1034 visitor.sampler = std::bind(&QRhiD3D12::visitSampler,
this, _1, _2, _3);
1035 visitor.storageBuffer = std::bind(&QRhiD3D12::visitStorageBuffer,
this, _1, _2, _3, _4);
1036 visitor.storageImage = std::bind(&QRhiD3D12::visitStorageImage,
this, _1, _2, _3, _4);
1041 for (
int s = 0;
s < 6; ++
s) {
1043 cbvSrvUavCount += visitorData.srvs[
s].count();
1044 cbvSrvUavCount += visitorData.uavs[
s].count();
1047 bool gotNewHeap =
false;
1048 if (!ensureShaderVisibleDescriptorHeapCapacity(&shaderVisibleCbvSrvUavHeap,
1049 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1057 qCDebug(QRHI_LOG_INFO,
"Created new shader-visible CBV/SRV/UAV descriptor heap,"
1058 " per-frame slice size is now %u,"
1059 " if this happens frequently then that's not great.",
1060 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[0].capacity);
1061 bindShaderVisibleHeaps(cbD);
1064 int rootParamIndex = 0;
1065 for (
int s = 0;
s < 6; ++
s) {
1066 if (!visitorData.cbufs[
s].isEmpty()) {
1067 for (
int i = 0,
count = visitorData.cbufs[
s].count();
i <
count; ++
i) {
1068 const auto &cbuf(visitorData.cbufs[
s][
i]);
1069 if (QD3D12Resource *
res = resourcePool.lookupRef(cbuf.first)) {
1071 D3D12_GPU_VIRTUAL_ADDRESS gpuAddr =
res->resource->GetGPUVirtualAddress() +
offset;
1072 if (cbD->currentGraphicsPipeline)
1073 cbD->cmdList->SetGraphicsRootConstantBufferView(rootParamIndex, gpuAddr);
1075 cbD->cmdList->SetComputeRootConstantBufferView(rootParamIndex, gpuAddr);
1077 rootParamIndex += 1;
1081 for (
int s = 0;
s < 6; ++
s) {
1082 if (!visitorData.srvs[
s].isEmpty()) {
1083 QD3D12DescriptorHeap &gpuSrvHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1084 QD3D12Descriptor startDesc = gpuSrvHeap.get(visitorData.srvs[
s].count());
1085 for (
int i = 0,
count = visitorData.srvs[
s].count();
i <
count; ++
i) {
1086 const auto &srv(visitorData.srvs[
s][
i]);
1087 dev->CopyDescriptorsSimple(1, gpuSrvHeap.incremented(startDesc,
i).cpuHandle, srv.cpuHandle,
1088 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1091 if (cbD->currentGraphicsPipeline)
1092 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1093 else if (cbD->currentComputePipeline)
1094 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1096 rootParamIndex += 1;
1099 for (
int s = 0;
s < 6; ++
s) {
1102 for (
const QD3D12Descriptor &samplerDescriptor : visitorData.
samplers[
s]) {
1103 if (cbD->currentGraphicsPipeline)
1104 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1105 else if (cbD->currentComputePipeline)
1106 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, samplerDescriptor.gpuHandle);
1108 rootParamIndex += 1;
1111 for (
int s = 0;
s < 6; ++
s) {
1112 if (!visitorData.uavs[
s].isEmpty()) {
1113 QD3D12DescriptorHeap &gpuUavHeap(shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot]);
1114 QD3D12Descriptor startDesc = gpuUavHeap.get(visitorData.uavs[
s].count());
1115 for (
int i = 0,
count = visitorData.uavs[
s].count();
i <
count; ++
i) {
1116 const auto &uav(visitorData.uavs[
s][
i]);
1117 if (QD3D12Resource *
res = resourcePool.lookupRef(uav.first)) {
1118 dev->CreateUnorderedAccessView(
res->resource,
nullptr, &uav.second,
1119 gpuUavHeap.incremented(startDesc,
i).cpuHandle);
1121 dev->CreateUnorderedAccessView(
nullptr,
nullptr,
nullptr,
1122 gpuUavHeap.incremented(startDesc,
i).cpuHandle);
1126 if (cbD->currentGraphicsPipeline)
1127 cbD->cmdList->SetGraphicsRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1128 else if (cbD->currentComputePipeline)
1129 cbD->cmdList->SetComputeRootDescriptorTable(rootParamIndex, startDesc.gpuHandle);
1131 rootParamIndex += 1;
1136 cbD->currentGraphicsSrb = srb;
1137 cbD->currentComputeSrb =
nullptr;
1139 cbD->currentGraphicsSrb =
nullptr;
1140 cbD->currentComputeSrb = srb;
1142 cbD->currentSrbGeneration = srbD->generation;
1150 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1151 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1153 bool needsBindVBuf =
false;
1154 for (
int i = 0;
i < bindingCount; ++
i) {
1155 const int inputSlot = startBinding +
i;
1160 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
1162 if (cbD->currentVertexBuffers[inputSlot] != bufD->handles[isDynamic ? currentFrameSlot : 0]
1163 || cbD->currentVertexOffsets[inputSlot] != bindings[
i].second)
1165 needsBindVBuf =
true;
1166 cbD->currentVertexBuffers[inputSlot] = bufD->handles[isDynamic ? currentFrameSlot : 0];
1167 cbD->currentVertexOffsets[inputSlot] = bindings[
i].second;
1171 if (needsBindVBuf) {
1175 QD3D12GraphicsPipeline *psD = cbD->currentGraphicsPipeline;
1177 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1179 for (
int i = 0, ie =
qMin(bindingCount, inputBindingCount);
i != ie; ++
i) {
1186 barrierGen.addTransitionBarrier(
handle, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
1187 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1190 if (QD3D12Resource *
res = resourcePool.lookupRef(
handle)) {
1192 res->resource->GetGPUVirtualAddress() +
offset,
1199 cbD->cmdList->IASetVertexBuffers(UINT(startBinding), vbv.
count(), vbv.
constData());
1203 QD3D12Buffer *ibufD =
QRHI_RES(QD3D12Buffer, indexBuf);
1207 ibufD->executeHostWritesForFrameSlot(currentFrameSlot);
1210 : DXGI_FORMAT_R32_UINT;
1211 if (cbD->currentIndexBuffer != ibufD->handles[isDynamic ? currentFrameSlot : 0]
1212 || cbD->currentIndexOffset != indexOffset
1213 || cbD->currentIndexFormat != dxgiFormat)
1215 cbD->currentIndexBuffer = ibufD->handles[isDynamic ? currentFrameSlot : 0];
1216 cbD->currentIndexOffset = indexOffset;
1217 cbD->currentIndexFormat = dxgiFormat;
1220 barrierGen.addTransitionBarrier(cbD->currentIndexBuffer, D3D12_RESOURCE_STATE_INDEX_BUFFER);
1221 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1224 if (QD3D12Resource *
res = resourcePool.lookupRef(cbD->currentIndexBuffer)) {
1225 const D3D12_INDEX_BUFFER_VIEW ibv = {
1226 res->resource->GetGPUVirtualAddress() + indexOffset,
1227 UINT(
res->desc.Width - indexOffset),
1230 cbD->cmdList->IASetIndexBuffer(&ibv);
1238 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1239 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1241 const QSize outputSize = cbD->currentTarget->pixelSize();
1245 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize,
viewport.viewport(), &
x, &
y, &
w, &
h))
1255 cbD->cmdList->RSSetViewports(1, &
v);
1257 if (cbD->currentGraphicsPipeline
1260 qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize,
viewport.viewport(), &
x, &
y, &
w, &
h);
1267 cbD->cmdList->RSSetScissorRects(1, &
r);
1273 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1274 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1276 const QSize outputSize = cbD->currentTarget->pixelSize();
1280 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.
scissor(), &
x, &
y, &
w, &
h))
1289 cbD->cmdList->RSSetScissorRects(1, &
r);
1294 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1295 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1296 float v[4] = {
c.redF(),
c.greenF(),
c.blueF(),
c.alphaF() };
1297 cbD->cmdList->OMSetBlendFactor(
v);
1302 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1303 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1304 cbD->cmdList->OMSetStencilRef(refValue);
1310 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1311 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1312 cbD->cmdList->DrawInstanced(vertexCount,
instanceCount, firstVertex, firstInstance);
1318 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1319 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1320 cbD->cmdList->DrawIndexedInstanced(indexCount,
instanceCount,
1321 firstIndex, vertexOffset,
1330 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1331#ifdef QRHI_D3D12_HAS_OLD_PIX
1344 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1345#ifdef QRHI_D3D12_HAS_OLD_PIX
1346 PIXEndEvent(cbD->cmdList);
1357 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1358#ifdef QRHI_D3D12_HAS_OLD_PIX
1368 return QRHI_RES(QD3D12CommandBuffer,
cb)->nativeHandles();
1378 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1379 cbD->resetPerPassState();
1380 bindShaderVisibleHeaps(cbD);
1381 if (cbD->currentTarget) {
1382 QD3D12RenderTargetData *rtD =
rtData(cbD->currentTarget);
1383 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
1386 rtD->dsAttCount ? &rtD->dsv :
nullptr);
1400 QD3D12SwapChain *swapChainD =
QRHI_RES(QD3D12SwapChain, swapChain);
1401 currentSwapChain = swapChainD;
1402 currentFrameSlot = swapChainD->currentFrameSlot;
1403 QD3D12SwapChain::FrameResources &fr(swapChainD->frameRes[currentFrameSlot]);
1416 for (QD3D12SwapChain *sc :
std::as_const(swapchains))
1417 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
1419 HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
1421 qWarning(
"Failed to reset command allocator: %s",
1422 qPrintable(QSystemError::windowsComString(hr)));
1426 if (!startCommandListForCurrentFrameSlot(&fr.cmdList))
1429 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1430 cbD->cmdList = fr.cmdList;
1432 swapChainD->rtWrapper.d.rtv[0] = swapChainD->sampleDesc.Count > 1
1433 ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
1434 : swapChainD->rtvs[swapChainD->currentBackBufferIndex].cpuHandle;
1436 swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
1437 : D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
1442 releaseQueue.executeDeferredReleases(currentFrameSlot);
1448 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1450 smallStagingAreas[currentFrameSlot].head = 0;
1452 bindShaderVisibleHeaps(cbD);
1454 finishActiveReadbacks();
1461 QD3D12SwapChain *swapChainD =
QRHI_RES(QD3D12SwapChain, swapChain);
1462 Q_ASSERT(currentSwapChain == swapChainD);
1463 QD3D12CommandBuffer *cbD = &swapChainD->cbWrapper;
1465 QD3D12ObjectHandle backBufferResourceHandle = swapChainD->colorBuffers[swapChainD->currentBackBufferIndex];
1466 if (swapChainD->sampleDesc.Count > 1) {
1467 QD3D12ObjectHandle msaaBackBufferResourceHandle = swapChainD->msaaBuffers[swapChainD->currentBackBufferIndex];
1468 barrierGen.addTransitionBarrier(msaaBackBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
1469 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
1470 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1471 const QD3D12Resource *
src = resourcePool.lookupRef(msaaBackBufferResourceHandle);
1472 const QD3D12Resource *
dst = resourcePool.lookupRef(backBufferResourceHandle);
1474 cbD->cmdList->ResolveSubresource(
dst->resource, 0,
src->resource, 0, swapChainD->colorFormat);
1477 barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
1478 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1480 ID3D12GraphicsCommandList1 *cmdList = cbD->cmdList;
1481 HRESULT hr = cmdList->Close();
1483 qWarning(
"Failed to close command list: %s",
1484 qPrintable(QSystemError::windowsComString(hr)));
1488 ID3D12CommandList *execList[] = { cmdList };
1489 cmdQueue->ExecuteCommandLists(1, execList);
1492 UINT presentFlags = 0;
1493 if (swapChainD->swapInterval == 0
1494 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
1496 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
1498 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
1499 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
1500 qWarning(
"Device loss detected in Present()");
1503 }
else if (FAILED(hr)) {
1508 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
1509 dcompDevice->Commit();
1512 swapChainD->addCommandCompletionSignalForCurrentFrameSlot();
1519 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
1525 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
1526 swapChainD->currentBackBufferIndex = swapChainD->swapChain->GetCurrentBackBufferIndex();
1529 currentSwapChain =
nullptr;
1546 currentFrameSlot = (currentFrameSlot + 1) % QD3D12_FRAMES_IN_FLIGHT;
1548 for (QD3D12SwapChain *sc :
std::as_const(swapchains))
1549 sc->waitCommandCompletionForFrameSlot(currentFrameSlot);
1551 if (!offscreenCb[currentFrameSlot])
1552 offscreenCb[currentFrameSlot] =
new QD3D12CommandBuffer(
this);
1553 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
1554 if (!startCommandListForCurrentFrameSlot(&cbD->cmdList))
1557 releaseQueue.executeDeferredReleases(currentFrameSlot);
1559 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1560 smallStagingAreas[currentFrameSlot].head = 0;
1562 bindShaderVisibleHeaps(cbD);
1564 offscreenActive =
true;
1574 offscreenActive =
false;
1576 QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
1577 ID3D12GraphicsCommandList1 *cmdList = cbD->cmdList;
1578 HRESULT hr = cmdList->Close();
1580 qWarning(
"Failed to close command list: %s",
1581 qPrintable(QSystemError::windowsComString(hr)));
1585 ID3D12CommandList *execList[] = { cmdList };
1586 cmdQueue->ExecuteCommandLists(1, execList);
1588 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
1595 finishActiveReadbacks(
true);
1605 QD3D12CommandBuffer *cbD =
nullptr;
1606 if (offscreenActive) {
1608 cbD = offscreenCb[currentFrameSlot];
1611 cbD = ¤tSwapChain->cbWrapper;
1616 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
1618 ID3D12GraphicsCommandList1 *cmdList = cbD->cmdList;
1619 HRESULT hr = cmdList->Close();
1621 qWarning(
"Failed to close command list: %s",
1622 qPrintable(QSystemError::windowsComString(hr)));
1626 ID3D12CommandList *execList[] = { cmdList };
1627 cmdQueue->ExecuteCommandLists(1, execList);
1629 releaseQueue.activatePendingDeferredReleaseRequests(currentFrameSlot);
1634 hr = cmdAllocators[currentFrameSlot]->Reset();
1636 qWarning(
"Failed to reset command allocator: %s",
1637 qPrintable(QSystemError::windowsComString(hr)));
1641 if (!startCommandListForCurrentFrameSlot(&cmdList))
1646 shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[currentFrameSlot].head = 0;
1647 smallStagingAreas[currentFrameSlot].head = 0;
1649 bindShaderVisibleHeaps(cbD);
1651 releaseQueue.executeDeferredReleases(currentFrameSlot);
1653 finishActiveReadbacks(
true);
1660 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1661 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
1662 enqueueResourceUpdates(cbD, resourceUpdates);
1667 const QColor &colorClearValue,
1670 QRhiCommandBuffer::BeginPassFlags)
1672 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1673 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
1675 if (resourceUpdates)
1676 enqueueResourceUpdates(cbD, resourceUpdates);
1678 QD3D12RenderTargetData *rtD =
rtData(rt);
1679 bool wantsColorClear =
true;
1680 bool wantsDsClear =
true;
1682 QD3D12TextureRenderTarget *rtTex =
QRHI_RES(QD3D12TextureRenderTarget, rt);
1685 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(rtTex->description(), rtD->currentResIdList))
1688 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
it != itEnd; ++
it) {
1689 QD3D12Texture *texD =
QRHI_RES(QD3D12Texture,
it->texture());
1690 QD3D12Texture *resolveTexD =
QRHI_RES(QD3D12Texture,
it->resolveTexture());
1691 QD3D12RenderBuffer *rbD =
QRHI_RES(QD3D12RenderBuffer,
it->renderBuffer());
1693 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
1695 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
1697 barrierGen.addTransitionBarrier(resolveTexD->handle, D3D12_RESOURCE_STATE_RENDER_TARGET);
1699 if (rtTex->m_desc.depthStencilBuffer()) {
1700 QD3D12RenderBuffer *rbD =
QRHI_RES(QD3D12RenderBuffer, rtTex->m_desc.depthStencilBuffer());
1702 barrierGen.addTransitionBarrier(rbD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
1703 }
else if (rtTex->m_desc.depthTexture()) {
1704 QD3D12Texture *depthTexD =
QRHI_RES(QD3D12Texture, rtTex->m_desc.depthTexture());
1705 barrierGen.addTransitionBarrier(depthTexD->handle, D3D12_RESOURCE_STATE_DEPTH_WRITE);
1707 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1710 barrierGen.addTransitionBarrier(currentSwapChain->sampleDesc.Count > 1
1711 ? currentSwapChain->msaaBuffers[currentSwapChain->currentBackBufferIndex]
1712 : currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex],
1713 D3D12_RESOURCE_STATE_RENDER_TARGET);
1714 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1717 cbD->cmdList->OMSetRenderTargets(UINT(rtD->colorAttCount),
1720 rtD->dsAttCount ? &rtD->dsv :
nullptr);
1722 if (rtD->colorAttCount && wantsColorClear) {
1723 float clearColor[4] = {
1724 colorClearValue.
redF(),
1725 colorClearValue.
greenF(),
1726 colorClearValue.
blueF(),
1729 for (
int i = 0;
i < rtD->colorAttCount; ++
i)
1730 cbD->cmdList->ClearRenderTargetView(rtD->rtv[
i], clearColor, 0,
nullptr);
1732 if (rtD->dsAttCount && wantsDsClear) {
1733 cbD->cmdList->ClearDepthStencilView(rtD->dsv,
1734 D3D12_CLEAR_FLAGS(D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL),
1741 cbD->recordingPass = QD3D12CommandBuffer::RenderPass;
1742 cbD->currentTarget = rt;
1744 cbD->resetPerPassState();
1749 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1750 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::RenderPass);
1753 QD3D12TextureRenderTarget *rtTex =
QRHI_RES(QD3D12TextureRenderTarget, cbD->currentTarget);
1754 for (
auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
1758 if (!colorAtt.resolveTexture())
1761 QD3D12Texture *dstTexD =
QRHI_RES(QD3D12Texture, colorAtt.resolveTexture());
1762 QD3D12Resource *dstRes = resourcePool.lookupRef(dstTexD->handle);
1766 QD3D12Texture *srcTexD =
QRHI_RES(QD3D12Texture, colorAtt.texture());
1767 QD3D12RenderBuffer *srcRbD =
QRHI_RES(QD3D12RenderBuffer, colorAtt.renderBuffer());
1769 QD3D12Resource *srcRes = resourcePool.lookupRef(srcTexD ? srcTexD->handle : srcRbD->
handle);
1774 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
1775 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
1776 int(srcTexD->dxgiFormat),
int(dstTexD->dxgiFormat));
1779 if (srcTexD->sampleDesc.Count <= 1) {
1780 qWarning(
"Cannot resolve a non-multisample texture");
1783 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
1784 qWarning(
"Resolve source and destination sizes do not match");
1788 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
1789 qWarning(
"Resolve source (%d) and destination (%d) formats do not match",
1790 int(srcRbD->dxgiFormat),
int(dstTexD->dxgiFormat));
1793 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
1794 qWarning(
"Resolve source and destination sizes do not match");
1799 barrierGen.addTransitionBarrier(srcTexD ? srcTexD->handle : srcRbD->
handle, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
1800 barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
1801 barrierGen.enqueueBufferedTransitionBarriers(cbD);
1803 const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
1804 for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
1805 const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
1806 const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
1807 UINT(colorAtt.resolveLayer()) + resolveIdx,
1808 dstTexD->mipLevelCount);
1809 cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresource,
1810 srcRes->resource, srcSubresource,
1811 dstTexD->dxgiFormat);
1817 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
1818 cbD->currentTarget =
nullptr;
1820 if (resourceUpdates)
1821 enqueueResourceUpdates(cbD, resourceUpdates);
1826 QRhiCommandBuffer::BeginPassFlags)
1828 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1829 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
1831 if (resourceUpdates)
1832 enqueueResourceUpdates(cbD, resourceUpdates);
1834 cbD->recordingPass = QD3D12CommandBuffer::ComputePass;
1836 cbD->resetPerPassState();
1841 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1842 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
1844 cbD->recordingPass = QD3D12CommandBuffer::NoPass;
1846 if (resourceUpdates)
1847 enqueueResourceUpdates(cbD, resourceUpdates);
1852 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1853 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
1854 QD3D12ComputePipeline *psD =
QRHI_RES(QD3D12ComputePipeline, ps);
1855 const bool pipelineChanged = cbD->currentComputePipeline != psD || cbD->currentPipelineGeneration != psD->generation;
1857 if (pipelineChanged) {
1858 cbD->currentGraphicsPipeline =
nullptr;
1859 cbD->currentComputePipeline = psD;
1860 cbD->currentPipelineGeneration = psD->generation;
1862 if (QD3D12Pipeline *pipeline = pipelinePool.lookupRef(psD->handle)) {
1863 Q_ASSERT(pipeline->type == QD3D12Pipeline::Compute);
1864 cbD->cmdList->SetPipelineState(pipeline->pso);
1865 if (QD3D12RootSignature *rs = rootSignaturePool.lookupRef(psD->rootSigHandle))
1866 cbD->cmdList->SetComputeRootSignature(rs->rootSig);
1873 QD3D12CommandBuffer *cbD =
QRHI_RES(QD3D12CommandBuffer,
cb);
1874 Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::ComputePass);
1875 cbD->cmdList->Dispatch(UINT(
x), UINT(
y), UINT(
z));
1878bool QD3D12DescriptorHeap::create(ID3D12Device *
device,
1880 D3D12_DESCRIPTOR_HEAP_TYPE heapType,
1881 D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags)
1885 this->heapType = heapType;
1886 this->heapFlags = heapFlags;
1888 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
1889 heapDesc.Type = heapType;
1890 heapDesc.NumDescriptors =
capacity;
1891 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS(heapFlags);
1893 HRESULT hr =
device->CreateDescriptorHeap(&heapDesc, __uuidof(ID3D12DescriptorHeap),
reinterpret_cast<void **
>(&heap));
1895 qWarning(
"Failed to create descriptor heap: %s",
qPrintable(QSystemError::windowsComString(hr)));
1901 descriptorByteSize =
device->GetDescriptorHandleIncrementSize(heapType);
1902 heapStart.cpuHandle = heap->GetCPUDescriptorHandleForHeapStart();
1903 if (heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
1904 heapStart.gpuHandle = heap->GetGPUDescriptorHandleForHeapStart();
1909void QD3D12DescriptorHeap::createWithExisting(
const QD3D12DescriptorHeap &
other,
1916 heapType =
other.heapType;
1917 heapFlags =
other.heapFlags;
1918 descriptorByteSize =
other.descriptorByteSize;
1919 heapStart = incremented(
other.heapStart, offsetInDescriptors);
1922void QD3D12DescriptorHeap::destroy()
1931void QD3D12DescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
1934 releaseQueue->deferredReleaseDescriptorHeap(heap);
1940QD3D12Descriptor QD3D12DescriptorHeap::get(
quint32 count)
1951QD3D12Descriptor QD3D12DescriptorHeap::at(
quint32 index)
const
1953 const quint32 startOffset =
index * descriptorByteSize;
1955 result.cpuHandle.ptr = heapStart.cpuHandle.ptr + startOffset;
1956 if (heapStart.gpuHandle.ptr != 0)
1957 result.gpuHandle.ptr = heapStart.gpuHandle.ptr + startOffset;
1961bool QD3D12CpuDescriptorPool::create(ID3D12Device *
device, D3D12_DESCRIPTOR_HEAP_TYPE heapType,
const char *debugName)
1963 QD3D12DescriptorHeap firstHeap;
1964 if (!firstHeap.create(
device, DESCRIPTORS_PER_HEAP, heapType, D3D12_DESCRIPTOR_HEAP_FLAG_NONE))
1966 heaps.append(HeapWithMap::init(firstHeap, DESCRIPTORS_PER_HEAP));
1967 descriptorByteSize = heaps[0].heap.descriptorByteSize;
1969 this->debugName = debugName;
1973void QD3D12CpuDescriptorPool::destroy()
1977 static bool leakCheck =
true;
1983 for (HeapWithMap &heap : heaps) {
1984 const int leakedDescriptorCount = heap.map.count(
true);
1985 if (leakedDescriptorCount > 0) {
1986 qWarning(
"QD3D12CpuDescriptorPool::destroy(): "
1987 "Heap %p for descriptor pool %p '%s' has %d unreleased descriptors",
1988 &heap.heap,
this, debugName, leakedDescriptorCount);
1992 for (HeapWithMap &heap : heaps)
1993 heap.heap.destroy();
1997QD3D12Descriptor QD3D12CpuDescriptorPool::allocate(
quint32 count)
2001 HeapWithMap &last(heaps.last());
2002 if (last.heap.head +
count <= last.heap.capacity) {
2003 quint32 firstIndex = last.heap.head;
2005 last.map.setBit(firstIndex +
i);
2006 return last.heap.get(
count);
2009 for (HeapWithMap &heap : heaps) {
2011 for (
quint32 i = 0;
i < DESCRIPTORS_PER_HEAP; ++
i) {
2012 if (heap.map.testBit(
i)) {
2016 if (freeCount ==
count) {
2017 quint32 firstIndex =
i - (freeCount - 1);
2019 heap.map.setBit(firstIndex +
j);
2020 return heap.heap.at(firstIndex);
2027 QD3D12DescriptorHeap newHeap;
2028 if (!newHeap.create(
device, DESCRIPTORS_PER_HEAP, last.heap.heapType, last.heap.heapFlags))
2031 heaps.append(HeapWithMap::init(newHeap, DESCRIPTORS_PER_HEAP));
2034 heaps.last().map.setBit(
i);
2036 return heaps.last().heap.get(
count);
2039void QD3D12CpuDescriptorPool::release(
const QD3D12Descriptor &descriptor,
quint32 count)
2042 if (!descriptor.isValid())
2045 const SIZE_T
addr = descriptor.cpuHandle.ptr;
2046 for (HeapWithMap &heap : heaps) {
2047 const SIZE_T
begin = heap.heap.heapStart.cpuHandle.ptr;
2048 const SIZE_T
end =
begin + heap.heap.descriptorByteSize * heap.heap.capacity;
2052 heap.map.setBit(firstIndex +
i,
false);
2057 qWarning(
"QD3D12CpuDescriptorPool::release: Descriptor with address %llu is not in any heap",
2058 quint64(descriptor.cpuHandle.ptr));
2061bool QD3D12StagingArea::create(QRhiD3D12 *rhi,
quint32 capacity, D3D12_HEAP_TYPE heapType)
2063 Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
2064 D3D12_RESOURCE_DESC resourceDesc = {};
2065 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
2067 resourceDesc.Height = 1;
2068 resourceDesc.DepthOrArraySize = 1;
2069 resourceDesc.MipLevels = 1;
2070 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
2071 resourceDesc.SampleDesc = { 1, 0 };
2072 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2073 resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
2074 UINT
state = heapType == D3D12_HEAP_TYPE_UPLOAD ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
2075 HRESULT hr = rhi->vma.createResource(heapType,
2077 D3D12_RESOURCE_STATES(
state),
2080 __uuidof(ID3D12Resource),
2081 reinterpret_cast<void **
>(&resource));
2083 qWarning(
"Failed to create buffer for staging area: %s",
2084 qPrintable(QSystemError::windowsComString(hr)));
2088 hr = resource->Map(0,
nullptr, &
p);
2090 qWarning(
"Failed to map buffer for staging area: %s",
2091 qPrintable(QSystemError::windowsComString(hr)));
2096 mem.p =
static_cast<quint8 *
>(
p);
2097 mem.gpuAddr = resource->GetGPUVirtualAddress();
2098 mem.buffer = resource;
2099 mem.bufferOffset = 0;
2107void QD3D12StagingArea::destroy()
2110 resource->Release();
2120void QD3D12StagingArea::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2123 releaseQueue->deferredReleaseResourceAndAllocation(resource,
allocation);
2127QD3D12StagingArea::Allocation QD3D12StagingArea::get(
quint32 byteSize)
2131 qWarning(
"Failed to allocate %u (%u) bytes from staging area of size %u with %u bytes left",
2132 allocSize, byteSize,
capacity, remainingCapacity());
2148void QD3D12ReleaseQueue::deferredReleaseResource(
const QD3D12ObjectHandle &
handle)
2150 DeferredReleaseEntry
e;
2155void QD3D12ReleaseQueue::deferredReleaseResourceWithViews(
const QD3D12ObjectHandle &
handle,
2156 QD3D12CpuDescriptorPool *
pool,
2157 const QD3D12Descriptor &viewsStart,
2160 DeferredReleaseEntry
e;
2161 e.type = DeferredReleaseEntry::Resource;
2163 e.poolForViews =
pool;
2164 e.viewsStart = viewsStart;
2165 e.viewCount = viewCount;
2169void QD3D12ReleaseQueue::deferredReleasePipeline(
const QD3D12ObjectHandle &
handle)
2171 DeferredReleaseEntry
e;
2172 e.type = DeferredReleaseEntry::Pipeline;
2177void QD3D12ReleaseQueue::deferredReleaseRootSignature(
const QD3D12ObjectHandle &
handle)
2179 DeferredReleaseEntry
e;
2180 e.type = DeferredReleaseEntry::RootSignature;
2185void QD3D12ReleaseQueue::deferredReleaseCallback(std::function<
void(
void*)> callback,
void *userData)
2187 DeferredReleaseEntry
e;
2188 e.type = DeferredReleaseEntry::Callback;
2189 e.callback = callback;
2190 e.callbackUserData = userData;
2194void QD3D12ReleaseQueue::deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
2197 DeferredReleaseEntry
e;
2198 e.type = DeferredReleaseEntry::ResourceAndAllocation;
2199 e.resourceAndAllocation = { resource,
allocation };
2203void QD3D12ReleaseQueue::deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap)
2205 DeferredReleaseEntry
e;
2206 e.type = DeferredReleaseEntry::DescriptorHeap;
2207 e.descriptorHeap = heap;
2211void QD3D12ReleaseQueue::deferredReleaseViews(QD3D12CpuDescriptorPool *
pool,
2212 const QD3D12Descriptor &viewsStart,
2215 DeferredReleaseEntry
e;
2216 e.type = DeferredReleaseEntry::Views;
2217 e.poolForViews =
pool;
2218 e.viewsStart = viewsStart;
2219 e.viewCount = viewCount;
2223void QD3D12ReleaseQueue::activatePendingDeferredReleaseRequests(
int frameSlot)
2225 for (DeferredReleaseEntry &
e :
queue) {
2226 if (!
e.frameSlotToBeReleasedIn.has_value())
2227 e.frameSlotToBeReleasedIn = frameSlot;
2231void QD3D12ReleaseQueue::executeDeferredReleases(
int frameSlot,
bool forced)
2233 for (
int i =
queue.count() - 1;
i >= 0; --
i) {
2234 const DeferredReleaseEntry &
e(
queue[
i]);
2235 if (forced || (
e.frameSlotToBeReleasedIn.has_value() &&
e.frameSlotToBeReleasedIn.value() == frameSlot)) {
2237 case DeferredReleaseEntry::Resource:
2238 resourcePool->remove(
e.handle);
2239 if (
e.poolForViews &&
e.viewsStart.isValid() &&
e.viewCount > 0)
2240 e.poolForViews->release(
e.viewsStart,
e.viewCount);
2242 case DeferredReleaseEntry::Pipeline:
2243 pipelinePool->remove(
e.handle);
2245 case DeferredReleaseEntry::RootSignature:
2246 rootSignaturePool->remove(
e.handle);
2248 case DeferredReleaseEntry::Callback:
2249 e.callback(
e.callbackUserData);
2251 case DeferredReleaseEntry::ResourceAndAllocation:
2254 e.resourceAndAllocation.first->Release();
2255 if (
e.resourceAndAllocation.second)
2256 e.resourceAndAllocation.second->Release();
2258 case DeferredReleaseEntry::DescriptorHeap:
2259 e.descriptorHeap->Release();
2261 case DeferredReleaseEntry::Views:
2262 e.poolForViews->release(
e.viewsStart,
e.viewCount);
2270void QD3D12ReleaseQueue::releaseAll()
2272 executeDeferredReleases(0,
true);
2275void QD3D12ResourceBarrierGenerator::addTransitionBarrier(
const QD3D12ObjectHandle &resourceHandle,
2276 D3D12_RESOURCE_STATES stateAfter)
2278 if (QD3D12Resource *
res = resourcePool->lookupRef(resourceHandle)) {
2279 if (stateAfter !=
res->state) {
2280 transitionResourceBarriers.append({ resourceHandle,
res->state, stateAfter });
2281 res->state = stateAfter;
2286void QD3D12ResourceBarrierGenerator::enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD)
2289 for (
const TransitionResourceBarrier &trb : transitionResourceBarriers) {
2290 if (QD3D12Resource *
res = resourcePool->lookupRef(trb.resourceHandle)) {
2291 D3D12_RESOURCE_BARRIER barrier = {};
2292 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2293 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2294 barrier.Transition.pResource =
res->resource;
2295 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
2296 barrier.Transition.StateBefore = trb.stateBefore;
2297 barrier.Transition.StateAfter = trb.stateAfter;
2298 barriers.
append(barrier);
2301 transitionResourceBarriers.clear();
2303 cbD->cmdList->ResourceBarrier(barriers.
count(), barriers.
constData());
2306void QD3D12ResourceBarrierGenerator::enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
2307 const QD3D12ObjectHandle &resourceHandle,
2309 D3D12_RESOURCE_STATES stateBefore,
2310 D3D12_RESOURCE_STATES stateAfter)
2312 if (QD3D12Resource *
res = resourcePool->lookupRef(resourceHandle)) {
2313 D3D12_RESOURCE_BARRIER barrier = {};
2314 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
2315 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2316 barrier.Transition.pResource =
res->resource;
2317 barrier.Transition.Subresource = subresource;
2318 barrier.Transition.StateBefore = stateBefore;
2319 barrier.Transition.StateAfter = stateAfter;
2320 cbD->cmdList->ResourceBarrier(1, &barrier);
2324void QD3D12ResourceBarrierGenerator::enqueueUavBarrier(QD3D12CommandBuffer *cbD,
2325 const QD3D12ObjectHandle &resourceHandle)
2327 if (QD3D12Resource *
res = resourcePool->lookupRef(resourceHandle)) {
2328 D3D12_RESOURCE_BARRIER barrier = {};
2329 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
2330 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
2331 barrier.UAV.pResource =
res->resource;
2332 cbD->cmdList->ResourceBarrier(1, &barrier);
2336void QD3D12ShaderBytecodeCache::insertWithCapacityLimit(
const QRhiShaderStage &
key,
const Shader &
s)
2338 if (
data.count() >= QRhiD3D12::MAX_SHADER_CACHE_ENTRIES)
2343bool QD3D12ShaderVisibleDescriptorHeap::create(ID3D12Device *
device,
2344 D3D12_DESCRIPTOR_HEAP_TYPE
type,
2345 quint32 perFrameDescriptorCount)
2347 Q_ASSERT(
type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ||
type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
2349 quint32 size = perFrameDescriptorCount * QD3D12_FRAMES_IN_FLIGHT;
2352 const quint32 CBV_SRV_UAV_MAX = 1000000;
2353 const quint32 SAMPLER_MAX = 2048;
2354 if (
type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
2356 else if (
type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
2359 if (!heap.create(
device,
size,
type, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)) {
2360 qWarning(
"Failed to create shader-visible descriptor heap of size %u",
size);
2364 perFrameDescriptorCount =
size / QD3D12_FRAMES_IN_FLIGHT;
2365 quint32 currentOffsetInDescriptors = 0;
2366 for (
int i = 0;
i < QD3D12_FRAMES_IN_FLIGHT; ++
i) {
2367 perFrameHeapSlice[
i].createWithExisting(heap, currentOffsetInDescriptors, perFrameDescriptorCount);
2368 currentOffsetInDescriptors += perFrameDescriptorCount;
2374void QD3D12ShaderVisibleDescriptorHeap::destroy()
2379void QD3D12ShaderVisibleDescriptorHeap::destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue)
2381 heap.destroyWithDeferredRelease(releaseQueue);
2387 return { binding, binding };
2399void QD3D12ShaderResourceVisitor::visit()
2401 for (
int bindingIdx = 0, bindingCount = srb->sortedBindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
2405 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
2406 const QD3D12ShaderStageData *sd = &stageData[stageIdx];
2410 if (!bd->
stage.testFlag(qd3d12_stageToSrb(sd->stage)))
2416 const int shaderRegister =
mapBinding(bd->
binding, sd->nativeResourceBindingMap).first;
2417 if (shaderRegister >= 0 && uniformBuffer)
2418 uniformBuffer(sd->stage, bd->
u.
ubuf, shaderRegister, bd->
binding);
2424 const int textureBaseShaderRegister =
mapBinding(bd->
binding, sd->nativeResourceBindingMap).first;
2425 const int samplerBaseShaderRegister =
mapBinding(bd->
binding, sd->nativeResourceBindingMap).second;
2427 if (textureBaseShaderRegister >= 0 &&
texture)
2429 if (samplerBaseShaderRegister >= 0 &&
sampler)
2437 const int baseShaderRegister =
mapBinding(bd->
binding, sd->nativeResourceBindingMap).first;
2438 if (baseShaderRegister >= 0 &&
texture) {
2447 const int baseShaderRegister =
mapBinding(bd->
binding, sd->nativeResourceBindingMap).first;
2448 if (baseShaderRegister >= 0 &&
sampler) {
2456 const int shaderRegister =
mapBinding(bd->
binding, sd->nativeResourceBindingMap).first;
2457 if (shaderRegister >= 0 && storageImage)
2458 storageImage(sd->stage, bd->
u.
simage, Load, shaderRegister);
2463 const int shaderRegister =
mapBinding(bd->
binding, sd->nativeResourceBindingMap).first;
2464 if (shaderRegister >= 0 && storageImage)
2465 storageImage(sd->stage, bd->
u.
simage, Store, shaderRegister);
2470 const int shaderRegister =
mapBinding(bd->
binding, sd->nativeResourceBindingMap).first;
2471 if (shaderRegister >= 0 && storageImage)
2472 storageImage(sd->stage, bd->
u.
simage, LoadStore, shaderRegister);
2477 const int shaderRegister =
mapBinding(bd->
binding, sd->nativeResourceBindingMap).first;
2478 if (shaderRegister >= 0 && storageBuffer)
2479 storageBuffer(sd->stage, bd->
u.
sbuf, Load, shaderRegister);
2484 const int shaderRegister =
mapBinding(bd->
binding, sd->nativeResourceBindingMap).first;
2485 if (shaderRegister >= 0 && storageBuffer)
2486 storageBuffer(sd->stage, bd->
u.
sbuf, Store, shaderRegister);
2491 const int shaderRegister =
mapBinding(bd->
binding, sd->nativeResourceBindingMap).first;
2492 if (shaderRegister >= 0 && storageBuffer)
2493 storageBuffer(sd->stage, bd->
u.
sbuf, LoadStore, shaderRegister);
2501bool QD3D12SamplerManager::create(ID3D12Device *
device)
2504 if (!shaderVisibleSamplerHeap.create(
device,
2505 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
2506 MAX_SAMPLERS / QD3D12_FRAMES_IN_FLIGHT))
2508 qWarning(
"Could not create shader-visible SAMPLER heap");
2516void QD3D12SamplerManager::destroy()
2519 shaderVisibleSamplerHeap.destroy();
2524QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(
const D3D12_SAMPLER_DESC &
desc)
2530 QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
2531 if (descriptor.isValid()) {
2532 device->CreateSampler(&
desc, descriptor.cpuHandle);
2533 gpuMap.insert({
desc}, descriptor);
2535 qWarning(
"Out of shader-visible SAMPLER descriptor heap space,"
2536 " this should not happen, maximum number of unique samplers is %u",
2537 shaderVisibleSamplerHeap.heap.capacity);
2543bool QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
2547 D3D12_ROOT_PARAMETER1 rootParams[3] = {};
2548 D3D12_DESCRIPTOR_RANGE1 descriptorRanges[2] = {};
2551 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
2552 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
2555 descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
2556 descriptorRanges[0].NumDescriptors = 1;
2557 descriptorRanges[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
2558 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
2559 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
2560 rootParams[1].DescriptorTable.NumDescriptorRanges = 1;
2561 rootParams[1].DescriptorTable.pDescriptorRanges = &descriptorRanges[0];
2564 descriptorRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
2565 descriptorRanges[1].NumDescriptors = 4;
2566 rootParams[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
2567 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
2568 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
2569 rootParams[2].DescriptorTable.pDescriptorRanges = &descriptorRanges[1];
2572 D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
2573 samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
2574 samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
2575 samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
2576 samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
2577 samplerDesc.MaxLOD = 10000.0f;
2578 samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
2580 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
2581 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
2582 rsDesc.Desc_1_1.NumParameters = 3;
2583 rsDesc.Desc_1_1.pParameters = rootParams;
2584 rsDesc.Desc_1_1.NumStaticSamplers = 1;
2585 rsDesc.Desc_1_1.pStaticSamplers = &samplerDesc;
2588 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
2590 qWarning(
"Failed to serialize root signature: %s",
qPrintable(QSystemError::windowsComString(hr)));
2593 ID3D12RootSignature *rootSig =
nullptr;
2594 hr = rhiD->dev->CreateRootSignature(0,
2597 __uuidof(ID3D12RootSignature),
2598 reinterpret_cast<void **
>(&rootSig));
2601 qWarning(
"Failed to create root signature: %s",
2602 qPrintable(QSystemError::windowsComString(hr)));
2606 rootSigHandle = QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
2608 D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
2609 psoDesc.pRootSignature = rootSig;
2610 psoDesc.CS.pShaderBytecode = g_csMipmap;
2611 psoDesc.CS.BytecodeLength =
sizeof(g_csMipmap);
2612 ID3D12PipelineState *pso =
nullptr;
2613 hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
2614 __uuidof(ID3D12PipelineState),
2615 reinterpret_cast<void **
>(&pso));
2617 qWarning(
"Failed to create compute pipeline state: %s",
2618 qPrintable(QSystemError::windowsComString(hr)));
2619 rhiD->rootSignaturePool.remove(rootSigHandle);
2624 pipelineHandle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
2629void QD3D12MipmapGenerator::destroy()
2631 rhiD->pipelinePool.remove(pipelineHandle);
2632 pipelineHandle = {};
2633 rhiD->rootSignaturePool.remove(rootSigHandle);
2637void QD3D12MipmapGenerator::generate(QD3D12CommandBuffer *cbD,
const QD3D12ObjectHandle &textureHandle)
2639 QD3D12Pipeline *pipeline = rhiD->pipelinePool.lookupRef(pipelineHandle);
2642 QD3D12RootSignature *rootSig = rhiD->rootSignaturePool.lookupRef(rootSigHandle);
2645 QD3D12Resource *
res = rhiD->resourcePool.lookupRef(textureHandle);
2649 const quint32 mipLevelCount =
res->desc.MipLevels;
2650 if (mipLevelCount < 2)
2653 if (
res->desc.SampleDesc.Count > 1) {
2654 qWarning(
"Cannot generate mipmaps for MSAA texture");
2658 const bool is1D =
res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D;
2660 qWarning(
"Cannot generate mipmaps for 1D texture");
2664 const bool is3D =
res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
2665 const bool isCubeOrArray =
res->desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D
2666 &&
res->desc.DepthOrArraySize > 1;
2667 const quint32 layerCount = isCubeOrArray ?
res->desc.DepthOrArraySize : 1;
2671 qWarning(
"3D texture mipmapping is not implemented for D3D12 atm");
2675 rhiD->barrierGen.addTransitionBarrier(textureHandle, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
2676 rhiD->barrierGen.enqueueBufferedTransitionBarriers(cbD);
2678 cbD->cmdList->SetPipelineState(pipeline->pso);
2679 cbD->cmdList->SetComputeRootSignature(rootSig->rootSig);
2681 const quint32 descriptorByteSize = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].descriptorByteSize;
2690 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
sizeof(CBufData), mipLevelCount * layerCount);
2691 std::optional<QD3D12StagingArea> ownStagingArea;
2692 if (rhiD->smallStagingAreas[rhiD->currentFrameSlot].remainingCapacity() < allocSize) {
2693 ownStagingArea = QD3D12StagingArea();
2694 if (!ownStagingArea->create(rhiD, allocSize, D3D12_HEAP_TYPE_UPLOAD)) {
2695 qWarning(
"Could not create staging area for mipmap generation");
2699 QD3D12StagingArea *workArea = ownStagingArea.has_value()
2700 ? &ownStagingArea.value()
2701 : &rhiD->smallStagingAreas[rhiD->currentFrameSlot];
2703 bool gotNewHeap =
false;
2704 if (!rhiD->ensureShaderVisibleDescriptorHeapCapacity(&rhiD->shaderVisibleCbvSrvUavHeap,
2705 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
2706 rhiD->currentFrameSlot,
2707 (1 + 4) * mipLevelCount * layerCount,
2710 qWarning(
"Could not ensure enough space in descriptor heap for mipmap generation");
2714 rhiD->bindShaderVisibleHeaps(cbD);
2718 UINT subresource = calcSubresource(
level,
layer,
res->desc.MipLevels);
2719 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
2720 D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
2721 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
2725 const quint32 dw = levelPlusOneMipWidth == 1 ? levelPlusOneMipHeight : levelPlusOneMipWidth;
2726 const quint32 dh = levelPlusOneMipHeight == 1 ? levelPlusOneMipWidth : levelPlusOneMipHeight;
2730 levelPlusOneMipWidth =
qMax(1u, levelPlusOneMipWidth);
2731 levelPlusOneMipHeight =
qMax(1u, levelPlusOneMipHeight);
2733 CBufData cbufData = {
2736 1.0f / float(levelPlusOneMipWidth),
2737 1.0f / float(levelPlusOneMipHeight)
2740 QD3D12StagingArea::Allocation cbuf = workArea->get(
sizeof(cbufData));
2741 memcpy(cbuf.p, &cbufData,
sizeof(cbufData));
2742 cbD->cmdList->SetComputeRootConstantBufferView(0, cbuf.gpuAddr);
2744 QD3D12Descriptor srv = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(1);
2745 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
2746 srvDesc.Format =
res->desc.Format;
2747 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
2748 if (isCubeOrArray) {
2749 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
2750 srvDesc.Texture2DArray.MostDetailedMip =
level;
2751 srvDesc.Texture2DArray.MipLevels = 1;
2752 srvDesc.Texture2DArray.FirstArraySlice =
layer;
2753 srvDesc.Texture2DArray.ArraySize = 1;
2755 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
2756 srvDesc.Texture3D.MostDetailedMip =
level;
2757 srvDesc.Texture3D.MipLevels = 1;
2759 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
2760 srvDesc.Texture2D.MostDetailedMip =
level;
2761 srvDesc.Texture2D.MipLevels = 1;
2763 rhiD->dev->CreateShaderResourceView(
res->resource, &srvDesc, srv.cpuHandle);
2764 cbD->cmdList->SetComputeRootDescriptorTable(1, srv.gpuHandle);
2766 QD3D12Descriptor uavStart = rhiD->shaderVisibleCbvSrvUavHeap.perFrameHeapSlice[rhiD->currentFrameSlot].get(4);
2767 D3D12_CPU_DESCRIPTOR_HANDLE uavCpuHandle = uavStart.cpuHandle;
2769 for (
quint32 uavIdx = 0; uavIdx < 4; ++uavIdx) {
2771 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
2772 uavDesc.Format =
res->desc.Format;
2773 if (isCubeOrArray) {
2774 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
2775 uavDesc.Texture2DArray.MipSlice = uavMipLevel;
2776 uavDesc.Texture2DArray.FirstArraySlice =
layer;
2777 uavDesc.Texture2DArray.ArraySize = 1;
2779 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
2780 uavDesc.Texture3D.MipSlice = uavMipLevel;
2781 uavDesc.Texture3D.FirstWSlice = 0;
2782 uavDesc.Texture3D.WSize = 1;
2784 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
2785 uavDesc.Texture2D.MipSlice = uavMipLevel;
2787 rhiD->dev->CreateUnorderedAccessView(
res->resource,
nullptr, &uavDesc, uavCpuHandle);
2788 uavCpuHandle.ptr += descriptorByteSize;
2790 cbD->cmdList->SetComputeRootDescriptorTable(2, uavStart.gpuHandle);
2792 cbD->cmdList->Dispatch(levelPlusOneMipWidth, levelPlusOneMipHeight, 1);
2794 rhiD->barrierGen.enqueueUavBarrier(cbD, textureHandle);
2795 rhiD->barrierGen.enqueueSubresourceTransitionBarrier(cbD, textureHandle, subresource,
2796 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
2797 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
2799 level += numGenMips;
2803 if (ownStagingArea.has_value())
2804 ownStagingArea->destroyWithDeferredRelease(&rhiD->releaseQueue);
2807bool QD3D12MemoryAllocator::create(ID3D12Device *
device, IDXGIAdapter1 *adapter)
2820 DXGI_ADAPTER_DESC1
desc;
2821 adapter->GetDesc1(&
desc);
2825 D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
2826 allocatorDesc.pDevice =
device;
2827 allocatorDesc.pAdapter = adapter;
2830 allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED;
2831 HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, &allocator);
2833 qWarning(
"Failed to initialize D3D12 Memory Allocator: %s",
2834 qPrintable(QSystemError::windowsComString(hr)));
2840void QD3D12MemoryAllocator::destroy()
2843 allocator->Release();
2844 allocator =
nullptr;
2848HRESULT QD3D12MemoryAllocator::createResource(D3D12_HEAP_TYPE heapType,
2849 const D3D12_RESOURCE_DESC *resourceDesc,
2850 D3D12_RESOURCE_STATES initialState,
2851 const D3D12_CLEAR_VALUE *optimizedClearValue,
2852 D3D12MA::Allocation **maybeAllocation,
2853 REFIID riidResource,
2857 D3D12MA::ALLOCATION_DESC allocDesc = {};
2858 allocDesc.HeapType = heapType;
2859 return allocator->CreateResource(&allocDesc,
2862 optimizedClearValue,
2867 *maybeAllocation =
nullptr;
2868 D3D12_HEAP_PROPERTIES heapProps = {};
2869 heapProps.Type = heapType;
2870 return device->CreateCommittedResource(&heapProps,
2871 D3D12_HEAP_FLAG_NONE,
2874 optimizedClearValue,
2880void QD3D12MemoryAllocator::getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget)
2883 allocator->GetBudget(localBudget, nonLocalBudget);
2886 *nonLocalBudget = {};
2890void QRhiD3D12::waitGpu()
2892 fullFenceCounter += 1u;
2893 if (SUCCEEDED(cmdQueue->Signal(fullFence, fullFenceCounter))) {
2894 if (SUCCEEDED(fullFence->SetEventOnCompletion(fullFenceCounter, fullFenceEvent)))
2895 WaitForSingleObject(fullFenceEvent, INFINITE);
2899DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleCount(
int sampleCount, DXGI_FORMAT
format)
const
2901 DXGI_SAMPLE_DESC
desc;
2906 int s =
qBound(1, sampleCount, 64);
2908 if (!supportedSampleCounts().
contains(
s)) {
2909 qWarning(
"Attempted to set unsupported sample count %d", sampleCount);
2914 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
2915 msaaInfo.Format =
format;
2916 msaaInfo.SampleCount =
s;
2917 if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo,
sizeof(msaaInfo)))) {
2918 if (msaaInfo.NumQualityLevels > 0) {
2919 desc.Count = UINT(
s);
2920 desc.Quality = msaaInfo.NumQualityLevels - 1;
2922 qWarning(
"No quality levels for multisampling with sample count %d",
s);
2930bool QRhiD3D12::startCommandListForCurrentFrameSlot(ID3D12GraphicsCommandList1 **cmdList)
2932 ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
2934 HRESULT hr = dev->CreateCommandList(0,
2935 D3D12_COMMAND_LIST_TYPE_DIRECT,
2938 __uuidof(ID3D12GraphicsCommandList1),
2939 reinterpret_cast<void **
>(cmdList));
2941 qWarning(
"Failed to create command list: %s",
qPrintable(QSystemError::windowsComString(hr)));
2945 HRESULT hr = (*cmdList)->Reset(cmdAlloc,
nullptr);
2947 qWarning(
"Failed to reset command list: %s",
qPrintable(QSystemError::windowsComString(hr)));
2957 case DXGI_FORMAT_R8G8B8A8_UNORM:
2959 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
2963 case DXGI_FORMAT_B8G8R8A8_UNORM:
2965 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
2969 case DXGI_FORMAT_R16G16B16A16_FLOAT:
2971 case DXGI_FORMAT_R32G32B32A32_FLOAT:
2973 case DXGI_FORMAT_R10G10B10A2_UNORM:
2989 QD3D12Buffer *bufD =
QRHI_RES(QD3D12Buffer, u.buf);
2991 for (
int i = 0;
i < QD3D12_FRAMES_IN_FLIGHT; ++
i) {
2992 if (u.offset == 0 && u.data.size() == bufD->m_size)
2993 bufD->pendingHostWrites[
i].clear();
2994 bufD->pendingHostWrites[
i].append({ u.offset, u.data });
2997 QD3D12Buffer *bufD =
QRHI_RES(QD3D12Buffer, u.buf);
2999 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
3007 QD3D12StagingArea::Allocation stagingAlloc;
3008 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(bufD->m_size, 1);
3009 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3010 stagingAlloc = smallStagingAreas[currentFrameSlot].get(bufD->m_size);
3012 std::optional<QD3D12StagingArea> ownStagingArea;
3013 if (!stagingAlloc.isValid()) {
3014 ownStagingArea = QD3D12StagingArea();
3015 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3017 stagingAlloc = ownStagingArea->get(allocSize);
3018 if (!stagingAlloc.isValid()) {
3019 ownStagingArea->destroy();
3024 memcpy(stagingAlloc.p + u.offset, u.data.constData(), u.data.size());
3026 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_DEST);
3027 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3029 if (QD3D12Resource *
res = resourcePool.lookupRef(bufD->handles[0])) {
3030 cbD->cmdList->CopyBufferRegion(
res->resource,
3032 stagingAlloc.buffer,
3033 stagingAlloc.bufferOffset + u.offset,
3037 if (ownStagingArea.has_value())
3038 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3040 QD3D12Buffer *bufD =
QRHI_RES(QD3D12Buffer, u.buf);
3042 bufD->executeHostWritesForFrameSlot(currentFrameSlot);
3043 if (QD3D12Resource *
res = resourcePool.lookupRef(bufD->handles[currentFrameSlot])) {
3045 u.result->data.resize(u.readSize);
3046 memcpy(u.result->data.data(),
reinterpret_cast<char *
>(
res->cpuMapPtr) + u.offset, u.readSize);
3048 if (u.result->completed)
3049 u.result->completed();
3051 QD3D12Readback readback;
3052 readback.frameSlot = currentFrameSlot;
3053 readback.result = u.result;
3054 readback.byteSize = u.readSize;
3055 const quint32 allocSize =
aligned(u.readSize, QD3D12StagingArea::ALIGNMENT);
3056 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
3057 if (u.result->completed)
3058 u.result->completed();
3061 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(u.readSize);
3062 if (!stagingAlloc.isValid()) {
3063 readback.staging.destroy();
3064 if (u.result->completed)
3065 u.result->completed();
3068 Q_ASSERT(stagingAlloc.bufferOffset == 0);
3069 barrierGen.addTransitionBarrier(bufD->handles[0], D3D12_RESOURCE_STATE_COPY_SOURCE);
3070 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3071 if (QD3D12Resource *
res = resourcePool.lookupRef(bufD->handles[0])) {
3072 cbD->cmdList->CopyBufferRegion(stagingAlloc.buffer, 0,
res->resource, u.offset, u.readSize);
3073 activeReadbacks.append(readback);
3075 readback.staging.destroy();
3076 if (u.result->completed)
3077 u.result->completed();
3086 QD3D12Texture *texD =
QRHI_RES(QD3D12Texture, u.dst);
3088 QD3D12Resource *
res = resourcePool.lookupRef(texD->handle);
3091 barrierGen.addTransitionBarrier(texD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
3092 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3093 for (
int layer = 0, maxLayer = u.subresDesc.size();
layer < maxLayer; ++
layer) {
3096 const UINT subresource = calcSubresource(UINT(
level), is3D ? 0u : UINT(
layer), texD->mipLevelCount);
3097 D3D12_PLACED_SUBRESOURCE_FOOTPRINT
layout;
3098 UINT64 totalBytes = 0;
3099 D3D12_RESOURCE_DESC
desc =
res->desc;
3101 desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
3102 desc.DepthOrArraySize = 1;
3104 dev->GetCopyableFootprints(&
desc, subresource, 1, 0,
3105 &
layout,
nullptr,
nullptr, &totalBytes);
3107 const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(
quint32(totalBytes), 1);
3108 QD3D12StagingArea::Allocation stagingAlloc;
3109 if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
3110 stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
3112 std::optional<QD3D12StagingArea> ownStagingArea;
3113 if (!stagingAlloc.isValid()) {
3114 ownStagingArea = QD3D12StagingArea();
3115 if (!ownStagingArea->create(
this, allocSize, D3D12_HEAP_TYPE_UPLOAD))
3117 stagingAlloc = ownStagingArea->get(allocSize);
3118 if (!stagingAlloc.isValid()) {
3119 ownStagingArea->destroy();
3124 const UINT requiredBytesPerLine =
layout.Footprint.RowPitch;
3125 const QSize subresSize = subresDesc.sourceSize().
isEmpty() ?
q->sizeForMipLevel(
level, texD->m_pixelSize)
3126 : subresDesc.sourceSize();
3127 const QPoint srcPos = subresDesc.sourceTopLeft();
3128 QPoint dstPos = subresDesc.destinationTopLeft();
3130 D3D12_TEXTURE_COPY_LOCATION
dst;
3131 dst.pResource =
res->resource;
3132 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3133 dst.SubresourceIndex = subresource;
3134 D3D12_TEXTURE_COPY_LOCATION
src;
3135 src.pResource = stagingAlloc.buffer;
3136 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
3137 src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
3138 src.PlacedFootprint.Footprint =
layout.Footprint;
3142 if (!subresDesc.image().isNull()) {
3144 const int bpc =
qMax(1,
img.depth() / 8);
3145 const int bpl =
img.bytesPerLine();
3152 srcBox.right = UINT(
size.width());
3153 srcBox.bottom = UINT(
size.height());
3157 const uchar *imgPtr =
img.constBits();
3159 for (
int y = 0,
h =
size.height();
y <
h; ++
y) {
3160 memcpy(stagingAlloc.p +
y * requiredBytesPerLine,
3161 imgPtr + srcPos.
x() * bpc + (
y + srcPos.
y()) * bpl,
3167 compressedFormatInfo(texD->m_format, subresSize, &bpl,
nullptr, &blockDim);
3180 const quint32 copyBytes =
qMin(bpl, requiredBytesPerLine);
3182 const char *imgPtr = imgData.
constData();
3184 for (
int y = 0;
y < rowCount; ++
y)
3185 memcpy(stagingAlloc.p +
y * requiredBytesPerLine, imgPtr +
y * bpl, copyBytes);
3186 }
else if (!subresDesc.data().isEmpty()) {
3189 srcBox.right = subresSize.
width();
3190 srcBox.bottom = subresSize.
height();
3195 if (subresDesc.dataStride())
3196 bpl = subresDesc.dataStride();
3198 textureFormatInfo(texD->m_format, subresSize, &bpl,
nullptr,
nullptr);
3200 const quint32 copyBytes =
qMin(bpl, requiredBytesPerLine);
3202 const char *imgPtr =
data.constData();
3203 for (
int y = 0,
h = subresSize.
height();
y <
h; ++
y)
3204 memcpy(stagingAlloc.p +
y * requiredBytesPerLine, imgPtr +
y * bpl, copyBytes);
3207 if (ownStagingArea.has_value())
3208 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3212 cbD->cmdList->CopyTextureRegion(&
dst,
3215 is3D ? UINT(
layer) : 0u,
3219 if (ownStagingArea.has_value())
3220 ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
3226 QD3D12Texture *srcD =
QRHI_RES(QD3D12Texture, u.src);
3227 QD3D12Texture *dstD =
QRHI_RES(QD3D12Texture, u.dst);
3230 QD3D12Resource *srcRes = resourcePool.lookupRef(srcD->handle);
3231 QD3D12Resource *dstRes = resourcePool.lookupRef(dstD->handle);
3232 if (!srcRes || !dstRes)
3235 barrierGen.addTransitionBarrier(srcD->handle, D3D12_RESOURCE_STATE_COPY_SOURCE);
3236 barrierGen.addTransitionBarrier(dstD->handle, D3D12_RESOURCE_STATE_COPY_DEST);
3237 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3239 const UINT srcSubresource = calcSubresource(UINT(u.desc.sourceLevel()),
3240 srcIs3D ? 0u : UINT(u.
desc.sourceLayer()),
3241 srcD->mipLevelCount);
3242 const UINT dstSubresource = calcSubresource(UINT(u.desc.destinationLevel()),
3243 dstIs3D ? 0u : UINT(u.
desc.destinationLayer()),
3244 dstD->mipLevelCount);
3245 const QPoint dp = u.desc.destinationTopLeft();
3246 const QSize mipSize =
q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
3247 const QSize copySize = u.desc.pixelSize().
isEmpty() ? mipSize : u.desc.pixelSize();
3248 const QPoint sp = u.desc.sourceTopLeft();
3251 srcBox.left = UINT(
sp.x());
3252 srcBox.top = UINT(
sp.y());
3253 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
3255 srcBox.right = srcBox.left + UINT(copySize.
width());
3256 srcBox.bottom = srcBox.top + UINT(copySize.
height());
3257 srcBox.back = srcBox.front + 1;
3259 D3D12_TEXTURE_COPY_LOCATION
src;
3260 src.pResource = srcRes->resource;
3261 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3262 src.SubresourceIndex = srcSubresource;
3263 D3D12_TEXTURE_COPY_LOCATION
dst;
3264 dst.pResource = dstRes->resource;
3265 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3266 dst.SubresourceIndex = dstSubresource;
3268 cbD->cmdList->CopyTextureRegion(&
dst,
3271 dstIs3D ? UINT(u.desc.destinationLayer()) : 0u,
3275 QD3D12Readback readback;
3276 readback.frameSlot = currentFrameSlot;
3277 readback.result = u.result;
3279 QD3D12ObjectHandle srcHandle;
3281 if (u.rb.texture()) {
3282 QD3D12Texture *texD =
QRHI_RES(QD3D12Texture, u.rb.texture());
3283 if (texD->sampleDesc.Count > 1) {
3284 qWarning(
"Multisample texture cannot be read back");
3288 readback.pixelSize =
q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
3289 readback.format = texD->m_format;
3290 srcHandle = texD->handle;
3293 readback.pixelSize = currentSwapChain->pixelSize;
3297 srcHandle = currentSwapChain->colorBuffers[currentSwapChain->currentBackBufferIndex];
3300 textureFormatInfo(readback.format,
3302 &readback.bytesPerLine,
3306 QD3D12Resource *srcRes = resourcePool.lookupRef(srcHandle);
3310 const UINT subresource = calcSubresource(UINT(u.rb.level()),
3311 is3D ? 0u : UINT(u.rb.
layer()),
3312 srcRes->
desc.MipLevels);
3313 D3D12_PLACED_SUBRESOURCE_FOOTPRINT
layout;
3316 UINT64 totalBytes = 0;
3317 dev->GetCopyableFootprints(&srcRes->desc, subresource, 1, 0,
3318 &
layout,
nullptr,
nullptr, &totalBytes);
3319 readback.stagingRowPitch =
layout.Footprint.RowPitch;
3321 const quint32 allocSize = aligned<quint32>(totalBytes, QD3D12StagingArea::ALIGNMENT);
3322 if (!readback.staging.create(
this, allocSize, D3D12_HEAP_TYPE_READBACK)) {
3323 if (u.result->completed)
3324 u.result->completed();
3327 QD3D12StagingArea::Allocation stagingAlloc = readback.staging.get(totalBytes);
3328 if (!stagingAlloc.isValid()) {
3329 readback.staging.destroy();
3330 if (u.result->completed)
3331 u.result->completed();
3334 Q_ASSERT(stagingAlloc.bufferOffset == 0);
3336 barrierGen.addTransitionBarrier(srcHandle, D3D12_RESOURCE_STATE_COPY_SOURCE);
3337 barrierGen.enqueueBufferedTransitionBarriers(cbD);
3339 D3D12_TEXTURE_COPY_LOCATION
dst;
3340 dst.pResource = stagingAlloc.buffer;
3341 dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
3342 dst.PlacedFootprint.Offset = 0;
3343 dst.PlacedFootprint.Footprint =
layout.Footprint;
3345 D3D12_TEXTURE_COPY_LOCATION
src;
3346 src.pResource = srcRes->resource;
3347 src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
3348 src.SubresourceIndex = subresource;
3350 D3D12_BOX srcBox = {};
3352 srcBox.front = UINT(u.rb.layer());
3353 srcBox.back = srcBox.front + 1;
3354 srcBox.right = readback.pixelSize.width();
3355 srcBox.bottom = readback.pixelSize.height();
3357 cbD->cmdList->CopyTextureRegion(&
dst, 0, 0, 0, &
src, is3D ? &srcBox :
nullptr);
3358 activeReadbacks.append(readback);
3360 QD3D12Texture *texD =
QRHI_RES(QD3D12Texture, u.dst);
3362 mipmapGen.generate(cbD, texD->handle);
3369void QRhiD3D12::finishActiveReadbacks(
bool forced)
3373 for (
int i = activeReadbacks.size() - 1;
i >= 0; --
i) {
3374 QD3D12Readback &readback(activeReadbacks[
i]);
3375 if (forced || currentFrameSlot == readback.frameSlot || readback.frameSlot < 0) {
3376 readback.result->format = readback.format;
3377 readback.result->pixelSize = readback.pixelSize;
3378 readback.result->data.resize(
int(readback.byteSize));
3381 quint8 *dstPtr =
reinterpret_cast<quint8 *
>(readback.result->data.data());
3382 const quint8 *srcPtr = readback.staging.mem.p;
3383 const quint32 lineSize =
qMin(readback.bytesPerLine, readback.stagingRowPitch);
3384 for (
int y = 0,
h = readback.pixelSize.height();
y <
h; ++
y)
3385 memcpy(dstPtr +
y * readback.bytesPerLine, srcPtr +
y * readback.stagingRowPitch, lineSize);
3387 memcpy(readback.result->data.data(), readback.staging.mem.p, readback.byteSize);
3390 readback.staging.destroy();
3392 if (readback.result->completed)
3393 completedCallbacks.append(readback.result->completed);
3395 activeReadbacks.removeLast();
3399 for (
auto f : completedCallbacks)
3403bool QRhiD3D12::ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *
h,
3404 D3D12_DESCRIPTOR_HEAP_TYPE
type,
3406 quint32 neededDescriptorCount,
3414 if (
h->perFrameHeapSlice[frameSlot].remainingCapacity() < neededDescriptorCount) {
3415 const quint32 newPerFrameSize =
qMax(
h->perFrameHeapSlice[frameSlot].capacity * 2,
3416 neededDescriptorCount);
3417 QD3D12ShaderVisibleDescriptorHeap newHeap;
3418 if (!newHeap.create(dev,
type, newPerFrameSize)) {
3419 qWarning(
"Could not create new shader-visible descriptor heap");
3422 h->destroyWithDeferredRelease(&releaseQueue);
3429void QRhiD3D12::bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD)
3431 ID3D12DescriptorHeap *heaps[] = {
3432 shaderVisibleCbvSrvUavHeap.heap.heap,
3433 samplerMgr.shaderVisibleSamplerHeap.heap.heap
3435 cbD->cmdList->SetDescriptorHeaps(2, heaps);
3443QD3D12Buffer::~QD3D12Buffer()
3448void QD3D12Buffer::destroy()
3462 for (
int i = 0;
i < QD3D12_FRAMES_IN_FLIGHT; ++
i) {
3464 rhiD->releaseQueue.deferredReleaseResource(handles[
i]);
3466 pendingHostWrites[
i].clear();
3470 rhiD->unregisterResource(
this);
3473bool QD3D12Buffer::create()
3475 if (!handles[0].
isNull())
3479 qWarning(
"UniformBuffer must always be Dynamic");
3484 qWarning(
"StorageBuffer cannot be combined with Dynamic");
3488 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
3491 UINT resourceFlags = D3D12_RESOURCE_FLAG_NONE;
3493 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
3497 for (
int i = 0;
i < QD3D12_FRAMES_IN_FLIGHT; ++
i) {
3498 if (
i == 0 || m_type == Dynamic) {
3499 D3D12_RESOURCE_DESC resourceDesc = {};
3500 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
3501 resourceDesc.Width = roundedSize;
3502 resourceDesc.Height = 1;
3503 resourceDesc.DepthOrArraySize = 1;
3504 resourceDesc.MipLevels = 1;
3505 resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
3506 resourceDesc.SampleDesc = { 1, 0 };
3507 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
3508 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
3509 ID3D12Resource *resource =
nullptr;
3512 D3D12_HEAP_TYPE heapType = m_type == Dynamic
3513 ? D3D12_HEAP_TYPE_UPLOAD
3514 : D3D12_HEAP_TYPE_DEFAULT;
3515 D3D12_RESOURCE_STATES resourceState = m_type == Dynamic
3516 ? D3D12_RESOURCE_STATE_GENERIC_READ
3517 : D3D12_RESOURCE_STATE_COMMON;
3518 hr = rhiD->vma.createResource(heapType,
3524 reinterpret_cast<void **
>(&resource));
3527 if (!m_objectName.isEmpty()) {
3529 if (m_type == Dynamic) {
3533 resource->SetName(
reinterpret_cast<LPCWSTR
>(decoratedName.
utf16()));
3535 void *cpuMemPtr =
nullptr;
3536 if (m_type == Dynamic) {
3538 hr = resource->Map(0,
nullptr, &cpuMemPtr);
3540 qWarning(
"Map() failed to dynamic buffer");
3541 resource->Release();
3547 handles[
i] = QD3D12Resource::addToPool(&rhiD->resourcePool,
3555 qWarning(
"Failed to create buffer: '%s' Type was %d, size was %u, using D3D12MA was %d.",
3556 qPrintable(QSystemError::windowsComString(hr)),
3559 int(rhiD->vma.isUsingD3D12MA()));
3563 rhiD->registerResource(
this);
3570 Q_ASSERT(
sizeof(
b.objects) /
sizeof(
b.objects[0]) >=
size_t(QD3D12_FRAMES_IN_FLIGHT));
3572 if (m_type == Dynamic) {
3573 for (
int i = 0;
i < QD3D12_FRAMES_IN_FLIGHT; ++
i) {
3574 executeHostWritesForFrameSlot(
i);
3575 if (QD3D12Resource *
res = rhiD->resourcePool.lookupRef(handles[
i]))
3576 b.objects[
i] =
res->resource;
3578 b.objects[
i] =
nullptr;
3580 b.slotCount = QD3D12_FRAMES_IN_FLIGHT;
3583 if (QD3D12Resource *
res = rhiD->resourcePool.lookupRef(handles[0]))
3584 b.objects[0] =
res->resource;
3586 b.objects[0] =
nullptr;
3591char *QD3D12Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
3602 if (QD3D12Resource *
res = rhiD->resourcePool.lookupRef(handles[rhiD->currentFrameSlot]))
3603 return static_cast<char *
>(
res->cpuMapPtr);
3608void QD3D12Buffer::endFullDynamicBufferUpdateForCurrentFrame()
3613void QD3D12Buffer::executeHostWritesForFrameSlot(
int frameSlot)
3615 if (pendingHostWrites[frameSlot].isEmpty())
3620 if (QD3D12Resource *
res = rhiD->resourcePool.lookupRef(handles[frameSlot])) {
3622 for (
const QD3D12Buffer::HostWrite &u :
std::as_const(pendingHostWrites[frameSlot]))
3625 pendingHostWrites[frameSlot].clear();
3633 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
3635 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
3637 return DXGI_FORMAT_R8_UNORM;
3639 return DXGI_FORMAT_R8G8_UNORM;
3641 return DXGI_FORMAT_R16_UNORM;
3643 return DXGI_FORMAT_R16G16_UNORM;
3645 return DXGI_FORMAT_R8_UNORM;
3648 return DXGI_FORMAT_R16G16B16A16_FLOAT;
3650 return DXGI_FORMAT_R32G32B32A32_FLOAT;
3652 return DXGI_FORMAT_R16_FLOAT;
3654 return DXGI_FORMAT_R32_FLOAT;
3657 return DXGI_FORMAT_R10G10B10A2_UNORM;
3660 return DXGI_FORMAT_R16_TYPELESS;
3662 return DXGI_FORMAT_R24G8_TYPELESS;
3664 return DXGI_FORMAT_R24G8_TYPELESS;
3666 return DXGI_FORMAT_R32_TYPELESS;
3669 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
3671 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
3673 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
3675 return DXGI_FORMAT_BC4_UNORM;
3677 return DXGI_FORMAT_BC5_UNORM;
3679 return DXGI_FORMAT_BC6H_UF16;
3681 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
3686 qWarning(
"QRhiD3D12 does not support ETC2 textures");
3687 return DXGI_FORMAT_R8G8B8A8_UNORM;
3703 qWarning(
"QRhiD3D12 does not support ASTC textures");
3704 return DXGI_FORMAT_R8G8B8A8_UNORM;
3709 return DXGI_FORMAT_R8G8B8A8_UNORM;
3714 const QSize &pixelSize,
3722QD3D12RenderBuffer::~QD3D12RenderBuffer()
3727void QD3D12RenderBuffer::destroy()
3735 rhiD->releaseQueue.deferredReleaseResourceWithViews(
handle, &rhiD->rtvPool, rtv, 1);
3736 else if (dsv.isValid())
3737 rhiD->releaseQueue.deferredReleaseResourceWithViews(
handle, &rhiD->dsvPool, dsv, 1);
3745 rhiD->unregisterResource(
this);
3748bool QD3D12RenderBuffer::create()
3753 if (m_pixelSize.isEmpty())
3762 sampleDesc = rhiD->effectiveSampleCount(m_sampleCount, dxgiFormat);
3763 D3D12_RESOURCE_DESC resourceDesc = {};
3764 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
3765 resourceDesc.Width = UINT64(m_pixelSize.width());
3766 resourceDesc.Height = UINT(m_pixelSize.height());
3767 resourceDesc.DepthOrArraySize = 1;
3768 resourceDesc.MipLevels = 1;
3769 resourceDesc.Format = dxgiFormat;
3770 resourceDesc.SampleDesc = sampleDesc;
3771 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
3772 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
3773 D3D12_CLEAR_VALUE clearValue = {};
3774 clearValue.Format = dxgiFormat;
3776 ID3D12Resource *resource =
nullptr;
3778 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
3780 D3D12_RESOURCE_STATE_RENDER_TARGET,
3783 __uuidof(ID3D12Resource),
3784 reinterpret_cast<void **
>(&resource));
3786 qWarning(
"Failed to create color buffer: %s",
qPrintable(QSystemError::windowsComString(hr)));
3789 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET,
allocation);
3790 rtv = rhiD->rtvPool.allocate(1);
3793 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
3794 rtvDesc.Format = dxgiFormat;
3795 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
3796 : D3D12_RTV_DIMENSION_TEXTURE2D;
3797 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, rtv.cpuHandle);
3802 dxgiFormat = DS_FORMAT;
3803 sampleDesc = rhiD->effectiveSampleCount(m_sampleCount, dxgiFormat);
3804 D3D12_RESOURCE_DESC resourceDesc = {};
3805 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
3806 resourceDesc.Width = UINT64(m_pixelSize.width());
3807 resourceDesc.Height = UINT(m_pixelSize.height());
3808 resourceDesc.DepthOrArraySize = 1;
3809 resourceDesc.MipLevels = 1;
3810 resourceDesc.Format = dxgiFormat;
3811 resourceDesc.SampleDesc = sampleDesc;
3812 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
3813 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
3814 if (m_flags.testFlag(UsedWithSwapChainOnly))
3815 resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
3816 D3D12_CLEAR_VALUE clearValue = {};
3817 clearValue.Format = dxgiFormat;
3818 clearValue.DepthStencil.Depth = 1.0f;
3819 clearValue.DepthStencil.Stencil = 0;
3820 ID3D12Resource *resource =
nullptr;
3822 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
3824 D3D12_RESOURCE_STATE_DEPTH_WRITE,
3827 __uuidof(ID3D12Resource),
3828 reinterpret_cast<void **
>(&resource));
3830 qWarning(
"Failed to create depth-stencil buffer: %s",
qPrintable(QSystemError::windowsComString(hr)));
3833 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_DEPTH_WRITE,
allocation);
3834 dsv = rhiD->dsvPool.allocate(1);
3837 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
3838 dsvDesc.Format = dxgiFormat;
3839 dsvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
3840 : D3D12_DSV_DIMENSION_TEXTURE2D;
3841 rhiD->dev->CreateDepthStencilView(resource, &dsvDesc, dsv.cpuHandle);
3846 if (!m_objectName.isEmpty()) {
3847 if (QD3D12Resource *
res = rhiD->resourcePool.lookupRef(
handle)) {
3849 res->resource->SetName(
reinterpret_cast<LPCWSTR
>(
name.utf16()));
3854 rhiD->registerResource(
this);
3861 return m_backingFormatHint;
3872QD3D12Texture::~QD3D12Texture()
3877void QD3D12Texture::destroy()
3884 rhiD->releaseQueue.deferredReleaseResourceWithViews(
handle, &rhiD->cbvSrvUavPool, srv, 1);
3890 rhiD->unregisterResource(
this);
3897 return DXGI_FORMAT_R16_FLOAT;
3899 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
3901 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
3903 return DXGI_FORMAT_R32_FLOAT;
3907 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32_FLOAT);
3915 return DXGI_FORMAT_D16_UNORM;
3917 return DXGI_FORMAT_D24_UNORM_S8_UINT;
3919 return DXGI_FORMAT_D24_UNORM_S8_UINT;
3921 return DXGI_FORMAT_D32_FLOAT;
3925 Q_UNREACHABLE_RETURN(DXGI_FORMAT_D32_FLOAT);
3941bool QD3D12Texture::prepareCreate(
QSize *adjustedSize)
3947 const bool isCube = m_flags.testFlag(CubeMap);
3948 const bool is3D = m_flags.testFlag(ThreeDimensional);
3949 const bool isArray = m_flags.testFlag(TextureArray);
3950 const bool hasMipMaps = m_flags.testFlag(MipMapped);
3951 const bool is1D = m_flags.testFlag(OneDimensional);
3954 : (m_pixelSize.isEmpty() ?
QSize(1, 1) : m_pixelSize);
3958 mipLevelCount =
uint(hasMipMaps ? rhiD->q->mipLevelsForSize(
size) : 1);
3959 sampleDesc = rhiD->effectiveSampleCount(m_sampleCount, dxgiFormat);
3960 if (sampleDesc.Count > 1) {
3962 qWarning(
"Cubemap texture cannot be multisample");
3966 qWarning(
"3D texture cannot be multisample");
3970 qWarning(
"Multisample texture cannot have mipmaps");
3974 if (isDepth && hasMipMaps) {
3975 qWarning(
"Depth texture cannot have mipmaps");
3978 if (isCube && is3D) {
3979 qWarning(
"Texture cannot be both cube and 3D");
3982 if (isArray && is3D) {
3983 qWarning(
"Texture cannot be both array and 3D");
3986 if (isCube && is1D) {
3987 qWarning(
"Texture cannot be both cube and 1D");
3991 qWarning(
"Texture cannot be both 1D and 3D");
3994 if (m_depth > 1 && !is3D) {
3995 qWarning(
"Texture cannot have a depth of %d when it is not 3D", m_depth);
3998 if (m_arraySize > 0 && !isArray) {
3999 qWarning(
"Texture cannot have an array size of %d when it is not an array", m_arraySize);
4002 if (m_arraySize < 1 && isArray) {
4003 qWarning(
"Texture is an array but array size is %d", m_arraySize);
4008 *adjustedSize =
size;
4013bool QD3D12Texture::finishCreate()
4017 const bool isCube = m_flags.testFlag(CubeMap);
4018 const bool is3D = m_flags.testFlag(ThreeDimensional);
4019 const bool isArray = m_flags.testFlag(TextureArray);
4020 const bool is1D = m_flags.testFlag(OneDimensional);
4022 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
4024 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
4027 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
4028 srvDesc.TextureCube.MipLevels = mipLevelCount;
4032 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
4033 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
4034 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4035 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4036 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
4038 srvDesc.Texture1DArray.FirstArraySlice = 0;
4039 srvDesc.Texture1DArray.ArraySize = UINT(
qMax(0, m_arraySize));
4042 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
4043 srvDesc.Texture1D.MipLevels = mipLevelCount;
4045 }
else if (isArray) {
4046 if (sampleDesc.Count > 1) {
4047 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
4048 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4049 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
4050 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
4052 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
4053 srvDesc.Texture2DMSArray.ArraySize = UINT(
qMax(0, m_arraySize));
4056 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
4057 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
4058 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
4059 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
4060 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
4062 srvDesc.Texture2DArray.FirstArraySlice = 0;
4063 srvDesc.Texture2DArray.ArraySize = UINT(
qMax(0, m_arraySize));
4067 if (sampleDesc.Count > 1) {
4068 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
4070 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
4071 srvDesc.Texture3D.MipLevels = mipLevelCount;
4073 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
4074 srvDesc.Texture2D.MipLevels = mipLevelCount;
4079 srv = rhiD->cbvSrvUavPool.allocate(1);
4083 if (QD3D12Resource *
res = rhiD->resourcePool.lookupRef(
handle)) {
4084 rhiD->dev->CreateShaderResourceView(
res->resource, &srvDesc, srv.cpuHandle);
4085 if (!m_objectName.isEmpty()) {
4087 res->resource->SetName(
reinterpret_cast<LPCWSTR
>(
name.utf16()));
4097bool QD3D12Texture::create()
4100 if (!prepareCreate(&
size))
4104 const bool isCube = m_flags.testFlag(CubeMap);
4105 const bool is3D = m_flags.testFlag(ThreeDimensional);
4106 const bool isArray = m_flags.testFlag(TextureArray);
4107 const bool is1D = m_flags.testFlag(OneDimensional);
4111 bool needsOptimizedClearValueSpecified =
false;
4112 UINT resourceFlags = 0;
4113 if (m_flags.testFlag(RenderTarget)) {
4115 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
4117 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
4118 needsOptimizedClearValueSpecified =
true;
4120 if (m_flags.testFlag(UsedWithGenerateMips)) {
4122 qWarning(
"Depth texture cannot have mipmaps generated");
4125 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4127 if (m_flags.testFlag(UsedWithLoadStore))
4128 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
4130 D3D12_RESOURCE_DESC resourceDesc = {};
4131 resourceDesc.Dimension = is1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
4132 : (is3D ? D3D12_RESOURCE_DIMENSION_TEXTURE3D
4133 : D3D12_RESOURCE_DIMENSION_TEXTURE2D);
4134 resourceDesc.Width = UINT64(
size.width());
4135 resourceDesc.Height = UINT(
size.height());
4136 resourceDesc.DepthOrArraySize = isCube ? 6
4137 : (isArray ? UINT(
qMax(0, m_arraySize))
4138 : (is3D ?
qMax(1, m_depth)
4140 resourceDesc.MipLevels = mipLevelCount;
4141 resourceDesc.Format = dxgiFormat;
4142 resourceDesc.SampleDesc = sampleDesc;
4143 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
4144 resourceDesc.Flags = D3D12_RESOURCE_FLAGS(resourceFlags);
4145 D3D12_CLEAR_VALUE clearValue = {};
4146 clearValue.Format = dxgiFormat;
4149 clearValue.DepthStencil.Depth = 1.0f;
4150 clearValue.DepthStencil.Stencil = 0;
4152 ID3D12Resource *resource =
nullptr;
4154 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
4156 D3D12_RESOURCE_STATE_COMMON,
4157 needsOptimizedClearValueSpecified ? &clearValue :
nullptr,
4159 __uuidof(ID3D12Resource),
4160 reinterpret_cast<
void **>(&resource));
4162 qWarning(
"Failed to create texture: '%s'"
4163 " Dim was %d Size was %ux%u Depth/ArraySize was %u MipLevels was %u Format was %d Sample count was %d",
4164 qPrintable(QSystemError::windowsComString(hr)),
4165 int(resourceDesc.Dimension),
4166 uint(resourceDesc.Width),
4167 uint(resourceDesc.Height),
4168 uint(resourceDesc.DepthOrArraySize),
4169 uint(resourceDesc.MipLevels),
4170 int(resourceDesc.Format),
4171 int(resourceDesc.SampleDesc.Count));
4175 handle = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_COMMON,
allocation);
4177 if (!finishCreate())
4180 rhiD->registerResource(
this);
4189 if (!prepareCreate())
4192 ID3D12Resource *resource =
reinterpret_cast<ID3D12Resource *
>(
src.object);
4193 D3D12_RESOURCE_STATES
state = D3D12_RESOURCE_STATES(
src.layout);
4196 handle = QD3D12Resource::addNonOwningToPool(&rhiD->resourcePool, resource,
state);
4198 if (!finishCreate())
4201 rhiD->registerResource(
this);
4208 if (QD3D12Resource *
res = rhiD->resourcePool.lookupRef(
handle))
4214void QD3D12Texture::setNativeLayout(
int layout)
4217 if (QD3D12Resource *
res = rhiD->resourcePool.lookupRef(
handle))
4218 res->state = D3D12_RESOURCE_STATES(
layout);
4221QD3D12Sampler::QD3D12Sampler(
QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
4222 AddressMode u, AddressMode
v, AddressMode
w)
4223 :
QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u,
v,
w)
4227QD3D12Sampler::~QD3D12Sampler()
4232void QD3D12Sampler::destroy()
4234 shaderVisibleDescriptor = {};
4238 rhiD->unregisterResource(
this);
4246 return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
4248 return D3D12_FILTER_MIN_MAG_MIP_POINT;
4251 return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
4253 return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
4258 return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
4260 return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
4263 return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
4265 return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
4268 Q_UNREACHABLE_RETURN(D3D12_FILTER_MIN_MAG_MIP_LINEAR);
4275 return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
4277 return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
4279 return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
4281 Q_UNREACHABLE_RETURN(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
4288 return D3D12_COMPARISON_FUNC_NEVER;
4290 return D3D12_COMPARISON_FUNC_LESS;
4292 return D3D12_COMPARISON_FUNC_EQUAL;
4294 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
4296 return D3D12_COMPARISON_FUNC_GREATER;
4298 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
4300 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
4302 return D3D12_COMPARISON_FUNC_ALWAYS;
4304 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_NEVER);
4307bool QD3D12Sampler::create()
4311 if (m_compareOp !=
Never)
4312 desc.Filter = D3D12_FILTER(
desc.Filter | 0x80);
4316 desc.MaxAnisotropy = 1.0f;
4318 desc.MaxLOD = m_mipmapMode ==
None ? 0.0f : 10000.0f;
4321 rhiD->registerResource(
this,
false);
4325QD3D12Descriptor QD3D12Sampler::lookupOrCreateShaderVisibleDescriptor()
4327 if (!shaderVisibleDescriptor.isValid()) {
4329 shaderVisibleDescriptor = rhiD->samplerMgr.getShaderVisibleDescriptor(
desc);
4331 return shaderVisibleDescriptor;
4342QD3D12TextureRenderTarget::~QD3D12TextureRenderTarget()
4347void QD3D12TextureRenderTarget::destroy()
4349 if (!rtv[0].isValid() && !dsv.isValid())
4353 if (dsv.isValid()) {
4354 if (ownsDsv && rhiD)
4355 rhiD->releaseQueue.deferredReleaseViews(&rhiD->dsvPool, dsv, 1);
4359 for (
int i = 0;
i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++
i) {
4360 if (rtv[
i].isValid()) {
4361 if (ownsRtv[
i] && rhiD)
4362 rhiD->releaseQueue.deferredReleaseViews(&rhiD->rtvPool, rtv[
i], 1);
4368 rhiD->unregisterResource(
this);
4375 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
4377 rpD->colorAttachmentCount = 0;
4378 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments();
it != itEnd; ++
it) {
4379 QD3D12Texture *texD =
QRHI_RES(QD3D12Texture,
it->texture());
4380 QD3D12RenderBuffer *rbD =
QRHI_RES(QD3D12RenderBuffer,
it->renderBuffer());
4382 rpD->colorFormat[rpD->colorAttachmentCount] = texD->dxgiFormat;
4384 rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
4385 rpD->colorAttachmentCount += 1;
4388 rpD->hasDepthStencil =
false;
4389 if (m_desc.depthStencilBuffer()) {
4390 rpD->hasDepthStencil =
true;
4391 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
4392 }
else if (m_desc.depthTexture()) {
4393 QD3D12Texture *depthTexD =
QRHI_RES(QD3D12Texture, m_desc.depthTexture());
4394 rpD->hasDepthStencil =
true;
4398 rpD->updateSerializedFormat();
4401 rhiD->registerResource(rpD);
4405bool QD3D12TextureRenderTarget::create()
4407 if (rtv[0].isValid() || dsv.isValid())
4411 Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
4412 Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
4413 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
4414 d.colorAttCount = 0;
4417 for (
auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments();
it != itEnd; ++
it, ++attIndex) {
4418 d.colorAttCount += 1;
4425 QD3D12Resource *
res = rhiD->resourcePool.lookupRef(texD->handle);
4427 qWarning(
"Could not look up texture handle for render target");
4430 const bool isMultiView =
it->multiViewCount() >= 2;
4431 UINT layerCount = isMultiView ? UINT(
it->multiViewCount()) : 1;
4432 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
4435 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
4436 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
4437 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
4438 rtvDesc.Texture2DArray.ArraySize = layerCount;
4441 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
4442 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
4443 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
4444 rtvDesc.Texture1DArray.ArraySize = layerCount;
4446 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
4447 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
4450 if (texD->sampleDesc.Count > 1) {
4451 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
4452 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
4453 rtvDesc.Texture2DMSArray.ArraySize = layerCount;
4455 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
4456 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
4457 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
4458 rtvDesc.Texture2DArray.ArraySize = layerCount;
4461 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
4462 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
4463 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
4464 rtvDesc.Texture3D.WSize = layerCount;
4466 if (texD->sampleDesc.Count > 1) {
4467 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
4469 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
4470 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
4473 rtv[attIndex] = rhiD->rtvPool.allocate(1);
4474 if (!rtv[attIndex].isValid()) {
4475 qWarning(
"Failed to allocate RTV for texture render target");
4478 rhiD->dev->CreateRenderTargetView(
res->resource, &rtvDesc, rtv[attIndex].cpuHandle);
4479 ownsRtv[attIndex] =
true;
4480 if (attIndex == 0) {
4481 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
4482 d.sampleCount = int(texD->sampleDesc.Count);
4485 QD3D12RenderBuffer *rbD =
QRHI_RES(QD3D12RenderBuffer, rb);
4486 ownsRtv[attIndex] =
false;
4487 rtv[attIndex] = rbD->rtv;
4488 if (attIndex == 0) {
4489 d.pixelSize = rbD->pixelSize();
4490 d.sampleCount = int(rbD->sampleDesc.Count);
4497 if (hasDepthStencil) {
4498 if (m_desc.depthTexture()) {
4500 QD3D12Texture *depthTexD =
QRHI_RES(QD3D12Texture, m_desc.depthTexture());
4501 QD3D12Resource *
res = rhiD->resourcePool.lookupRef(depthTexD->handle);
4503 qWarning(
"Could not look up depth texture handle");
4506 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
4508 dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
4509 : D3D12_DSV_DIMENSION_TEXTURE2D;
4511 if (depthTexD->sampleDesc.Count > 1) {
4512 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
4513 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
4514 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
4515 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
4517 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
4518 dsvDesc.Texture2DMSArray.ArraySize = UINT(
qMax(0, depthTexD->arraySize()));
4521 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
4522 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
4523 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
4524 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
4526 dsvDesc.Texture2DArray.FirstArraySlice = 0;
4527 dsvDesc.Texture2DArray.ArraySize = UINT(
qMax(0, depthTexD->arraySize()));
4531 dsv = rhiD->dsvPool.allocate(1);
4532 if (!dsv.isValid()) {
4533 qWarning(
"Failed to allocate DSV for texture render target");
4536 rhiD->dev->CreateDepthStencilView(
res->resource, &dsvDesc, dsv.cpuHandle);
4537 if (
d.colorAttCount == 0) {
4538 d.pixelSize = depthTexD->pixelSize();
4539 d.sampleCount = int(depthTexD->sampleDesc.Count);
4543 QD3D12RenderBuffer *depthRbD =
QRHI_RES(QD3D12RenderBuffer, m_desc.depthStencilBuffer());
4544 dsv = depthRbD->dsv;
4545 if (
d.colorAttCount == 0) {
4546 d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
4547 d.sampleCount = int(depthRbD->sampleDesc.Count);
4555 D3D12_CPU_DESCRIPTOR_HANDLE nullDescHandle = { 0 };
4556 for (
int i = 0;
i < QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS; ++
i)
4557 d.rtv[
i] =
i <
d.colorAttCount ? rtv[
i].cpuHandle : nullDescHandle;
4558 d.dsv = dsv.cpuHandle;
4559 d.rp =
QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
4561 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D12Texture, QD3D12RenderBuffer>(m_desc, &
d.currentResIdList);
4563 rhiD->registerResource(
this);
4567QSize QD3D12TextureRenderTarget::pixelSize()
const
4569 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D12Texture, QD3D12RenderBuffer>(m_desc,
d.currentResIdList))
4570 const_cast<QD3D12TextureRenderTarget *
>(
this)->
create();
4575float QD3D12TextureRenderTarget::devicePixelRatio()
const
4580int QD3D12TextureRenderTarget::sampleCount()
const
4582 return d.sampleCount;
4590QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
4595void QD3D12ShaderResourceBindings::destroy()
4597 sortedBindings.clear();
4601 rhiD->unregisterResource(
this);
4604bool QD3D12ShaderResourceBindings::create()
4606 if (!sortedBindings.isEmpty())
4610 if (!rhiD->sanityCheckShaderResourceBindings(
this))
4613 rhiD->updateLayoutDesc(
this);
4615 std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
4618 hasDynamicOffset =
false;
4622 hasDynamicOffset =
true;
4636 rhiD->registerResource(
this,
false);
4640void QD3D12ShaderResourceBindings::updateResources(UpdateFlags
flags)
4642 sortedBindings.clear();
4643 std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
4644 if (!
flags.testFlag(BindingsAreSorted))
4655void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage
s,
4660 D3D12_ROOT_PARAMETER1 rootParam = {};
4661 rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
4662 rootParam.ShaderVisibility = qd3d12_stageToVisibility(
s);
4663 rootParam.Descriptor.ShaderRegister = shaderRegister;
4664 visitorData.cbParams[
s].append(rootParam);
4667void QD3D12ShaderResourceBindings::visitTexture(QD3D12Stage
s,
4671 D3D12_DESCRIPTOR_RANGE1
range = {};
4672 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
4673 range.NumDescriptors = 1;
4674 range.BaseShaderRegister = shaderRegister;
4675 range.OffsetInDescriptorsFromTableStart = visitorData.currentSrvRangeOffset[
s];
4676 visitorData.currentSrvRangeOffset[
s] += 1;
4677 visitorData.srvRanges[
s].append(
range);
4678 if (visitorData.srvRanges[
s].count() == 1) {
4679 visitorData.srvTables[
s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
4680 visitorData.srvTables[
s].ShaderVisibility = qd3d12_stageToVisibility(
s);
4684void QD3D12ShaderResourceBindings::visitSampler(QD3D12Stage
s,
4691 int &rangeStoreIdx(visitorData.samplerRangeHeads[
s]);
4692 if (rangeStoreIdx == 16) {
4693 qWarning(
"Sampler count in QD3D12Stage %d exceeds the limit of 16, this is disallowed by QRhi",
s);
4696 D3D12_DESCRIPTOR_RANGE1
range = {};
4697 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
4698 range.NumDescriptors = 1;
4699 range.BaseShaderRegister = shaderRegister;
4700 visitorData.samplerRanges[
s][rangeStoreIdx] =
range;
4701 D3D12_ROOT_PARAMETER1
param = {};
4702 param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
4703 param.ShaderVisibility = qd3d12_stageToVisibility(
s);
4704 param.DescriptorTable.NumDescriptorRanges = 1;
4705 param.DescriptorTable.pDescriptorRanges = &visitorData.samplerRanges[
s][rangeStoreIdx];
4707 visitorData.samplerTables[
s].append(
param);
4710void QD3D12ShaderResourceBindings::visitStorageBuffer(QD3D12Stage
s,
4712 QD3D12ShaderResourceVisitor::StorageOp,
4715 D3D12_DESCRIPTOR_RANGE1
range = {};
4716 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
4717 range.NumDescriptors = 1;
4718 range.BaseShaderRegister = shaderRegister;
4719 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[
s];
4720 visitorData.currentUavRangeOffset[
s] += 1;
4721 visitorData.uavRanges[
s].append(
range);
4722 if (visitorData.uavRanges[
s].count() == 1) {
4723 visitorData.uavTables[
s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
4724 visitorData.uavTables[
s].ShaderVisibility = qd3d12_stageToVisibility(
s);
4728void QD3D12ShaderResourceBindings::visitStorageImage(QD3D12Stage
s,
4730 QD3D12ShaderResourceVisitor::StorageOp,
4733 D3D12_DESCRIPTOR_RANGE1
range = {};
4734 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
4735 range.NumDescriptors = 1;
4736 range.BaseShaderRegister = shaderRegister;
4737 range.OffsetInDescriptorsFromTableStart = visitorData.currentUavRangeOffset[
s];
4738 visitorData.currentUavRangeOffset[
s] += 1;
4739 visitorData.uavRanges[
s].append(
range);
4740 if (visitorData.uavRanges[
s].count() == 1) {
4741 visitorData.uavTables[
s].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
4742 visitorData.uavTables[
s].ShaderVisibility = qd3d12_stageToVisibility(
s);
4746QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(
const QD3D12ShaderStageData *stageData,
4763 QD3D12ShaderResourceVisitor visitor(
this, stageData, stageCount);
4767 using namespace std::placeholders;
4768 visitor.uniformBuffer = std::bind(&QD3D12ShaderResourceBindings::visitUniformBuffer,
this, _1, _2, _3, _4);
4769 visitor.texture = std::bind(&QD3D12ShaderResourceBindings::visitTexture,
this, _1, _2, _3);
4770 visitor.sampler = std::bind(&QD3D12ShaderResourceBindings::visitSampler,
this, _1, _2, _3);
4771 visitor.storageBuffer = std::bind(&QD3D12ShaderResourceBindings::visitStorageBuffer,
this, _1, _2, _3, _4);
4772 visitor.storageImage = std::bind(&QD3D12ShaderResourceBindings::visitStorageImage,
this, _1, _2, _3, _4);
4797 for (
int s = 0;
s < 6; ++
s) {
4798 if (!visitorData.cbParams[
s].isEmpty())
4799 rootParams.
append(visitorData.cbParams[
s].constData(), visitorData.cbParams[
s].count());
4801 for (
int s = 0;
s < 6; ++
s) {
4802 if (!visitorData.srvRanges[
s].isEmpty()) {
4803 visitorData.srvTables[
s].DescriptorTable.NumDescriptorRanges = visitorData.srvRanges[
s].count();
4804 visitorData.srvTables[
s].DescriptorTable.pDescriptorRanges = visitorData.srvRanges[
s].constData();
4805 rootParams.
append(visitorData.srvTables[
s]);
4808 for (
int s = 0;
s < 6; ++
s) {
4809 if (!visitorData.samplerTables[
s].isEmpty())
4810 rootParams.
append(visitorData.samplerTables[
s].constData(), visitorData.samplerTables[
s].count());
4812 for (
int s = 0;
s < 6; ++
s) {
4813 if (!visitorData.uavRanges[
s].isEmpty()) {
4814 visitorData.uavTables[
s].DescriptorTable.NumDescriptorRanges = visitorData.uavRanges[
s].count();
4815 visitorData.uavTables[
s].DescriptorTable.pDescriptorRanges = visitorData.uavRanges[
s].constData();
4816 rootParams.
append(visitorData.uavTables[
s]);
4820 D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsDesc = {};
4821 rsDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
4823 rsDesc.Desc_1_1.NumParameters = rootParams.
count();
4824 rsDesc.Desc_1_1.pParameters = rootParams.
constData();
4828 for (
int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
4829 if (stageData[stageIdx].valid && stageData[stageIdx].stage == VS)
4830 rsFlags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
4832 rsDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAGS(rsFlags);
4835 HRESULT hr = D3D12SerializeVersionedRootSignature(&rsDesc, &signature,
nullptr);
4837 qWarning(
"Failed to serialize root signature: %s",
qPrintable(QSystemError::windowsComString(hr)));
4840 ID3D12RootSignature *rootSig =
nullptr;
4841 hr = rhiD->dev->CreateRootSignature(0,
4844 __uuidof(ID3D12RootSignature),
4845 reinterpret_cast<void **
>(&rootSig));
4848 qWarning(
"Failed to create root signature: %s",
qPrintable(QSystemError::windowsComString(hr)));
4852 return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
4864static inline void makeHlslTargetString(
char target[7],
const char stage[3],
int version)
4866 const int smMajor = version / 10;
4867 const int smMinor = version % 10;
4871 target[3] =
'0' + smMajor;
4873 target[5] =
'0' + smMinor;
4877enum class HlslCompileFlag
4879 WithDebugInfo = 0x01
4886 qWarning(
"Unable to resolve function D3DCompile()");
4890 ID3DBlob *bytecode =
nullptr;
4891 ID3DBlob *errors =
nullptr;
4892 UINT d3dCompileFlags = 0;
4893 if (
flags &
int(HlslCompileFlag::WithDebugInfo))
4894 d3dCompileFlags |= D3DCOMPILE_DEBUG;
4897 nullptr,
nullptr,
nullptr,
4899 if (FAILED(hr) || !bytecode) {
4900 qWarning(
"HLSL shader compilation failed: 0x%x",
uint(hr));
4903 int(errors->GetBufferSize()));
4910 result.resize(
int(bytecode->GetBufferSize()));
4911 memcpy(
result.data(), bytecode->GetBufferPointer(),
size_t(
result.size()));
4912 bytecode->Release();
4916#ifdef QRHI_D3D12_HAS_DXC
4919#define DXC_CP_UTF8 65001
4922#ifndef DXC_ARG_DEBUG
4923#define DXC_ARG_DEBUG L"-Zi"
4928 static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
4929 IDxcCompiler *compiler = dxc.first;
4931 qWarning(
"Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
4932 "Bundling these are out of scope for Qt. Try https://github.com/microsoft/DirectXShaderCompiler/releases");
4935 IDxcLibrary *library = dxc.second;
4939 IDxcBlobEncoding *sourceBlob =
nullptr;
4945 qWarning(
"Failed to create source blob for dxc: 0x%x (%s)",
4947 qPrintable(QSystemError::windowsComString(hr)));
4956 if (
flags &
int(HlslCompileFlag::WithDebugInfo)) {
4958 argPtrs.
append(
reinterpret_cast<LPCWSTR
>(debugArg.
utf16()));
4961 IDxcOperationResult *
result =
nullptr;
4962 hr = compiler->Compile(sourceBlob,
4964 reinterpret_cast<LPCWSTR
>(entryPointStr.
utf16()),
4965 reinterpret_cast<LPCWSTR
>(targetStr.
utf16()),
4970 sourceBlob->Release();
4974 qWarning(
"HLSL shader compilation failed: 0x%x (%s)",
4976 qPrintable(QSystemError::windowsComString(hr)));
4978 IDxcBlobEncoding *errorsBlob =
nullptr;
4979 if (SUCCEEDED(
result->GetErrorBuffer(&errorsBlob))) {
4982 int(errorsBlob->GetBufferSize()));
4983 errorsBlob->Release();
4990 IDxcBlob *bytecode =
nullptr;
4991 if FAILED(
result->GetResult(&bytecode)) {
4992 qWarning(
"No result from IDxcCompiler: 0x%x (%s)",
4994 qPrintable(QSystemError::windowsComString(hr)));
4999 ba.
resize(
int(bytecode->GetBufferSize()));
5000 memcpy(
ba.
data(), bytecode->GetBufferPointer(),
size_t(
ba.
size()));
5001 bytecode->Release();
5014 const int shaderModelMax = 67;
5015 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5021 *usedShaderKey =
key;
5022 return intermediateBytecodeShader.
shader();
5029 for (
int sm = shaderModelMax; sm >= 50; --sm) {
5037 qWarning() <<
"No HLSL (shader model 6.7..5.0) code found in baked shader" <<
shader;
5042 *usedShaderKey =
key;
5045 switch (
shader.stage()) {
5047 makeHlslTargetString(
target,
"vs",
key.sourceVersion().version());
5050 makeHlslTargetString(
target,
"hs",
key.sourceVersion().version());
5053 makeHlslTargetString(
target,
"ds",
key.sourceVersion().version());
5056 makeHlslTargetString(
target,
"gs",
key.sourceVersion().version());
5059 makeHlslTargetString(
target,
"ps",
key.sourceVersion().version());
5062 makeHlslTargetString(
target,
"cs",
key.sourceVersion().version());
5066 if (
key.sourceVersion().version() >= 60) {
5067#ifdef QRHI_D3D12_HAS_DXC
5070 qWarning(
"Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
5071 "but the Qt build has no support for DXC. "
5072 "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
5083 f |= D3D12_COLOR_WRITE_ENABLE_RED;
5085 f |= D3D12_COLOR_WRITE_ENABLE_GREEN;
5087 f |= D3D12_COLOR_WRITE_ENABLE_BLUE;
5089 f |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
5103 return D3D12_BLEND_ZERO;
5105 return D3D12_BLEND_ONE;
5107 return rgb ? D3D12_BLEND_SRC_COLOR : D3D12_BLEND_SRC_ALPHA;
5109 return rgb ? D3D12_BLEND_INV_SRC_COLOR : D3D12_BLEND_INV_SRC_ALPHA;
5111 return rgb ? D3D12_BLEND_DEST_COLOR : D3D12_BLEND_DEST_ALPHA;
5113 return rgb ? D3D12_BLEND_INV_DEST_COLOR : D3D12_BLEND_INV_DEST_ALPHA;
5115 return D3D12_BLEND_SRC_ALPHA;
5117 return D3D12_BLEND_INV_SRC_ALPHA;
5119 return D3D12_BLEND_DEST_ALPHA;
5121 return D3D12_BLEND_INV_DEST_ALPHA;
5124 return D3D12_BLEND_BLEND_FACTOR;
5127 return D3D12_BLEND_INV_BLEND_FACTOR;
5129 return D3D12_BLEND_SRC_ALPHA_SAT;
5131 return rgb ? D3D12_BLEND_SRC1_COLOR : D3D12_BLEND_SRC1_ALPHA;
5133 return rgb ? D3D12_BLEND_INV_SRC1_COLOR : D3D12_BLEND_INV_SRC1_ALPHA;
5135 return D3D12_BLEND_SRC1_ALPHA;
5137 return D3D12_BLEND_INV_SRC1_ALPHA;
5139 Q_UNREACHABLE_RETURN(D3D12_BLEND_ZERO);
5146 return D3D12_BLEND_OP_ADD;
5148 return D3D12_BLEND_OP_SUBTRACT;
5150 return D3D12_BLEND_OP_REV_SUBTRACT;
5152 return D3D12_BLEND_OP_MIN;
5154 return D3D12_BLEND_OP_MAX;
5156 Q_UNREACHABLE_RETURN(D3D12_BLEND_OP_ADD);
5163 return D3D12_CULL_MODE_NONE;
5165 return D3D12_CULL_MODE_FRONT;
5167 return D3D12_CULL_MODE_BACK;
5169 Q_UNREACHABLE_RETURN(D3D12_CULL_MODE_NONE);
5176 return D3D12_FILL_MODE_SOLID;
5178 return D3D12_FILL_MODE_WIREFRAME;
5180 Q_UNREACHABLE_RETURN(D3D12_FILL_MODE_SOLID);
5187 return D3D12_COMPARISON_FUNC_NEVER;
5189 return D3D12_COMPARISON_FUNC_LESS;
5191 return D3D12_COMPARISON_FUNC_EQUAL;
5193 return D3D12_COMPARISON_FUNC_LESS_EQUAL;
5195 return D3D12_COMPARISON_FUNC_GREATER;
5197 return D3D12_COMPARISON_FUNC_NOT_EQUAL;
5199 return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
5201 return D3D12_COMPARISON_FUNC_ALWAYS;
5203 Q_UNREACHABLE_RETURN(D3D12_COMPARISON_FUNC_ALWAYS);
5210 return D3D12_STENCIL_OP_ZERO;
5212 return D3D12_STENCIL_OP_KEEP;
5214 return D3D12_STENCIL_OP_REPLACE;
5216 return D3D12_STENCIL_OP_INCR_SAT;
5218 return D3D12_STENCIL_OP_DECR_SAT;
5220 return D3D12_STENCIL_OP_INVERT;
5222 return D3D12_STENCIL_OP_INCR;
5224 return D3D12_STENCIL_OP_DECR;
5226 Q_UNREACHABLE_RETURN(D3D12_STENCIL_OP_KEEP);
5233 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
5235 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
5237 qWarning(
"Triangle fans are not supported with D3D");
5238 return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
5240 return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
5242 return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
5244 return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
5246 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
5247 return D3D_PRIMITIVE_TOPOLOGY(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
5249 Q_UNREACHABLE_RETURN(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
5258 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
5261 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
5263 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
5265 return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
5267 Q_UNREACHABLE_RETURN(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
5274 return DXGI_FORMAT_R32G32B32A32_FLOAT;
5276 return DXGI_FORMAT_R32G32B32_FLOAT;
5278 return DXGI_FORMAT_R32G32_FLOAT;
5280 return DXGI_FORMAT_R32_FLOAT;
5282 return DXGI_FORMAT_R8G8B8A8_UNORM;
5284 return DXGI_FORMAT_R8G8_UNORM;
5286 return DXGI_FORMAT_R8_UNORM;
5288 return DXGI_FORMAT_R32G32B32A32_UINT;
5290 return DXGI_FORMAT_R32G32B32_UINT;
5292 return DXGI_FORMAT_R32G32_UINT;
5294 return DXGI_FORMAT_R32_UINT;
5296 return DXGI_FORMAT_R32G32B32A32_SINT;
5298 return DXGI_FORMAT_R32G32B32_SINT;
5300 return DXGI_FORMAT_R32G32_SINT;
5302 return DXGI_FORMAT_R32_SINT;
5306 return DXGI_FORMAT_R16G16B16A16_FLOAT;
5308 return DXGI_FORMAT_R16G16_FLOAT;
5310 return DXGI_FORMAT_R16_FLOAT;
5312 Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
5320QD3D12GraphicsPipeline::~QD3D12GraphicsPipeline()
5325void QD3D12GraphicsPipeline::destroy()
5332 rhiD->releaseQueue.deferredReleasePipeline(
handle);
5333 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
5340 rhiD->unregisterResource(
this);
5343bool QD3D12GraphicsPipeline::create()
5349 if (!rhiD->sanityCheckGraphicsPipeline(
this))
5352 rhiD->pipelineCreationStart();
5356 const QD3D12Stage d3dStage = qd3d12_stage(shaderStage.type());
5357 stageData[d3dStage].valid =
true;
5358 stageData[d3dStage].stage = d3dStage;
5359 auto cacheIt = rhiD->shaderBytecodeCache.data.constFind(shaderStage);
5360 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
5361 shaderBytecode[d3dStage] = cacheIt->bytecode;
5362 stageData[d3dStage].nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
5366 int compileFlags = 0;
5367 if (m_flags.testFlag(CompileShadersWithDebugInfo))
5368 compileFlags |= int(HlslCompileFlag::WithDebugInfo);
5369 const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
5370 shaderStage.shaderVariant(),
5379 shaderBytecode[d3dStage] = bytecode;
5380 stageData[d3dStage].nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
5381 rhiD->shaderBytecodeCache.insertWithCapacityLimit(shaderStage,
5382 { bytecode, stageData[d3dStage].nativeResourceBindingMap });
5386 QD3D12ShaderResourceBindings *srbD =
QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
5388 rootSigHandle = srbD->createRootSignature(stageData.data(), 5);
5389 if (rootSigHandle.isNull()) {
5390 qWarning(
"Failed to create root signature");
5394 ID3D12RootSignature *rootSig =
nullptr;
5395 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
5396 rootSig = rs->rootSig;
5398 qWarning(
"Cannot create graphics pipeline state without root signature");
5402 QD3D12RenderPassDescriptor *rpD =
QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
5403 const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleCount(m_sampleCount, DXGI_FORMAT(rpD->colorFormat[0]));
5406 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
5407 QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
5408 QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
5409 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
5410 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
5411 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
5412 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
5413 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
5414 QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
5415 QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
5416 QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
5417 QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
5418 QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
5419 QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
5420 QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
5421 QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
5424 stream.rootSig.object = rootSig;
5428 if (!shaderBytecode[VS].isEmpty()) {
5429 for (
auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
5432 D3D12_INPUT_ELEMENT_DESC
desc = {};
5437 const int matrixSlice =
it->matrixSlice();
5438 if (matrixSlice < 0) {
5439 desc.SemanticName =
"TEXCOORD";
5440 desc.SemanticIndex = UINT(
it->location());
5445 matrixSliceSemantics.append(
sem);
5446 desc.SemanticName = matrixSliceSemantics.last().constData();
5447 desc.SemanticIndex = UINT(matrixSlice);
5450 desc.InputSlot = UINT(
it->binding());
5451 desc.AlignedByteOffset =
it->offset();
5454 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
5457 desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
5463 stream.inputLayout.object.NumElements = inputDescs.
count();
5466 stream.primitiveTopology.object = toD3DTopologyType(m_topology);
5467 topology =
toD3DTopology(m_topology, m_patchControlPointCount);
5470 const int d3dStage = qd3d12_stage(shaderStage.type());
5473 stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].
constData();
5474 stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].
size();
5477 stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].
constData();
5478 stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].
size();
5481 stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].
constData();
5482 stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].
size();
5485 stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].
constData();
5486 stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].
size();
5489 stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].
constData();
5490 stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].
size();
5500 stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
5501 stream.rasterizerState.object.DepthBias = m_depthBias;
5502 stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
5503 stream.rasterizerState.object.DepthClipEnable = TRUE;
5504 stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
5506 stream.depthStencilState.object.DepthEnable = m_depthTest;
5507 stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
5509 stream.depthStencilState.object.StencilEnable = m_stencilTest;
5510 if (m_stencilTest) {
5511 stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
5512 stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
5513 stream.depthStencilState.object.FrontFace.StencilFailOp =
toD3DStencilOp(m_stencilFront.failOp);
5514 stream.depthStencilState.object.FrontFace.StencilDepthFailOp =
toD3DStencilOp(m_stencilFront.depthFailOp);
5515 stream.depthStencilState.object.FrontFace.StencilPassOp =
toD3DStencilOp(m_stencilFront.passOp);
5516 stream.depthStencilState.object.FrontFace.StencilFunc =
toD3DCompareOp(m_stencilFront.compareOp);
5518 stream.depthStencilState.object.BackFace.StencilDepthFailOp =
toD3DStencilOp(m_stencilBack.depthFailOp);
5520 stream.depthStencilState.object.BackFace.StencilFunc =
toD3DCompareOp(m_stencilBack.compareOp);
5523 stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
5524 for (
int i = 0, ie = m_targetBlends.count();
i != ie; ++
i) {
5526 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
5527 blend.BlendEnable =
b.enable;
5535 stream.blendState.object.RenderTarget[
i] = blend;
5537 if (m_targetBlends.isEmpty()) {
5538 D3D12_RENDER_TARGET_BLEND_DESC blend = {};
5539 blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
5540 stream.blendState.object.RenderTarget[0] = blend;
5543 stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
5544 for (
int i = 0;
i < rpD->colorAttachmentCount; ++
i)
5545 stream.rtFormats.object.RTFormats[
i] = DXGI_FORMAT(rpD->colorFormat[
i]);
5547 stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
5549 stream.sampleDesc.object = sampleDesc;
5551 stream.sampleMask.object = 0xFFFFFFFF;
5553 viewInstanceMask = 0;
5554 const bool isMultiView = m_multiViewCount >= 2;
5555 stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
5558 for (
int i = 0;
i < m_multiViewCount; ++
i) {
5559 viewInstanceMask |= (1 <<
i);
5560 viewInstanceLocations.
append({ 0, UINT(
i) });
5562 stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.
constData();
5565 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(
stream), &
stream };
5567 ID3D12PipelineState *pso =
nullptr;
5568 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<void **
>(&pso));
5570 qWarning(
"Failed to create graphics pipeline state: %s",
5571 qPrintable(QSystemError::windowsComString(hr)));
5572 rhiD->rootSignaturePool.remove(rootSigHandle);
5577 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Graphics, pso);
5579 rhiD->pipelineCreationEnd();
5581 rhiD->registerResource(
this);
5590QD3D12ComputePipeline::~QD3D12ComputePipeline()
5595void QD3D12ComputePipeline::destroy()
5602 rhiD->releaseQueue.deferredReleasePipeline(
handle);
5603 rhiD->releaseQueue.deferredReleaseRootSignature(rootSigHandle);
5610 rhiD->unregisterResource(
this);
5613bool QD3D12ComputePipeline::create()
5619 rhiD->pipelineCreationStart();
5621 stageData.valid =
true;
5622 stageData.stage = CS;
5625 auto cacheIt = rhiD->shaderBytecodeCache.
data.constFind(m_shaderStage);
5626 if (cacheIt != rhiD->shaderBytecodeCache.data.constEnd()) {
5627 shaderBytecode = cacheIt->bytecode;
5628 stageData.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
5632 int compileFlags = 0;
5633 if (m_flags.testFlag(CompileShadersWithDebugInfo))
5634 compileFlags |= int(HlslCompileFlag::WithDebugInfo);
5635 const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
5636 m_shaderStage.shaderVariant(),
5645 shaderBytecode = bytecode;
5646 stageData.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
5647 rhiD->shaderBytecodeCache.insertWithCapacityLimit(m_shaderStage, { bytecode,
5648 stageData.nativeResourceBindingMap });
5651 QD3D12ShaderResourceBindings *srbD =
QRHI_RES(QD3D12ShaderResourceBindings, m_shaderResourceBindings);
5653 rootSigHandle = srbD->createRootSignature(&stageData, 1);
5654 if (rootSigHandle.isNull()) {
5655 qWarning(
"Failed to create root signature");
5659 ID3D12RootSignature *rootSig =
nullptr;
5660 if (QD3D12RootSignature *rs = rhiD->rootSignaturePool.lookupRef(rootSigHandle))
5661 rootSig = rs->rootSig;
5663 qWarning(
"Cannot create compute pipeline state without root signature");
5668 QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
5669 QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
5671 stream.rootSig.object = rootSig;
5673 stream.CS.object.BytecodeLength = shaderBytecode.
size();
5674 const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {
sizeof(
stream), &
stream };
5675 ID3D12PipelineState *pso =
nullptr;
5676 HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState),
reinterpret_cast<void **
>(&pso));
5678 qWarning(
"Failed to create compute pipeline state: %s",
5679 qPrintable(QSystemError::windowsComString(hr)));
5680 rhiD->rootSignaturePool.remove(rootSigHandle);
5685 handle = QD3D12Pipeline::addToPool(&rhiD->pipelinePool, QD3D12Pipeline::Compute, pso);
5687 rhiD->pipelineCreationEnd();
5689 rhiD->registerResource(
this);
5699 serializedFormatData.reserve(16);
5702QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
5707void QD3D12RenderPassDescriptor::destroy()
5711 rhiD->unregisterResource(
this);
5719 const QD3D12RenderPassDescriptor *
o =
QRHI_RES(
const QD3D12RenderPassDescriptor,
other);
5721 if (colorAttachmentCount !=
o->colorAttachmentCount)
5724 if (hasDepthStencil !=
o->hasDepthStencil)
5727 for (
int i = 0;
i < colorAttachmentCount; ++
i) {
5732 if (hasDepthStencil) {
5733 if (dsFormat !=
o->dsFormat)
5740void QD3D12RenderPassDescriptor::updateSerializedFormat()
5742 serializedFormatData.clear();
5743 auto p = std::back_inserter(serializedFormatData);
5745 *
p++ = colorAttachmentCount;
5746 *
p++ = hasDepthStencil;
5747 for (
int i = 0;
i < colorAttachmentCount; ++
i)
5749 *
p++ = hasDepthStencil ? dsFormat : 0;
5754 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
5755 rpD->colorAttachmentCount = colorAttachmentCount;
5756 rpD->hasDepthStencil = hasDepthStencil;
5758 rpD->dsFormat = dsFormat;
5760 rpD->updateSerializedFormat();
5763 rhiD->registerResource(rpD);
5769 return serializedFormatData;
5778QD3D12CommandBuffer::~QD3D12CommandBuffer()
5783void QD3D12CommandBuffer::destroy()
5790 nativeHandlesStruct.commandList = cmdList;
5791 return &nativeHandlesStruct;
5800QD3D12SwapChainRenderTarget::~QD3D12SwapChainRenderTarget()
5805void QD3D12SwapChainRenderTarget::destroy()
5810QSize QD3D12SwapChainRenderTarget::pixelSize()
const
5815float QD3D12SwapChainRenderTarget::devicePixelRatio()
const
5820int QD3D12SwapChainRenderTarget::sampleCount()
const
5822 return d.sampleCount;
5827 rtWrapper(rhi,
this),
5832QD3D12SwapChain::~QD3D12SwapChain()
5837void QD3D12SwapChain::destroy()
5844 swapChain->Release();
5845 swapChain =
nullptr;
5846 sourceSwapChain1->Release();
5847 sourceSwapChain1 =
nullptr;
5849 for (
int i = 0;
i < QD3D12_FRAMES_IN_FLIGHT; ++
i) {
5850 FrameResources &fr(frameRes[
i]);
5852 fr.fence->Release();
5854 CloseHandle(fr.fenceEvent);
5856 fr.cmdList->Release();
5861 dcompVisual->Release();
5862 dcompVisual =
nullptr;
5866 dcompTarget->Release();
5867 dcompTarget =
nullptr;
5872 rhiD->swapchains.remove(
this);
5873 rhiD->unregisterResource(
this);
5877void QD3D12SwapChain::releaseBuffers()
5882 rhiD->resourcePool.remove(colorBuffers[
i]);
5883 rhiD->rtvPool.release(rtvs[
i], 1);
5885 rhiD->resourcePool.remove(msaaBuffers[
i]);
5886 if (msaaRtvs[
i].isValid())
5887 rhiD->rtvPool.release(msaaRtvs[
i], 1);
5891void QD3D12SwapChain::waitCommandCompletionForFrameSlot(
int frameSlot)
5893 FrameResources &fr(frameRes[frameSlot]);
5894 if (fr.fence->GetCompletedValue() < fr.fenceCounter) {
5895 fr.fence->SetEventOnCompletion(fr.fenceCounter, fr.fenceEvent);
5896 WaitForSingleObject(fr.fenceEvent, INFINITE);
5900void QD3D12SwapChain::addCommandCompletionSignalForCurrentFrameSlot()
5903 FrameResources &fr(frameRes[currentFrameSlot]);
5904 fr.fenceCounter += 1u;
5905 rhiD->cmdQueue->Signal(fr.fence, fr.fenceCounter);
5918QSize QD3D12SwapChain::surfacePixelSize()
5921 return m_window->size() * m_window->devicePixelRatio();
5927 QRect wr =
w->geometry();
5930 IDXGIOutput *currentOutput =
nullptr;
5931 IDXGIOutput *
output =
nullptr;
5932 for (UINT
i = 0; adapter->EnumOutputs(
i, &
output) != DXGI_ERROR_NOT_FOUND; ++
i) {
5933 DXGI_OUTPUT_DESC
desc;
5935 const RECT
r =
desc.DesktopCoordinates;
5937 if (dr.contains(center)) {
5944 if (currentOutput) {
5945 ok = SUCCEEDED(currentOutput->QueryInterface(__uuidof(IDXGIOutput6),
reinterpret_cast<void **
>(
result)));
5946 currentOutput->Release();
5954 IDXGIOutput6 *out6 =
nullptr;
5956 ok = SUCCEEDED(out6->GetDesc1(
result));
5962bool QD3D12SwapChain::isFormatSupported(
Format f)
5968 qWarning(
"Attempted to call isFormatSupported() without a window set");
5973 DXGI_OUTPUT_DESC1 desc1;
5975 if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
5987 DXGI_OUTPUT_DESC1 hdrOutputDesc;
5989 info.isHardCodedDefaults =
false;
5991 info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance;
5992 info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance;
6003 QD3D12RenderPassDescriptor *rpD =
new QD3D12RenderPassDescriptor(m_rhi);
6004 rpD->colorAttachmentCount = 1;
6005 rpD->hasDepthStencil = m_depthStencil !=
nullptr;
6006 rpD->colorFormat[0] = int(srgbAdjustedColorFormat);
6007 rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
6008 rpD->updateSerializedFormat();
6011 rhiD->registerResource(rpD);
6015bool QRhiD3D12::ensureDirectCompositionDevice()
6020 qCDebug(QRHI_LOG_INFO,
"Creating Direct Composition device (needed for semi-transparent windows)");
6022 return dcompDevice ? true :
false;
6025static const DXGI_FORMAT
DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
6028void QD3D12SwapChain::chooseFormats()
6032 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
6033 DXGI_OUTPUT_DESC1 hdrOutputDesc;
6037 if (hdrOutputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
6039 case HDRExtendedSrgbLinear:
6041 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
6046 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
6056 qWarning(
"The output associated with the window is not HDR capable "
6057 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
6060 sampleDesc = rhiD->effectiveSampleCount(m_sampleCount,
colorFormat);
6063bool QD3D12SwapChain::createOrResize()
6069 const bool needsRegistration = !
window ||
window != m_window;
6076 m_currentPixelSize = surfacePixelSize();
6077 pixelSize = m_currentPixelSize;
6079 if (pixelSize.isEmpty())
6082 HWND hwnd =
reinterpret_cast<HWND
>(
window->winId());
6086 if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
6087 if (rhiD->ensureDirectCompositionDevice()) {
6089 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd,
true, &dcompTarget);
6091 qWarning(
"Failed to create Direct Compsition target for the window: %s",
6092 qPrintable(QSystemError::windowsComString(hr)));
6095 if (dcompTarget && !dcompVisual) {
6096 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
6098 qWarning(
"Failed to create DirectComposition visual: %s",
6099 qPrintable(QSystemError::windowsComString(hr)));
6104 if (
window->requestedFormat().alphaBufferSize() <= 0)
6105 qWarning(
"Swapchain says surface has alpha but the window has no alphaBufferSize set. "
6106 "This may lead to problems.");
6111 if (swapInterval == 0 && rhiD->supportsAllowTearing)
6112 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
6117 DXGI_SWAP_CHAIN_DESC1
desc = {};
6118 desc.Width = UINT(pixelSize.width());
6119 desc.Height = UINT(pixelSize.height());
6121 desc.SampleDesc.Count = 1;
6122 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
6124 desc.Flags = swapChainFlags;
6125 desc.Scaling = DXGI_SCALING_NONE;
6126 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
6132 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
6137 desc.Scaling = DXGI_SCALING_STRETCH;
6141 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &
desc,
nullptr, &sourceSwapChain1);
6143 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &
desc,
nullptr,
nullptr, &sourceSwapChain1);
6148 if (FAILED(hr) && m_format != SDR) {
6152 hr = rhiD->dxgiFactory->CreateSwapChainForComposition(rhiD->cmdQueue, &
desc,
nullptr, &sourceSwapChain1);
6154 hr = rhiD->dxgiFactory->CreateSwapChainForHwnd(rhiD->cmdQueue, hwnd, &
desc,
nullptr,
nullptr, &sourceSwapChain1);
6157 if (SUCCEEDED(hr)) {
6158 if (FAILED(sourceSwapChain1->QueryInterface(__uuidof(IDXGISwapChain3),
reinterpret_cast<void **
>(&swapChain)))) {
6159 qWarning(
"IDXGISwapChain3 not available");
6162 if (m_format != SDR) {
6163 hr = swapChain->SetColorSpace1(hdrColorSpace);
6165 qWarning(
"Failed to set color space on swapchain: %s",
6166 qPrintable(QSystemError::windowsComString(hr)));
6170 hr = dcompVisual->SetContent(swapChain);
6171 if (SUCCEEDED(hr)) {
6172 hr = dcompTarget->SetRoot(dcompVisual);
6174 qWarning(
"Failed to associate Direct Composition visual with the target: %s",
6175 qPrintable(QSystemError::windowsComString(hr)));
6178 qWarning(
"Failed to set content for Direct Composition visual: %s",
6179 qPrintable(QSystemError::windowsComString(hr)));
6183 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
6187 qWarning(
"Failed to create D3D12 swapchain: %s",
qPrintable(QSystemError::windowsComString(hr)));
6191 for (
int i = 0;
i < QD3D12_FRAMES_IN_FLIGHT; ++
i) {
6192 hr = rhiD->dev->CreateFence(0,
6193 D3D12_FENCE_FLAG_NONE,
6194 __uuidof(ID3D12Fence),
6195 reinterpret_cast<void **
>(&frameRes[
i].fence));
6197 qWarning(
"Failed to create fence for swapchain: %s",
6198 qPrintable(QSystemError::windowsComString(hr)));
6201 frameRes[
i].fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
6203 frameRes[
i].fenceCounter = 0;
6208 UINT(pixelSize.width()),
6209 UINT(pixelSize.height()),
6212 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
6213 qWarning(
"Device loss detected in ResizeBuffers()");
6214 rhiD->deviceLost =
true;
6216 }
else if (FAILED(hr)) {
6217 qWarning(
"Failed to resize D3D12 swapchain: %s",
qPrintable(QSystemError::windowsComString(hr)));
6223 ID3D12Resource *colorBuffer;
6224 hr = swapChain->GetBuffer(
i, __uuidof(ID3D12Resource),
reinterpret_cast<void **
>(&colorBuffer));
6226 qWarning(
"Failed to get buffer %u for D3D12 swapchain: %s",
6227 i,
qPrintable(QSystemError::windowsComString(hr)));
6230 colorBuffers[
i] = QD3D12Resource::addToPool(&rhiD->resourcePool, colorBuffer, D3D12_RESOURCE_STATE_PRESENT);
6231 rtvs[
i] = rhiD->rtvPool.allocate(1);
6232 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6233 rtvDesc.Format = srgbAdjustedColorFormat;
6234 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
6235 rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[
i].cpuHandle);
6238 if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
6239 qWarning(
"Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
6240 m_depthStencil->sampleCount(), m_sampleCount);
6242 if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
6244 m_depthStencil->setPixelSize(pixelSize);
6245 if (!m_depthStencil->create())
6246 qWarning(
"Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
6247 pixelSize.width(), pixelSize.height());
6249 qWarning(
"Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
6250 m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
6251 pixelSize.width(), pixelSize.height());
6255 ds = m_depthStencil ?
QRHI_RES(QD3D12RenderBuffer, m_depthStencil) :
nullptr;
6257 if (sampleDesc.Count > 1) {
6259 D3D12_RESOURCE_DESC resourceDesc = {};
6260 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
6261 resourceDesc.Width = UINT64(pixelSize.width());
6262 resourceDesc.Height = UINT(pixelSize.height());
6263 resourceDesc.DepthOrArraySize = 1;
6264 resourceDesc.MipLevels = 1;
6265 resourceDesc.Format = srgbAdjustedColorFormat;
6266 resourceDesc.SampleDesc = sampleDesc;
6267 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
6268 resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
6269 D3D12_CLEAR_VALUE clearValue = {};
6271 ID3D12Resource *resource =
nullptr;
6273 HRESULT hr = rhiD->vma.createResource(D3D12_HEAP_TYPE_DEFAULT,
6275 D3D12_RESOURCE_STATE_RENDER_TARGET,
6278 __uuidof(ID3D12Resource),
6279 reinterpret_cast<void **
>(&resource));
6281 qWarning(
"Failed to create MSAA color buffer: %s",
qPrintable(QSystemError::windowsComString(hr)));
6284 msaaBuffers[
i] = QD3D12Resource::addToPool(&rhiD->resourcePool, resource, D3D12_RESOURCE_STATE_RENDER_TARGET,
allocation);
6285 msaaRtvs[
i] = rhiD->rtvPool.allocate(1);
6286 if (!msaaRtvs[
i].isValid())
6288 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
6289 rtvDesc.Format = srgbAdjustedColorFormat;
6290 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS
6291 : D3D12_RTV_DIMENSION_TEXTURE2D;
6292 rhiD->dev->CreateRenderTargetView(resource, &rtvDesc, msaaRtvs[
i].cpuHandle);
6296 currentBackBufferIndex = swapChain->GetCurrentBackBufferIndex();
6297 currentFrameSlot = 0;
6300 QD3D12SwapChainRenderTarget *rtD =
QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapper);
6301 rtD->d.rp =
QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
6302 rtD->d.pixelSize = pixelSize;
6303 rtD->d.dpr = float(
window->devicePixelRatio());
6304 rtD->d.sampleCount = int(sampleDesc.Count);
6305 rtD->d.colorAttCount = 1;
6306 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
6308 if (needsRegistration) {
6309 rhiD->swapchains.insert(
this);
6310 rhiD->registerResource(
this);
IOBluetoothDevice * device
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
The QColor class provides colors based on RGB, HSV or CMYK values.
float greenF() const noexcept
Returns the green color component of this color.
float redF() const noexcept
Returns the red color component of this color.
float alphaF() const noexcept
Returns the alpha color component of this color.
float blueF() const noexcept
Returns the blue color component of this color.
const_iterator cend() const
const_iterator constFind(const Key &key) const
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
\inmodule QtCore\reentrant
constexpr int x() const noexcept
Returns the x coordinate of this point.
constexpr void setY(int y) noexcept
Sets the y coordinate of this point to the given y coordinate.
constexpr int y() const noexcept
Returns the y coordinate of this point.
constexpr void setX(int x) noexcept
Sets the x coordinate of this point to the given x coordinate.
\inmodule QtCore\reentrant
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
constexpr QSize size() const noexcept
Returns the size of the rectangle.
constexpr QPoint center() const noexcept
Returns the center point of the rectangle.
Type
Specifies storage type of buffer resource.
QPair< QRhiBuffer *, quint32 > VertexInput
Synonym for QPair<QRhiBuffer *, quint32>.
QPair< int, quint32 > DynamicOffset
Synonym for QPair<int, quint32>.
IndexFormat
Specifies the index data type.
float depthClearValue() const
quint32 stencilClearValue() const
BlendOp
Specifies the blend operation.
PolygonMode
Specifies the polygon rasterization mode.
BlendFactor
Specifies the blend factor.
CompareOp
Specifies the depth or stencil comparison function.
CullMode
Specifies the culling mode.
Topology
Specifies the primitive topology.
StencilOp
Specifies the stencil operation.
static const QRhiShaderResourceBinding::Data * shaderResourceBindingData(const QRhiShaderResourceBinding &binding)
static bool sortedBindingLessThan(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
Type
Specifies the type of the renderbuffer.
QVarLengthArray< BufferOp, BUFFER_OPS_STATIC_ALLOC > bufferOps
QVarLengthArray< TextureOp, TEXTURE_OPS_STATIC_ALLOC > textureOps
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
virtual Type resourceType() const =0
Filter
Specifies the minification, magnification, or mipmap filtering.
AddressMode
Specifies the addressing mode.
CompareOp
Specifies the texture comparison function.
std::array< int, 4 > scissor() const
virtual QRhiSwapChainHdrInfo hdrInfo()
\variable QRhiSwapChainHdrInfo::isHardCodedDefaults
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Associates with the QRhiRenderPassDescriptor desc.
@ PreserveDepthStencilContents
Format
Specifies the texture format.
ResourceLimit
Describes the resource limit to query.
@ MaxThreadsPerThreadGroup
@ MaxThreadGroupsPerDimension
Feature
Flag values to indicate what features are supported by the backend currently in use.
@ NonDynamicUniformBuffers
@ RenderToNonBaseMipLevel
@ MultisampleRenderBuffer
@ PipelineCacheDataLoadSave
@ ReadBackNonUniformBuffer
@ RenderToOneDimensionalTexture
@ OneDimensionalTextureMipmaps
@ ReadBackNonBaseMipLevel
@ ThreeDimensionalTextureMipmaps
@ NonFourAlignedEffectiveIndexBufferOffset
@ ThreeDimensionalTextures
@ ReadBackAnyTextureFormat
static const int MAX_MIP_LEVELS
FrameOpResult
Describes the result of operations that can have a soft failure.
const_iterator cend() const noexcept
const_iterator constFind(const T &value) const
QByteArray shader() const
QByteArray entryPoint() const
Variant
Describes what kind of shader code an entry contains.
Source
Describes what kind of shader code an entry contains.
@ TessellationEvaluationStage
@ TessellationControlStage
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
static QString fromUtf16(const char16_t *, qsizetype size=-1)
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray toUtf8() const &
const T * constData() const
void reserve(qsizetype sz)
QMap< QString, QString > map
[6]
QSet< QString >::iterator it
pD3DCompile resolveD3DCompile()
IDCompositionDevice * createDirectCompositionDevice()
Combined button and popup list for selecting options.
QTextStream & center(QTextStream &stream)
Calls QTextStream::setFieldAlignment(QTextStream::AlignCenter) on stream and returns stream.
constexpr uint qCountTrailingZeroBits(quint32 v) noexcept
ABI::Windows::Storage::Streams::IBuffer NativeBuffer
Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt,...)
std::pair< T1, T2 > QPair
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError * error
static QT_BEGIN_NAMESPACE const int BUFFER_COUNT
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qBound(const T &min, const T &val, const T &max)
constexpr const T & qMax(const T &a, const T &b)
static bool contains(const QJsonArray &haystack, unsigned needle)
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLuint64 GLenum void * handle
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum GLuint GLint level
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLenum GLsizei count
const void GLsizei GLsizei stride
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum const GLint * param
GLenum GLuint GLintptr offset
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
GLdouble GLdouble GLdouble GLdouble q
GLenum GLenum colorFormat
GLsizeiptr const void GLenum usage
static bool isCompressedFormat(QOpenGLTexture::TextureFormat internalFormat)
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
static QPair< int, int > mapBinding(int binding, int stageIndex, const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
static bool output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result)
static D3D11_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
static bool outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result)
static const DXGI_FORMAT DEFAULT_SRGB_FORMAT
Int aligned(Int v, Int byteAlign)
static DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
static const DXGI_FORMAT DEFAULT_FORMAT
static D3D11_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f, bool rgb)
static D3D11_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
static D3D11_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
static QD3D11RenderTargetData * rtData(QRhiRenderTarget *rt)
static UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
static D3D11_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
static D3D11_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
static DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
static D3D11_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t, int patchControlPointCount)
static D3D11_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
static bool isDepthTextureFormat(QRhiTexture::Format format)
static D3D11_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
static DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
#define DXGI_ADAPTER_FLAG_SOFTWARE
\variable QRhiD3D11NativeHandles::dev
static QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
static D3D11_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
static DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
std::unique_ptr< ThunkPool::ThunkAllocation > allocation
#define qPrintable(string)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
unsigned long long quint64
QT_BEGIN_NAMESPACE typedef uchar * output
QFileInfo info(fileName)
[8]
view viewport() -> scroll(dx, dy, deviceRect)
\inmodule QtCore \reentrant
\variable QRhiReadbackResult::completed
TextureAndSampler texSamplers[MAX_TEX_SAMPLER_ARRAY_SIZE]
TextureAndOrSamplerData stex
QRhiShaderResourceBinding::StageFlags stage
union QRhiShaderResourceBinding::Data::@328 u
QRhiShaderResourceBinding::Type type