d3d12: Use template class for caching

This commit is contained in:
vlj 2015-05-15 21:48:43 +02:00 committed by Vincent Lejeune
parent a58974eac8
commit ba66992ee3
6 changed files with 172 additions and 527 deletions

View File

@ -471,7 +471,7 @@ bool D3D12GSRender::LoadProgram()
return false;
}
PipelineProperties prop = {};
D3D12PipelineProperties prop = {};
/*
#define GL_POINTS 0x0000
#define GL_LINES 0x0001
@ -504,8 +504,8 @@ bool D3D12GSRender::LoadProgram()
prop.Topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
break;
}
m_PSO = m_cachePSO.getGraphicPipelineState(m_device, m_rootSignature, m_cur_vertex_prog, m_cur_fragment_prog, prop, m_IASet);
prop.IASet = m_IASet;
m_PSO = m_cachePSO.getGraphicPipelineState(m_device, m_rootSignature, m_cur_vertex_prog, m_cur_fragment_prog, prop, std::make_pair(m_device, m_rootSignature));
return m_PSO != nullptr;
}

View File

@ -2,279 +2,10 @@
#if defined (DX12_SUPPORT)
#include "D3D12PipelineState.h"
#include "Emu/Memory/vm.h"
#include "Utilities/Log.h"
#include <wrl/client.h>
#include <d3dcompiler.h>
#include <unordered_map>
#include "VertexProgramDecompiler.h"
#include "FragmentProgramDecompiler.h"
#include "Utilities/File.h"
#include <stdlib.h>
#pragma comment (lib, "d3dcompiler.lib")
namespace ProgramHashUtil
{
size_t getFPBinarySize(void *ptr)
{
const qword *instBuffer = (const qword*)ptr;
size_t instIndex = 0;
while (true)
{
const qword& inst = instBuffer[instIndex];
bool isSRC0Constant = ((inst.word[1] >> 8) & 0x3) == 2;
bool isSRC1Constant = ((inst.word[2] >> 8) & 0x3) == 2;
bool isSRC2Constant = ((inst.word[3] >> 8) & 0x3) == 2;
bool end = (inst.word[0] >> 8) & 0x1;
if (isSRC0Constant || isSRC1Constant || isSRC2Constant)
{
instIndex += 2;
if (end)
return instIndex * 4 * 4;
continue;
}
instIndex++;
if (end)
return (instIndex) * 4 * 4;
}
}
};
PipelineStateObjectCache::PipelineStateObjectCache() : m_currentShaderId(0)
{}
PipelineStateObjectCache::~PipelineStateObjectCache()
{
for (auto pair : m_cachePSO)
pair.second->Release();
}
bool PipelineStateObjectCache::SearchFp(const RSXFragmentProgram& rsx_fp, Shader& shader)
{
binary2FS::const_iterator It = m_cacheFS.find(vm::get_ptr<void>(rsx_fp.addr));
if (It != m_cacheFS.end())
{
shader = It->second;
return true;
}
return false;
}
bool PipelineStateObjectCache::SearchVp(const RSXVertexProgram& rsx_vp, Shader& shader)
{
binary2VS::const_iterator It = m_cacheVS.find((void*)rsx_vp.data.data());
if (It != m_cacheVS.end())
{
shader = It->second;
return true;
}
return false;
}
ID3D12PipelineState *PipelineStateObjectCache::GetProg(const PSOKey &key) const
{
std::unordered_map<PSOKey, ID3D12PipelineState *, PSOKeyHash, PSOKeyCompare>::const_iterator It = m_cachePSO.find(key);
if (It == m_cachePSO.end())
return nullptr;
return It->second;
}
void PipelineStateObjectCache::AddVertexProgram(Shader& vp, RSXVertexProgram& rsx_vp)
{
size_t actualVPSize = rsx_vp.data.size() * 4;
void *fpShadowCopy = malloc(actualVPSize);
memcpy(fpShadowCopy, rsx_vp.data.data(), actualVPSize);
vp.Id = (u32)m_currentShaderId++;
m_cacheVS.insert(std::make_pair(fpShadowCopy, vp));
}
void PipelineStateObjectCache::AddFragmentProgram(Shader& fp, RSXFragmentProgram& rsx_fp)
{
size_t actualFPSize = ProgramHashUtil::getFPBinarySize(vm::get_ptr<u8>(rsx_fp.addr));
void *fpShadowCopy = malloc(actualFPSize);
memcpy(fpShadowCopy, vm::get_ptr<u8>(rsx_fp.addr), actualFPSize);
fp.Id = (u32)m_currentShaderId++;
m_cacheFS.insert(std::make_pair(fpShadowCopy, fp));
}
void PipelineStateObjectCache::Add(ID3D12PipelineState *prog, const PSOKey& PSOKey)
{
m_cachePSO.insert(std::make_pair(PSOKey, prog));
}
ID3D12PipelineState *PipelineStateObjectCache::getGraphicPipelineState(
ID3D12Device *device,
ID3D12RootSignature *rootSignature,
RSXVertexProgram *vertexShader,
RSXFragmentProgram *fragmentShader,
const PipelineProperties &pipelineProperties,
const std::vector<D3D12_INPUT_ELEMENT_DESC> &IASet)
{
ID3D12PipelineState *result = nullptr;
Shader m_vertex_prog, m_fragment_prog;
bool m_fp_buf_num = SearchFp(*fragmentShader, m_fragment_prog);
bool m_vp_buf_num = SearchVp(*vertexShader, m_vertex_prog);
if (!m_fp_buf_num)
{
LOG_WARNING(RSX, "FP not found in buffer!");
FragmentDecompiler FS(fragmentShader->addr, fragmentShader->size, fragmentShader->offset);
const std::string &shader = FS.Decompile();
m_fragment_prog.Compile(shader, SHADER_TYPE::SHADER_TYPE_FRAGMENT);
AddFragmentProgram(m_fragment_prog, *fragmentShader);
// TODO: This shouldn't use current dir
fs::file("./FragmentProgram.hlsl", o_write | o_create | o_trunc).write(shader.c_str(), shader.size());
}
if (!m_vp_buf_num)
{
LOG_WARNING(RSX, "VP not found in buffer!");
VertexDecompiler VS(vertexShader->data);
std::string shaderCode = VS.Decompile();
m_vertex_prog.Compile(shaderCode, SHADER_TYPE::SHADER_TYPE_VERTEX);
AddVertexProgram(m_vertex_prog, *vertexShader);
// TODO: This shouldn't use current dir
fs::file("./VertexProgram.hlsl", o_write | o_create | o_trunc).write(shaderCode.c_str(), shaderCode.size());
}
if (m_fp_buf_num && m_vp_buf_num)
{
result = GetProg({ m_vertex_prog.Id, m_fragment_prog.Id, pipelineProperties });
}
if (result != nullptr)
{
return result;
/* // RSX Debugger: Check if this program was modified and update it
if (Ini.GSLogPrograms.GetValue())
{
for (auto& program : m_debug_programs)
{
if (program.id == m_program.id && program.modified)
{
// TODO: This isn't working perfectly. Is there any better/shorter way to update the program
m_vertex_prog.shader = program.vp_shader;
m_fragment_prog.shader = program.fp_shader;
m_vertex_prog.Wait();
m_vertex_prog.Compile();
checkForGlError("m_vertex_prog.Compile");
m_fragment_prog.Wait();
m_fragment_prog.Compile();
checkForGlError("m_fragment_prog.Compile");
glAttachShader(m_program.id, m_vertex_prog.id);
glAttachShader(m_program.id, m_fragment_prog.id);
glLinkProgram(m_program.id);
checkForGlError("glLinkProgram");
glDetachShader(m_program.id, m_vertex_prog.id);
glDetachShader(m_program.id, m_fragment_prog.id);
program.vp_id = m_vertex_prog.id;
program.fp_id = m_fragment_prog.id;
program.modified = false;
}
}
}
m_program.Use();*/
}
else
{
// LOG_WARNING(RSX, "Add program :");
// LOG_WARNING(RSX, "*** vp id = %d", m_vertex_prog.Id);
// LOG_WARNING(RSX, "*** fp id = %d", m_fragment_prog.Id);
D3D12_GRAPHICS_PIPELINE_STATE_DESC graphicPipelineStateDesc = {};
if (m_vertex_prog.bytecode != nullptr)
{
graphicPipelineStateDesc.VS.BytecodeLength = m_vertex_prog.bytecode->GetBufferSize();
graphicPipelineStateDesc.VS.pShaderBytecode = m_vertex_prog.bytecode->GetBufferPointer();
}
if (m_fragment_prog.bytecode != nullptr)
{
graphicPipelineStateDesc.PS.BytecodeLength = m_fragment_prog.bytecode->GetBufferSize();
graphicPipelineStateDesc.PS.pShaderBytecode = m_fragment_prog.bytecode->GetBufferPointer();
}
graphicPipelineStateDesc.pRootSignature = rootSignature;
// Sensible default value
static D3D12_RASTERIZER_DESC CD3D12_RASTERIZER_DESC =
{
D3D12_FILL_MODE_SOLID,
D3D12_CULL_MODE_NONE,
FALSE,
D3D12_DEFAULT_DEPTH_BIAS,
D3D12_DEFAULT_DEPTH_BIAS_CLAMP,
D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,
TRUE,
FALSE,
FALSE,
0,
D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF,
};
static D3D12_DEPTH_STENCIL_DESC CD3D12_DEPTH_STENCIL_DESC =
{
TRUE,
D3D12_DEPTH_WRITE_MASK_ALL,
D3D12_COMPARISON_FUNC_LESS_EQUAL,
FALSE,
D3D12_DEFAULT_STENCIL_READ_MASK,
D3D12_DEFAULT_STENCIL_WRITE_MASK,
};
static D3D12_BLEND_DESC CD3D12_BLEND_DESC =
{
FALSE,
FALSE,
{
FALSE,FALSE,
D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
D3D12_LOGIC_OP_NOOP,
D3D12_COLOR_WRITE_ENABLE_ALL,
}
};
graphicPipelineStateDesc.BlendState = CD3D12_BLEND_DESC;
graphicPipelineStateDesc.DepthStencilState = CD3D12_DEPTH_STENCIL_DESC;
graphicPipelineStateDesc.RasterizerState = CD3D12_RASTERIZER_DESC;
graphicPipelineStateDesc.PrimitiveTopologyType = pipelineProperties.Topology;
graphicPipelineStateDesc.NumRenderTargets = 1;
graphicPipelineStateDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
graphicPipelineStateDesc.DSVFormat = DXGI_FORMAT_D16_UNORM;
graphicPipelineStateDesc.InputLayout.pInputElementDescs = IASet.data();
graphicPipelineStateDesc.InputLayout.NumElements = (UINT)IASet.size();
graphicPipelineStateDesc.SampleDesc.Count = 1;
graphicPipelineStateDesc.SampleMask = UINT_MAX;
graphicPipelineStateDesc.NodeMask = 1;
device->CreateGraphicsPipelineState(&graphicPipelineStateDesc, IID_PPV_ARGS(&result));
Add(result, {m_vertex_prog.Id, m_fragment_prog.Id, pipelineProperties });
// RSX Debugger
/*if (Ini.GSLogPrograms.GetValue())
{
RSXDebuggerProgram program;
program.id = m_program.id;
program.vp_id = m_vertex_prog.id;
program.fp_id = m_fragment_prog.id;
program.vp_shader = m_vertex_prog.shader;
program.fp_shader = m_fragment_prog.shader;
m_debug_programs.push_back(program);
}*/
}
return result;
}
#define TO_STRING(x) #x
void Shader::Compile(const std::string &code, SHADER_TYPE st)

