diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index 15066d83d8..15a4106367 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -457,7 +457,10 @@ bool D3D12GSRender::LoadProgram() return false; } - m_PSO = m_cachePSO.getGraphicPipelineState(m_device, m_rootSignature, m_cur_vertex_prog, m_cur_fragment_prog, m_IASet); + PipelineProperties prop = {}; + prop.Topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + + m_PSO = m_cachePSO.getGraphicPipelineState(m_device, m_rootSignature, m_cur_vertex_prog, m_cur_fragment_prog, prop, m_IASet); return m_PSO != nullptr; } diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp index 601f06fa45..c9eb3ece15 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -58,11 +58,9 @@ bool PipelineStateObjectCache::SearchVp(const RSXVertexProgram& rsx_vp, Shader& return false; } -ID3D12PipelineState *PipelineStateObjectCache::GetProg(u32 fp, u32 vp) const +ID3D12PipelineState *PipelineStateObjectCache::GetProg(const PSOKey &key) const { - u64 vpLong = vp; - u64 key = vpLong << 32 | fp; - std::unordered_map::const_iterator It = m_cachePSO.find(key); + std::unordered_map::const_iterator It = m_cachePSO.find(key); if (It == m_cachePSO.end()) return nullptr; return It->second; @@ -86,14 +84,18 @@ void PipelineStateObjectCache::AddFragmentProgram(Shader& fp, RSXFragmentProgram m_cacheFS.insert(std::make_pair(fpShadowCopy, fp)); } -void PipelineStateObjectCache::Add(ID3D12PipelineState *prog, Shader& fp, Shader& vp) +void PipelineStateObjectCache::Add(ID3D12PipelineState *prog, const PSOKey& PSOKey) { - u64 vpLong = vp.Id; - u64 key = vpLong << 32 | fp.Id; - m_cachePSO.insert(std::make_pair(key, prog)); + m_cachePSO.insert(std::make_pair(PSOKey, prog)); } -ID3D12PipelineState *PipelineStateObjectCache::getGraphicPipelineState(ID3D12Device *device, ID3D12RootSignature *rootSignature, RSXVertexProgram *vertexShader, RSXFragmentProgram *fragmentShader, const std::vector &IASet) +ID3D12PipelineState *PipelineStateObjectCache::getGraphicPipelineState( + ID3D12Device *device, + ID3D12RootSignature *rootSignature, + RSXVertexProgram *vertexShader, + RSXFragmentProgram *fragmentShader, + const PipelineProperties &pipelineProperties, + const std::vector &IASet) { ID3D12PipelineState *result = nullptr; Shader m_vertex_prog, m_fragment_prog; @@ -123,7 +125,9 @@ ID3D12PipelineState *PipelineStateObjectCache::getGraphicPipelineState(ID3D12Dev } if (m_fp_buf_num && m_vp_buf_num) - result = GetProg(m_fragment_prog.Id, m_vertex_prog.Id); + { + result = GetProg({ m_vertex_prog.Id, m_fragment_prog.Id, pipelineProperties }); + } if (result != nullptr) { @@ -221,7 +225,7 @@ ID3D12PipelineState *PipelineStateObjectCache::getGraphicPipelineState(ID3D12Dev graphicPipelineStateDesc.BlendState = CD3D12_BLEND_DESC; graphicPipelineStateDesc.DepthStencilState = CD3D12_DEPTH_STENCIL_DESC; graphicPipelineStateDesc.RasterizerState = CD3D12_RASTERIZER_DESC; - graphicPipelineStateDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + graphicPipelineStateDesc.PrimitiveTopologyType = pipelineProperties.Topology; graphicPipelineStateDesc.NumRenderTargets = 1; graphicPipelineStateDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; @@ -234,7 +238,7 @@ ID3D12PipelineState *PipelineStateObjectCache::getGraphicPipelineState(ID3D12Dev graphicPipelineStateDesc.NodeMask = 1; device->CreateGraphicsPipelineState(&graphicPipelineStateDesc, IID_PPV_ARGS(&result)); - Add(result, m_fragment_prog, m_vertex_prog); + Add(result, {m_vertex_prog.Id, m_fragment_prog.Id, pipelineProperties }); // RSX Debugger /*if (Ini.GSLogPrograms.GetValue()) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h index f3fb266d4b..2e8f92fc35 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h @@ -13,6 +13,11 @@ enum class SHADER_TYPE SHADER_TYPE_FRAGMENT }; +struct PipelineProperties +{ + D3D12_PRIMITIVE_TOPOLOGY_TYPE Topology; +}; + /** Storage for a shader * Embeds the D3DBlob corresponding to */ @@ -139,6 +144,31 @@ struct FragmentProgramCompare typedef std::unordered_map binary2VS; typedef std::unordered_map binary2FS; +struct PSOKey +{ + u32 vpIdx; + u32 fpIdx; + PipelineProperties properties; +}; + +struct PSOKeyHash +{ + size_t operator()(const PSOKey &key) const + { + size_t hashValue = 0; + hashValue ^= std::hash()(key.vpIdx); + return hashValue; + } +}; + +struct PSOKeyCompare +{ + size_t operator()(const PSOKey &key1, const PSOKey &key2) const + { + return (key1.vpIdx == key2.vpIdx) && (key1.fpIdx == key2.fpIdx) && (key1.properties.Topology == key2.properties.Topology); + } +}; + /** * Cache for shader blobs and Pipeline state object * The class is responsible for creating the object so the state only has to call getGraphicPipelineState @@ -149,20 +179,27 @@ private: size_t m_currentShaderId; binary2VS m_cacheVS; binary2FS m_cacheFS; - // Key is vertex << 32 | fragment ids - std::unordered_map m_cachePSO; + + std::unordered_map m_cachePSO; bool SearchFp(const RSXFragmentProgram& rsx_fp, Shader& shader); bool SearchVp(const RSXVertexProgram& rsx_vp, Shader& shader); - ID3D12PipelineState *GetProg(u32 fp, u32 vp) const; + ID3D12PipelineState *GetProg(const PSOKey &psoKey) const; void AddVertexProgram(Shader& vp, RSXVertexProgram& rsx_vp); void AddFragmentProgram(Shader& fp, RSXFragmentProgram& rsx_fp); - void Add(ID3D12PipelineState *prog, Shader& fp, Shader& vp); + void Add(ID3D12PipelineState *prog, const PSOKey& PSOKey); public: PipelineStateObjectCache(); ~PipelineStateObjectCache(); // Note: the last param is not taken into account if the PSO is not regenerated - ID3D12PipelineState *getGraphicPipelineState(ID3D12Device *device, ID3D12RootSignature *rootSignature, RSXVertexProgram *vertexShader, RSXFragmentProgram *fragmentShader, const std::vector &IASet); + ID3D12PipelineState *getGraphicPipelineState( + ID3D12Device *device, + ID3D12RootSignature *rootSignature, + RSXVertexProgram *vertexShader, + RSXFragmentProgram *fragmentShader, + const PipelineProperties &pipelineProperties, + const std::vector &IASet + ); };