#include "d3d11_context_common.h" #include "d3d11_context_def.h" #include "d3d11_context_imm.h" namespace dxvk { template D3D11CommonContext::D3D11CommonContext( D3D11Device* pParent, const Rc& Device, DxvkCsChunkFlags CsFlags) : D3D11DeviceContext(pParent, Device, CsFlags), m_contextExt(GetTypedContext()), m_annotation(GetTypedContext(), Device) { } template D3D11CommonContext::~D3D11CommonContext() { } template HRESULT STDMETHODCALLTYPE D3D11CommonContext::QueryInterface(REFIID riid, void** ppvObject) { if (ppvObject == nullptr) return E_POINTER; *ppvObject = nullptr; if (riid == __uuidof(IUnknown) || riid == __uuidof(ID3D11DeviceChild) || riid == __uuidof(ID3D11DeviceContext) || riid == __uuidof(ID3D11DeviceContext1) || riid == __uuidof(ID3D11DeviceContext2) || riid == __uuidof(ID3D11DeviceContext3) || riid == __uuidof(ID3D11DeviceContext4)) { *ppvObject = ref(this); return S_OK; } if (riid == __uuidof(ID3D11VkExtContext) || riid == __uuidof(ID3D11VkExtContext1)) { *ppvObject = ref(&m_contextExt); return S_OK; } if (riid == __uuidof(ID3DUserDefinedAnnotation) || riid == __uuidof(IDXVKUserDefinedAnnotation)) { *ppvObject = ref(&m_annotation); return S_OK; } if (riid == __uuidof(ID3D10Multithread)) { *ppvObject = ref(&m_multithread); return S_OK; } Logger::warn("D3D11DeviceContext::QueryInterface: Unknown interface query"); Logger::warn(str::format(riid)); return E_NOINTERFACE; } template void STDMETHODCALLTYPE D3D11CommonContext::UpdateSubresource( ID3D11Resource* pDstResource, UINT DstSubresource, const D3D11_BOX* pDstBox, const void* pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch) { UpdateResource(pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch, 0); } template void STDMETHODCALLTYPE D3D11CommonContext::UpdateSubresource1( ID3D11Resource* pDstResource, UINT DstSubresource, const D3D11_BOX* pDstBox, const void* pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch, UINT CopyFlags) { UpdateResource(pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch, CopyFlags); } template void STDMETHODCALLTYPE D3D11CommonContext::IASetInputLayout(ID3D11InputLayout* pInputLayout) { D3D10DeviceLock lock = LockContext(); auto inputLayout = static_cast(pInputLayout); if (m_state.ia.inputLayout != inputLayout) { bool equal = false; // Some games (e.g. Grim Dawn) create lots and lots of // identical input layouts, so we'll only apply the state // if the input layouts has actually changed between calls. if (m_state.ia.inputLayout != nullptr && inputLayout != nullptr) equal = m_state.ia.inputLayout->Compare(inputLayout); m_state.ia.inputLayout = inputLayout; if (!equal) ApplyInputLayout(); } } template void STDMETHODCALLTYPE D3D11CommonContext::IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY Topology) { D3D10DeviceLock lock = LockContext(); if (m_state.ia.primitiveTopology != Topology) { m_state.ia.primitiveTopology = Topology; ApplyPrimitiveTopology(); } } template void STDMETHODCALLTYPE D3D11CommonContext::IASetVertexBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppVertexBuffers, const UINT* pStrides, const UINT* pOffsets) { D3D10DeviceLock lock = LockContext(); for (uint32_t i = 0; i < NumBuffers; i++) { auto newBuffer = static_cast(ppVertexBuffers[i]); bool needsUpdate = m_state.ia.vertexBuffers[StartSlot + i].buffer != newBuffer; if (needsUpdate) m_state.ia.vertexBuffers[StartSlot + i].buffer = newBuffer; needsUpdate |= m_state.ia.vertexBuffers[StartSlot + i].offset != pOffsets[i] || m_state.ia.vertexBuffers[StartSlot + i].stride != pStrides[i]; if (needsUpdate) { m_state.ia.vertexBuffers[StartSlot + i].offset = pOffsets[i]; m_state.ia.vertexBuffers[StartSlot + i].stride = pStrides[i]; BindVertexBuffer(StartSlot + i, newBuffer, pOffsets[i], pStrides[i]); } } } template void STDMETHODCALLTYPE D3D11CommonContext::IASetIndexBuffer( ID3D11Buffer* pIndexBuffer, DXGI_FORMAT Format, UINT Offset) { D3D10DeviceLock lock = LockContext(); auto newBuffer = static_cast(pIndexBuffer); bool needsUpdate = m_state.ia.indexBuffer.buffer != newBuffer; if (needsUpdate) m_state.ia.indexBuffer.buffer = newBuffer; needsUpdate |= m_state.ia.indexBuffer.offset != Offset || m_state.ia.indexBuffer.format != Format; if (needsUpdate) { m_state.ia.indexBuffer.offset = Offset; m_state.ia.indexBuffer.format = Format; BindIndexBuffer(newBuffer, Offset, Format); } } template void STDMETHODCALLTYPE D3D11CommonContext::IAGetInputLayout(ID3D11InputLayout** ppInputLayout) { D3D10DeviceLock lock = LockContext(); *ppInputLayout = m_state.ia.inputLayout.ref(); } template void STDMETHODCALLTYPE D3D11CommonContext::IAGetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY* pTopology) { D3D10DeviceLock lock = LockContext(); *pTopology = m_state.ia.primitiveTopology; } template void STDMETHODCALLTYPE D3D11CommonContext::IAGetVertexBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppVertexBuffers, UINT* pStrides, UINT* pOffsets) { D3D10DeviceLock lock = LockContext(); for (uint32_t i = 0; i < NumBuffers; i++) { const bool inRange = StartSlot + i < m_state.ia.vertexBuffers.size(); if (ppVertexBuffers) { ppVertexBuffers[i] = inRange ? m_state.ia.vertexBuffers[StartSlot + i].buffer.ref() : nullptr; } if (pStrides) { pStrides[i] = inRange ? m_state.ia.vertexBuffers[StartSlot + i].stride : 0u; } if (pOffsets) { pOffsets[i] = inRange ? m_state.ia.vertexBuffers[StartSlot + i].offset : 0u; } } } template void STDMETHODCALLTYPE D3D11CommonContext::IAGetIndexBuffer( ID3D11Buffer** ppIndexBuffer, DXGI_FORMAT* pFormat, UINT* pOffset) { D3D10DeviceLock lock = LockContext(); if (ppIndexBuffer) *ppIndexBuffer = m_state.ia.indexBuffer.buffer.ref(); if (pFormat) *pFormat = m_state.ia.indexBuffer.format; if (pOffset) *pOffset = m_state.ia.indexBuffer.offset; } template void STDMETHODCALLTYPE D3D11CommonContext::VSSetShader( ID3D11VertexShader* pVertexShader, ID3D11ClassInstance* const* ppClassInstances, UINT NumClassInstances) { D3D10DeviceLock lock = LockContext(); auto shader = static_cast(pVertexShader); if (NumClassInstances) Logger::err("D3D11: Class instances not supported"); if (m_state.vs.shader != shader) { m_state.vs.shader = shader; BindShader(GetCommonShader(shader)); } } template void STDMETHODCALLTYPE D3D11CommonContext::VSSetConstantBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { D3D10DeviceLock lock = LockContext(); SetConstantBuffers( m_state.vs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers); } template void STDMETHODCALLTYPE D3D11CommonContext::VSSetConstantBuffers1( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants) { D3D10DeviceLock lock = LockContext(); SetConstantBuffers1( m_state.vs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); } template void STDMETHODCALLTYPE D3D11CommonContext::VSSetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView* const* ppShaderResourceViews) { D3D10DeviceLock lock = LockContext(); SetShaderResources( m_state.vs.shaderResources, StartSlot, NumViews, ppShaderResourceViews); } template void STDMETHODCALLTYPE D3D11CommonContext::VSSetSamplers( UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) { D3D10DeviceLock lock = LockContext(); SetSamplers( m_state.vs.samplers, StartSlot, NumSamplers, ppSamplers); } template void STDMETHODCALLTYPE D3D11CommonContext::VSGetShader( ID3D11VertexShader** ppVertexShader, ID3D11ClassInstance** ppClassInstances, UINT* pNumClassInstances) { D3D10DeviceLock lock = LockContext(); if (ppVertexShader) *ppVertexShader = m_state.vs.shader.ref(); if (pNumClassInstances) *pNumClassInstances = 0; } template void STDMETHODCALLTYPE D3D11CommonContext::VSGetConstantBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers) { D3D10DeviceLock lock = LockContext(); GetConstantBuffers( m_state.vs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, nullptr, nullptr); } template void STDMETHODCALLTYPE D3D11CommonContext::VSGetConstantBuffers1( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers, UINT* pFirstConstant, UINT* pNumConstants) { D3D10DeviceLock lock = LockContext(); GetConstantBuffers( m_state.vs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); } template void STDMETHODCALLTYPE D3D11CommonContext::VSGetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView** ppShaderResourceViews) { D3D10DeviceLock lock = LockContext(); GetShaderResources(m_state.vs.shaderResources, StartSlot, NumViews, ppShaderResourceViews); } template void STDMETHODCALLTYPE D3D11CommonContext::VSGetSamplers( UINT StartSlot, UINT NumSamplers, ID3D11SamplerState** ppSamplers) { D3D10DeviceLock lock = LockContext(); GetSamplers(m_state.vs.samplers, StartSlot, NumSamplers, ppSamplers); } template void STDMETHODCALLTYPE D3D11CommonContext::HSSetShader( ID3D11HullShader* pHullShader, ID3D11ClassInstance* const* ppClassInstances, UINT NumClassInstances) { D3D10DeviceLock lock = LockContext(); auto shader = static_cast(pHullShader); if (NumClassInstances) Logger::err("D3D11: Class instances not supported"); if (m_state.hs.shader != shader) { m_state.hs.shader = shader; BindShader(GetCommonShader(shader)); } } template void STDMETHODCALLTYPE D3D11CommonContext::HSSetConstantBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { D3D10DeviceLock lock = LockContext(); SetConstantBuffers( m_state.hs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers); } template void STDMETHODCALLTYPE D3D11CommonContext::HSSetConstantBuffers1( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants) { D3D10DeviceLock lock = LockContext(); SetConstantBuffers1( m_state.hs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); } template void STDMETHODCALLTYPE D3D11CommonContext::HSSetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView* const* ppShaderResourceViews) { D3D10DeviceLock lock = LockContext(); SetShaderResources( m_state.hs.shaderResources, StartSlot, NumViews, ppShaderResourceViews); } template void STDMETHODCALLTYPE D3D11CommonContext::HSSetSamplers( UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) { D3D10DeviceLock lock = LockContext(); SetSamplers( m_state.hs.samplers, StartSlot, NumSamplers, ppSamplers); } template void STDMETHODCALLTYPE D3D11CommonContext::HSGetShader( ID3D11HullShader** ppHullShader, ID3D11ClassInstance** ppClassInstances, UINT* pNumClassInstances) { D3D10DeviceLock lock = LockContext(); if (ppHullShader) *ppHullShader = m_state.hs.shader.ref(); if (pNumClassInstances) *pNumClassInstances = 0; } template void STDMETHODCALLTYPE D3D11CommonContext::HSGetConstantBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers) { D3D10DeviceLock lock = LockContext(); GetConstantBuffers( m_state.hs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, nullptr, nullptr); } template void STDMETHODCALLTYPE D3D11CommonContext::HSGetConstantBuffers1( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers, UINT* pFirstConstant, UINT* pNumConstants) { D3D10DeviceLock lock = LockContext(); GetConstantBuffers( m_state.hs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); } template void STDMETHODCALLTYPE D3D11CommonContext::HSGetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView** ppShaderResourceViews) { D3D10DeviceLock lock = LockContext(); GetShaderResources(m_state.hs.shaderResources, StartSlot, NumViews, ppShaderResourceViews); } template void STDMETHODCALLTYPE D3D11CommonContext::HSGetSamplers( UINT StartSlot, UINT NumSamplers, ID3D11SamplerState** ppSamplers) { D3D10DeviceLock lock = LockContext(); GetSamplers(m_state.hs.samplers, StartSlot, NumSamplers, ppSamplers); } template void STDMETHODCALLTYPE D3D11CommonContext::DSSetShader( ID3D11DomainShader* pDomainShader, ID3D11ClassInstance* const* ppClassInstances, UINT NumClassInstances) { D3D10DeviceLock lock = LockContext(); auto shader = static_cast(pDomainShader); if (NumClassInstances) Logger::err("D3D11: Class instances not supported"); if (m_state.ds.shader != shader) { m_state.ds.shader = shader; BindShader(GetCommonShader(shader)); } } template void STDMETHODCALLTYPE D3D11CommonContext::DSSetConstantBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { D3D10DeviceLock lock = LockContext(); SetConstantBuffers( m_state.ds.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers); } template void STDMETHODCALLTYPE D3D11CommonContext::DSSetConstantBuffers1( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants) { D3D10DeviceLock lock = LockContext(); SetConstantBuffers1( m_state.ds.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); } template void STDMETHODCALLTYPE D3D11CommonContext::DSSetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView* const* ppShaderResourceViews) { D3D10DeviceLock lock = LockContext(); SetShaderResources( m_state.ds.shaderResources, StartSlot, NumViews, ppShaderResourceViews); } template void STDMETHODCALLTYPE D3D11CommonContext::DSSetSamplers( UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) { D3D10DeviceLock lock = LockContext(); SetSamplers( m_state.ds.samplers, StartSlot, NumSamplers, ppSamplers); } template void STDMETHODCALLTYPE D3D11CommonContext::DSGetShader( ID3D11DomainShader** ppDomainShader, ID3D11ClassInstance** ppClassInstances, UINT* pNumClassInstances) { D3D10DeviceLock lock = LockContext(); if (ppDomainShader) *ppDomainShader = m_state.ds.shader.ref(); if (pNumClassInstances) *pNumClassInstances = 0; } template void STDMETHODCALLTYPE D3D11CommonContext::DSGetConstantBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers) { D3D10DeviceLock lock = LockContext(); GetConstantBuffers( m_state.ds.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, nullptr, nullptr); } template void STDMETHODCALLTYPE D3D11CommonContext::DSGetConstantBuffers1( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers, UINT* pFirstConstant, UINT* pNumConstants) { D3D10DeviceLock lock = LockContext(); GetConstantBuffers( m_state.ds.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); } template void STDMETHODCALLTYPE D3D11CommonContext::DSGetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView** ppShaderResourceViews) { D3D10DeviceLock lock = LockContext(); GetShaderResources(m_state.ds.shaderResources, StartSlot, NumViews, ppShaderResourceViews); } template void STDMETHODCALLTYPE D3D11CommonContext::DSGetSamplers( UINT StartSlot, UINT NumSamplers, ID3D11SamplerState** ppSamplers) { D3D10DeviceLock lock = LockContext(); GetSamplers(m_state.ds.samplers, StartSlot, NumSamplers, ppSamplers); } template void STDMETHODCALLTYPE D3D11CommonContext::GSSetShader( ID3D11GeometryShader* pShader, ID3D11ClassInstance* const* ppClassInstances, UINT NumClassInstances) { D3D10DeviceLock lock = LockContext(); auto shader = static_cast(pShader); if (NumClassInstances) Logger::err("D3D11: Class instances not supported"); if (m_state.gs.shader != shader) { m_state.gs.shader = shader; BindShader(GetCommonShader(shader)); } } template void STDMETHODCALLTYPE D3D11CommonContext::GSSetConstantBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { D3D10DeviceLock lock = LockContext(); SetConstantBuffers( m_state.gs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers); } template void STDMETHODCALLTYPE D3D11CommonContext::GSSetConstantBuffers1( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants) { D3D10DeviceLock lock = LockContext(); SetConstantBuffers1( m_state.gs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); } template void STDMETHODCALLTYPE D3D11CommonContext::GSSetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView* const* ppShaderResourceViews) { D3D10DeviceLock lock = LockContext(); SetShaderResources( m_state.gs.shaderResources, StartSlot, NumViews, ppShaderResourceViews); } template void STDMETHODCALLTYPE D3D11CommonContext::GSSetSamplers( UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) { D3D10DeviceLock lock = LockContext(); SetSamplers( m_state.gs.samplers, StartSlot, NumSamplers, ppSamplers); } template void STDMETHODCALLTYPE D3D11CommonContext::GSGetShader( ID3D11GeometryShader** ppGeometryShader, ID3D11ClassInstance** ppClassInstances, UINT* pNumClassInstances) { D3D10DeviceLock lock = LockContext(); if (ppGeometryShader) *ppGeometryShader = m_state.gs.shader.ref(); if (pNumClassInstances) *pNumClassInstances = 0; } template void STDMETHODCALLTYPE D3D11CommonContext::GSGetConstantBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers) { D3D10DeviceLock lock = LockContext(); GetConstantBuffers( m_state.gs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, nullptr, nullptr); } template void STDMETHODCALLTYPE D3D11CommonContext::GSGetConstantBuffers1( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers, UINT* pFirstConstant, UINT* pNumConstants) { D3D10DeviceLock lock = LockContext(); GetConstantBuffers( m_state.gs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); } template void STDMETHODCALLTYPE D3D11CommonContext::GSGetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView** ppShaderResourceViews) { D3D10DeviceLock lock = LockContext(); GetShaderResources(m_state.gs.shaderResources, StartSlot, NumViews, ppShaderResourceViews); } template void STDMETHODCALLTYPE D3D11CommonContext::GSGetSamplers( UINT StartSlot, UINT NumSamplers, ID3D11SamplerState** ppSamplers) { D3D10DeviceLock lock = LockContext(); GetSamplers(m_state.gs.samplers, StartSlot, NumSamplers, ppSamplers); } template void STDMETHODCALLTYPE D3D11CommonContext::PSSetShader( ID3D11PixelShader* pPixelShader, ID3D11ClassInstance* const* ppClassInstances, UINT NumClassInstances) { D3D10DeviceLock lock = LockContext(); auto shader = static_cast(pPixelShader); if (NumClassInstances) Logger::err("D3D11: Class instances not supported"); if (m_state.ps.shader != shader) { m_state.ps.shader = shader; BindShader(GetCommonShader(shader)); } } template void STDMETHODCALLTYPE D3D11CommonContext::PSSetConstantBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { D3D10DeviceLock lock = LockContext(); SetConstantBuffers( m_state.ps.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers); } template void STDMETHODCALLTYPE D3D11CommonContext::PSSetConstantBuffers1( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants) { D3D10DeviceLock lock = LockContext(); SetConstantBuffers1( m_state.ps.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); } template void STDMETHODCALLTYPE D3D11CommonContext::PSSetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView* const* ppShaderResourceViews) { D3D10DeviceLock lock = LockContext(); SetShaderResources( m_state.ps.shaderResources, StartSlot, NumViews, ppShaderResourceViews); } template void STDMETHODCALLTYPE D3D11CommonContext::PSSetSamplers( UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) { D3D10DeviceLock lock = LockContext(); SetSamplers( m_state.ps.samplers, StartSlot, NumSamplers, ppSamplers); } template void STDMETHODCALLTYPE D3D11CommonContext::PSGetShader( ID3D11PixelShader** ppPixelShader, ID3D11ClassInstance** ppClassInstances, UINT* pNumClassInstances) { D3D10DeviceLock lock = LockContext(); if (ppPixelShader) *ppPixelShader = m_state.ps.shader.ref(); if (pNumClassInstances) *pNumClassInstances = 0; } template void STDMETHODCALLTYPE D3D11CommonContext::PSGetConstantBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers) { D3D10DeviceLock lock = LockContext(); GetConstantBuffers( m_state.ps.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, nullptr, nullptr); } template void STDMETHODCALLTYPE D3D11CommonContext::PSGetConstantBuffers1( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers, UINT* pFirstConstant, UINT* pNumConstants) { D3D10DeviceLock lock = LockContext(); GetConstantBuffers( m_state.ps.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); } template void STDMETHODCALLTYPE D3D11CommonContext::PSGetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView** ppShaderResourceViews) { D3D10DeviceLock lock = LockContext(); GetShaderResources(m_state.ps.shaderResources, StartSlot, NumViews, ppShaderResourceViews); } template void STDMETHODCALLTYPE D3D11CommonContext::PSGetSamplers( UINT StartSlot, UINT NumSamplers, ID3D11SamplerState** ppSamplers) { D3D10DeviceLock lock = LockContext(); GetSamplers(m_state.ps.samplers, StartSlot, NumSamplers, ppSamplers); } template void STDMETHODCALLTYPE D3D11CommonContext::CSSetShader( ID3D11ComputeShader* pComputeShader, ID3D11ClassInstance* const* ppClassInstances, UINT NumClassInstances) { D3D10DeviceLock lock = LockContext(); auto shader = static_cast(pComputeShader); if (NumClassInstances) Logger::err("D3D11: Class instances not supported"); if (m_state.cs.shader != shader) { m_state.cs.shader = shader; BindShader(GetCommonShader(shader)); } } template void STDMETHODCALLTYPE D3D11CommonContext::CSSetConstantBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { D3D10DeviceLock lock = LockContext(); SetConstantBuffers( m_state.cs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers); } template void STDMETHODCALLTYPE D3D11CommonContext::CSSetConstantBuffers1( UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants) { D3D10DeviceLock lock = LockContext(); SetConstantBuffers1( m_state.cs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); } template void STDMETHODCALLTYPE D3D11CommonContext::CSSetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView* const* ppShaderResourceViews) { D3D10DeviceLock lock = LockContext(); SetShaderResources( m_state.cs.shaderResources, StartSlot, NumViews, ppShaderResourceViews); } template void STDMETHODCALLTYPE D3D11CommonContext::CSSetSamplers( UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) { D3D10DeviceLock lock = LockContext(); SetSamplers( m_state.cs.samplers, StartSlot, NumSamplers, ppSamplers); } template void STDMETHODCALLTYPE D3D11CommonContext::CSSetUnorderedAccessViews( UINT StartSlot, UINT NumUAVs, ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, const UINT* pUAVInitialCounts) { D3D10DeviceLock lock = LockContext(); if (TestRtvUavHazards(0, nullptr, NumUAVs, ppUnorderedAccessViews)) return; // Unbind previously bound conflicting UAVs uint32_t uavSlotId = computeUavBinding (DxbcProgramType::ComputeShader, 0); uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::ComputeShader, 0); int32_t uavId = m_state.cs.uavMask.findNext(0); while (uavId >= 0) { if (uint32_t(uavId) < StartSlot || uint32_t(uavId) >= StartSlot + NumUAVs) { for (uint32_t i = 0; i < NumUAVs; i++) { auto uav = static_cast(ppUnorderedAccessViews[i]); if (CheckViewOverlap(uav, m_state.cs.unorderedAccessViews[uavId].ptr())) { m_state.cs.unorderedAccessViews[uavId] = nullptr; m_state.cs.uavMask.clr(uavId); BindUnorderedAccessView( uavSlotId + uavId, nullptr, ctrSlotId + uavId, ~0u); } } uavId = m_state.cs.uavMask.findNext(uavId + 1); } else { uavId = m_state.cs.uavMask.findNext(StartSlot + NumUAVs); } } // Actually bind the given UAVs for (uint32_t i = 0; i < NumUAVs; i++) { auto uav = static_cast(ppUnorderedAccessViews[i]); auto ctr = pUAVInitialCounts ? pUAVInitialCounts[i] : ~0u; if (m_state.cs.unorderedAccessViews[StartSlot + i] != uav || ctr != ~0u) { m_state.cs.unorderedAccessViews[StartSlot + i] = uav; m_state.cs.uavMask.set(StartSlot + i, uav != nullptr); BindUnorderedAccessView( uavSlotId + StartSlot + i, uav, ctrSlotId + StartSlot + i, ctr); ResolveCsSrvHazards(uav); } } } template void STDMETHODCALLTYPE D3D11CommonContext::CSGetShader( ID3D11ComputeShader** ppComputeShader, ID3D11ClassInstance** ppClassInstances, UINT* pNumClassInstances) { D3D10DeviceLock lock = LockContext(); if (ppComputeShader) *ppComputeShader = m_state.cs.shader.ref(); if (pNumClassInstances) *pNumClassInstances = 0; } template void STDMETHODCALLTYPE D3D11CommonContext::CSGetConstantBuffers( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers) { D3D10DeviceLock lock = LockContext(); GetConstantBuffers( m_state.cs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, nullptr, nullptr); } template void STDMETHODCALLTYPE D3D11CommonContext::CSGetConstantBuffers1( UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers, UINT* pFirstConstant, UINT* pNumConstants) { D3D10DeviceLock lock = LockContext(); GetConstantBuffers( m_state.cs.constantBuffers, StartSlot, NumBuffers, ppConstantBuffers, pFirstConstant, pNumConstants); } template void STDMETHODCALLTYPE D3D11CommonContext::CSGetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView** ppShaderResourceViews) { D3D10DeviceLock lock = LockContext(); GetShaderResources(m_state.cs.shaderResources, StartSlot, NumViews, ppShaderResourceViews); } template void STDMETHODCALLTYPE D3D11CommonContext::CSGetSamplers( UINT StartSlot, UINT NumSamplers, ID3D11SamplerState** ppSamplers) { D3D10DeviceLock lock = LockContext(); GetSamplers(m_state.cs.samplers, StartSlot, NumSamplers, ppSamplers); } template void STDMETHODCALLTYPE D3D11CommonContext::CSGetUnorderedAccessViews( UINT StartSlot, UINT NumUAVs, ID3D11UnorderedAccessView** ppUnorderedAccessViews) { D3D10DeviceLock lock = LockContext(); for (uint32_t i = 0; i < NumUAVs; i++) { ppUnorderedAccessViews[i] = StartSlot + i < m_state.cs.unorderedAccessViews.size() ? m_state.cs.unorderedAccessViews[StartSlot + i].ref() : nullptr; } } template void STDMETHODCALLTYPE D3D11CommonContext::OMSetRenderTargets( UINT NumViews, ID3D11RenderTargetView* const* ppRenderTargetViews, ID3D11DepthStencilView* pDepthStencilView) { D3D10DeviceLock lock = LockContext(); if constexpr (!IsDeferred) GetTypedContext()->FlushImplicit(true); SetRenderTargetsAndUnorderedAccessViews( NumViews, ppRenderTargetViews, pDepthStencilView, NumViews, 0, nullptr, nullptr); } template void STDMETHODCALLTYPE D3D11CommonContext::OMSetRenderTargetsAndUnorderedAccessViews( UINT NumRTVs, ID3D11RenderTargetView* const* ppRenderTargetViews, ID3D11DepthStencilView* pDepthStencilView, UINT UAVStartSlot, UINT NumUAVs, ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, const UINT* pUAVInitialCounts) { D3D10DeviceLock lock = LockContext(); if constexpr (!IsDeferred) GetTypedContext()->FlushImplicit(true); SetRenderTargetsAndUnorderedAccessViews( NumRTVs, ppRenderTargetViews, pDepthStencilView, UAVStartSlot, NumUAVs, ppUnorderedAccessViews, pUAVInitialCounts); } template void STDMETHODCALLTYPE D3D11CommonContext::OMSetBlendState( ID3D11BlendState* pBlendState, const FLOAT BlendFactor[4], UINT SampleMask) { D3D10DeviceLock lock = LockContext(); auto blendState = static_cast(pBlendState); if (m_state.om.cbState != blendState || m_state.om.sampleMask != SampleMask) { m_state.om.cbState = blendState; m_state.om.sampleMask = SampleMask; ApplyBlendState(); } if (BlendFactor != nullptr) { for (uint32_t i = 0; i < 4; i++) m_state.om.blendFactor[i] = BlendFactor[i]; ApplyBlendFactor(); } } template void STDMETHODCALLTYPE D3D11CommonContext::OMSetDepthStencilState( ID3D11DepthStencilState* pDepthStencilState, UINT StencilRef) { D3D10DeviceLock lock = LockContext(); auto depthStencilState = static_cast(pDepthStencilState); if (m_state.om.dsState != depthStencilState) { m_state.om.dsState = depthStencilState; ApplyDepthStencilState(); } if (m_state.om.stencilRef != StencilRef) { m_state.om.stencilRef = StencilRef; ApplyStencilRef(); } } template void STDMETHODCALLTYPE D3D11CommonContext::OMGetRenderTargets( UINT NumViews, ID3D11RenderTargetView** ppRenderTargetViews, ID3D11DepthStencilView** ppDepthStencilView) { OMGetRenderTargetsAndUnorderedAccessViews( NumViews, ppRenderTargetViews, ppDepthStencilView, NumViews, 0, nullptr); } template void STDMETHODCALLTYPE D3D11CommonContext::OMGetRenderTargetsAndUnorderedAccessViews( UINT NumRTVs, ID3D11RenderTargetView** ppRenderTargetViews, ID3D11DepthStencilView** ppDepthStencilView, UINT UAVStartSlot, UINT NumUAVs, ID3D11UnorderedAccessView** ppUnorderedAccessViews) { D3D10DeviceLock lock = LockContext(); if (ppRenderTargetViews) { for (UINT i = 0; i < NumRTVs; i++) { ppRenderTargetViews[i] = i < m_state.om.renderTargetViews.size() ? m_state.om.renderTargetViews[i].ref() : nullptr; } } if (ppDepthStencilView) *ppDepthStencilView = m_state.om.depthStencilView.ref(); if (ppUnorderedAccessViews) { for (UINT i = 0; i < NumUAVs; i++) { ppUnorderedAccessViews[i] = UAVStartSlot + i < m_state.ps.unorderedAccessViews.size() ? m_state.ps.unorderedAccessViews[UAVStartSlot + i].ref() : nullptr; } } } template void STDMETHODCALLTYPE D3D11CommonContext::OMGetBlendState( ID3D11BlendState** ppBlendState, FLOAT BlendFactor[4], UINT* pSampleMask) { D3D10DeviceLock lock = LockContext(); if (ppBlendState) *ppBlendState = ref(m_state.om.cbState); if (BlendFactor) std::memcpy(BlendFactor, m_state.om.blendFactor, sizeof(FLOAT) * 4); if (pSampleMask) *pSampleMask = m_state.om.sampleMask; } template void STDMETHODCALLTYPE D3D11CommonContext::OMGetDepthStencilState( ID3D11DepthStencilState** ppDepthStencilState, UINT* pStencilRef) { D3D10DeviceLock lock = LockContext(); if (ppDepthStencilState) *ppDepthStencilState = ref(m_state.om.dsState); if (pStencilRef) *pStencilRef = m_state.om.stencilRef; } template BOOL STDMETHODCALLTYPE D3D11CommonContext::IsAnnotationEnabled() { return m_annotation.GetStatus(); } template template void D3D11CommonContext::BindShader( const D3D11CommonShader* pShaderModule) { // Bind the shader and the ICB at once EmitCs([ cSlice = pShaderModule != nullptr && pShaderModule->GetIcb() != nullptr ? DxvkBufferSlice(pShaderModule->GetIcb()) : DxvkBufferSlice(), cShader = pShaderModule != nullptr ? pShaderModule->GetShader() : nullptr ] (DxvkContext* ctx) mutable { VkShaderStageFlagBits stage = GetShaderStage(ShaderStage); uint32_t slotId = computeConstantBufferBinding(ShaderStage, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT); ctx->bindShader(stage, Forwarder::move(cShader)); ctx->bindResourceBuffer(stage, slotId, Forwarder::move(cSlice)); }); } template void D3D11CommonContext::BindFramebuffer() { DxvkRenderTargets attachments; uint32_t sampleCount = 0; // D3D11 doesn't have the concept of a framebuffer object, // so we'll just create a new one every time the render // target bindings are updated. Set up the attachments. for (UINT i = 0; i < m_state.om.renderTargetViews.size(); i++) { if (m_state.om.renderTargetViews[i] != nullptr) { attachments.color[i] = { m_state.om.renderTargetViews[i]->GetImageView(), m_state.om.renderTargetViews[i]->GetRenderLayout() }; sampleCount = m_state.om.renderTargetViews[i]->GetSampleCount(); } } if (m_state.om.depthStencilView != nullptr) { attachments.depth = { m_state.om.depthStencilView->GetImageView(), m_state.om.depthStencilView->GetRenderLayout() }; sampleCount = m_state.om.depthStencilView->GetSampleCount(); } // Create and bind the framebuffer object to the context EmitCs([ cAttachments = std::move(attachments) ] (DxvkContext* ctx) mutable { ctx->bindRenderTargets(Forwarder::move(cAttachments)); }); // If necessary, update push constant for the sample count if (m_state.om.sampleCount != sampleCount) { m_state.om.sampleCount = sampleCount; ApplyRasterizerSampleCount(); } } template void D3D11CommonContext::BindDrawBuffers( D3D11Buffer* pBufferForArgs, D3D11Buffer* pBufferForCount) { EmitCs([ cArgBuffer = pBufferForArgs ? pBufferForArgs->GetBufferSlice() : DxvkBufferSlice(), cCntBuffer = pBufferForCount ? pBufferForCount->GetBufferSlice() : DxvkBufferSlice() ] (DxvkContext* ctx) mutable { ctx->bindDrawBuffers( Forwarder::move(cArgBuffer), Forwarder::move(cCntBuffer)); }); } template void D3D11CommonContext::BindVertexBuffer( UINT Slot, D3D11Buffer* pBuffer, UINT Offset, UINT Stride) { if (likely(pBuffer != nullptr)) { EmitCs([ cSlotId = Slot, cBufferSlice = pBuffer->GetBufferSlice(Offset), cStride = Stride ] (DxvkContext* ctx) mutable { ctx->bindVertexBuffer(cSlotId, Forwarder::move(cBufferSlice), cStride); }); } else { EmitCs([ cSlotId = Slot ] (DxvkContext* ctx) { ctx->bindVertexBuffer(cSlotId, DxvkBufferSlice(), 0); }); } } template void D3D11CommonContext::BindIndexBuffer( D3D11Buffer* pBuffer, UINT Offset, DXGI_FORMAT Format) { VkIndexType indexType = Format == DXGI_FORMAT_R16_UINT ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32; EmitCs([ cBufferSlice = pBuffer != nullptr ? pBuffer->GetBufferSlice(Offset) : DxvkBufferSlice(), cIndexType = indexType ] (DxvkContext* ctx) mutable { ctx->bindIndexBuffer( Forwarder::move(cBufferSlice), cIndexType); }); } template void D3D11CommonContext::BindXfbBuffer( UINT Slot, D3D11Buffer* pBuffer, UINT Offset) { DxvkBufferSlice bufferSlice; DxvkBufferSlice counterSlice; if (pBuffer != nullptr) { bufferSlice = pBuffer->GetBufferSlice(); counterSlice = pBuffer->GetSOCounter(); } EmitCs([ cSlotId = Slot, cOffset = Offset, cBufferSlice = bufferSlice, cCounterSlice = counterSlice ] (DxvkContext* ctx) mutable { if (cCounterSlice.defined() && cOffset != ~0u) { ctx->updateBuffer( cCounterSlice.buffer(), cCounterSlice.offset(), sizeof(cOffset), &cOffset); } ctx->bindXfbBuffer(cSlotId, Forwarder::move(cBufferSlice), Forwarder::move(cCounterSlice)); }); } template template void D3D11CommonContext::BindConstantBuffer( UINT Slot, D3D11Buffer* pBuffer, UINT Offset, UINT Length) { EmitCs([ cSlotId = Slot, cBufferSlice = pBuffer ? pBuffer->GetBufferSlice(16 * Offset, 16 * Length) : DxvkBufferSlice() ] (DxvkContext* ctx) mutable { VkShaderStageFlagBits stage = GetShaderStage(ShaderStage); ctx->bindResourceBuffer(stage, cSlotId, Forwarder::move(cBufferSlice)); }); } template template void D3D11CommonContext::BindConstantBufferRange( UINT Slot, UINT Offset, UINT Length) { EmitCs([ cSlotId = Slot, cOffset = 16 * Offset, cLength = 16 * Length ] (DxvkContext* ctx) { VkShaderStageFlagBits stage = GetShaderStage(ShaderStage); ctx->bindResourceBufferRange(stage, cSlotId, cOffset, cLength); }); } template template void D3D11CommonContext::BindSampler( UINT Slot, D3D11SamplerState* pSampler) { EmitCs([ cSlotId = Slot, cSampler = pSampler != nullptr ? pSampler->GetDXVKSampler() : nullptr ] (DxvkContext* ctx) mutable { VkShaderStageFlagBits stage = GetShaderStage(ShaderStage); ctx->bindResourceSampler(stage, cSlotId, Forwarder::move(cSampler)); }); } template template void D3D11CommonContext::BindShaderResource( UINT Slot, D3D11ShaderResourceView* pResource) { EmitCs([ cSlotId = Slot, cImageView = pResource != nullptr ? pResource->GetImageView() : nullptr, cBufferView = pResource != nullptr ? pResource->GetBufferView() : nullptr ] (DxvkContext* ctx) mutable { VkShaderStageFlagBits stage = GetShaderStage(ShaderStage); ctx->bindResourceView(stage, cSlotId, Forwarder::move(cImageView), Forwarder::move(cBufferView)); }); } template template void D3D11CommonContext::BindUnorderedAccessView( UINT UavSlot, D3D11UnorderedAccessView* pUav, UINT CtrSlot, UINT Counter) { EmitCs([ cUavSlotId = UavSlot, cCtrSlotId = CtrSlot, cImageView = pUav != nullptr ? pUav->GetImageView() : nullptr, cBufferView = pUav != nullptr ? pUav->GetBufferView() : nullptr, cCounterSlice = pUav != nullptr ? pUav->GetCounterSlice() : DxvkBufferSlice(), cCounterValue = Counter ] (DxvkContext* ctx) mutable { VkShaderStageFlags stages = ShaderStage == DxbcProgramType::PixelShader ? VK_SHADER_STAGE_ALL_GRAPHICS : VK_SHADER_STAGE_COMPUTE_BIT; if (cCounterSlice.defined() && cCounterValue != ~0u) { ctx->updateBuffer( cCounterSlice.buffer(), cCounterSlice.offset(), sizeof(uint32_t), &cCounterValue); } ctx->bindResourceView(stages, cUavSlotId, Forwarder::move(cImageView), Forwarder::move(cBufferView)); ctx->bindResourceBuffer(stages, cCtrSlotId, Forwarder::move(cCounterSlice)); }); } template void D3D11CommonContext::GetConstantBuffers( const D3D11ConstantBufferBindings& Bindings, UINT StartSlot, UINT NumBuffers, ID3D11Buffer** ppConstantBuffers, UINT* pFirstConstant, UINT* pNumConstants) { for (uint32_t i = 0; i < NumBuffers; i++) { const bool inRange = StartSlot + i < Bindings.size(); if (ppConstantBuffers) { ppConstantBuffers[i] = inRange ? Bindings[StartSlot + i].buffer.ref() : nullptr; } if (pFirstConstant) { pFirstConstant[i] = inRange ? Bindings[StartSlot + i].constantOffset : 0u; } if (pNumConstants) { pNumConstants[i] = inRange ? Bindings[StartSlot + i].constantCount : 0u; } } } template void D3D11CommonContext::GetShaderResources( const D3D11ShaderResourceBindings& Bindings, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView** ppShaderResourceViews) { for (uint32_t i = 0; i < NumViews; i++) { ppShaderResourceViews[i] = StartSlot + i < Bindings.views.size() ? Bindings.views[StartSlot + i].ref() : nullptr; } } template void D3D11CommonContext::GetSamplers( const D3D11SamplerBindings& Bindings, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState** ppSamplers) { for (uint32_t i = 0; i < NumSamplers; i++) { ppSamplers[i] = StartSlot + i < Bindings.size() ? ref(Bindings[StartSlot + i]) : nullptr; } } template template void D3D11CommonContext::ResolveSrvHazards( T* pView, D3D11ShaderResourceBindings& Bindings) { uint32_t slotId = computeSrvBinding(ShaderStage, 0); int32_t srvId = Bindings.hazardous.findNext(0); while (srvId >= 0) { auto srv = Bindings.views[srvId].ptr(); if (likely(srv && srv->TestHazards())) { bool hazard = CheckViewOverlap(pView, srv); if (unlikely(hazard)) { Bindings.views[srvId] = nullptr; Bindings.hazardous.clr(srvId); BindShaderResource(slotId + srvId, nullptr); } } else { // Avoid further redundant iterations Bindings.hazardous.clr(srvId); } srvId = Bindings.hazardous.findNext(srvId + 1); } } template template void D3D11CommonContext::ResolveCsSrvHazards( T* pView) { if (!pView) return; ResolveSrvHazards (pView, m_state.cs.shaderResources); } template template void D3D11CommonContext::ResolveOmSrvHazards( T* pView) { if (!pView) return; ResolveSrvHazards (pView, m_state.vs.shaderResources); ResolveSrvHazards (pView, m_state.hs.shaderResources); ResolveSrvHazards (pView, m_state.ds.shaderResources); ResolveSrvHazards (pView, m_state.gs.shaderResources); ResolveSrvHazards (pView, m_state.ps.shaderResources); } template bool D3D11CommonContext::ResolveOmRtvHazards( D3D11UnorderedAccessView* pView) { if (!pView || !pView->HasBindFlag(D3D11_BIND_RENDER_TARGET)) return false; bool hazard = false; if (CheckViewOverlap(pView, m_state.om.depthStencilView.ptr())) { m_state.om.depthStencilView = nullptr; hazard = true; } for (uint32_t i = 0; i < m_state.om.maxRtv; i++) { if (CheckViewOverlap(pView, m_state.om.renderTargetViews[i].ptr())) { m_state.om.renderTargetViews[i] = nullptr; hazard = true; } } return hazard; } template void D3D11CommonContext::ResolveOmUavHazards( D3D11RenderTargetView* pView) { if (!pView || !pView->HasBindFlag(D3D11_BIND_UNORDERED_ACCESS)) return; uint32_t uavSlotId = computeUavBinding (DxbcProgramType::PixelShader, 0); uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::PixelShader, 0); for (uint32_t i = 0; i < m_state.om.maxUav; i++) { if (CheckViewOverlap(pView, m_state.ps.unorderedAccessViews[i].ptr())) { m_state.ps.unorderedAccessViews[i] = nullptr; BindUnorderedAccessView( uavSlotId + i, nullptr, ctrSlotId + i, ~0u); } } } template template void D3D11CommonContext::SetConstantBuffers( D3D11ConstantBufferBindings& Bindings, UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) { uint32_t slotId = computeConstantBufferBinding(ShaderStage, StartSlot); for (uint32_t i = 0; i < NumBuffers; i++) { auto newBuffer = static_cast(ppConstantBuffers[i]); UINT constantCount = 0; if (likely(newBuffer != nullptr)) constantCount = std::min(newBuffer->Desc()->ByteWidth / 16, UINT(D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT)); if (Bindings[StartSlot + i].buffer != newBuffer || Bindings[StartSlot + i].constantBound != constantCount) { Bindings[StartSlot + i].buffer = newBuffer; Bindings[StartSlot + i].constantOffset = 0; Bindings[StartSlot + i].constantCount = constantCount; Bindings[StartSlot + i].constantBound = constantCount; BindConstantBuffer(slotId + i, newBuffer, 0, constantCount); } } } template template void D3D11CommonContext::SetConstantBuffers1( D3D11ConstantBufferBindings& Bindings, UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers, const UINT* pFirstConstant, const UINT* pNumConstants) { uint32_t slotId = computeConstantBufferBinding(ShaderStage, StartSlot); for (uint32_t i = 0; i < NumBuffers; i++) { auto newBuffer = static_cast(ppConstantBuffers[i]); UINT constantOffset; UINT constantCount; UINT constantBound; if (likely(newBuffer != nullptr)) { UINT bufferConstantsCount = newBuffer->Desc()->ByteWidth / 16; constantBound = std::min(bufferConstantsCount, UINT(D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT)); if (likely(pFirstConstant && pNumConstants)) { constantOffset = pFirstConstant[i]; constantCount = pNumConstants [i]; if (unlikely(constantCount > D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT)) continue; constantBound = (constantOffset + constantCount > bufferConstantsCount) ? bufferConstantsCount - std::min(constantOffset, bufferConstantsCount) : constantCount; } else { constantOffset = 0; constantCount = constantBound; } } else { constantOffset = 0; constantCount = 0; constantBound = 0; } // Do a full rebind if either the buffer changes, or if either the current or // the previous number of bound constants were zero, since we're binding a null // buffer to the backend in that case. bool needsUpdate = Bindings[StartSlot + i].buffer != newBuffer; if (!needsUpdate) { needsUpdate |= !constantBound; needsUpdate |= !Bindings[StartSlot + i].constantBound; } if (needsUpdate) { Bindings[StartSlot + i].buffer = newBuffer; Bindings[StartSlot + i].constantOffset = constantOffset; Bindings[StartSlot + i].constantCount = constantCount; Bindings[StartSlot + i].constantBound = constantBound; BindConstantBuffer(slotId + i, newBuffer, constantOffset, constantBound); } else if (Bindings[StartSlot + i].constantOffset != constantOffset || Bindings[StartSlot + i].constantCount != constantCount) { Bindings[StartSlot + i].constantOffset = constantOffset; Bindings[StartSlot + i].constantCount = constantCount; Bindings[StartSlot + i].constantBound = constantBound; BindConstantBufferRange(slotId + i, constantOffset, constantBound); } } } template template void D3D11CommonContext::SetShaderResources( D3D11ShaderResourceBindings& Bindings, UINT StartSlot, UINT NumResources, ID3D11ShaderResourceView* const* ppResources) { uint32_t slotId = computeSrvBinding(ShaderStage, StartSlot); for (uint32_t i = 0; i < NumResources; i++) { auto resView = static_cast(ppResources[i]); if (Bindings.views[StartSlot + i] != resView) { if (unlikely(resView && resView->TestHazards())) { if (TestSrvHazards(resView)) resView = nullptr; // Only set if necessary, but don't reset it on every // bind as this would be more expensive than a few // redundant checks in OMSetRenderTargets and friends. Bindings.hazardous.set(StartSlot + i, resView); } Bindings.views[StartSlot + i] = resView; BindShaderResource(slotId + i, resView); } } } template template void D3D11CommonContext::SetSamplers( D3D11SamplerBindings& Bindings, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) { uint32_t slotId = computeSamplerBinding(ShaderStage, StartSlot); for (uint32_t i = 0; i < NumSamplers; i++) { auto sampler = static_cast(ppSamplers[i]); if (Bindings[StartSlot + i] != sampler) { Bindings[StartSlot + i] = sampler; BindSampler(slotId + i, sampler); } } } template void D3D11CommonContext::SetRenderTargetsAndUnorderedAccessViews( UINT NumRTVs, ID3D11RenderTargetView* const* ppRenderTargetViews, ID3D11DepthStencilView* pDepthStencilView, UINT UAVStartSlot, UINT NumUAVs, ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, const UINT* pUAVInitialCounts) { if (TestRtvUavHazards(NumRTVs, ppRenderTargetViews, NumUAVs, ppUnorderedAccessViews)) return; bool needsUpdate = false; if (likely(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL)) { // Native D3D11 does not change the render targets if // the parameters passed to this method are invalid. if (!ValidateRenderTargets(NumRTVs, ppRenderTargetViews, pDepthStencilView)) return; for (uint32_t i = 0; i < m_state.om.renderTargetViews.size(); i++) { auto rtv = i < NumRTVs ? static_cast(ppRenderTargetViews[i]) : nullptr; if (m_state.om.renderTargetViews[i] != rtv) { m_state.om.renderTargetViews[i] = rtv; needsUpdate = true; ResolveOmSrvHazards(rtv); if (NumUAVs == D3D11_KEEP_UNORDERED_ACCESS_VIEWS) ResolveOmUavHazards(rtv); } } auto dsv = static_cast(pDepthStencilView); if (m_state.om.depthStencilView != dsv) { m_state.om.depthStencilView = dsv; needsUpdate = true; ResolveOmSrvHazards(dsv); } m_state.om.maxRtv = NumRTVs; } if (unlikely(NumUAVs || m_state.om.maxUav)) { uint32_t uavSlotId = computeUavBinding (DxbcProgramType::PixelShader, 0); uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::PixelShader, 0); if (likely(NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS)) { uint32_t newMaxUav = NumUAVs ? UAVStartSlot + NumUAVs : 0; uint32_t oldMaxUav = std::exchange(m_state.om.maxUav, newMaxUav); for (uint32_t i = 0; i < std::max(oldMaxUav, newMaxUav); i++) { D3D11UnorderedAccessView* uav = nullptr; uint32_t ctr = ~0u; if (i >= UAVStartSlot && i < UAVStartSlot + NumUAVs) { uav = static_cast(ppUnorderedAccessViews[i - UAVStartSlot]); ctr = pUAVInitialCounts ? pUAVInitialCounts[i - UAVStartSlot] : ~0u; } if (m_state.ps.unorderedAccessViews[i] != uav || ctr != ~0u) { m_state.ps.unorderedAccessViews[i] = uav; BindUnorderedAccessView( uavSlotId + i, uav, ctrSlotId + i, ctr); ResolveOmSrvHazards(uav); if (NumRTVs == D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) needsUpdate |= ResolveOmRtvHazards(uav); } } } } if (needsUpdate) BindFramebuffer(); } template bool D3D11CommonContext::TestRtvUavHazards( UINT NumRTVs, ID3D11RenderTargetView* const* ppRTVs, UINT NumUAVs, ID3D11UnorderedAccessView* const* ppUAVs) { if (NumRTVs == D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) NumRTVs = 0; if (NumUAVs == D3D11_KEEP_UNORDERED_ACCESS_VIEWS) NumUAVs = 0; for (uint32_t i = 0; i < NumRTVs; i++) { auto rtv = static_cast(ppRTVs[i]); if (!rtv) continue; for (uint32_t j = 0; j < i; j++) { if (CheckViewOverlap(rtv, static_cast(ppRTVs[j]))) return true; } if (rtv->HasBindFlag(D3D11_BIND_UNORDERED_ACCESS)) { for (uint32_t j = 0; j < NumUAVs; j++) { if (CheckViewOverlap(rtv, static_cast(ppUAVs[j]))) return true; } } } for (uint32_t i = 0; i < NumUAVs; i++) { auto uav = static_cast(ppUAVs[i]); if (!uav) continue; for (uint32_t j = 0; j < i; j++) { if (CheckViewOverlap(uav, static_cast(ppUAVs[j]))) return true; } } return false; } template template bool D3D11CommonContext::TestSrvHazards( D3D11ShaderResourceView* pView) { bool hazard = false; if (ShaderStage == DxbcProgramType::ComputeShader) { int32_t uav = m_state.cs.uavMask.findNext(0); while (uav >= 0 && !hazard) { hazard = CheckViewOverlap(pView, m_state.cs.unorderedAccessViews[uav].ptr()); uav = m_state.cs.uavMask.findNext(uav + 1); } } else { hazard = CheckViewOverlap(pView, m_state.om.depthStencilView.ptr()); for (uint32_t i = 0; !hazard && i < m_state.om.maxRtv; i++) hazard = CheckViewOverlap(pView, m_state.om.renderTargetViews[i].ptr()); for (uint32_t i = 0; !hazard && i < m_state.om.maxUav; i++) hazard = CheckViewOverlap(pView, m_state.ps.unorderedAccessViews[i].ptr()); } return hazard; } template void D3D11CommonContext::UpdateResource( ID3D11Resource* pDstResource, UINT DstSubresource, const D3D11_BOX* pDstBox, const void* pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch, UINT CopyFlags) { auto context = static_cast(this); D3D10DeviceLock lock = context->LockContext(); if (!pDstResource) return; // We need a different code path for buffers D3D11_RESOURCE_DIMENSION resourceType; pDstResource->GetType(&resourceType); if (likely(resourceType == D3D11_RESOURCE_DIMENSION_BUFFER)) { const auto bufferResource = static_cast(pDstResource); uint64_t bufferSize = bufferResource->Desc()->ByteWidth; // Provide a fast path for mapped buffer updates since some // games use UpdateSubresource to update constant buffers. if (likely(bufferResource->GetMapMode() == D3D11_COMMON_BUFFER_MAP_MODE_DIRECT) && likely(!pDstBox)) { context->UpdateMappedBuffer(bufferResource, 0, bufferSize, pSrcData, 0); return; } // Validate buffer range to update uint64_t offset = 0; uint64_t length = bufferSize; if (pDstBox) { offset = pDstBox->left; length = pDstBox->right - offset; } if (unlikely(offset + length > bufferSize)) return; // Still try to be fast if a box is provided but we update the full buffer if (likely(bufferResource->GetMapMode() == D3D11_COMMON_BUFFER_MAP_MODE_DIRECT)) { CopyFlags &= D3D11_COPY_DISCARD | D3D11_COPY_NO_OVERWRITE; if (likely(length == bufferSize) || unlikely(CopyFlags != 0)) { context->UpdateMappedBuffer(bufferResource, offset, length, pSrcData, CopyFlags); return; } } // Otherwise we can't really do anything fancy, so just do a GPU copy context->UpdateBuffer(bufferResource, offset, length, pSrcData); } else { D3D11CommonTexture* textureResource = GetCommonTexture(pDstResource); context->UpdateTexture(textureResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch); } } template bool D3D11CommonContext::ValidateRenderTargets( UINT NumViews, ID3D11RenderTargetView* const* ppRenderTargetViews, ID3D11DepthStencilView* pDepthStencilView) { Rc refView; VkExtent3D dsvExtent = { 0u, 0u, 0u }; VkExtent3D rtvExtent = { 0u, 0u, 0u }; if (pDepthStencilView != nullptr) { refView = static_cast( pDepthStencilView)->GetImageView(); dsvExtent = refView->mipLevelExtent(0); } for (uint32_t i = 0; i < NumViews; i++) { if (ppRenderTargetViews[i] != nullptr) { auto curView = static_cast( ppRenderTargetViews[i])->GetImageView(); if (!rtvExtent.width) rtvExtent = curView->mipLevelExtent(0); if (refView != nullptr) { // Render target views must all have the same sample count, // layer count, and type. The size can mismatch under certain // conditions, the D3D11 documentation is wrong here. if (curView->info().type != refView->info().type || curView->info().numLayers != refView->info().numLayers) return false; if (curView->imageInfo().sampleCount != refView->imageInfo().sampleCount) return false; // Color targets must all be the same size VkExtent3D curExtent = curView->mipLevelExtent(0); if (curExtent.width != rtvExtent.width || curExtent.height != rtvExtent.height) return false; } else { // Set reference view. All remaining views // must be compatible to the reference view. refView = curView; } } } // Based on testing, the depth-stencil target is allowed // to be larger than all color targets, but not smaller if (rtvExtent.width && dsvExtent.width) { if (rtvExtent.width > dsvExtent.width || rtvExtent.height > dsvExtent.height) return false; } return true; } // Explicitly instantiate here template class D3D11CommonContext; template class D3D11CommonContext; }