View File

@ -2,28 +2,37 @@
#if defined (DX12_SUPPORT)
#include <d3d12.h>
#include "Emu/RSX/RSXFragmentProgram.h"
#include "Emu/RSX/RSXVertexProgram.h"
#include <wrl/client.h>
#include "../Common/ProgramStateCache.h"
#include "VertexProgramDecompiler.h"
#include "FragmentProgramDecompiler.h"
#include "Utilities/File.h"
enum class SHADER_TYPE
{
SHADER_TYPE_VERTEX,
SHADER_TYPE_FRAGMENT
};
struct PipelineProperties
struct D3D12PipelineProperties
{
D3D12_PRIMITIVE_TOPOLOGY_TYPE Topology;
std::vector<D3D12_INPUT_ELEMENT_DESC> IASet;
bool operator==(const D3D12PipelineProperties &in) const
{
return Topology == in.Topology;
}
};
/** Storage for a shader
* Embeds the D3DBlob corresponding to
* Embeds the D3DBlob
*/
class Shader
struct Shader
{
public:
enum class SHADER_TYPE
{
SHADER_TYPE_VERTEX,
SHADER_TYPE_FRAGMENT
};
Shader() : bytecode(nullptr) {}
~Shader() {}
@ -37,222 +46,127 @@ public:
// void Decompile(RSXFragmentProgram& prog)
/** Compile the decompiled fragment shader into a format we can use with OpenGL. */
void Compile(const std::string &code, SHADER_TYPE st);
void Compile(const std::string &code, enum class SHADER_TYPE st);
};
namespace ProgramHashUtil
struct D3D12Traits
{
// Based on
// https://github.com/AlexAltea/nucleus/blob/master/nucleus/gpu/rsx_pgraph.cpp
union qword
{
u64 dword[2];
u32 word[4];
};
typedef Shader VertexProgramData;
typedef Shader FragmentProgramData;
typedef ID3D12PipelineState PipelineData;
typedef D3D12PipelineProperties PipelineProperties;
typedef std::pair<ID3D12Device *, ID3D12RootSignature *> ExtraData;
struct HashVertexProgram
static
void RecompileFragmentProgram(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID)
{
size_t operator()(const void *program) const
FragmentDecompiler FS(RSXFP->addr, RSXFP->size, RSXFP->offset);
const std::string &shader = FS.Decompile();
fragmentProgramData.Compile(shader, Shader::SHADER_TYPE::SHADER_TYPE_FRAGMENT);
// TODO: This shouldn't use current dir
fs::file("./FragmentProgram.hlsl", o_write | o_create | o_trunc).write(shader.c_str(), shader.size());
fragmentProgramData.Id = (u32)ID;
}
static
void RecompileVertexProgram(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID)
{
VertexDecompiler VS(RSXVP->data);
std::string shaderCode = VS.Decompile();
vertexProgramData.Compile(shaderCode, Shader::SHADER_TYPE::SHADER_TYPE_VERTEX);
// TODO: This shouldn't use current dir
fs::file("./VertexProgram.hlsl", o_write | o_create | o_trunc).write(shaderCode.c_str(), shaderCode.size());
vertexProgramData.Id = (u32)ID;
}
static
PipelineData *BuildProgram(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData)
{
ID3D12PipelineState *result;
D3D12_GRAPHICS_PIPELINE_STATE_DESC graphicPipelineStateDesc = {};
if (vertexProgramData.bytecode != nullptr)
{
// 64-bit Fowler/Noll/Vo FNV-1a hash code
size_t hash = 0xCBF29CE484222325ULL;
const qword *instbuffer = (const qword*)program;
size_t instIndex = 0;
bool end = false;
return 0;
while (true)
graphicPipelineStateDesc.VS.BytecodeLength = vertexProgramData.bytecode->GetBufferSize();
graphicPipelineStateDesc.VS.pShaderBytecode = vertexProgramData.bytecode->GetBufferPointer();
}
if (fragmentProgramData.bytecode != nullptr)
{
graphicPipelineStateDesc.PS.BytecodeLength = fragmentProgramData.bytecode->GetBufferSize();
graphicPipelineStateDesc.PS.pShaderBytecode = fragmentProgramData.bytecode->GetBufferPointer();
}
graphicPipelineStateDesc.pRootSignature = extraData.second;
// Sensible default value
static D3D12_RASTERIZER_DESC CD3D12_RASTERIZER_DESC =
{
D3D12_FILL_MODE_SOLID,
D3D12_CULL_MODE_NONE,
FALSE,
D3D12_DEFAULT_DEPTH_BIAS,
D3D12_DEFAULT_DEPTH_BIAS_CLAMP,
D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,
TRUE,
FALSE,
FALSE,
0,
D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF,
};
static D3D12_DEPTH_STENCIL_DESC CD3D12_DEPTH_STENCIL_DESC =
{
TRUE,
D3D12_DEPTH_WRITE_MASK_ALL,
D3D12_COMPARISON_FUNC_LESS_EQUAL,
FALSE,
D3D12_DEFAULT_STENCIL_READ_MASK,
D3D12_DEFAULT_STENCIL_WRITE_MASK,
};
static D3D12_BLEND_DESC CD3D12_BLEND_DESC =
{
FALSE,
FALSE,
{
const qword inst = instbuffer[instIndex];
bool end = inst.word[0] >> 31;
if (end)
return hash;
hash ^= inst.dword[0];
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
hash ^= inst.dword[1];
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
instIndex++;
FALSE,FALSE,
D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
D3D12_LOGIC_OP_NOOP,
D3D12_COLOR_WRITE_ENABLE_ALL,
}
return 0;
}
};
};
graphicPipelineStateDesc.BlendState = CD3D12_BLEND_DESC;
graphicPipelineStateDesc.DepthStencilState = CD3D12_DEPTH_STENCIL_DESC;
graphicPipelineStateDesc.RasterizerState = CD3D12_RASTERIZER_DESC;
graphicPipelineStateDesc.PrimitiveTopologyType = pipelineProperties.Topology;
struct VertexProgramCompare
graphicPipelineStateDesc.NumRenderTargets = 1;
graphicPipelineStateDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
graphicPipelineStateDesc.DSVFormat = DXGI_FORMAT_D16_UNORM;
graphicPipelineStateDesc.InputLayout.pInputElementDescs = pipelineProperties.IASet.data();
graphicPipelineStateDesc.InputLayout.NumElements = (UINT)pipelineProperties.IASet.size();
graphicPipelineStateDesc.SampleDesc.Count = 1;
graphicPipelineStateDesc.SampleMask = UINT_MAX;
graphicPipelineStateDesc.NodeMask = 1;
extraData.first->CreateGraphicsPipelineState(&graphicPipelineStateDesc, IID_PPV_ARGS(&result));
return result;
}
static
void DeleteProgram(PipelineData *ptr)
{
bool operator()(const void *binary1, const void *binary2) const
{
const qword *instBuffer1 = (const qword*)binary1;
const qword *instBuffer2 = (const qword*)binary2;
size_t instIndex = 0;
return true;
while (true)
{
const qword& inst1 = instBuffer1[instIndex];
const qword& inst2 = instBuffer2[instIndex];
bool end = (inst1.word[0] >> 31) && (inst2.word[0] >> 31);
if (end)
return true;
if (inst1.dword[0] != inst2.dword[0] || inst1.dword[1] != inst2.dword[1])
return false;
instIndex++;
}
}
};
struct FragmentProgramUtil
{
/**
* returns true if the given source Operand is a constant
*/
static bool isConstant(u32 sourceOperand)
{
return ((sourceOperand >> 8) & 0x3) == 2;
}
/**
* RSX fragment program constants are inlined inside shader code.
* This function takes an instruction from a fragment program and
* returns an equivalent instruction where inlined constants
* are masked.
* This allows to hash/compare fragment programs even if their
* inlined constants are modified inbetween
*/
static qword fragmentMaskConstant(const qword &initialQword)
{
qword result = initialQword;
if (isConstant(initialQword.word[1]))
result.word[1] = 0;
if (isConstant(initialQword.word[2]))
result.word[2] = 0;
if (isConstant(initialQword.word[3]))
result.word[3] = 0;
return result;
}
};
struct HashFragmentProgram
{
size_t operator()(const void *program) const
{
// 64-bit Fowler/Noll/Vo FNV-1a hash code
size_t hash = 0xCBF29CE484222325ULL;
const qword *instbuffer = (const qword*)program;
size_t instIndex = 0;
while (true)
{
const qword& inst = instbuffer[instIndex];
bool end = (inst.word[0] >> 8) & 0x1;
if (end)
return hash;
const qword& maskedInst = FragmentProgramUtil::fragmentMaskConstant(inst);
hash ^= maskedInst.dword[0];
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
hash ^= maskedInst.dword[1];
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
instIndex++;
// Skip constants
if (FragmentProgramUtil::isConstant(inst.word[1]) ||
FragmentProgramUtil::isConstant(inst.word[2]) ||
FragmentProgramUtil::isConstant(inst.word[3]))
instIndex++;
}
return 0;
}
};
struct FragmentProgramCompare
{
bool operator()(const void *binary1, const void *binary2) const
{
const qword *instBuffer1 = (const qword*)binary1;
const qword *instBuffer2 = (const qword*)binary2;
size_t instIndex = 0;
while (true)
{
const qword& inst1 = instBuffer1[instIndex];
const qword& inst2 = instBuffer2[instIndex];
bool end = ((inst1.word[0] >> 8) & 0x1) && ((inst2.word[0] >> 8) & 0x1);
if (end)
return true;
const qword& maskedInst1 = FragmentProgramUtil::fragmentMaskConstant(inst1);
const qword& maskedInst2 = FragmentProgramUtil::fragmentMaskConstant(inst2);
if (maskedInst1.dword[0] != maskedInst2.dword[0] || maskedInst1.dword[1] != maskedInst2.dword[1])
return false;
instIndex++;
// Skip constants
if (FragmentProgramUtil::isConstant(inst1.word[1]) ||
FragmentProgramUtil::isConstant(inst1.word[2]) ||
FragmentProgramUtil::isConstant(inst1.word[3]))
instIndex++;
}
}
};
}
typedef std::unordered_map<void *, Shader, ProgramHashUtil::HashVertexProgram, ProgramHashUtil::VertexProgramCompare> binary2VS;
typedef std::unordered_map<void *, Shader, ProgramHashUtil::HashFragmentProgram, ProgramHashUtil::FragmentProgramCompare> 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<unsigned>()(key.vpIdx);
return hashValue;
ptr->Release();
}
};
struct PSOKeyCompare
class PipelineStateObjectCache : public ProgramStateCache<D3D12Traits>
{
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
*/
class PipelineStateObjectCache
{
private:
size_t m_currentShaderId;
binary2VS m_cacheVS;
binary2FS m_cacheFS;
std::unordered_map<PSOKey, ID3D12PipelineState *, PSOKeyHash, PSOKeyCompare> m_cachePSO;
bool SearchFp(const RSXFragmentProgram& rsx_fp, Shader& shader);
bool SearchVp(const RSXVertexProgram& rsx_vp, Shader& shader);
ID3D12PipelineState *GetProg(const PSOKey &psoKey) const;
void AddVertexProgram(Shader& vp, RSXVertexProgram& rsx_vp);
void AddFragmentProgram(Shader& fp, RSXFragmentProgram& rsx_fp);
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 PipelineProperties &pipelineProperties,
const std::vector<D3D12_INPUT_ELEMENT_DESC> &IASet
);
};

