You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/RenderDll/XRenderD3D9/DX12/Device/CCryDX12DeviceContext.cpp

3061 lines
115 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "CCryDX12DeviceContext.hpp"
#include "CCryDX12Device.hpp"
#include "DX12/Resource/CCryDX12Resource.hpp"
#include "DX12/Resource/Misc/CCryDX12Buffer.hpp"
#include "DX12/Resource/Misc/CCryDX12Shader.hpp"
#include "DX12/Resource/Misc/CCryDX12Query.hpp"
#include "DX12/Resource/State/CCryDX12SamplerState.hpp"
#include "DX12/Resource/Texture/CCryDX12Texture1D.hpp"
#include "DX12/Resource/Texture/CCryDX12Texture2D.hpp"
#include "DX12/Resource/Texture/CCryDX12Texture3D.hpp"
#include "DX12/Resource/View/CCryDX12DepthStencilView.hpp"
#include "DX12/Resource/View/CCryDX12RenderTargetView.hpp"
#include "DX12/Resource/View/CCryDX12ShaderResourceView.hpp"
#include "DX12/Resource/View/CCryDX12UnorderedAccessView.hpp"
#include "DX12/API/DX12Device.hpp"
#define DX12_SUBMISSION_UNBOUND 3 // never commit, only when the heaps overflow, or on present
#define DX12_SUBMISSION_PERPSO 2 // commit whenever the PSO changes
#define DX12_SUBMISSION_PERDRAW 1 // commit whenever a new draw is requested
#define DX12_SUBMISSION_SYNC 0 // commit always and wait as well
#define DX12_SUBMISSION_MODE DX12_SUBMISSION_UNBOUND
CCryDX12DeviceContext* CCryDX12DeviceContext::Create(CCryDX12Device* pDeviced)
{
return DX12::PassAddRef(new CCryDX12DeviceContext(pDeviced));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CCryDX12DeviceContext::CCryDX12DeviceContext(CCryDX12Device* pDevice)
: Super()
, m_pDevice(pDevice)
, m_pDX12Device(pDevice->GetDX12Device())
, m_CmdFenceSet(pDevice->GetDX12Device())
, m_DirectListPool(pDevice->GetDX12Device(), m_CmdFenceSet, CMDQUEUE_GRAPHICS)
, m_CopyListPool(pDevice->GetDX12Device(), m_CmdFenceSet, CMDQUEUE_COPY)
, m_TimestampHeap(pDevice->GetDX12Device())
, m_PipelineHeap(pDevice->GetDX12Device())
, m_OcclusionHeap(pDevice->GetDX12Device())
, m_CurrentRootSignature{}
, m_CurrentPSO{}
, m_OutstandingQueries{}
, m_TimestampIndex{}
, m_OcclusionIndex{}
, m_bInCopyRegion{}
{
DX12_FUNC_LOG
// Timer query heap
{
D3D12_QUERY_HEAP_DESC desc = {};
desc.Count = 1024;
desc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP;
m_TimestampHeap.Init(m_pDX12Device, desc);
}
// Occlusion query heap
{
D3D12_QUERY_HEAP_DESC desc = {};
desc.Count = 64;
desc.Type = D3D12_QUERY_HEAP_TYPE_OCCLUSION;
m_OcclusionHeap.Init(m_pDX12Device, desc);
}
// Pipeline query heap
{
D3D12_QUERY_HEAP_DESC desc = {};
desc.Count = 16;
desc.Type = D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS;
m_PipelineHeap.Init(m_pDX12Device, desc);
}
const CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_READBACK);
const CD3DX12_RESOURCE_DESC timestampHeapBuffer = CD3DX12_RESOURCE_DESC::Buffer(sizeof(UINT64) * m_TimestampHeap.GetCapacity());
if(S_OK != m_pDX12Device->GetD3D12Device()->CreateCommittedResource(
&heapProperties,
D3D12_HEAP_FLAG_NONE,
&timestampHeapBuffer,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_GRAPHICS_PPV_ARGS(&m_TimestampDownloadBuffer)))
{
DX12_ERROR("Could not create intermediate timestamp download buffer!");
}
const CD3DX12_RESOURCE_DESC occlusionHeapBuffer = CD3DX12_RESOURCE_DESC::Buffer(sizeof(UINT64) * m_OcclusionHeap.GetCapacity());
if (S_OK != m_pDX12Device->GetD3D12Device()->CreateCommittedResource(
&heapProperties,
D3D12_HEAP_FLAG_NONE,
&occlusionHeapBuffer,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_GRAPHICS_PPV_ARGS(&m_OcclusionDownloadBuffer)))
{
DX12_ERROR("Could not create intermediate occlusion download buffer!");
}
m_pSamplerHeap = NULL;
m_pResourceHeap = NULL;
m_bCurrentNative = false;
m_nResDynOffset = 0;
m_nFrame = 0;
m_nStencilRef = -1;
m_TimestampMemory = nullptr;
m_OcclusionMemory = nullptr;
m_TimestampMapValid = false;
m_OcclusionMapValid = false;
m_CmdFenceSet.Init();
m_DirectListPool.Init();
m_CopyListPool.Init(D3D12_COMMAND_LIST_TYPE_COPY);
m_DirectListPool.AcquireCommandList(m_DirectCommandList);
m_CopyListPool.AcquireCommandList(m_CopyCommandList);
m_DirectCommandList->Begin();
m_DirectCommandList->SetResourceAndSamplerStateHeaps();
m_CopyCommandList->Begin();
m_pDX12Device->CalibrateClocks(m_DirectCommandList->GetD3D12CommandQueue());
}
CCryDX12DeviceContext::~CCryDX12DeviceContext()
{
DX12_FUNC_LOG
D3D12_RANGE sNoWrite = { 0, 0 };
if (m_TimestampMemory)
{
m_TimestampDownloadBuffer->Unmap(0, &sNoWrite);
}
if (m_OcclusionMemory)
{
m_OcclusionDownloadBuffer->Unmap(0, &sNoWrite);
}
m_TimestampDownloadBuffer->Release();
m_OcclusionDownloadBuffer->Release();
}
bool CCryDX12DeviceContext::PreparePSO(DX12::CommandMode commandMode)
{
DX12::Device* device = m_pDevice->GetDX12Device();
auto& state = m_PipelineState[commandMode];
const DX12::RootSignature* newRootSignature = m_CurrentRootSignature[commandMode];
const DX12::PipelineState* newPipelineState = m_CurrentPSO;
bool bForceFlush = false;
if (state.m_StateFlags & EPSPB_PipelineState)
{
if (commandMode == DX12::CommandModeGraphics)
{
DX12::RootSignature::GraphicsInitParams rootSignatureParams;
state.MakeInitParams(rootSignatureParams);
newRootSignature = device->GetRootSignatureCache().AcquireRootSignature(rootSignatureParams);
DX12::GraphicsPipelineState::InitParams psoParams;
psoParams.rootSignature = newRootSignature;
state.MakeInitParams(psoParams);
newPipelineState = device->GetPSOCache().AcquirePipelineState(psoParams);
}
else
{
DX12::RootSignature::ComputeInitParams rootSignatureParams;
state.MakeInitParams(rootSignatureParams);
newRootSignature = device->GetRootSignatureCache().AcquireRootSignature(rootSignatureParams);
DX12::ComputePipelineState::InitParams psoParams;
psoParams.rootSignature = newRootSignature;
state.MakeInitParams(psoParams);
newPipelineState = device->GetPSOCache().AcquirePipelineState(psoParams);
}
if (!newPipelineState)
{
return false;
}
if constexpr (DX12_SUBMISSION_MODE == DX12_SUBMISSION_PERPSO)
{
if (m_OutstandingQueries == 0)
{
bForceFlush = true;
}
}
}
// check for overflow and submit early
if (bForceFlush || m_DirectCommandList->IsFull(
/* 256, */ newRootSignature->GetPipelineLayout().m_NumDescriptors,
/* 16, */ newRootSignature->GetPipelineLayout().m_NumDynamicSamplers,
/* 8, */ state.OutputMerger.NumRenderTargets.Get(),
/* 1, */ state.OutputMerger.DepthStencilView ? 1 : 0))
{
const bool bWait = false;
SubmitDirectCommands(bWait);
#ifdef DX12_STATS
m_NumCommandListOverflows++;
#endif // DX12_STATS
ResetCachedState();
}
if (state.m_StateFlags & EPSPB_PipelineState)
{
if (newPipelineState != m_CurrentPSO)
{
#ifdef DX12_STATS
m_NumPSOs += 1;
#endif
m_DirectCommandList->SetPipelineState(newPipelineState);
m_CurrentPSO = newPipelineState;
}
if (newRootSignature != m_CurrentRootSignature[commandMode])
{
#ifdef DX12_STATS
m_NumRootSignatures += 1;
#endif
m_DirectCommandList->SetRootSignature(commandMode, newRootSignature);
m_CurrentRootSignature[commandMode] = newRootSignature;
state.m_StateFlags |= EPSPB_InputResources;
}
}
return true;
}
void CCryDX12DeviceContext::PrepareGraphicsFF()
{
auto& state = m_PipelineState[DX12::CommandModeGraphics];
const UINT& stateFlags = state.m_StateFlags;
if (stateFlags & EPSPB_IndexBuffer & (state.InputAssembler.IndexBuffer ? ~0 : 0))
{
AZ_Assert(state.InputAssembler.IndexBuffer, "IndexBuffer is required by the Draw but has not been set!");
m_DirectCommandList->BindAndSetIndexBufferView(state.InputAssembler.IndexBuffer->GetDX12View(), state.InputAssembler.IndexBufferFormat.Get(), state.InputAssembler.IndexBufferOffset.Get());
}
if (stateFlags & EPSPB_PrimitiveTopology)
{
m_DirectCommandList->SetPrimitiveTopology(static_cast<D3D12_PRIMITIVE_TOPOLOGY> (state.InputAssembler.PrimitiveTopology.Get()));
}
if (stateFlags & EPSPB_VertexBuffers)
{
m_DirectCommandList->ClearVertexBufferHeap(state.InputAssembler.NumVertexBuffers.Get());
for (UINT i = 0, S = state.InputAssembler.NumVertexBuffers.Get(); i < S; ++i)
{
CCryDX12Buffer* buffer = state.InputAssembler.VertexBuffers.Get(i);
if (buffer)
{
TRange<UINT> bindRange = TRange<UINT> (state.InputAssembler.Offsets.Get(i), state.InputAssembler.Offsets.Get(i));
UINT bindStride = state.InputAssembler.Strides.Get(i);
AZ_Assert(buffer, "VertexBuffer is required by the PSO but has not been set!");
m_DirectCommandList->BindVertexBufferView(buffer->GetDX12View(), i, bindRange, bindStride);
}
}
m_DirectCommandList->SetVertexBufferHeap(state.InputAssembler.NumVertexBuffers.Get());
}
if (stateFlags & EPSPB_Viewports)
{
UINT numScissors = state.Rasterizer.ScissorEnabled.Get() ? state.Rasterizer.NumScissors.Get() : 0;
if (state.Rasterizer.NumViewports.Get() >= numScissors)
{
D3D12_VIEWPORT viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
D3D12_RECT scissors[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
for (UINT i = 0, S = state.Rasterizer.NumViewports.Get(); i < S; ++i)
{
const D3D11_VIEWPORT& v = state.Rasterizer.Viewports.Get(i);
viewports[i].TopLeftX = v.TopLeftX;
viewports[i].TopLeftY = v.TopLeftY;
viewports[i].Width = v.Width;
viewports[i].Height = v.Height;
viewports[i].MinDepth = v.MinDepth;
viewports[i].MaxDepth = v.MaxDepth;
if (i < numScissors)
{
const D3D11_RECT& s = state.Rasterizer.Scissors.Get(i);
scissors[i].bottom = s.bottom;
scissors[i].left = s.left;
scissors[i].right = s.right;
scissors[i].top = s.top;
}
else
{
scissors[i].top = static_cast<LONG>(v.TopLeftY);
scissors[i].left = static_cast<LONG>(v.TopLeftX);
scissors[i].right = static_cast<LONG>(v.TopLeftX + v.Width);
scissors[i].bottom = static_cast<LONG>(v.TopLeftY + v.Height);
}
}
m_DirectCommandList->SetViewports(state.Rasterizer.NumViewports.Get(), viewports);
m_DirectCommandList->SetScissorRects(state.Rasterizer.NumViewports.Get(), scissors);
}
else
{
// This should not happen, ever!
DX12_NOT_IMPLEMENTED;
}
}
if (stateFlags & EPSPB_StencilRef)
{
m_DirectCommandList->SetStencilRef(state.OutputMerger.StencilRef.Get());
}
if (stateFlags & EPSPB_OutputResources)
{
BindOutputViews();
}
}
bool CCryDX12DeviceContext::PrepareGraphicsState()
{
if (!m_PipelineState[DX12::CommandModeGraphics].AreShadersBound() || m_PipelineState[DX12::CommandModeGraphics].InputAssembler.InputLayout.m_Value == NULL)
{
return false;
}
if (!PreparePSO(DX12::CommandModeGraphics))
{
return false;
}
PrepareGraphicsFF();
BindResources(DX12::CommandModeGraphics);
m_PipelineState[DX12::CommandModeGraphics].m_StateFlags = 0;
return true;
}
bool CCryDX12DeviceContext::PrepareComputeState()
{
if (!m_PipelineState[DX12::CommandModeCompute].AreShadersBound())
{
return false;
}
if (!PreparePSO(DX12::CommandModeCompute))
{
return false;
}
BindResources(DX12::CommandModeCompute);
m_PipelineState[DX12::CommandModeCompute].m_StateFlags = 0;
return true;
}
void CCryDX12DeviceContext::BindResources(DX12::CommandMode commandMode)
{
const auto& state = m_PipelineState[commandMode];
const auto stateFlags = state.m_StateFlags;
if ((stateFlags & EPSPB_InputResources) == 0)
{
return;
}
DX12_ASSERT(stateFlags & (BIT(EPSP_ConstantBuffers) | BIT(EPSP_Resources) | BIT(EPSP_Samplers)), "Redundant BindResources() called without state-changes");
const DX12::PipelineLayout& layout = m_CurrentRootSignature[commandMode]->GetPipelineLayout();
AZ::u32 resourceDescriptorOffset = 0;
AZ::u32 samplerDescriptorOffset = 0;
if (stateFlags & (EPSPB_ConstantBuffers | EPSPB_Resources))
{
for (const DX12::ResourceLayoutBinding& resourceBinding : layout.m_TableResources)
{
auto& stage = state.Stages[resourceBinding.ShaderStage];
switch (resourceBinding.ViewType)
{
case D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
{
CCryDX12Buffer* buffer = stage.ConstantBufferViews.Get(resourceBinding.ShaderSlot);
TRange<UINT> bindRange = stage.ConstBufferBindRange.Get(resourceBinding.ShaderSlot);
DX12_ASSERT(resourceDescriptorOffset == resourceBinding.DescriptorOffset, "ConstantBuffer offset has shifted: resource mapping invalid!");
m_DirectCommandList->WriteConstantBufferDescriptor(buffer ? &buffer->GetDX12View() : nullptr, resourceDescriptorOffset++, bindRange.start, bindRange.Length());
break;
}
case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
{
CCryDX12ShaderResourceView* resource = stage.ShaderResourceViews.Get(resourceBinding.ShaderSlot);
DX12_ASSERT(resourceDescriptorOffset == resourceBinding.DescriptorOffset, "ShaderResourceView offset has shifted: resource mapping invalid!");
m_DirectCommandList->WriteShaderResourceDescriptor(resource ? &resource->GetDX12View() : nullptr, resourceDescriptorOffset++);
break;
}
case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
{
CCryDX12UnorderedAccessView* resource = stage.UnorderedAccessViews.Get(resourceBinding.ShaderSlot);
DX12_ASSERT(resourceDescriptorOffset == resourceBinding.DescriptorOffset, "UnorderedAccessView offset has shifted: resource mapping invalid!");
m_DirectCommandList->WriteUnorderedAccessDescriptor(resource ? &resource->GetDX12View() : nullptr, resourceDescriptorOffset++);
break;
}
}
}
if (stateFlags & EPSPB_ConstantBuffers)
{
for (const DX12::ConstantBufferLayoutBinding& constantBufferBinding : layout.m_ConstantViews)
{
auto& stage = state.Stages[constantBufferBinding.ShaderStage];
CCryDX12Buffer* buffer = stage.ConstantBufferViews.Get(constantBufferBinding.ShaderSlot);
TRange<UINT> bindRange = stage.ConstBufferBindRange.Get(constantBufferBinding.ShaderSlot);
D3D12_GPU_VIRTUAL_ADDRESS gpuAddress = { 0ull };
if (buffer)
{
gpuAddress = buffer->GetDX12View().GetCBVDesc().BufferLocation + bindRange.start;
}
m_DirectCommandList->SetConstantBufferView(commandMode, constantBufferBinding.RootParameterIndex, gpuAddress);
}
}
}
// Bind samplers
if (stateFlags & EPSPB_Samplers)
{
for (const DX12::ResourceLayoutBinding& samplerBinding : layout.m_Samplers)
{
const DX12::EShaderStage i = samplerBinding.ShaderStage;
DX12_ASSERT(samplerBinding.ViewType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, "");
{
CCryDX12SamplerState* sampler = state.Stages[i].SamplerState.Get(samplerBinding.ShaderSlot);
DX12_ASSERT(samplerDescriptorOffset == samplerBinding.DescriptorOffset, "Sampler offset has shifted: resource mapping invalid!");
m_DirectCommandList->WriteSamplerStateDescriptor(sampler ? &sampler->GetDX12SamplerState() : nullptr, samplerDescriptorOffset++);
}
}
}
if (stateFlags & (BIT(EPSP_ConstantBuffers) | BIT(EPSP_Resources)))
{
m_DirectCommandList->SetDescriptorTables(commandMode, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
m_DirectCommandList->IncrementInputCursors(layout.m_NumDescriptors, 0);
}
if (stateFlags & (BIT(EPSP_Samplers)))
{
m_DirectCommandList->SetDescriptorTables(commandMode, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
m_DirectCommandList->IncrementInputCursors(0, layout.m_NumDynamicSamplers);
}
}
void CCryDX12DeviceContext::BindOutputViews()
{
const DX12::ResourceView* dsv = NULL;
const DX12::ResourceView* rtv[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
size_t numRTVs = 0;
auto& outputMerger = m_PipelineState[DX12::CommandModeGraphics].OutputMerger;
// Get current depth stencil views
{
CCryDX12DepthStencilView* view = outputMerger.DepthStencilView;
if (view)
{
dsv = &view->GetDX12View();
}
}
// Get current render target views
for (UINT i = 0, S = outputMerger.NumRenderTargets.Get(); i < S; ++i)
{
CCryDX12RenderTargetView* view = outputMerger.RenderTargetViews.Get(i);
if (view)
{
rtv[numRTVs++] = &view->GetDX12View();
}
}
m_DirectCommandList->BindAndSetOutputViews(numRTVs, rtv, dsv);
#ifdef DX12_STATS
m_NumberSettingOutputViews++;
#endif
}
namespace DX12
{
const char* StateToString(D3D12_RESOURCE_STATES state);
}
void CCryDX12DeviceContext::DebugPrintResources(DX12::CommandMode commandMode)
{
const DX12::PipelineLayout& layout = m_CurrentRootSignature[commandMode]->GetPipelineLayout();
DX12_LOG("Resource Heap Descriptor Tables:");
auto& state = m_PipelineState[commandMode];
UINT stateFlags = state.m_StateFlags;
UINT resourceDescriptorOffset = 0;
UINT samplerDescriptorOffset = 0;
// Bind constant buffers
for (const DX12::ResourceLayoutBinding& resourceBinding : layout.m_TableResources)
{
const DX12::EShaderStage i = resourceBinding.ShaderStage;
if (resourceBinding.ViewType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV)
{
CCryDX12Buffer* buffer = state.Stages[i].ConstantBufferViews.Get(resourceBinding.ShaderSlot);
auto bindRange = state.Stages[i].ConstBufferBindRange.Get(resourceBinding.ShaderSlot);
#ifdef GFX_DEBUG
AZ_Assert(buffer, "ConstantBuffer is required by the PSO but has not been set!");
AZ_Assert(resourceDescriptorOffset == resourceBinding.DescriptorOffset, "ConstantBuffer offset has shifted: resource mapping invalid!");
#endif
DX12_LOG(" %s: C %2d -> %2d %s [%s]",
i == DX12::ESS_Compute ? "Every shader stage" :
i == DX12::ESS_Vertex ? "Vertex shader stage" :
i == DX12::ESS_Hull ? "Hull shader stage" :
i == DX12::ESS_Domain ? "Domain shader stage" :
i == DX12::ESS_Geometry ? "Geometry shader stage" :
i == DX12::ESS_Pixel ? "Pixel shader stage" : "Unknown shader stage",
resourceBinding.ShaderSlot,
resourceDescriptorOffset++,
buffer ? buffer->GetName().c_str() : "nullptr",
buffer ? DX12::StateToString(buffer->GetDX12Resource().GetCurrentState()) : "-");
}
else if (resourceBinding.ViewType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV)
{
CCryDX12ShaderResourceView* resource = state.Stages[i].ShaderResourceViews.Get(resourceBinding.ShaderSlot);
#ifdef GFX_DEBUG
AZ_Assert(resource, "ShaderResourceView is required by the PSO but has not been set!");
AZ_Assert(resourceDescriptorOffset == resourceBinding.DescriptorOffset, "ShaderResourceView offset has shifted: resource mapping invalid!");
#endif
DX12_LOG(" %s: T %2d -> %2d %s [%s]",
i == DX12::ESS_Compute ? "Every shader stage" :
i == DX12::ESS_Vertex ? "Vertex shader stage" :
i == DX12::ESS_Hull ? "Hull shader stage" :
i == DX12::ESS_Domain ? "Domain shader stage" :
i == DX12::ESS_Geometry ? "Geometry shader stage" :
i == DX12::ESS_Pixel ? "Pixel shader stage" : "Unknown shader stage",
resourceBinding.ShaderSlot,
resourceDescriptorOffset++,
resource ? resource->GetResourceName().c_str() : "nullptr",
resource ? DX12::StateToString(resource->GetDX12Resource().GetCurrentState()) : "-");
}
else if (resourceBinding.ViewType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV)
{
CCryDX12UnorderedAccessView* resource = state.Stages[i].UnorderedAccessViews.Get(resourceBinding.ShaderSlot);
#ifdef GFX_DEBUG
AZ_Assert(resource, "UnorderedAccessView is required by the PSO but has not been set!");
AZ_Assert(resourceDescriptorOffset == resourceBinding.DescriptorOffset, "UnorderedAccessView offset has shifted: resource mapping invalid!");
#endif
DX12_LOG(" %s: U %2d -> %2d %s [%s]",
i == DX12::ESS_Compute ? "Every shader stage" :
i == DX12::ESS_Vertex ? "Vertex shader stage" :
i == DX12::ESS_Hull ? "Hull shader stage" :
i == DX12::ESS_Domain ? "Domain shader stage" :
i == DX12::ESS_Geometry ? "Geometry shader stage" :
i == DX12::ESS_Pixel ? "Pixel shader stage" : "Unknown shader stage",
resourceBinding.ShaderSlot,
resourceDescriptorOffset++,
resource ? resource->GetResourceName().c_str() : "nullptr",
resource ? DX12::StateToString(resource->GetDX12Resource().GetCurrentState()) : "-");
}
}
// Bind samplers
for (const DX12::ResourceLayoutBinding& samplerBinding : layout.m_Samplers)
{
const DX12::EShaderStage i = samplerBinding.ShaderStage;
AZ_Assert(samplerBinding.ViewType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, "");
{
CCryDX12SamplerState* sampler = state.Stages[i].SamplerState.Get(samplerBinding.ShaderSlot);
#ifdef GFX_DEBUG
AZ_Assert(sampler, "Sampler is required by the PSO but has not been set!");
AZ_Assert(samplerDescriptorOffset == samplerBinding.DescriptorOffset, "Sampler offset has shifted: resource mapping invalid!");
#endif
DX12_LOG(" %s: S %2d -> %2d",
i == DX12::ESS_Compute ? "Every shader stage" :
i == DX12::ESS_Vertex ? "Vertex shader stage" :
i == DX12::ESS_Hull ? "Hull shader stage" :
i == DX12::ESS_Domain ? "Domain shader stage" :
i == DX12::ESS_Geometry ? "Geometry shader stage" :
i == DX12::ESS_Pixel ? "Pixel shader stage" : "Unknown shader stage",
samplerBinding.ShaderSlot,
samplerDescriptorOffset++);
}
}
}
void CCryDX12DeviceContext::CeaseDirectCommandQueue(bool wait)
{
AZ_TRACE_METHOD();
AZ_Assert(m_DirectCommandList != nullptr, "CommandList hasn't been allocated!");
AZ_Assert(m_OutstandingQueries == 0, "Flushing command list with outstanding queries!");
m_DirectCommandList->End();
m_DirectListPool.ForfeitCommandList(m_DirectCommandList, wait);
}
void CCryDX12DeviceContext::ResumeDirectCommandQueue()
{
AZ_TRACE_METHOD();
AZ_Assert(m_DirectCommandList == nullptr, "CommandList hasn't been submitted!");
m_DirectListPool.AcquireCommandList(m_DirectCommandList);
m_DirectCommandList->Begin();
m_DirectCommandList->SetResourceAndSamplerStateHeaps();
ResetCachedState();
}
void CCryDX12DeviceContext::CeaseCopyCommandQueue(bool wait)
{
AZ_TRACE_METHOD();
AZ_Assert(m_CopyCommandList != nullptr, "CommandList hasn't been allocated!");
m_CopyCommandList->End();
m_CopyListPool.ForfeitCommandList(m_CopyCommandList, wait);
}
void CCryDX12DeviceContext::ResumeCopyCommandQueue()
{
AZ_TRACE_METHOD();
AZ_Assert(m_CopyCommandList == nullptr, "CommandList hasn't been submitted!");
m_CopyListPool.AcquireCommandList(m_CopyCommandList);
m_CopyCommandList->Begin();
}
void CCryDX12DeviceContext::CeaseAllCommandQueues(bool wait)
{
AZ_TRACE_METHOD();
CeaseDirectCommandQueue(wait);
CeaseCopyCommandQueue(wait);
}
void CCryDX12DeviceContext::ResumeAllCommandQueues()
{
AZ_TRACE_METHOD();
ResumeDirectCommandQueue();
ResumeCopyCommandQueue();
}
void CCryDX12DeviceContext::SubmitDirectCommands(bool wait)
{
if (m_DirectCommandList->IsUtilized())
{
AZ_TRACE_METHOD();
CeaseDirectCommandQueue(wait);
ResumeDirectCommandQueue();
}
}
void CCryDX12DeviceContext::SubmitCopyCommands(bool wait)
{
if (m_CopyCommandList->IsUtilized())
{
AZ_TRACE_METHOD();
CeaseCopyCommandQueue(wait);
ResumeCopyCommandQueue();
}
}
void CCryDX12DeviceContext::SubmitDirectCommands(bool wait, const UINT64 fenceValue)
{
if (m_DirectCommandList->IsUtilized() && (m_CmdFenceSet.GetCurrentValue(CMDQUEUE_GRAPHICS) == fenceValue))
{
#ifdef DX12_STATS
m_NumCommandListSplits++;
#endif // DX12_STATS
SubmitDirectCommands(wait);
}
}
void CCryDX12DeviceContext::SubmitCopyCommands(bool wait, const UINT64 fenceValue)
{
if (m_CopyCommandList->IsUtilized() && (m_CmdFenceSet.GetCurrentValue(CMDQUEUE_COPY) == fenceValue))
{
#ifdef DX12_STATS
m_NumCommandListSplits++;
#endif // DX12_STATS
SubmitCopyCommands(wait);
}
}
void CCryDX12DeviceContext::SubmitAllCommands(bool bWaitForGpu)
{
SubmitAllCommands(bWaitForGpu, m_CmdFenceSet.GetCurrentValues());
}
void CCryDX12DeviceContext::SubmitAllCommands(bool wait, const UINT64 (&fenceValues)[CMDQUEUE_NUM])
{
SubmitDirectCommands(wait, fenceValues[CMDQUEUE_GRAPHICS]);
SubmitCopyCommands(wait, fenceValues[CMDQUEUE_COPY]);
}
void CCryDX12DeviceContext::SubmitAllCommands(bool wait, const UINT64(&fenceValues)[CMDQUEUE_NUM], int fenceId)
{
AZ::u64 fenceValuesMasked[CMDQUEUE_NUM];
fenceValuesMasked[CMDQUEUE_GRAPHICS] = fenceValues[CMDQUEUE_GRAPHICS];
fenceValuesMasked[CMDQUEUE_COPY] = fenceValues[CMDQUEUE_COPY];
fenceValuesMasked[fenceId] = 0;
SubmitDirectCommands(wait, fenceValuesMasked[CMDQUEUE_GRAPHICS]);
SubmitCopyCommands(wait, fenceValuesMasked[CMDQUEUE_COPY]);
}
void CCryDX12DeviceContext::SubmitAllCommands(bool wait, const std::atomic<AZ::u64>(&fenceValues)[CMDQUEUE_NUM])
{
SubmitDirectCommands(wait, fenceValues[CMDQUEUE_GRAPHICS]);
SubmitCopyCommands(wait, fenceValues[CMDQUEUE_COPY]);
}
void CCryDX12DeviceContext::SubmitAllCommands(bool wait, const std::atomic<AZ::u64>(&fenceValues)[CMDQUEUE_NUM], int fenceId)
{
AZ::u64 fenceValuesMasked[CMDQUEUE_NUM];
fenceValuesMasked[CMDQUEUE_GRAPHICS] = fenceValues[CMDQUEUE_GRAPHICS];
fenceValuesMasked[CMDQUEUE_COPY] = fenceValues[CMDQUEUE_COPY];
fenceValuesMasked[fenceId] = 0;
SubmitDirectCommands(wait, fenceValuesMasked[CMDQUEUE_GRAPHICS]);
SubmitCopyCommands(wait, fenceValuesMasked[CMDQUEUE_COPY]);
}
void CCryDX12DeviceContext::Finish(DX12::SwapChain* pDX12SwapChain)
{
AZ_TRACE_METHOD();
m_DirectCommandList->PresentRenderTargetView(pDX12SwapChain);
SubmitAllCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC, m_CmdFenceSet.GetCurrentValues());
// Release resource after pass fence and FRAME_FENCE_LATENCY later
m_pDX12Device->FlushReleaseHeap(DX12::Device::ResourceReleasePolicy::Deferred);
m_pDX12Device->FinishFrame();
m_pDX12Device->CalibrateClocks(m_DirectListPool.GetD3D12CommandQueue());
#ifdef DX12_STATS
m_NumMapDiscardSkips = 0;
m_NumMapDiscards = 0;
m_NumCommandListOverflows = 0;
m_NumCommandListSplits = 0;
m_NumPSOs = 0;
m_NumRootSignatures = 0;
m_NumberSettingOutputViews = 0;
#endif // DX12_STATS
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CCryDX12DeviceContext::TimestampIndex([[maybe_unused]] DX12::CommandList* pCmdList)
{
UINT index = m_TimestampIndex;
m_TimestampIndex = (m_TimestampIndex + 1) % m_TimestampHeap.GetCapacity();
return index;
}
ID3D12Resource* CCryDX12DeviceContext::QueryTimestamp(DX12::CommandList* pCmdList, UINT index)
{
pCmdList->EndQuery(m_TimestampHeap, D3D12_QUERY_TYPE_TIMESTAMP, index);
m_TimestampMapValid = false;
if (m_TimestampMemory)
{
const D3D12_RANGE sNoWrite = { 0, 0 };
m_TimestampDownloadBuffer->Unmap(0, &sNoWrite);
m_TimestampMemory = nullptr;
}
return m_TimestampDownloadBuffer;
}
void CCryDX12DeviceContext::ResolveTimestamp(DX12::CommandList* pCmdList, UINT index, void* mem)
{
if (mem)
{
if (!m_TimestampMapValid)
{
if (m_TimestampMemory)
{
const D3D12_RANGE sNoWrite = { 0, 0 };
m_TimestampDownloadBuffer->Unmap(0, &sNoWrite);
m_TimestampMemory = nullptr;
}
pCmdList->ResolveQueryData(m_TimestampHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0, m_TimestampHeap.GetCapacity(), m_TimestampDownloadBuffer, 0);
// Resources on D3D12_HEAP_TYPE_READBACK heaps do not support persistent map.
const D3D12_RANGE sFullRead = { 0, sizeof(UINT64) * m_TimestampHeap.GetCapacity() };
m_TimestampDownloadBuffer->Map(0, &sFullRead, &m_TimestampMemory);
m_TimestampMapValid = true;
}
memcpy(mem, (char*)m_TimestampMemory + index * 8, 8);
}
}
UINT64 CCryDX12DeviceContext::MakeCpuTimestamp(UINT64 gpuTimestamp) const
{
return m_pDX12Device->MakeCpuTimestamp(gpuTimestamp);
}
UINT64 CCryDX12DeviceContext::MakeCpuTimestampMicroseconds(UINT64 gpuTimestamp) const
{
return m_pDX12Device->MakeCpuTimestampMicroseconds(gpuTimestamp);
}
UINT CCryDX12DeviceContext::OcclusionIndex(DX12::CommandList* pCmdList, bool counter)
{
UINT index = m_OcclusionIndex;
m_OcclusionIndex = (m_OcclusionIndex + 1) % m_OcclusionHeap.GetCapacity();
pCmdList->BeginQuery(m_OcclusionHeap, counter ? D3D12_QUERY_TYPE_OCCLUSION : D3D12_QUERY_TYPE_BINARY_OCCLUSION, index);
return index;
}
ID3D12Resource* CCryDX12DeviceContext::QueryOcclusion(DX12::CommandList* pCmdList, UINT index, bool counter)
{
pCmdList->EndQuery(m_OcclusionHeap, counter ? D3D12_QUERY_TYPE_OCCLUSION : D3D12_QUERY_TYPE_BINARY_OCCLUSION, index);
m_OcclusionMapValid = false;
if (m_OcclusionMemory)
{
const D3D12_RANGE sNoWrite = { 0, 0 };
m_OcclusionDownloadBuffer->Unmap(0, &sNoWrite);
m_OcclusionMemory = nullptr;
}
return m_OcclusionDownloadBuffer;
}
void CCryDX12DeviceContext::ResolveOcclusion(DX12::CommandList* pCmdList, UINT index, void* mem)
{
if (mem)
{
if (!m_OcclusionMapValid)
{
if (m_OcclusionMemory)
{
const D3D12_RANGE sNoWrite = { 0, 0 };
m_OcclusionDownloadBuffer->Unmap(0, &sNoWrite);
m_OcclusionMemory = nullptr;
}
pCmdList->ResolveQueryData(m_OcclusionHeap, D3D12_QUERY_TYPE_OCCLUSION, 0, m_OcclusionHeap.GetCapacity(), m_OcclusionDownloadBuffer, 0);
// Resources on D3D12_HEAP_TYPE_READBACK heaps do not support persistent map.
const D3D12_RANGE sFullRead = { 0, sizeof(UINT64) * m_OcclusionHeap.GetCapacity() };
m_OcclusionDownloadBuffer->Map(0, &sFullRead, &m_OcclusionMemory);
m_OcclusionMapValid = true;
}
memcpy(mem, (char*)m_OcclusionMemory + index * 8, 8);
}
}
void CCryDX12DeviceContext::WaitForIdle()
{
DX12::CommandListFence fence(m_pDX12Device);
fence.Init();
m_DirectListPool.GetD3D12CommandQueue()->Signal(fence.GetFence(), 1);
fence.WaitForFence(1);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma region /* ID3D11DeviceChild implementation */
void STDMETHODCALLTYPE CCryDX12DeviceContext::GetDevice(
[[maybe_unused]] _Out_ ID3D11Device** ppDevice)
{
DX12_FUNC_LOG
}
HRESULT STDMETHODCALLTYPE CCryDX12DeviceContext::GetPrivateData(
[[maybe_unused]] _In_ REFGUID guid,
[[maybe_unused]] _Inout_ UINT* pDataSize,
[[maybe_unused]] _Out_writes_bytes_opt_(*pDataSize) void* pData)
{
DX12_FUNC_LOG
return -1;
}
HRESULT STDMETHODCALLTYPE CCryDX12DeviceContext::SetPrivateData(
[[maybe_unused]] _In_ REFGUID guid,
[[maybe_unused]] _In_ UINT DataSize,
[[maybe_unused]] _In_reads_bytes_opt_(DataSize) const void* pData)
{
DX12_FUNC_LOG
return -1;
}
HRESULT STDMETHODCALLTYPE CCryDX12DeviceContext::SetPrivateDataInterface(
[[maybe_unused]] _In_ REFGUID guid,
[[maybe_unused]] _In_opt_ const IUnknown* pData)
{
DX12_FUNC_LOG
return -1;
}
#pragma endregion
#pragma region /* ID3D11DeviceContext implementation */
void STDMETHODCALLTYPE CCryDX12DeviceContext::VSSetConstantBuffers(
_In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) UINT NumBuffers,
_In_reads_opt_(NumBuffers) ID3D11Buffer* const* ppConstantBuffers)
{
VSSetConstantBuffers1(StartSlot, NumBuffers, ppConstantBuffers, NULL, NULL);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::PSSetShaderResources(
_In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumViews,
_In_reads_opt_(NumViews) ID3D11ShaderResourceView* const* ppShaderResourceViews)
{
DX12_FUNC_LOG
for (UINT i = StartSlot, S = StartSlot + NumViews; i < S; ++i, ++ppShaderResourceViews)
{
CCryDX12ShaderResourceView* srv = reinterpret_cast<CCryDX12ShaderResourceView*>(*ppShaderResourceViews);
if (m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Pixel].ShaderResourceViews.Set(i, srv) && srv)
{
srv->BeginResourceStateTransition(m_DirectCommandList.get());
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::PSSetShader(
_In_opt_ ID3D11PixelShader* pPixelShader,
[[maybe_unused]] _In_reads_opt_(NumClassInstances) ID3D11ClassInstance* const* ppClassInstances,
[[maybe_unused]] UINT NumClassInstances)
{
DX12_FUNC_LOG
m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Pixel].Shader.Set(reinterpret_cast<CCryDX12Shader*>(pPixelShader));
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::PSSetSamplers(
_In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) UINT NumSamplers,
_In_reads_opt_(NumSamplers) ID3D11SamplerState* const* ppSamplers)
{
DX12_FUNC_LOG
for (UINT i = StartSlot, S = StartSlot + NumSamplers; i < S; ++i, ++ppSamplers)
{
m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Pixel].SamplerState.Set(i, reinterpret_cast<CCryDX12SamplerState*>(*ppSamplers));
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::VSSetShader(
_In_opt_ ID3D11VertexShader* pVertexShader,
[[maybe_unused]] _In_reads_opt_(NumClassInstances) ID3D11ClassInstance* const* ppClassInstances,
[[maybe_unused]] UINT NumClassInstances)
{
DX12_FUNC_LOG
m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Vertex].Shader.Set(reinterpret_cast<CCryDX12Shader*>(pVertexShader));
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DrawIndexed(
_In_ UINT IndexCount,
_In_ UINT StartIndexLocation,
_In_ INT BaseVertexLocation)
{
DX12_FUNC_LOG
SubmitCopyCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
if (PrepareGraphicsState())
{
m_DirectCommandList->DrawIndexedInstanced(IndexCount, 1, StartIndexLocation, BaseVertexLocation, 0);
#ifdef AZ_DEBUG_BUILD
m_PipelineState[DX12::CommandModeGraphics].DebugPrint();
#endif
if constexpr (DX12_SUBMISSION_MODE <= DX12_SUBMISSION_PERDRAW)
{
if (m_OutstandingQueries == 0)
{
SubmitDirectCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
}
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::Draw(
_In_ UINT VertexCount,
_In_ UINT StartVertexLocation)
{
DX12_FUNC_LOG
SubmitCopyCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
if (PrepareGraphicsState())
{
m_DirectCommandList->DrawInstanced(VertexCount, 1, StartVertexLocation, 0);
#ifdef AZ_DEBUG_BUILD
m_PipelineState[DX12::CommandModeGraphics].DebugPrint();
#endif
if constexpr (DX12_SUBMISSION_MODE <= DX12_SUBMISSION_PERDRAW)
{
if (m_OutstandingQueries == 0)
{
SubmitDirectCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
}
}
}
}
HRESULT STDMETHODCALLTYPE CCryDX12DeviceContext::Map(
_In_ ID3D11Resource* pResource,
_In_ UINT Subresource,
_In_ D3D11_MAP MapType,
[[maybe_unused]] _In_ UINT MapFlags,
_Out_ D3D11_MAPPED_SUBRESOURCE* pMappedResource)
{
DX12_FUNC_LOG
ZeroMemory(pMappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE));
DX12_LOG(" Mapping resource: %p (%d)", pResource, Subresource);
ICryDX12Resource* dx12Resource = DX12_EXTRACT_ICRYDX12RESOURCE(pResource);
DX12::Resource& resource = dx12Resource->GetDX12Resource();
if (!resource.IsOffCard())
{
return S_FALSE;
}
switch (MapType)
{
case D3D11_MAP_READ:
// Ensure the command-list using the resource is executed
SubmitAllCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC, resource.GetFenceValues(CMDTYPE_WRITE));
// Block the CPU-thread until the resource is safe to map
resource.WaitForUnused(m_DirectListPool, CMDTYPE_WRITE);
break;
case D3D11_MAP_WRITE:
case D3D11_MAP_READ_WRITE:
// Ensure the command-list using the resource is executed
SubmitAllCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC, resource.GetFenceValues(CMDTYPE_ANY));
// Block the CPU-thread until the resource is safe to map
resource.WaitForUnused(m_DirectListPool, CMDTYPE_ANY);
break;
case D3D11_MAP_WRITE_DISCARD:
DX12_LOG("Using D3D11_MAP_WRITE_DISCARD on old ID3D12Resource: %p", DX12_EXTRACT_D3D12RESOURCE(pResource));
#ifdef DX12_STATS
m_NumMapDiscardSkips += !resource.IsUsed(m_DirectListPool);
m_NumMapDiscards++;
#endif // DX12_STATS
// If the resource is not currently used, we do not need to discard the memory
if (resource.IsUsed(m_DirectListPool))
{
dx12Resource->MapDiscard(m_DirectCommandList);
}
DX12_LOG("New ID3D12Resource: %p", DX12_EXTRACT_D3D12RESOURCE(pResource));
break;
case D3D11_MAP_WRITE_NO_OVERWRITE:
break;
default:
break;
}
static D3D12_RANGE sRg[] =
{
{ 0, 0 }, // It is valid to specify the CPU won't read any data by passing a range where End is less than or equal to Begin
{ 0, 0 } // It is valid to specify the CPU didn't write any data by passing a range where End is less than or equal to Begin.
};
static D3D12_RANGE* pRanges[] =
{
nullptr, // D3D11_MAP_READ = 1,
nullptr, // D3D11_MAP_WRITE = 2,
nullptr, // D3D11_MAP_READ_WRITE = 3,
&sRg[0], // D3D11_MAP_WRITE_DISCARD = 4,
&sRg[0], // D3D11_MAP_WRITE_NO_OVERWRITE = 5
};
AZ_Assert((MapType - 1) < AZ_ARRAY_SIZE(pRanges), "Invalid map type");
AZ_Assert(!D3D12IsLayoutOpaque(resource.GetDesc().Layout), "Opaque layouts are unmappable until 12.2!");
HRESULT hr = dx12Resource->GetD3D12Resource()->Map(Subresource, pRanges[MapType - 1], &(pMappedResource->pData));
if (S_OK != hr)
{
AZ_Assert(0, "Could not map resource!");
return hr;
}
return S_OK;
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::Unmap(
_In_ ID3D11Resource* pResource,
_In_ UINT Subresource)
{
DX12_FUNC_LOG
DX12_LOG("Unmapping resource: %p (%d)", pResource, Subresource);
ICryDX12Resource* dx12Resource = DX12_EXTRACT_ICRYDX12RESOURCE(pResource);
DX12::Resource& resource = dx12Resource->GetDX12Resource();
// NOTE: Don't know MapType, can't optimize writeRange!
AZ_Assert(!D3D12IsLayoutOpaque(resource.GetDesc().Layout), "Opaque layouts are unmappable until 12.2!");
dx12Resource->GetD3D12Resource()->Unmap(Subresource, NULL);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::PSSetConstantBuffers(
_In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) UINT NumBuffers,
_In_reads_opt_(NumBuffers) ID3D11Buffer* const* ppConstantBuffers)
{
PSSetConstantBuffers1(StartSlot, NumBuffers, ppConstantBuffers, NULL, NULL);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::IASetInputLayout(
_In_opt_ ID3D11InputLayout* pInputLayout)
{
DX12_FUNC_LOG
m_PipelineState[DX12::CommandModeGraphics].InputAssembler.InputLayout.Set(reinterpret_cast<CCryDX12InputLayout*>(pInputLayout));
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::IASetVertexBuffers(
_In_range_(0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumBuffers,
_In_reads_opt_(NumBuffers) ID3D11Buffer* const* ppVertexBuffers,
_In_reads_opt_(NumBuffers) const UINT* pStrides,
_In_reads_opt_(NumBuffers) const UINT* pOffsets)
{
DX12_FUNC_LOG
auto& inputAssembler = m_PipelineState[DX12::CommandModeGraphics].InputAssembler;
for (UINT i = StartSlot, S = StartSlot + NumBuffers; i < S; ++i, ++ppVertexBuffers, ++pStrides, ++pOffsets)
{
CCryDX12Buffer* vb = reinterpret_cast<CCryDX12Buffer*>(*ppVertexBuffers);
inputAssembler.Strides.Set(i, *pStrides);
inputAssembler.Offsets.Set(i, *pOffsets);
if (inputAssembler.VertexBuffers.Set(i, vb) && vb)
{
vb->BeginResourceStateTransition(m_DirectCommandList.get(), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
}
}
UINT numVertexBuffers = 0;
for (UINT i = 0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; ++i)
{
if (inputAssembler.VertexBuffers.Get(i))
{
numVertexBuffers = i + 1;
}
}
inputAssembler.NumVertexBuffers.Set(numVertexBuffers);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::IASetIndexBuffer(
_In_opt_ ID3D11Buffer* pIndexBuffer,
_In_ DXGI_FORMAT Format,
_In_ UINT Offset)
{
DX12_FUNC_LOG
auto& inputAssembler = m_PipelineState[DX12::CommandModeGraphics].InputAssembler;
CCryDX12Buffer* ib = reinterpret_cast<CCryDX12Buffer*>(pIndexBuffer);
inputAssembler.IndexBufferFormat.Set(Format);
inputAssembler.IndexBufferOffset.Set(Offset);
if (inputAssembler.IndexBuffer.Set(ib) && ib)
{
ib->BeginResourceStateTransition(m_DirectCommandList.get(), D3D12_RESOURCE_STATE_INDEX_BUFFER);
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DrawIndexedInstanced(
_In_ UINT IndexCountPerInstance,
_In_ UINT InstanceCount,
_In_ UINT StartIndexLocation,
_In_ INT BaseVertexLocation,
_In_ UINT StartInstanceLocation)
{
DX12_FUNC_LOG
SubmitCopyCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
if (PrepareGraphicsState())
{
m_DirectCommandList->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation);
#ifdef AZ_DEBUG_BUILD
m_PipelineState[DX12::CommandModeGraphics].DebugPrint();
#endif
if constexpr (DX12_SUBMISSION_MODE <= DX12_SUBMISSION_PERDRAW)
{
if (m_OutstandingQueries == 0)
{
SubmitDirectCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
}
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DrawInstanced(
_In_ UINT VertexCountPerInstance,
_In_ UINT InstanceCount,
_In_ UINT StartVertexLocation,
_In_ UINT StartInstanceLocation)
{
DX12_FUNC_LOG
SubmitCopyCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
if (PrepareGraphicsState())
{
m_DirectCommandList->DrawInstanced(VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation);
#ifdef AZ_DEBUG_BUILD
m_PipelineState[DX12::CommandModeGraphics].DebugPrint();
#endif
if constexpr (DX12_SUBMISSION_MODE <= DX12_SUBMISSION_PERDRAW)
{
if (m_OutstandingQueries == 0)
{
SubmitDirectCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
}
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::GSSetConstantBuffers(
_In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) UINT NumBuffers,
_In_reads_opt_(NumBuffers) ID3D11Buffer* const* ppConstantBuffers)
{
GSSetConstantBuffers1(StartSlot, NumBuffers, ppConstantBuffers, NULL, NULL);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::GSSetShader(
_In_opt_ ID3D11GeometryShader* pShader,
[[maybe_unused]] _In_reads_opt_(NumClassInstances) ID3D11ClassInstance* const* ppClassInstances,
[[maybe_unused]] UINT NumClassInstances)
{
DX12_FUNC_LOG
m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Geometry].Shader.Set(reinterpret_cast<CCryDX12Shader*>(pShader));
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::IASetPrimitiveTopology(
_In_ D3D11_PRIMITIVE_TOPOLOGY Topology)
{
DX12_FUNC_LOG
m_PipelineState[DX12::CommandModeGraphics].InputAssembler.PrimitiveTopology.Set(Topology);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::VSSetShaderResources(
_In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumViews,
_In_reads_opt_(NumViews) ID3D11ShaderResourceView* const* ppShaderResourceViews)
{
DX12_FUNC_LOG
for (UINT i = StartSlot, S = StartSlot + NumViews; i < S; ++i, ++ppShaderResourceViews)
{
CCryDX12ShaderResourceView* srv = reinterpret_cast<CCryDX12ShaderResourceView*>(*ppShaderResourceViews);
if (m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Vertex].ShaderResourceViews.Set(i, srv) && srv)
{
srv->BeginResourceStateTransition(m_DirectCommandList.get());
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::VSSetSamplers(
_In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) UINT NumSamplers,
_In_reads_opt_(NumSamplers) ID3D11SamplerState* const* ppSamplers)
{
DX12_FUNC_LOG
for (UINT i = StartSlot, S = StartSlot + NumSamplers; i < S; ++i, ++ppSamplers)
{
m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Vertex].SamplerState.Set(i, reinterpret_cast<CCryDX12SamplerState*>(*ppSamplers));
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::Begin(
_In_ ID3D11Asynchronous* pAsync)
{
DX12_FUNC_LOG
auto pQuery = reinterpret_cast<CCryDX12Query*>(pAsync);
D3D11_QUERY_DESC desc;
pQuery->GetDesc(&desc);
if (desc.Query == D3D11_QUERY_EVENT)
{
return;
}
else if (desc.Query == D3D11_QUERY_TIMESTAMP_DISJOINT)
{
return;
}
else if (desc.Query == D3D11_QUERY_TIMESTAMP)
{
return;
}
else if (desc.Query == D3D11_QUERY_OCCLUSION || desc.Query == D3D11_QUERY_OCCLUSION_PREDICATE)
{
auto pOcclusionQuery = reinterpret_cast<CCryDX12ResourceQuery*>(pAsync);
pOcclusionQuery->SetFenceValue(m_CmdFenceSet.GetCurrentValue(CMDQUEUE_GRAPHICS));
pOcclusionQuery->SetQueryIndex(OcclusionIndex(m_DirectCommandList, desc.Query == D3D11_QUERY_OCCLUSION));
++m_OutstandingQueries;
}
else
{
__debugbreak();
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::End(
_In_ ID3D11Asynchronous* pAsync)
{
DX12_FUNC_LOG
auto pQuery = reinterpret_cast<CCryDX12Query*>(pAsync);
D3D11_QUERY_DESC desc;
pQuery->GetDesc(&desc);
if (desc.Query == D3D11_QUERY_EVENT)
{
// Record fence of commands prior to this point
auto pEventQuery = reinterpret_cast<CCryDX12EventQuery*>(pAsync);
pEventQuery->SetFenceValue(InsertFence());
}
else if (desc.Query == D3D11_QUERY_TIMESTAMP_DISJOINT)
{
return;
}
else if (desc.Query == D3D11_QUERY_TIMESTAMP)
{
// Record fence of commands following at this point
auto pTimestampQuery = reinterpret_cast<CCryDX12ResourceQuery*>(pAsync);
pTimestampQuery->SetFenceValue(InsertFence());
pTimestampQuery->SetQueryIndex(TimestampIndex(m_DirectCommandList));
pTimestampQuery->SetQueryResource(QueryTimestamp(m_DirectCommandList, pTimestampQuery->GetQueryIndex()));
}
else if (desc.Query == D3D11_QUERY_OCCLUSION)
{
auto pOcclusionQuery = reinterpret_cast<CCryDX12ResourceQuery*>(pAsync);
pOcclusionQuery->SetFenceValue(InsertFence());
pOcclusionQuery->SetQueryResource(QueryOcclusion(m_DirectCommandList, pOcclusionQuery->GetQueryIndex(), desc.Query == D3D11_QUERY_OCCLUSION));
AZ_Assert(m_OutstandingQueries != 0, "End without a Start");
--m_OutstandingQueries;
}
else // || desc.Query == D3D11_QUERY_OCCLUSION_PREDICATE)
{
__debugbreak();
}
}
HRESULT STDMETHODCALLTYPE CCryDX12DeviceContext::GetData(
_In_ ID3D11Asynchronous* pAsync,
_Out_writes_bytes_opt_(DataSize) void* pData,
[[maybe_unused]] _In_ UINT DataSize,
_In_ UINT GetDataFlags)
{
DX12_FUNC_LOG
auto pQuery = reinterpret_cast<CCryDX12Query*>(pAsync);
D3D11_QUERY_DESC desc;
pQuery->GetDesc(&desc);
if (desc.Query == D3D11_QUERY_EVENT)
{
AZ_Assert(DataSize >= sizeof(BOOL), "Invalid data size");
auto pEventQuery = reinterpret_cast<CCryDX12EventQuery*>(pAsync);
bool bComplete = TestForFence(pEventQuery->GetFenceValue()) == S_OK;
if (!bComplete && !(GetDataFlags & D3D11_ASYNC_GETDATA_DONOTFLUSH))
{
// Ensure the command-list issuing the query is executed
SubmitDirectCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC, pEventQuery->GetFenceValue());
FlushToFence(pEventQuery->GetFenceValue());
}
return (*reinterpret_cast<BOOL*>(pData) = bComplete) ? S_OK : S_FALSE;
}
else if (desc.Query == D3D11_QUERY_TIMESTAMP_DISJOINT)
{
AZ_Assert(DataSize >= sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT), "Invalid data size");
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT sData;
// D3D12 WARNING: ID3D12CommandQueue::ID3D12CommandQueue::GetTimestampFrequency: Use
// ID3D12Device::SetStablePowerstate for reliable timestamp queries [ EXECUTION WARNING #736: UNSTABLE_POWER_STATE]
sData.Disjoint = FALSE;
sData.Frequency = m_pDX12Device->GetGpuTimestampFrequency();
*reinterpret_cast<D3D11_QUERY_DATA_TIMESTAMP_DISJOINT*>(pData) = sData;
return S_OK;
}
else if (desc.Query == D3D11_QUERY_TIMESTAMP)
{
AZ_Assert(DataSize >= sizeof(UINT64), "Invalid data size");
auto pTimestampQuery = reinterpret_cast<CCryDX12ResourceQuery*>(pAsync);
bool bComplete = TestForFence(pTimestampQuery->GetFenceValue()) == S_OK;
if (!bComplete && !(GetDataFlags & D3D11_ASYNC_GETDATA_DONOTFLUSH))
{
// Ensure the command-list issuing the timestamp is executed
SubmitDirectCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC, pTimestampQuery->GetFenceValue());
FlushToFence(pTimestampQuery->GetFenceValue());
}
// Since we do FlushToFence if not completed, it will be completed now.
ResolveTimestamp(m_DirectCommandList, pTimestampQuery->GetQueryIndex(), pData);
return S_OK;
}
else if (desc.Query == D3D11_QUERY_OCCLUSION)
{
AZ_Assert(DataSize >= sizeof(UINT64), "Invalid data size");
auto pOcclusionQuery = reinterpret_cast<CCryDX12ResourceQuery*>(pAsync);
bool bComplete = TestForFence(pOcclusionQuery->GetFenceValue()) == S_OK;
if (!bComplete && !(GetDataFlags & D3D11_ASYNC_GETDATA_DONOTFLUSH))
{
// Ensure the command-list issuing the query is executed
SubmitDirectCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC, pOcclusionQuery->GetFenceValue());
FlushToFence(pOcclusionQuery->GetFenceValue());
}
if (bComplete)
{
ResolveOcclusion(m_DirectCommandList, pOcclusionQuery->GetQueryIndex(), pData);
}
return (bComplete) ? S_OK : S_FALSE;
}
else // || desc.Query == D3D11_QUERY_OCCLUSION_PREDICATE
{
__debugbreak();
}
return S_OK;
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::SetPredication(
[[maybe_unused]] _In_opt_ ID3D11Predicate* pPredicate,
[[maybe_unused]] _In_ BOOL PredicateValue)
{
DX12_FUNC_LOG
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::GSSetShaderResources(
_In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumViews,
_In_reads_opt_(NumViews) ID3D11ShaderResourceView* const* ppShaderResourceViews)
{
DX12_FUNC_LOG
auto& geometry = m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Geometry];
for (UINT i = StartSlot, S = StartSlot + NumViews; i < S; ++i, ++ppShaderResourceViews)
{
CCryDX12ShaderResourceView* srv = reinterpret_cast<CCryDX12ShaderResourceView*>(*ppShaderResourceViews);
if (geometry.ShaderResourceViews.Set(i, srv) && srv)
{
srv->BeginResourceStateTransition(m_DirectCommandList.get());
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::GSSetSamplers(
_In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) UINT NumSamplers,
_In_reads_opt_(NumSamplers) ID3D11SamplerState* const* ppSamplers)
{
DX12_FUNC_LOG
auto& geometry = m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Geometry];
for (UINT i = StartSlot, S = StartSlot + NumSamplers; i < S; ++i, ++ppSamplers)
{
geometry.SamplerState.Set(i, reinterpret_cast<CCryDX12SamplerState*>(*ppSamplers));
}
}
static void ValidateSwapChain([[maybe_unused]] CCryDX12RenderTargetView& rtv)
{
#if defined(DEBUG)
if (DX12::SwapChain* swapChain = rtv.GetDX12Resource().GetDX12SwapChain())
{
AZ_Assert(swapChain->GetCurrentBackBuffer().GetD3D12Resource() == rtv.GetDX12Resource().GetD3D12Resource(), "invalid swap chain buffer");
}
#endif
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::OMSetRenderTargets(
_In_range_(0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT) UINT NumViews,
_In_reads_opt_(NumViews) ID3D11RenderTargetView* const* ppRenderTargetViews,
_In_opt_ ID3D11DepthStencilView* pDepthStencilView)
{
DX12_FUNC_LOG
auto& outputMerger = m_PipelineState[DX12::CommandModeGraphics].OutputMerger;
outputMerger.NumRenderTargets.Set(NumViews);
for (UINT i = 0; i < NumViews; ++i)
{
CCryDX12RenderTargetView* rtv = reinterpret_cast<CCryDX12RenderTargetView*>(ppRenderTargetViews[i]);
if (outputMerger.RenderTargetViews.Set(i, rtv))
{
if (!rtv)
{
outputMerger.RTVFormats.Set(i, DXGI_FORMAT_UNKNOWN);
continue;
}
ValidateSwapChain(*rtv);
DX12_LOG("Setting render target: %p (%d)", rtv, i);
// TODO: this might not be the earliest moment when it is known that the resource is used as render-target
D3D11_RENDER_TARGET_VIEW_DESC desc;
rtv->GetDesc(&desc);
rtv->BeginResourceStateTransition(m_DirectCommandList.get());
outputMerger.RTVFormats.Set(i, desc.Format);
}
}
for (UINT i = NumViews; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
{
outputMerger.RenderTargetViews.Set(i, nullptr);
outputMerger.RTVFormats.Set(i, DXGI_FORMAT_UNKNOWN);
}
{
CCryDX12DepthStencilView* dsv = reinterpret_cast<CCryDX12DepthStencilView*>(pDepthStencilView);
if (outputMerger.DepthStencilView.Set(dsv))
{
if (!dsv)
{
outputMerger.DSVFormat.Set(DXGI_FORMAT_UNKNOWN);
return;
}
DX12_LOG("Setting depth stencil view: %p", dsv);
// TODO: this might not be the earliest moment when it is known that the resource is used as depth-stencil
D3D11_DEPTH_STENCIL_VIEW_DESC desc;
dsv->GetDesc(&desc);
dsv->BeginResourceStateTransition(m_DirectCommandList.get());
outputMerger.DSVFormat.Set(desc.Format);
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews(
_In_ UINT NumRTVs,
[[maybe_unused]] _In_reads_opt_(NumRTVs) ID3D11RenderTargetView* const* ppRenderTargetViews,
[[maybe_unused]] _In_opt_ ID3D11DepthStencilView* pDepthStencilView,
_In_range_(0, D3D11_1_UAV_SLOT_COUNT - 1) UINT UAVStartSlot,
_In_ UINT NumUAVs,
_In_reads_opt_(NumUAVs) ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
[[maybe_unused]] _In_reads_opt_(NumUAVs) const UINT* pUAVInitialCounts)
{
DX12_FUNC_LOG
if (NumRTVs > 0 && NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL)
{
DX12_NOT_IMPLEMENTED //@TODO: Only the Unordered Access View portion of this function is implemented.
}
auto& graphicsStage = m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Pixel];
for (UINT i = UAVStartSlot, S = UAVStartSlot + NumUAVs; i < S; ++i, ++ppUnorderedAccessViews)
{
CCryDX12UnorderedAccessView* uav = reinterpret_cast<CCryDX12UnorderedAccessView*>(*ppUnorderedAccessViews);
if (graphicsStage.UnorderedAccessViews.Set(i, uav) && uav)
{
uav->BeginResourceStateTransition(m_DirectCommandList.get());
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::OMSetBlendState(
_In_opt_ ID3D11BlendState* pBlendState,
[[maybe_unused]] _In_opt_ const FLOAT BlendFactor[4],
_In_ UINT SampleMask)
{
DX12_FUNC_LOG
auto& outputMerger = m_PipelineState[DX12::CommandModeGraphics].OutputMerger;
outputMerger.BlendState.Set(reinterpret_cast<CCryDX12BlendState*>(pBlendState));
outputMerger.SampleMask.Set(SampleMask);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::OMSetDepthStencilState(
_In_opt_ ID3D11DepthStencilState* pDepthStencilState,
_In_ UINT StencilRef)
{
DX12_FUNC_LOG
auto& state = m_PipelineState[DX12::CommandModeGraphics];
state.Rasterizer.DepthStencilState.Set(reinterpret_cast<CCryDX12DepthStencilState*>(pDepthStencilState));
state.OutputMerger.StencilRef.Set(StencilRef);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::SOSetTargets(
[[maybe_unused]] _In_range_(0, D3D11_SO_BUFFER_SLOT_COUNT) UINT NumBuffers,
[[maybe_unused]] _In_reads_opt_(NumBuffers) ID3D11Buffer* const* ppSOTargets,
[[maybe_unused]] _In_reads_opt_(NumBuffers) const UINT* pOffsets)
{
DX12_FUNC_LOG
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DrawAuto()
{
DX12_FUNC_LOG
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DrawIndexedInstancedIndirect(
[[maybe_unused]] _In_ ID3D11Buffer* pBufferForArgs,
[[maybe_unused]] _In_ UINT AlignedByteOffsetForArgs)
{
DX12_FUNC_LOG
DX12_ASSERT(false, "unimplemented");
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DrawInstancedIndirect(
[[maybe_unused]] _In_ ID3D11Buffer* pBufferForArgs,
[[maybe_unused]] _In_ UINT AlignedByteOffsetForArgs)
{
DX12_FUNC_LOG
DX12_ASSERT(false, "unimplemented");
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::Dispatch(
_In_ UINT ThreadGroupCountX,
_In_ UINT ThreadGroupCountY,
_In_ UINT ThreadGroupCountZ)
{
DX12_FUNC_LOG
SubmitCopyCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
if (PrepareComputeState())
{
m_DirectCommandList->Dispatch(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ);
#ifdef AZ_DEBUG_BUILD
m_PipelineState[DX12::CommandModeCompute].DebugPrint();
#endif
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DispatchIndirect(
[[maybe_unused]] _In_ ID3D11Buffer* pBufferForArgs,
[[maybe_unused]] _In_ UINT AlignedByteOffsetForArgs)
{
DX12_FUNC_LOG
DX12_ASSERT(false, "unimplemented");
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::RSSetState(
_In_opt_ ID3D11RasterizerState* pRasterizerState)
{
DX12_FUNC_LOG
auto& rasterizer = m_PipelineState[DX12::CommandModeGraphics].Rasterizer;
rasterizer.RasterizerState.Set(reinterpret_cast<CCryDX12RasterizerState*>(pRasterizerState));
if (pRasterizerState)
{
const D3D11_RASTERIZER_DESC& d3d11Desc = rasterizer.RasterizerState->GetD3D11RasterizerDesc();
rasterizer.ScissorEnabled.Set(d3d11Desc.ScissorEnable);
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::RSSetViewports(
_In_range_(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT NumViewports,
_In_reads_opt_(NumViewports) const D3D11_VIEWPORT* pViewports)
{
DX12_FUNC_LOG
auto& rasterizer = m_PipelineState[DX12::CommandModeGraphics].Rasterizer;
rasterizer.NumViewports.Set(NumViewports);
if (NumViewports)
{
for (UINT i = 0; i < NumViewports; ++i, ++pViewports)
{
rasterizer.Viewports.Set(i, *pViewports);
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::RSSetScissorRects(
_In_range_(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT NumRects,
_In_reads_opt_(NumRects) const D3D11_RECT* pRects)
{
DX12_FUNC_LOG
auto& rasterizer = m_PipelineState[DX12::CommandModeGraphics].Rasterizer;
rasterizer.NumScissors.Set(NumRects);
if (NumRects)
{
for (UINT i = 0; i < NumRects; ++i, ++pRects)
{
rasterizer.Scissors.Set(i, *pRects);
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CopySubresourceRegion(
_In_ ID3D11Resource* pDstResource,
_In_ UINT DstSubresource,
_In_ UINT DstX,
_In_ UINT DstY,
_In_ UINT DstZ,
_In_ ID3D11Resource* pSrcResource,
_In_ UINT SrcSubresource,
_In_opt_ const D3D11_BOX* pSrcBox)
{
DX12_FUNC_LOG
CopySubresourceRegion1(
pDstResource,
DstSubresource,
DstX,
DstY,
DstZ,
pSrcResource,
SrcSubresource,
pSrcBox,
0);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CopyResource(
_In_ ID3D11Resource* pDstResource,
_In_ ID3D11Resource* pSrcResource)
{
DX12_FUNC_LOG
CopyResource1(
pDstResource,
pSrcResource,
0);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::UploadResource(
_In_ ICryDX12Resource* pDstResource,
_In_ const D3D11_SUBRESOURCE_DATA* pInitialData,
_In_ size_t numInitialData)
{
DX12_FUNC_LOG
AZ_TRACE_METHOD();
ID3D12Resource* pDstResource12 = pDstResource->GetD3D12Resource();
DX12::Resource& dstResource = pDstResource->GetDX12Resource();
DX12::Resource::InitialData* id = dstResource.GetOrCreateInitialData();
D3D12_RESOURCE_DESC desc = dstResource.GetDesc();
const UINT maxSubResource = 64;
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layouts[maxSubResource];
UINT nRows[maxSubResource];
UINT64 rowSizes[maxSubResource];
CRY_ASSERT(numInitialData <= maxSubResource);
dstResource.GetDevice()->GetD3D12Device()->GetCopyableFootprints(&desc, 0, numInitialData, 0, layouts, nRows, rowSizes, &id->m_UploadSize);
id->m_SubResourceData.resize(numInitialData);
//Manually compute id->m_Size. This number is used to figure out the size of the intermediate CPU/GPU buffer into which the texture data is copied.
//The reason for doing this manually is because pTotalBytes (set by GetCopyableFootprints) is not completely accurate. For some reason it
//seems like it doesnt take into account the 256 byte alignment padding of the last mip of a texture. Hence manually calculating the size
//using the pNumRows (in this case nRows) and pRowSizeInBytes (in this case rowSizes).
UINT64 totalBufferSize = 0;
for (UINT i = 0; i < numInitialData; ++i)
{
D3D12_SUBRESOURCE_DATA initialDestData;
initialDestData.RowPitch = pInitialData[i].SysMemPitch;
initialDestData.SlicePitch = pInitialData[i].SysMemSlicePitch;
UINT64 slicePitchSize = 0;
slicePitchSize = pInitialData[i].SysMemSlicePitch * desc.DepthOrArraySize; // Exact size of the texture data. No padding.
//TODO: pInitialData[i].SysMemSlicePitch can be 0 if the texture loading code doesnt set it. Fix this. For now we just query the GPU for the size (which is padded and wastes memory).
if (slicePitchSize == 0)
{
slicePitchSize = dstResource.GetRequiredUploadSize(i, 1);
}
BYTE* destMemory = new uint8_t[slicePitchSize];
UINT gpuSlicePitchSize = layouts[i].Footprint.RowPitch * nRows[i];
D3D12_MEMCPY_DEST destData = { destMemory, layouts[i].Footprint.RowPitch, gpuSlicePitchSize };
const BYTE* pSrc = static_cast<const BYTE*> (pInitialData[i].pSysMem);
for (UINT z = 0; z < layouts[i].Footprint.Depth; ++z)
{
BYTE* pDestSlice = static_cast<BYTE*> (destData.pData) + pInitialData[i].SysMemSlicePitch * z;
const BYTE* pSrcSlice = pSrc + pInitialData[i].SysMemSlicePitch * z;
for (UINT y = 0; y < nRows[i]; ++y)
{
memcpy(pDestSlice + pInitialData[i].SysMemPitch * y,
pSrcSlice + pInitialData[i].SysMemPitch * y,
pInitialData[i].SysMemPitch);
}
}
initialDestData.pData = destMemory;
id->m_SubResourceData[i] = initialDestData;
totalBufferSize += gpuSlicePitchSize;
}
id->m_Size = totalBufferSize;
UploadResource(&dstResource, id);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::UploadResource(
[[maybe_unused]] _In_ DX12::Resource* pDstResource,
[[maybe_unused]] _In_ const DX12::Resource::InitialData* pSrcData)
{
DX12_FUNC_LOG
// TODO: This needs to be thread-safe
// pDstResource->InitDeferred(m_pGraphicsCmdList);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::UpdateSubresource(
_In_ ID3D11Resource* pDstResource,
_In_ UINT DstSubresource,
_In_opt_ const D3D11_BOX* pDstBox,
_In_ const void* pSrcData,
_In_ UINT SrcRowPitch,
_In_ UINT SrcDepthPitch)
{
DX12_FUNC_LOG
UpdateSubresource1(
pDstResource,
DstSubresource,
pDstBox,
pSrcData,
SrcRowPitch,
SrcDepthPitch,
0);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CopyStructureCount(
[[maybe_unused]] _In_ ID3D11Buffer* pDstBuffer,
[[maybe_unused]] _In_ UINT DstAlignedByteOffset,
[[maybe_unused]] _In_ ID3D11UnorderedAccessView* pSrcView)
{
DX12_FUNC_LOG
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::ClearRenderTargetView(
_In_ ID3D11RenderTargetView* pRenderTargetView,
_In_ const FLOAT ColorRGBA[4])
{
DX12_FUNC_LOG
DX12::ResourceView* view = DX12_EXTRACT_DX12VIEW(pRenderTargetView);
CCryDX12RenderTargetView* rtv = reinterpret_cast<CCryDX12RenderTargetView*>(pRenderTargetView);
DX12_LOG("Clearing render target view: %p %s", pRenderTargetView, rtv->GetResourceName().c_str());
ValidateSwapChain(*rtv);
m_DirectCommandList->ClearRenderTargetView(*view, ColorRGBA);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::ClearUnorderedAccessViewUint(
_In_ ID3D11UnorderedAccessView* pUnorderedAccessView,
_In_ const UINT Values[4])
{
DX12_FUNC_LOG
DX12::ResourceView* view = DX12_EXTRACT_DX12VIEW(pUnorderedAccessView);
CCryDX12UnorderedAccessView* uav = reinterpret_cast<CCryDX12UnorderedAccessView*>(pUnorderedAccessView);
DX12_LOG("Clearing unordered access view [int]: %p %s", pUnorderedAccessView, uav->GetResourceName().c_str());
m_DirectCommandList->ClearUnorderedAccessView(*view, Values);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::ClearUnorderedAccessViewFloat(
_In_ ID3D11UnorderedAccessView* pUnorderedAccessView,
_In_ const FLOAT Values[4])
{
DX12_FUNC_LOG
DX12::ResourceView* view = DX12_EXTRACT_DX12VIEW(pUnorderedAccessView);
CCryDX12UnorderedAccessView* uav = reinterpret_cast<CCryDX12UnorderedAccessView*>(pUnorderedAccessView);
DX12_LOG("Clearing unordered access view [float]: %p %s", pUnorderedAccessView, uav->GetResourceName().c_str());
m_DirectCommandList->ClearUnorderedAccessView(*view, Values);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::ClearDepthStencilView(
_In_ ID3D11DepthStencilView* pDepthStencilView,
_In_ UINT ClearFlags, // DX11 and DX12 clear flags are identical
_In_ FLOAT Depth,
_In_ UINT8 Stencil)
{
DX12_FUNC_LOG
DX12::ResourceView* view = DX12_EXTRACT_DX12VIEW(pDepthStencilView);
CCryDX12DepthStencilView* dsv = reinterpret_cast<CCryDX12DepthStencilView*>(pDepthStencilView);
DX12_LOG("Clearing depth stencil view: %p %s", pDepthStencilView, dsv->GetResourceName().c_str());
m_DirectCommandList->ClearDepthStencilView(*view, D3D12_CLEAR_FLAGS(ClearFlags), Depth, Stencil);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::GenerateMips(
[[maybe_unused]] _In_ ID3D11ShaderResourceView* pShaderResourceView)
{
DX12_FUNC_LOG
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::SetResourceMinLOD(
[[maybe_unused]] _In_ ID3D11Resource* pResource,
[[maybe_unused]] FLOAT MinLOD)
{
DX12_FUNC_LOG
}
FLOAT STDMETHODCALLTYPE CCryDX12DeviceContext::GetResourceMinLOD(
[[maybe_unused]] _In_ ID3D11Resource* pResource)
{
DX12_FUNC_LOG
return 0.0f;
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::ResolveSubresource(
[[maybe_unused]] _In_ ID3D11Resource* pDstResource,
[[maybe_unused]] _In_ UINT DstSubresource,
[[maybe_unused]] _In_ ID3D11Resource* pSrcResource,
[[maybe_unused]] _In_ UINT SrcSubresource,
[[maybe_unused]] _In_ DXGI_FORMAT Format)
{
DX12_FUNC_LOG
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::HSSetShaderResources(
_In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumViews,
_In_reads_opt_(NumViews) ID3D11ShaderResourceView* const* ppShaderResourceViews)
{
DX12_FUNC_LOG
for (UINT i = StartSlot, S = StartSlot + NumViews; i < S; ++i, ++ppShaderResourceViews)
{
CCryDX12ShaderResourceView* srv = reinterpret_cast<CCryDX12ShaderResourceView*>(*ppShaderResourceViews);
if (m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Hull].ShaderResourceViews.Set(i, srv) && srv)
{
srv->BeginResourceStateTransition(m_DirectCommandList.get());
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::HSSetShader(
_In_opt_ ID3D11HullShader* pHullShader,
[[maybe_unused]] _In_reads_opt_(NumClassInstances) ID3D11ClassInstance* const* ppClassInstances,
[[maybe_unused]] UINT NumClassInstances)
{
DX12_FUNC_LOG
m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Hull].Shader.Set(reinterpret_cast<CCryDX12Shader*>(pHullShader));
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::HSSetSamplers(
_In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) UINT NumSamplers,
_In_reads_opt_(NumSamplers) ID3D11SamplerState* const* ppSamplers)
{
DX12_FUNC_LOG
for (UINT i = StartSlot, S = StartSlot + NumSamplers; i < S; ++i, ++ppSamplers)
{
m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Hull].SamplerState.Set(i, reinterpret_cast<CCryDX12SamplerState*>(*ppSamplers));
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::HSSetConstantBuffers(
_In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) UINT NumBuffers,
_In_reads_opt_(NumBuffers) ID3D11Buffer* const* ppConstantBuffers)
{
HSSetConstantBuffers1(StartSlot, NumBuffers, ppConstantBuffers, NULL, NULL);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DSSetShaderResources(
_In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumViews,
_In_reads_opt_(NumViews) ID3D11ShaderResourceView* const* ppShaderResourceViews)
{
DX12_FUNC_LOG
for (UINT i = StartSlot, S = StartSlot + NumViews; i < S; ++i, ++ppShaderResourceViews)
{
CCryDX12ShaderResourceView* srv = reinterpret_cast<CCryDX12ShaderResourceView*>(*ppShaderResourceViews);
if (m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Domain].ShaderResourceViews.Set(i, srv) && srv)
{
srv->BeginResourceStateTransition(m_DirectCommandList.get());
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DSSetShader(
_In_opt_ ID3D11DomainShader* pDomainShader,
[[maybe_unused]] _In_reads_opt_(NumClassInstances) ID3D11ClassInstance* const* ppClassInstances,
[[maybe_unused]] UINT NumClassInstances)
{
DX12_FUNC_LOG
m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Domain].Shader.Set(reinterpret_cast<CCryDX12Shader*>(pDomainShader));
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DSSetSamplers(
_In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) UINT NumSamplers,
_In_reads_opt_(NumSamplers) ID3D11SamplerState* const* ppSamplers)
{
DX12_FUNC_LOG
for (UINT i = StartSlot, S = StartSlot + NumSamplers; i < S; ++i, ++ppSamplers)
{
m_PipelineState[DX12::CommandModeGraphics].Stages[DX12::ESS_Domain].SamplerState.Set(i, reinterpret_cast<CCryDX12SamplerState*>(*ppSamplers));
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DSSetConstantBuffers(
_In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) UINT NumBuffers,
_In_reads_opt_(NumBuffers) ID3D11Buffer* const* ppConstantBuffers)
{
DSSetConstantBuffers1(StartSlot, NumBuffers, ppConstantBuffers, NULL, NULL);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CSSetShaderResources(
_In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumViews,
_In_reads_opt_(NumViews) ID3D11ShaderResourceView* const* ppShaderResourceViews)
{
DX12_FUNC_LOG
auto& compute = m_PipelineState[DX12::CommandModeCompute].Stages[DX12::ESS_Compute];
for (UINT i = StartSlot, S = StartSlot + NumViews; i < S; ++i, ++ppShaderResourceViews)
{
CCryDX12ShaderResourceView* srv = reinterpret_cast<CCryDX12ShaderResourceView*>(*ppShaderResourceViews);
if (compute.ShaderResourceViews.Set(i, srv) && srv)
{
srv->BeginResourceStateTransition(m_DirectCommandList.get());
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CSSetUnorderedAccessViews(
_In_range_(0, D3D11_1_UAV_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_1_UAV_SLOT_COUNT - StartSlot) UINT NumUAVs,
_In_reads_opt_(NumUAVs) ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
[[maybe_unused]] _In_reads_opt_(NumUAVs) const UINT* pUAVInitialCounts)
{
DX12_FUNC_LOG
auto& compute = m_PipelineState[DX12::CommandModeCompute].Stages[DX12::ESS_Compute];
for (UINT i = StartSlot, S = StartSlot + NumUAVs; i < S; ++i, ++ppUnorderedAccessViews)
{
CCryDX12UnorderedAccessView* uav = reinterpret_cast<CCryDX12UnorderedAccessView*>(*ppUnorderedAccessViews);
if (compute.UnorderedAccessViews.Set(i, uav) && uav)
{
uav->BeginResourceStateTransition(m_DirectCommandList.get());
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CSSetShader(
_In_opt_ ID3D11ComputeShader* pComputeShader,
[[maybe_unused]] _In_reads_opt_(NumClassInstances) ID3D11ClassInstance* const* ppClassInstances,
[[maybe_unused]] UINT NumClassInstances)
{
DX12_FUNC_LOG
m_PipelineState[DX12::CommandModeCompute].Stages[DX12::ESS_Compute].Shader.Set(reinterpret_cast<CCryDX12Shader*>(pComputeShader));
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CSSetSamplers(
_In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) UINT NumSamplers,
_In_reads_opt_(NumSamplers) ID3D11SamplerState* const* ppSamplers)
{
DX12_FUNC_LOG
for (UINT i = StartSlot, S = StartSlot + NumSamplers; i < S; ++i, ++ppSamplers)
{
m_PipelineState[DX12::CommandModeCompute].Stages[DX12::ESS_Compute].SamplerState.Set(i, reinterpret_cast<CCryDX12SamplerState*>(*ppSamplers));
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CSSetConstantBuffers(
_In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) UINT StartSlot,
_In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) UINT NumBuffers,
_In_reads_opt_(NumBuffers) ID3D11Buffer* const* ppConstantBuffers)
{
CSSetConstantBuffers1(StartSlot, NumBuffers, ppConstantBuffers, NULL, NULL);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::VSGetConstantBuffers(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) UINT NumBuffers,
[[maybe_unused]] _Out_writes_opt_(NumBuffers) ID3D11Buffer** ppConstantBuffers)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::PSGetShaderResources(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumViews,
[[maybe_unused]] _Out_writes_opt_(NumViews) ID3D11ShaderResourceView** ppShaderResourceViews)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::PSGetShader(
[[maybe_unused]] _Out_ ID3D11PixelShader** ppPixelShader,
[[maybe_unused]] _Out_writes_opt_(*pNumClassInstances) ID3D11ClassInstance** ppClassInstances,
[[maybe_unused]] _Inout_opt_ UINT* pNumClassInstances)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::PSGetSamplers(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) UINT NumSamplers,
[[maybe_unused]] _Out_writes_opt_(NumSamplers) ID3D11SamplerState** ppSamplers)
{
DX12_FUNC_LOG
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::VSGetShader(
[[maybe_unused]] _Out_ ID3D11VertexShader** ppVertexShader,
[[maybe_unused]] _Out_writes_opt_(*pNumClassInstances) ID3D11ClassInstance** ppClassInstances,
[[maybe_unused]] _Inout_opt_ UINT* pNumClassInstances)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::PSGetConstantBuffers(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) UINT NumBuffers,
[[maybe_unused]] _Out_writes_opt_(NumBuffers) ID3D11Buffer** ppConstantBuffers)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::IAGetInputLayout(
_Out_ ID3D11InputLayout** ppInputLayout)
{
DX12_FUNC_LOG
*ppInputLayout = m_PipelineState[DX12::CommandModeGraphics].InputAssembler.InputLayout;
if (*ppInputLayout)
{
(*ppInputLayout)->AddRef();
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::IAGetVertexBuffers(
[[maybe_unused]] _In_range_(0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumBuffers,
[[maybe_unused]] _Out_writes_opt_(NumBuffers) ID3D11Buffer** ppVertexBuffers,
[[maybe_unused]] _Out_writes_opt_(NumBuffers) UINT* pStrides,
[[maybe_unused]] _Out_writes_opt_(NumBuffers) UINT* pOffsets)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::IAGetIndexBuffer(
_Out_opt_ ID3D11Buffer** pIndexBuffer,
_Out_opt_ DXGI_FORMAT* Format,
_Out_opt_ UINT* Offset)
{
DX12_FUNC_LOG
auto& inputAssembler = m_PipelineState[DX12::CommandModeGraphics].InputAssembler;
* pIndexBuffer = inputAssembler.IndexBuffer;
if (*pIndexBuffer)
{
(*pIndexBuffer)->AddRef();
}
*Format = inputAssembler.IndexBufferFormat.Get();
*Offset = inputAssembler.IndexBufferOffset.Get();
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::GSGetConstantBuffers(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) UINT NumBuffers,
[[maybe_unused]] _Out_writes_opt_(NumBuffers) ID3D11Buffer** ppConstantBuffers)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::GSGetShader(
[[maybe_unused]] _Out_ ID3D11GeometryShader** ppGeometryShader,
[[maybe_unused]] _Out_writes_opt_(*pNumClassInstances) ID3D11ClassInstance** ppClassInstances,
[[maybe_unused]] _Inout_opt_ UINT* pNumClassInstances)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::IAGetPrimitiveTopology(
_Out_ D3D11_PRIMITIVE_TOPOLOGY* pTopology)
{
DX12_FUNC_LOG
*pTopology = m_PipelineState[DX12::CommandModeGraphics].InputAssembler.PrimitiveTopology.Get();
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::VSGetShaderResources(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumViews,
[[maybe_unused]] _Out_writes_opt_(NumViews) ID3D11ShaderResourceView** ppShaderResourceViews)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::VSGetSamplers(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) UINT NumSamplers,
[[maybe_unused]] _Out_writes_opt_(NumSamplers) ID3D11SamplerState** ppSamplers)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::GetPredication(
[[maybe_unused]] _Out_opt_ ID3D11Predicate** ppPredicate,
[[maybe_unused]] _Out_opt_ BOOL* pPredicateValue)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::GSGetShaderResources(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumViews,
[[maybe_unused]] _Out_writes_opt_(NumViews) ID3D11ShaderResourceView** ppShaderResourceViews)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::GSGetSamplers(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) UINT NumSamplers,
[[maybe_unused]] _Out_writes_opt_(NumSamplers) ID3D11SamplerState** ppSamplers)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::OMGetRenderTargets(
[[maybe_unused]] _In_range_(0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT) UINT NumViews,
[[maybe_unused]] _Out_writes_opt_(NumViews) ID3D11RenderTargetView** ppRenderTargetViews,
[[maybe_unused]] _Out_opt_ ID3D11DepthStencilView** ppDepthStencilView)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::OMGetRenderTargetsAndUnorderedAccessViews(
[[maybe_unused]] _In_range_(0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT) UINT NumRTVs,
[[maybe_unused]] _Out_writes_opt_(NumRTVs) ID3D11RenderTargetView** ppRenderTargetViews,
[[maybe_unused]] _Out_opt_ ID3D11DepthStencilView** ppDepthStencilView,
[[maybe_unused]] _In_range_(0, D3D11_PS_CS_UAV_REGISTER_COUNT - 1) UINT UAVStartSlot,
[[maybe_unused]] _In_range_(0, D3D11_PS_CS_UAV_REGISTER_COUNT - UAVStartSlot) UINT NumUAVs,
[[maybe_unused]] _Out_writes_opt_(NumUAVs) ID3D11UnorderedAccessView** ppUnorderedAccessViews)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::OMGetBlendState(
[[maybe_unused]] _Out_opt_ ID3D11BlendState** ppBlendState,
[[maybe_unused]] _Out_opt_ FLOAT BlendFactor[4],
[[maybe_unused]] _Out_opt_ UINT* pSampleMask)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::OMGetDepthStencilState(
[[maybe_unused]] _Out_opt_ ID3D11DepthStencilState** ppDepthStencilState,
[[maybe_unused]] _Out_opt_ UINT* pStencilRef)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::SOGetTargets(
[[maybe_unused]] _In_range_(0, D3D11_SO_BUFFER_SLOT_COUNT) UINT NumBuffers,
[[maybe_unused]] _Out_writes_opt_(NumBuffers) ID3D11Buffer** ppSOTargets)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::RSGetState(
[[maybe_unused]] _Out_ ID3D11RasterizerState** ppRasterizerState)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::RSGetViewports(
[[maybe_unused]] _Inout_ UINT* pNumViewports,
[[maybe_unused]] _Out_writes_opt_(*pNumViewports) D3D11_VIEWPORT* pViewports)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::RSGetScissorRects(
[[maybe_unused]] _Inout_ UINT* pNumRects,
[[maybe_unused]] _Out_writes_opt_(*pNumRects) D3D11_RECT* pRects)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::HSGetShaderResources(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumViews,
[[maybe_unused]] _Out_writes_opt_(NumViews) ID3D11ShaderResourceView** ppShaderResourceViews)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::HSGetShader(
[[maybe_unused]] _Out_ ID3D11HullShader** ppHullShader,
[[maybe_unused]] _Out_writes_opt_(*pNumClassInstances) ID3D11ClassInstance** ppClassInstances,
[[maybe_unused]] _Inout_opt_ UINT* pNumClassInstances)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::HSGetSamplers(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) UINT NumSamplers,
[[maybe_unused]] _Out_writes_opt_(NumSamplers) ID3D11SamplerState** ppSamplers)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::HSGetConstantBuffers(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) UINT NumBuffers,
[[maybe_unused]] _Out_writes_opt_(NumBuffers) ID3D11Buffer** ppConstantBuffers)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DSGetShaderResources(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumViews,
[[maybe_unused]] _Out_writes_opt_(NumViews) ID3D11ShaderResourceView** ppShaderResourceViews)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DSGetShader(
[[maybe_unused]] _Out_ ID3D11DomainShader** ppDomainShader,
[[maybe_unused]] _Out_writes_opt_(*pNumClassInstances) ID3D11ClassInstance** ppClassInstances,
[[maybe_unused]] _Inout_opt_ UINT* pNumClassInstances)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DSGetSamplers(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) UINT NumSamplers,
[[maybe_unused]] _Out_writes_opt_(NumSamplers) ID3D11SamplerState** ppSamplers)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::DSGetConstantBuffers(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) UINT NumBuffers,
[[maybe_unused]] _Out_writes_opt_(NumBuffers) ID3D11Buffer** ppConstantBuffers)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CSGetShaderResources(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) UINT NumViews,
[[maybe_unused]] _Out_writes_opt_(NumViews) ID3D11ShaderResourceView** ppShaderResourceViews)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CSGetUnorderedAccessViews(
[[maybe_unused]] _In_range_(0, D3D11_PS_CS_UAV_REGISTER_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_PS_CS_UAV_REGISTER_COUNT - StartSlot) UINT NumUAVs,
[[maybe_unused]] _Out_writes_opt_(NumUAVs) ID3D11UnorderedAccessView** ppUnorderedAccessViews)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CSGetShader(
[[maybe_unused]] _Out_ ID3D11ComputeShader** ppComputeShader,
[[maybe_unused]] _Out_writes_opt_(*pNumClassInstances) ID3D11ClassInstance** ppClassInstances,
[[maybe_unused]] _Inout_opt_ UINT* pNumClassInstances)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CSGetSamplers(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) UINT NumSamplers,
[[maybe_unused]] _Out_writes_opt_(NumSamplers) ID3D11SamplerState** ppSamplers)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CSGetConstantBuffers(
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) UINT StartSlot,
[[maybe_unused]] _In_range_(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) UINT NumBuffers,
[[maybe_unused]] _Out_writes_opt_(NumBuffers) ID3D11Buffer** ppConstantBuffers)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::ClearState()
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::Flush()
{
DX12_FUNC_LOG
SubmitAllCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC, m_CmdFenceSet.GetCurrentValues());
}
D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE CCryDX12DeviceContext::GetType()
{
DX12_FUNC_LOG
return D3D11_DEVICE_CONTEXT_IMMEDIATE;
}
UINT STDMETHODCALLTYPE CCryDX12DeviceContext::GetContextFlags()
{
DX12_FUNC_LOG
return 0;
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::ExecuteCommandList(
[[maybe_unused]] _In_ ID3D11CommandList* pCommandList,
[[maybe_unused]] _In_ BOOL RestoreContextState)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
HRESULT STDMETHODCALLTYPE CCryDX12DeviceContext::FinishCommandList(
[[maybe_unused]] BOOL RestoreDeferredContextState,
[[maybe_unused]] _Out_opt_ ID3D11CommandList** ppCommandList)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
return E_FAIL;
}
#pragma endregion
#pragma region /* D3D 11.1 specific functions */
void STDMETHODCALLTYPE CCryDX12DeviceContext::CopySubresourceRegion1(
_In_ ID3D11Resource* pDstResource,
_In_ UINT DstSubresource,
_In_ UINT DstX,
_In_ UINT DstY,
_In_ UINT DstZ,
_In_ ID3D11Resource* pSrcResource,
_In_ UINT SrcSubresource,
_In_opt_ const D3D11_BOX* pSrcBox,
_In_ UINT CopyFlags)
{
DX12_FUNC_LOG
ICryDX12Resource* dstDX12Resource = DX12_EXTRACT_ICRYDX12RESOURCE(pDstResource);
ICryDX12Resource* srcDX12Resource = DX12_EXTRACT_ICRYDX12RESOURCE(pSrcResource);
DX12::Resource& dstResource = dstDX12Resource->GetDX12Resource();
DX12::Resource& srcResource = srcDX12Resource->GetDX12Resource();
// TODO: copy command on the swap chain are special (can't execute on any other queue), make an API for that
const bool bDirect = !m_bInCopyRegion;
DX12::CommandListPool& rCmdListPool = bDirect ? m_DirectListPool : m_CopyListPool;
DX12::CommandList* pCmdList = bDirect ? m_DirectCommandList : m_CopyCommandList;
// TODO: move into the command-list function
UINT64 maxFenceValues[CMDQUEUE_NUM];
switch (CopyFlags)
{
case D3D11_COPY_NO_OVERWRITE:
// If the resource is currently used, the flag lied!
AZ_Assert(!dstResource.IsUsed(rCmdListPool), "Destination resource is in use for non-discard copy!");
SubmitAllCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC,
srcResource.GetFenceValues(CMDTYPE_WRITE),
rCmdListPool.GetFenceID());
break;
default:
SubmitAllCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC, DX12::MaxFenceValues(
srcResource.GetFenceValues(CMDTYPE_WRITE),
dstResource.GetFenceValues(CMDTYPE_ANY),
maxFenceValues),
rCmdListPool.GetFenceID());
// Block the GPU-thread until the resource is safe to be updated (unlike Map() we stage the copy and don't need to block the CPU)
break;
}
D3D12_BOX box;
if (pSrcBox)
{
box.top = pSrcBox->top;
box.bottom = pSrcBox->bottom;
box.left = pSrcBox->left;
box.right = pSrcBox->right;
box.front = pSrcBox->front;
box.back = pSrcBox->back;
}
// TODO: copy from active render-target should be more elegant
if (m_DirectCommandList->IsUsedByOutputViews(srcResource) ||
m_DirectCommandList->IsUsedByOutputViews(dstResource))
{
// Make the render-targets rebind, so the resource-barrier is closed
m_PipelineState[DX12::CommandModeGraphics].m_StateFlags |= EPSPB_OutputResources;
}
AZ_Assert(dstResource.GetDX12SwapChain() == nullptr, "Can't copy to swap chain buffer");
pCmdList->CopySubresource(dstResource, DstSubresource, DstX, DstY, DstZ, srcResource, SrcSubresource, pSrcBox ? &box : NULL);
if constexpr (DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC)
{
if (!bDirect)
{
SubmitCopyCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
}
else
{
SubmitDirectCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::CopyResource1(
_In_ ID3D11Resource* pDstResource,
_In_ ID3D11Resource* pSrcResource,
_In_ UINT CopyFlags)
{
DX12_FUNC_LOG
AZ_TRACE_METHOD();
ICryDX12Resource* dstDX12Resource = DX12_EXTRACT_ICRYDX12RESOURCE(pDstResource);
ICryDX12Resource* srcDX12Resource = DX12_EXTRACT_ICRYDX12RESOURCE(pSrcResource);
DX12::Resource& dstResource = dstDX12Resource->GetDX12Resource();
DX12::Resource& srcResource = srcDX12Resource->GetDX12Resource();
const bool bDirect = !m_bInCopyRegion;
DX12::CommandListPool& rCmdListPool = bDirect ? m_DirectListPool : m_CopyListPool;
DX12::CommandList* pCmdList = bDirect ? m_DirectCommandList : m_CopyCommandList;
// TODO: move into the command-list function
UINT64 maxFenceValues[CMDQUEUE_NUM];
switch (CopyFlags)
{
case D3D11_COPY_NO_OVERWRITE:
// If the resource is currently used, the flag lied!
AZ_Assert(!dstResource.IsUsed(rCmdListPool), "Destination resource is in use for non-discard copy!");
SubmitAllCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC,
srcResource.GetFenceValues(CMDTYPE_WRITE),
rCmdListPool.GetFenceID());
break;
default:
SubmitAllCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC, DX12::MaxFenceValues(
srcResource.GetFenceValues(CMDTYPE_WRITE),
dstResource.GetFenceValues(CMDTYPE_ANY),
maxFenceValues),
rCmdListPool.GetFenceID());
// Block the GPU-thread until the resource is safe to be updated (unlike Map() we stage the update and don't need to block the CPU)
break;
}
// TODO: copy from active render-target should be more elegant
if (m_DirectCommandList->IsUsedByOutputViews(srcResource) ||
m_DirectCommandList->IsUsedByOutputViews(dstResource))
{
// Make the render-targets rebind, so the resource-barrier is closed
m_PipelineState[DX12::CommandModeGraphics].m_StateFlags |= EPSPB_OutputResources;
}
AZ_Assert(dstResource.GetDX12SwapChain() == nullptr, "Can't copy to swap chain buffer");
pCmdList->CopyResource(dstResource, srcResource);
if constexpr (DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC)
{
if (!bDirect)
{
SubmitCopyCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
}
else
{
SubmitDirectCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
}
}
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::UpdateSubresource1(
_In_ ID3D11Resource* pDstResource,
_In_ UINT DstSubresource,
_In_opt_ const D3D11_BOX* pDstBox,
_In_ const void* pSrcData,
_In_ UINT SrcRowPitch,
_In_ UINT SrcDepthPitch,
_In_ UINT CopyFlags)
{
DX12_FUNC_LOG
AZ_TRACE_METHOD();
ICryDX12Resource* dx12Resource = DX12_EXTRACT_ICRYDX12RESOURCE(pDstResource);
DX12::Resource& resource = dx12Resource->GetDX12Resource();
// TODO: copy command on the swap chain are special (can't execute on any other queue), make an API for that
const bool bDirect = !m_bInCopyRegion;
DX12::CommandListPool& rCmdListPool = bDirect ? m_DirectListPool : m_CopyListPool;
DX12::CommandList* pCmdList = bDirect ? m_DirectCommandList : m_CopyCommandList;
// TODO: move into the command-list function
switch (CopyFlags)
{
case D3D11_COPY_NO_OVERWRITE:
// If the resource is currently used, the flag lied!
AZ_Assert(!resource.IsUsed(rCmdListPool), "Destination resource is in use for non-discard copy!");
break;
default:
SubmitAllCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC, resource.GetFenceValues(CMDTYPE_ANY), rCmdListPool.GetFenceID());
// Block the GPU-thread until the resource is safe to be updated (unlike Map() we stage the update and don't need to block the CPU)
break;
}
D3D12_BOX box;
if (pDstBox)
{
box.top = pDstBox->top;
box.bottom = pDstBox->bottom;
box.left = pDstBox->left;
box.right = pDstBox->right;
box.front = pDstBox->front;
box.back = pDstBox->back;
}
// TODO: copy from active render-target should be more elegant
if (m_DirectCommandList->IsUsedByOutputViews(resource))
{
// Make the render-targets rebind, so the resource-barrier is closed
m_PipelineState[DX12::CommandModeGraphics].m_StateFlags |= EPSPB_OutputResources;
}
AZ_Assert(resource.GetDX12SwapChain() == nullptr, "Can't copy to swap chain buffer");
pCmdList->UpdateSubresourceRegion(resource, DstSubresource, pDstBox ? &box : NULL, pSrcData, SrcRowPitch, SrcDepthPitch);
if constexpr (DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC)
{
if (!bDirect)
{
SubmitCopyCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
}
else
{
SubmitDirectCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
}
}
}
void CCryDX12DeviceContext::DiscardResource(ID3D11Resource* pResource)
{
DX12_FUNC_LOG
ICryDX12Resource* dx12Resource = DX12_EXTRACT_ICRYDX12RESOURCE(pResource);
DX12::Resource& resource = dx12Resource->GetDX12Resource();
// Ensure the command-list using the resource is executed
SubmitDirectCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC,
resource.GetFenceValue(CMDQUEUE_GRAPHICS, CMDTYPE_ANY)
);
m_CopyCommandList->DiscardResource(resource, nullptr);
SubmitCopyCommands(DX12_SUBMISSION_MODE == DX12_SUBMISSION_SYNC);
}
void CCryDX12DeviceContext::DiscardView([[maybe_unused]] ID3D11View* pResourceView)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void CCryDX12DeviceContext::VSSetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants)
{
DX12_FUNC_LOG
SetConstantBuffers1(DX12::ESS_Vertex, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants, DX12::CommandModeGraphics);
}
void CCryDX12DeviceContext::HSSetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants)
{
DX12_FUNC_LOG
SetConstantBuffers1(DX12::ESS_Hull, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants, DX12::CommandModeGraphics);
}
void CCryDX12DeviceContext::DSSetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants)
{
DX12_FUNC_LOG
SetConstantBuffers1(DX12::ESS_Domain, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants, DX12::CommandModeGraphics);
}
void CCryDX12DeviceContext::GSSetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants)
{
DX12_FUNC_LOG
SetConstantBuffers1(DX12::ESS_Geometry, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants, DX12::CommandModeGraphics);
}
void CCryDX12DeviceContext::PSSetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants)
{
DX12_FUNC_LOG
SetConstantBuffers1(DX12::ESS_Pixel, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants, DX12::CommandModeGraphics);
}
void CCryDX12DeviceContext::CSSetConstantBuffers1(UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants)
{
DX12_FUNC_LOG
SetConstantBuffers1(DX12::ESS_Compute, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants, DX12::CommandModeCompute);
}
void CCryDX12DeviceContext::SetConstantBuffers1(
DX12::EShaderStage shaderStage,
UINT StartSlot,
UINT NumBuffers,
ID3D11Buffer* const* ppConstantBuffers,
const UINT* pFirstConstant,
const UINT* pNumConstants,
DX12::CommandMode commandMode)
{
auto& stage = m_PipelineState[commandMode].Stages[shaderStage];
for (UINT i = StartSlot, S = StartSlot + NumBuffers, j = 0; i < S; ++i, ++ppConstantBuffers, ++j)
{
CCryDX12Buffer* cb = reinterpret_cast<CCryDX12Buffer*>(*ppConstantBuffers);
TRange < UINT > bindRange;
if (pFirstConstant)
{
bindRange.start = pFirstConstant[j] * DX12::CONSTANT_BUFFER_ELEMENT_SIZE;
bindRange.end = bindRange.start + pNumConstants[j] * DX12::CONSTANT_BUFFER_ELEMENT_SIZE;
}
stage.ConstBufferBindRange.Set(i, bindRange);
if (stage.ConstantBufferViews.Set(i, cb) && cb)
{
cb->BeginResourceStateTransition(m_DirectCommandList, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
}
}
}
void CCryDX12DeviceContext::VSGetConstantBuffers1([[maybe_unused]] UINT StartSlot, [[maybe_unused]] UINT NumBuffers, [[maybe_unused]] ID3D11Buffer** ppConstantBuffers, [[maybe_unused]] UINT* pFirstConstant, [[maybe_unused]] UINT* pNumConstants)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void CCryDX12DeviceContext::HSGetConstantBuffers1([[maybe_unused]] UINT StartSlot, [[maybe_unused]] UINT NumBuffers, [[maybe_unused]] ID3D11Buffer** ppConstantBuffers, [[maybe_unused]] UINT* pFirstConstant, [[maybe_unused]] UINT* pNumConstants)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void CCryDX12DeviceContext::DSGetConstantBuffers1([[maybe_unused]] UINT StartSlot, [[maybe_unused]] UINT NumBuffers, [[maybe_unused]] ID3D11Buffer** ppConstantBuffers, [[maybe_unused]] UINT* pFirstConstant, [[maybe_unused]] UINT* pNumConstants)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void CCryDX12DeviceContext::GSGetConstantBuffers1([[maybe_unused]] UINT StartSlot, [[maybe_unused]] UINT NumBuffers, [[maybe_unused]] ID3D11Buffer** ppConstantBuffers, [[maybe_unused]] UINT* pFirstConstant, [[maybe_unused]] UINT* pNumConstants)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void CCryDX12DeviceContext::PSGetConstantBuffers1([[maybe_unused]] UINT StartSlot, [[maybe_unused]] UINT NumBuffers, [[maybe_unused]] ID3D11Buffer** ppConstantBuffers, [[maybe_unused]] UINT* pFirstConstant, [[maybe_unused]] UINT* pNumConstants)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void CCryDX12DeviceContext::CSGetConstantBuffers1([[maybe_unused]] UINT StartSlot, [[maybe_unused]] UINT NumBuffers, [[maybe_unused]] ID3D11Buffer** ppConstantBuffers, [[maybe_unused]] UINT* pFirstConstant, [[maybe_unused]] UINT* pNumConstants)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void CCryDX12DeviceContext::SwapDeviceContextState([[maybe_unused]] ID3DDeviceContextState* pState, [[maybe_unused]] ID3DDeviceContextState** ppPreviousState)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void CCryDX12DeviceContext::ClearView(ID3D11View* pView, const FLOAT Color[4], const D3D11_RECT* pRect, UINT NumRects)
{
DX12_FUNC_LOG
DX12_LOG("Clearing view: %p", pView);
DX12::ResourceView* view = DX12_EXTRACT_DX12VIEW(pView);
m_DirectCommandList->ClearView(*view, Color, NumRects, pRect);
}
void CCryDX12DeviceContext::DiscardView1([[maybe_unused]] ID3D11View* pResourceView, [[maybe_unused]] const D3D11_RECT* pRects, [[maybe_unused]] UINT NumRects)
{
DX12_FUNC_LOG
DX12_NOT_IMPLEMENTED
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::ClearRectsRenderTargetView(
_In_ ID3D11RenderTargetView* pRenderTargetView,
_In_ const FLOAT ColorRGBA[4],
_In_ UINT NumRects,
_In_reads_opt_(NumRects) const D3D11_RECT* pRects)
{
DX12_FUNC_LOG
DX12::ResourceView* view = DX12_EXTRACT_DX12VIEW(pRenderTargetView);
CCryDX12RenderTargetView* rtv = reinterpret_cast<CCryDX12RenderTargetView*>(pRenderTargetView);
DX12_LOG("Clearing render target view: %p %s", pRenderTargetView, rtv->GetResourceName().c_str());
m_DirectCommandList->ClearRenderTargetView(*view, ColorRGBA, NumRects, pRects);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::ClearRectsUnorderedAccessViewUint(
_In_ ID3D11UnorderedAccessView* pUnorderedAccessView,
_In_ const UINT Values[4],
_In_ UINT NumRects,
_In_reads_opt_(NumRects) const D3D11_RECT* pRects)
{
DX12_FUNC_LOG
DX12::ResourceView* view = DX12_EXTRACT_DX12VIEW(pUnorderedAccessView);
CCryDX12UnorderedAccessView* uav = reinterpret_cast<CCryDX12UnorderedAccessView*>(pUnorderedAccessView);
DX12_LOG("Clearing unordered access view [int]: %p %s", pUnorderedAccessView, uav->GetResourceName().c_str());
m_DirectCommandList->ClearUnorderedAccessView(*view, Values, NumRects, pRects);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::ClearRectsUnorderedAccessViewFloat(
_In_ ID3D11UnorderedAccessView* pUnorderedAccessView,
_In_ const FLOAT Values[4],
_In_ UINT NumRects,
_In_reads_opt_(NumRects) const D3D11_RECT* pRects)
{
DX12_FUNC_LOG
DX12::ResourceView* view = DX12_EXTRACT_DX12VIEW(pUnorderedAccessView);
CCryDX12UnorderedAccessView* uav = reinterpret_cast<CCryDX12UnorderedAccessView*>(pUnorderedAccessView);
DX12_LOG("Clearing unordered access view [float]: %p %s", pUnorderedAccessView, uav->GetResourceName().c_str());
m_DirectCommandList->ClearUnorderedAccessView(*view, Values, NumRects, pRects);
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::ClearRectsDepthStencilView(
_In_ ID3D11DepthStencilView* pDepthStencilView,
_In_ UINT ClearFlags, // DX11 and DX12 clear flags are identical
_In_ FLOAT Depth,
_In_ UINT8 Stencil,
_In_ UINT NumRects,
_In_reads_opt_(NumRects) const D3D11_RECT* pRects)
{
DX12_FUNC_LOG
DX12::ResourceView* view = DX12_EXTRACT_DX12VIEW(pDepthStencilView);
CCryDX12DepthStencilView* dsv = reinterpret_cast<CCryDX12DepthStencilView*>(pDepthStencilView);
DX12_LOG("Clearing depth stencil view: %p %s", pDepthStencilView, dsv->GetResourceName().c_str());
m_DirectCommandList->ClearDepthStencilView(*view, D3D12_CLEAR_FLAGS(ClearFlags), Depth, Stencil, NumRects, pRects);
}
HRESULT STDMETHODCALLTYPE CCryDX12DeviceContext::CopyStagingResource(
_In_ ID3D11Resource* pStagingResource,
_In_ ID3D11Resource* pSourceResource,
_In_ UINT SubResource,
_In_ BOOL Upload)
{
DX12_FUNC_LOG
if (Upload)
{
CopySubresourceRegion1(pSourceResource, SubResource, 0, 0, 0, pStagingResource, 0, nullptr, D3D11_COPY_NO_OVERWRITE);
}
else
{
CopySubresourceRegion1(pStagingResource, 0, 0, 0, 0, pSourceResource, SubResource, nullptr, D3D11_COPY_NO_OVERWRITE);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CCryDX12DeviceContext::MapStagingResource(
_In_ ID3D11Resource* pTextureResource,
_In_ ID3D11Resource* pStagingResource,
_In_ UINT SubResource,
_In_ BOOL Upload,
_Out_ void** ppStagingMemory,
_Out_ uint32* pRowPitch)
{
DX12_FUNC_LOG
ICryDX12Resource* dx12Resource = DX12_EXTRACT_ICRYDX12RESOURCE(pStagingResource);
DX12::Resource& rResource = dx12Resource->GetDX12Resource();
ICryDX12Resource* dx12TextureResource = DX12_EXTRACT_ICRYDX12RESOURCE(pTextureResource);
DX12::Resource& rTextureResource = dx12TextureResource->GetDX12Resource();
// If this assert trips, you may need to increase MAX_SUBRESOURCES. Just be wary of growing the stack too much.
AZ_Assert(SubResource < MAX_SUBRESOURCES, "Too many sub resources: (sub ID %d requested, %d allowed)", SubResource, MAX_SUBRESOURCES);
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layouts[MAX_SUBRESOURCES];
// From our source texture resource, get the offset and description information for all the subresources up through the one we're trying
// to map. Our staging resource will contain a buffer large enough for *all* the subresources, so we need to get the correct offset
// into this buffer. If we just get the Layout for the one SubResource, it will come back with an offset of 0, which is incorrect.
GetDevice()->GetD3D12Device()->GetCopyableFootprints(&rTextureResource.GetDesc(), 0, SubResource + 1, 0, layouts, nullptr, nullptr, nullptr);
const D3D12_RANGE sNoRead = { 0, 0 }; // It is valid to specify the CPU won't read any data by passing a range where End is less than or equal to Begin
const D3D12_RANGE sFullRead = { 0, rResource.GetRequiredUploadSize(0, 1) }; // Our buffer only has 1 subresource, so get the full size of it to map.
HRESULT result = rResource.GetD3D12Resource()->Map(0, Upload ? &sNoRead : &sFullRead, ppStagingMemory);
// Map() will return a pointer to the start of our buffer. Adjust the pointer to the offset of the desired mapped subresource within the buffer.
*ppStagingMemory = *reinterpret_cast<uint8**>(ppStagingMemory) + layouts[SubResource].Offset;
*pRowPitch = layouts[SubResource].Footprint.RowPitch;
return result;
}
void STDMETHODCALLTYPE CCryDX12DeviceContext::UnmapStagingResource(
_In_ ID3D11Resource* pStagingResource,
_In_ BOOL Upload)
{
DX12_FUNC_LOG
ICryDX12Resource* dx12Resource = DX12_EXTRACT_ICRYDX12RESOURCE(pStagingResource);
DX12::Resource& rResource = dx12Resource->GetDX12Resource();
const D3D12_RANGE sNoWrite = { 0, 0 }; // It is valid to specify the CPU didn't write any data by passing a range where End is less than or equal to Begin.
const D3D12_RANGE sFullWrite = { 0, rResource.GetRequiredUploadSize(0, 1) };
rResource.GetD3D12Resource()->Unmap(0, Upload ? &sFullWrite : &sNoWrite);
}
HRESULT STDMETHODCALLTYPE CCryDX12DeviceContext::TestStagingResource(
_In_ ID3D11Resource* pStagingResource)
{
DX12_FUNC_LOG
ICryDX12Resource* dx12Resource = DX12_EXTRACT_ICRYDX12RESOURCE(pStagingResource);
DX12::Resource& rResource = dx12Resource->GetDX12Resource();
return
TestForFence(rResource.GetFenceValue(CMDQUEUE_GRAPHICS, CMDTYPE_ANY)) &&
TestForFence(rResource.GetFenceValue(CMDQUEUE_COPY, CMDTYPE_ANY));
}
HRESULT STDMETHODCALLTYPE CCryDX12DeviceContext::WaitStagingResource(
_In_ ID3D11Resource* pStagingResource)
{
DX12_FUNC_LOG
ICryDX12Resource* dx12Resource = DX12_EXTRACT_ICRYDX12RESOURCE(pStagingResource);
DX12::Resource& rResource = dx12Resource->GetDX12Resource();
if (rResource.GetFenceValue(CMDQUEUE_GRAPHICS, CMDTYPE_WRITE) == m_DirectListPool.GetCurrentFenceValue())
{
SubmitDirectCommands(false);
}
if (rResource.GetFenceValue(CMDQUEUE_COPY, CMDTYPE_WRITE) == m_CopyListPool.GetCurrentFenceValue())
{
SubmitCopyCommands(false);
}
rResource.WaitForUnused(m_DirectListPool, CMDTYPE_ANY);
rResource.WaitForUnused(m_CopyListPool, CMDTYPE_ANY);
return S_OK;
}
void CCryDX12DeviceContext::ResetCachedState()
{
m_PipelineState[DX12::CommandModeGraphics].Invalidate();
m_PipelineState[DX12::CommandModeCompute].Invalidate();
m_CurrentPSO = nullptr;
m_CurrentRootSignature[DX12::CommandModeGraphics] = m_CurrentRootSignature[DX12::CommandModeCompute] = nullptr;
}
#pragma endregion