View File

@ -69,7 +69,7 @@ void FragmentDecompiler::SetDst(std::string code, bool append_mask)
{
if (dst.set_cond)
{
AddCode("$ifcond " + m_parr.AddParam(PARAM_NONE, typeName[3], "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + code + ";");
AddCode("$ifcond " + m_parr.AddParam(PF_PARAM_NONE, typeName[3], "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + code + ";");
}
else
{
@ -86,7 +86,7 @@ void FragmentDecompiler::SetDst(std::string code, bool append_mask)
if (dst.set_cond)
{
AddCode(m_parr.AddParam(PARAM_NONE, typeName[3], "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + dest + ";");
AddCode(m_parr.AddParam(PF_PARAM_NONE, typeName[3], "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + dest + ";");
}
}
@ -114,24 +114,24 @@ std::string FragmentDecompiler::GetMask()
std::string FragmentDecompiler::AddReg(u32 index, int fp16)
{
return m_parr.AddParam(PARAM_NONE, typeName[3], std::string(fp16 ? "h" : "r") + std::to_string(index), typeName[3] + "(0.0)");
return m_parr.AddParam(PF_PARAM_NONE, typeName[3], std::string(fp16 ? "h" : "r") + std::to_string(index), typeName[3] + "(0.0)");
}
bool FragmentDecompiler::HasReg(u32 index, int fp16)
{
return m_parr.HasParam(PARAM_NONE, typeName[3],
return m_parr.HasParam(PF_PARAM_NONE, typeName[3],
std::string(fp16 ? "h" : "r") + std::to_string(index));
}
std::string FragmentDecompiler::AddCond()
{
return m_parr.AddParam(PARAM_NONE, typeName[3], "cc" + std::to_string(src0.cond_reg_index));
return m_parr.AddParam(PF_PARAM_NONE, typeName[3], "cc" + std::to_string(src0.cond_reg_index));
}
std::string FragmentDecompiler::AddConst()
{
std::string name = std::string("fc") + std::to_string(m_size + 4 * 4);
if (m_parr.HasParam(PARAM_UNIFORM, typeName[3], name))
if (m_parr.HasParam(PF_PARAM_UNIFORM, typeName[3], name))
{
return name;
}
@ -143,14 +143,14 @@ std::string FragmentDecompiler::AddConst()
u32 y = GetData(data[1]);
u32 z = GetData(data[2]);
u32 w = GetData(data[3]);
return m_parr.AddParam(PARAM_UNIFORM, typeName[3], name,
return m_parr.AddParam(PF_PARAM_UNIFORM, typeName[3], name,
std::string(typeName[3] + "(") + std::to_string((float&)x) + ", " + std::to_string((float&)y)
+ ", " + std::to_string((float&)z) + ", " + std::to_string((float&)w) + ")");
}
std::string FragmentDecompiler::AddTex()
{
return m_parr.AddParam(PARAM_UNIFORM, "sampler2D", std::string("tex") + std::to_string(dst.tex_num));
return m_parr.AddParam(PF_PARAM_UNIFORM, "sampler2D", std::string("tex") + std::to_string(dst.tex_num));
}
std::string FragmentDecompiler::Format(const std::string& code)
@ -275,7 +275,7 @@ void FragmentDecompiler::AddCodeCond(const std::string& dst, const std::string&
cond = "(" + AddCond() + swizzle + " " + cond + " " + typeName[3] + "(0., 0., 0., 0.))";
ShaderVar dst_var(dst);
ShaderVariable dst_var(dst);
dst_var.symplify();
//const char *c_mask = f;
@ -320,12 +320,12 @@ template<typename T> std::string FragmentDecompiler::GetSRC(T src)
default:
if (dst.src_attr_reg_num < sizeof(reg_table) / sizeof(reg_table[0]))
{
ret += m_parr.AddParam(PARAM_IN, typeName[3], reg_table[dst.src_attr_reg_num]);
ret += m_parr.AddParam(PF_PARAM_IN, typeName[3], reg_table[dst.src_attr_reg_num]);
}
else
{
LOG_ERROR(RSX, "Bad src reg num: %d", fmt::by_value(dst.src_attr_reg_num));
ret += m_parr.AddParam(PARAM_IN, typeName[3], "unk");
ret += m_parr.AddParam(PF_PARAM_IN, typeName[3], "unk");
Emu.Pause();
}
break;
@ -425,7 +425,7 @@ void FragmentDecompiler::insertOutputs(std::stringstream & OS)
for (int i = 0; i < sizeof(table) / sizeof(*table); ++i)
{
if (m_parr.HasParam(PARAM_NONE, typeName[3], table[i].second))
if (m_parr.HasParam(PF_PARAM_NONE, typeName[3], table[i].second))
OS << " " << typeName[3] << " " << table[i].first << " : SV_TARGET" << i << ";" << std::endl;
}
OS << "};" << std::endl;
@ -443,7 +443,7 @@ void FragmentDecompiler::insertConstants(std::stringstream & OS)
}
OS << "};" << std::endl;*/
for (ParamType PT : m_parr.params[PARAM_UNIFORM])
for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM])
{
for (ParamItem PI : PT.items)
OS << PT.type << " " << PI.name << " = " << PI.value << ";" << std::endl;
@ -454,13 +454,13 @@ void FragmentDecompiler::insertMainStart(std::stringstream & OS)
{
OS << "PixelOutput main(PixelInput In)" << std::endl;
OS << "{" << std::endl;
for (ParamType PT : m_parr.params[PARAM_IN])
for (ParamType PT : m_parr.params[PF_PARAM_IN])
{
for (ParamItem PI : PT.items)
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl;
}
// Declare output
for (ParamType PT : m_parr.params[PARAM_NONE])
for (ParamType PT : m_parr.params[PF_PARAM_NONE])
{
for (ParamItem PI : PT.items)
OS << " " << PT.type << " " << PI.name << " = float4(0., 0., 0., 0.);" << std::endl;
@ -480,7 +480,7 @@ void FragmentDecompiler::insertMainEnd(std::stringstream & OS)
OS << " PixelOutput Out;" << std::endl;
for (int i = 0; i < sizeof(table) / sizeof(*table); ++i)
{
if (m_parr.HasParam(PARAM_NONE, typeName[3], table[i].second))
if (m_parr.HasParam(PF_PARAM_NONE, typeName[3], table[i].second))
OS << " Out." << table[i].first << " = " << table[i].second << ";" << std::endl;
}
OS << " return Out;" << std::endl;

View File

@ -5,12 +5,12 @@
enum ParamFlag
{
PARAM_IN,
PARAM_OUT,
PARAM_UNIFORM,
PARAM_CONST,
PARAM_NONE,
PARAM_COUNT,
PF_PARAM_IN,
PF_PARAM_OUT,
PF_PARAM_UNIFORM,
PF_PARAM_CONST,
PF_PARAM_NONE,
PF_PARAM_COUNT,
};
struct ParamItem
@ -51,7 +51,7 @@ struct ParamType
struct ParamArray
{
std::vector<ParamType> params[PARAM_COUNT];
std::vector<ParamType> params[PF_PARAM_COUNT];
ParamType* SearchParam(const ParamFlag &flag, const std::string& type)
{
@ -105,14 +105,14 @@ struct ParamArray
}
};
class ShaderVar
class ShaderVariable
{
public:
std::string name;
std::vector<std::string> swizzles;
ShaderVar() = default;
ShaderVar(const std::string& var)
ShaderVariable() = default;
ShaderVariable(const std::string& var)
{
auto var_blocks = fmt::split(var, { "." });
@ -138,7 +138,7 @@ public:
return swizzles[swizzles.size() - 1].length();
}
ShaderVar& symplify()
ShaderVariable& symplify()
{
std::unordered_map<char, char> swizzle;

View File

@ -52,13 +52,13 @@ std::string VertexDecompiler::GetDST(bool isSca)
switch (isSca ? 0x1f : d3.dst)
{
case 0x1f:
ret += m_parr.AddParam(PARAM_NONE, typeName[3], std::string("tmp") + std::to_string(isSca ? d3.sca_dst_tmp : d0.dst_tmp));
ret += m_parr.AddParam(PF_PARAM_NONE, typeName[3], std::string("tmp") + std::to_string(isSca ? d3.sca_dst_tmp : d0.dst_tmp));
break;
default:
if (d3.dst > 15)
LOG_ERROR(RSX, fmt::Format("dst index out of range: %u", d3.dst));
ret += m_parr.AddParam(PARAM_NONE, typeName[3], std::string("dst_reg") + std::to_string(d3.dst), d3.dst == 0 ? typeName[3] + "(0.0f, 0.0f, 0.0f, 1.0f)" : typeName[3] + "(0.0, 0.0, 0.0, 0.0)");
ret += m_parr.AddParam(PF_PARAM_NONE, typeName[3], std::string("dst_reg") + std::to_string(d3.dst), d3.dst == 0 ? typeName[3] + "(0.0f, 0.0f, 0.0f, 1.0f)" : typeName[3] + "(0.0, 0.0, 0.0, 0.0)");
break;
}
@ -82,21 +82,21 @@ std::string VertexDecompiler::GetSRC(const u32 n)
switch (src[n].reg_type)
{
case 1: //temp
ret += m_parr.AddParam(PARAM_NONE, typeName[3], "tmp" + std::to_string(src[n].tmp_src));
ret += m_parr.AddParam(PF_PARAM_NONE, typeName[3], "tmp" + std::to_string(src[n].tmp_src));
break;
case 2: //input
if (d1.input_src < (sizeof(reg_table) / sizeof(reg_table[0])))
{
ret += m_parr.AddParam(PARAM_IN, typeName[3], reg_table[d1.input_src], d1.input_src);
ret += m_parr.AddParam(PF_PARAM_IN, typeName[3], reg_table[d1.input_src], d1.input_src);
}
else
{
LOG_ERROR(RSX, "Bad input src num: %d", fmt::by_value(d1.input_src));
ret += m_parr.AddParam(PARAM_IN, typeName[3], "in_unk", d1.input_src);
ret += m_parr.AddParam(PF_PARAM_IN, typeName[3], "in_unk", d1.input_src);
}
break;
case 3: //const
m_parr.AddParam(PARAM_UNIFORM, typeName[3], std::string("vc[468]"));
m_parr.AddParam(PF_PARAM_UNIFORM, typeName[3], std::string("vc[468]"));
ret += std::string("vc[") + std::to_string(d1.const_src) + (d3.index_const ? " + " + AddAddrReg() : "") + "]";
break;
@ -161,7 +161,7 @@ void VertexDecompiler::SetDST(bool is_sca, std::string value)
if (d0.cond_update_enable_0 && d0.cond_update_enable_1)
{
dest = m_parr.AddParam(PARAM_NONE, typeName[3], "cc" + std::to_string(d0.cond_reg_sel_1), typeName[3] + "(0.0)") + mask;
dest = m_parr.AddParam(PF_PARAM_NONE, typeName[3], "cc" + std::to_string(d0.cond_reg_sel_1), typeName[3] + "(0.0)") + mask;
}
else if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f))
{
@ -197,7 +197,7 @@ std::string VertexDecompiler::GetFunc()
std::string VertexDecompiler::GetTex()
{
return m_parr.AddParam(PARAM_UNIFORM, "sampler2D", std::string("vtex") + std::to_string(/*?.tex_num*/0));
return m_parr.AddParam(PF_PARAM_UNIFORM, "sampler2D", std::string("vtex") + std::to_string(/*?.tex_num*/0));
}
std::string VertexDecompiler::Format(const std::string& code)
@ -312,7 +312,7 @@ void VertexDecompiler::AddCodeCond(const std::string& dst, const std::string& sr
std::string cond = fmt::Format("%s(cc%d%s, vec4(0.0))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str());
ShaderVar dst_var(dst);
ShaderVariable dst_var(dst);
dst_var.symplify();
//const char *c_mask = f;
@ -340,7 +340,7 @@ std::string VertexDecompiler::AddAddrMask()
std::string VertexDecompiler::AddAddrReg()
{
static const char f[] = { 'x', 'y', 'z', 'w' };
return m_parr.AddParam(PARAM_NONE, "ivec4", "a" + std::to_string(d0.addr_reg_sel_1), "ivec4(0)") + AddAddrMask();
return m_parr.AddParam(PF_PARAM_NONE, "ivec4", "a" + std::to_string(d0.addr_reg_sel_1), "ivec4(0)") + AddAddrMask();
}
u32 VertexDecompiler::GetAddr()
@ -428,11 +428,11 @@ std::string VertexDecompiler::BuildCode()
std::stringstream OS;
insertHeader(OS);
insertInputs(OS, m_parr.params[PARAM_IN]);
insertInputs(OS, m_parr.params[PF_PARAM_IN]);
OS << std::endl;
insertOutputs(OS, m_parr.params[PARAM_NONE]);
insertOutputs(OS, m_parr.params[PF_PARAM_NONE]);
OS << std::endl;
insertConstants(OS, m_parr.params[PARAM_UNIFORM]);
insertConstants(OS, m_parr.params[PF_PARAM_UNIFORM]);
OS << std::endl;
insertMainStart(OS);
@ -541,11 +541,11 @@ void VertexDecompiler::insertMainStart(std::stringstream & OS)
// Declare inside main function
for (auto &i : reg_table)
{
if (m_parr.HasParam(PARAM_NONE, typeName[3], i.src_reg))
if (m_parr.HasParam(PF_PARAM_NONE, typeName[3], i.src_reg))
OS << " float4 " << i.src_reg << ";" << std::endl;
}
for (const ParamType PT : m_parr.params[PARAM_IN])
for (const ParamType PT : m_parr.params[PF_PARAM_IN])
{
for (const ParamItem &PI : PT.items)
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl;
@ -559,7 +559,7 @@ void VertexDecompiler::insertMainEnd(std::stringstream & OS)
// Declare inside main function
for (auto &i : reg_table)
{
if (m_parr.HasParam(PARAM_NONE, typeName[3], i.src_reg))
if (m_parr.HasParam(PF_PARAM_NONE, typeName[3], i.src_reg))
OS << " Out." << i.src_reg << " = " << i.src_reg << ";" << std::endl;
}
// TODO: Find why I need to do this
@ -583,7 +583,7 @@ VertexDecompiler::VertexDecompiler(std::vector<u32>& data) :
std::string VertexDecompiler::Decompile()
{
for (unsigned i = 0; i < PARAM_COUNT; i++)
for (unsigned i = 0; i < PF_PARAM_COUNT; i++)
m_parr.params[i].clear();
m_instr_count = 0;