mirror of https://github.com/RPCS3/rpcs3.git
d3d12: Use template class for caching
This commit is contained in:
parent
a58974eac8
commit
ba66992ee3
|
@ -471,7 +471,7 @@ bool D3D12GSRender::LoadProgram()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PipelineProperties prop = {};
|
D3D12PipelineProperties prop = {};
|
||||||
/*
|
/*
|
||||||
#define GL_POINTS 0x0000
|
#define GL_POINTS 0x0000
|
||||||
#define GL_LINES 0x0001
|
#define GL_LINES 0x0001
|
||||||
|
@ -504,8 +504,8 @@ bool D3D12GSRender::LoadProgram()
|
||||||
prop.Topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
prop.Topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
prop.IASet = m_IASet;
|
||||||
m_PSO = m_cachePSO.getGraphicPipelineState(m_device, m_rootSignature, m_cur_vertex_prog, m_cur_fragment_prog, prop, 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;
|
return m_PSO != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,279 +2,10 @@
|
||||||
#if defined (DX12_SUPPORT)
|
#if defined (DX12_SUPPORT)
|
||||||
|
|
||||||
#include "D3D12PipelineState.h"
|
#include "D3D12PipelineState.h"
|
||||||
#include "Emu/Memory/vm.h"
|
|
||||||
#include "Utilities/Log.h"
|
|
||||||
#include <wrl/client.h>
|
|
||||||
#include <d3dcompiler.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")
|
#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
|
#define TO_STRING(x) #x
|
||||||
|
|
||||||
void Shader::Compile(const std::string &code, SHADER_TYPE st)
|
void Shader::Compile(const std::string &code, SHADER_TYPE st)
|
||||||
|
|
|
@ -2,28 +2,37 @@
|
||||||
#if defined (DX12_SUPPORT)
|
#if defined (DX12_SUPPORT)
|
||||||
|
|
||||||
#include <d3d12.h>
|
#include <d3d12.h>
|
||||||
#include "Emu/RSX/RSXFragmentProgram.h"
|
|
||||||
#include "Emu/RSX/RSXVertexProgram.h"
|
|
||||||
#include <wrl/client.h>
|
#include <wrl/client.h>
|
||||||
|
#include "../Common/ProgramStateCache.h"
|
||||||
|
#include "VertexProgramDecompiler.h"
|
||||||
|
#include "FragmentProgramDecompiler.h"
|
||||||
|
#include "Utilities/File.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
struct Shader
|
||||||
|
{
|
||||||
|
public:
|
||||||
enum class SHADER_TYPE
|
enum class SHADER_TYPE
|
||||||
{
|
{
|
||||||
SHADER_TYPE_VERTEX,
|
SHADER_TYPE_VERTEX,
|
||||||
SHADER_TYPE_FRAGMENT
|
SHADER_TYPE_FRAGMENT
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PipelineProperties
|
|
||||||
{
|
|
||||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE Topology;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Storage for a shader
|
|
||||||
* Embeds the D3DBlob corresponding to
|
|
||||||
*/
|
|
||||||
class Shader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Shader() : bytecode(nullptr) {}
|
Shader() : bytecode(nullptr) {}
|
||||||
~Shader() {}
|
~Shader() {}
|
||||||
|
|
||||||
|
@ -37,222 +46,127 @@ public:
|
||||||
// void Decompile(RSXFragmentProgram& prog)
|
// void Decompile(RSXFragmentProgram& prog)
|
||||||
|
|
||||||
/** Compile the decompiled fragment shader into a format we can use with OpenGL. */
|
/** 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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct D3D12Traits
|
||||||
|
{
|
||||||
|
typedef Shader VertexProgramData;
|
||||||
|
typedef Shader FragmentProgramData;
|
||||||
|
typedef ID3D12PipelineState PipelineData;
|
||||||
|
typedef D3D12PipelineProperties PipelineProperties;
|
||||||
|
typedef std::pair<ID3D12Device *, ID3D12RootSignature *> ExtraData;
|
||||||
|
|
||||||
|
static
|
||||||
|
void RecompileFragmentProgram(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID)
|
||||||
|
{
|
||||||
|
FragmentDecompiler FS(RSXFP->addr, RSXFP->size, RSXFP->offset);
|
||||||
|
const std::string &shader = FS.Decompile();
|
||||||
|
fragmentProgramData.Compile(shader, Shader::SHADER_TYPE::SHADER_TYPE_FRAGMENT);
|
||||||
|
|
||||||
namespace ProgramHashUtil
|
// TODO: This shouldn't use current dir
|
||||||
{
|
fs::file("./FragmentProgram.hlsl", o_write | o_create | o_trunc).write(shader.c_str(), shader.size());
|
||||||
// Based on
|
fragmentProgramData.Id = (u32)ID;
|
||||||
// https://github.com/AlexAltea/nucleus/blob/master/nucleus/gpu/rsx_pgraph.cpp
|
|
||||||
union qword
|
|
||||||
{
|
|
||||||
u64 dword[2];
|
|
||||||
u32 word[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HashVertexProgram
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
bool end = false;
|
|
||||||
return 0;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
struct VertexProgramCompare
|
graphicPipelineStateDesc.NumRenderTargets = 1;
|
||||||
{
|
graphicPipelineStateDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
bool operator()(const void *binary1, const void *binary2) const
|
graphicPipelineStateDesc.DSVFormat = DXGI_FORMAT_D16_UNORM;
|
||||||
{
|
|
||||||
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
|
graphicPipelineStateDesc.InputLayout.pInputElementDescs = pipelineProperties.IASet.data();
|
||||||
{
|
graphicPipelineStateDesc.InputLayout.NumElements = (UINT)pipelineProperties.IASet.size();
|
||||||
/**
|
graphicPipelineStateDesc.SampleDesc.Count = 1;
|
||||||
* returns true if the given source Operand is a constant
|
graphicPipelineStateDesc.SampleMask = UINT_MAX;
|
||||||
*/
|
graphicPipelineStateDesc.NodeMask = 1;
|
||||||
static bool isConstant(u32 sourceOperand)
|
|
||||||
{
|
|
||||||
return ((sourceOperand >> 8) & 0x3) == 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
extraData.first->CreateGraphicsPipelineState(&graphicPipelineStateDesc, IID_PPV_ARGS(&result));
|
||||||
* 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;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
struct HashFragmentProgram
|
static
|
||||||
|
void DeleteProgram(PipelineData *ptr)
|
||||||
{
|
{
|
||||||
size_t operator()(const void *program) const
|
ptr->Release();
|
||||||
{
|
|
||||||
// 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
|
class PipelineStateObjectCache : public ProgramStateCache<D3D12Traits>
|
||||||
{
|
{
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ void FragmentDecompiler::SetDst(std::string code, bool append_mask)
|
||||||
{
|
{
|
||||||
if (dst.set_cond)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -86,7 +86,7 @@ void FragmentDecompiler::SetDst(std::string code, bool append_mask)
|
||||||
|
|
||||||
if (dst.set_cond)
|
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)
|
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)
|
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(fp16 ? "h" : "r") + std::to_string(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FragmentDecompiler::AddCond()
|
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 FragmentDecompiler::AddConst()
|
||||||
{
|
{
|
||||||
std::string name = std::string("fc") + std::to_string(m_size + 4 * 4);
|
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;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -143,14 +143,14 @@ std::string FragmentDecompiler::AddConst()
|
||||||
u32 y = GetData(data[1]);
|
u32 y = GetData(data[1]);
|
||||||
u32 z = GetData(data[2]);
|
u32 z = GetData(data[2]);
|
||||||
u32 w = GetData(data[3]);
|
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::string(typeName[3] + "(") + std::to_string((float&)x) + ", " + std::to_string((float&)y)
|
||||||
+ ", " + std::to_string((float&)z) + ", " + std::to_string((float&)w) + ")");
|
+ ", " + std::to_string((float&)z) + ", " + std::to_string((float&)w) + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FragmentDecompiler::AddTex()
|
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)
|
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.))";
|
cond = "(" + AddCond() + swizzle + " " + cond + " " + typeName[3] + "(0., 0., 0., 0.))";
|
||||||
|
|
||||||
ShaderVar dst_var(dst);
|
ShaderVariable dst_var(dst);
|
||||||
dst_var.symplify();
|
dst_var.symplify();
|
||||||
|
|
||||||
//const char *c_mask = f;
|
//const char *c_mask = f;
|
||||||
|
@ -320,12 +320,12 @@ template<typename T> std::string FragmentDecompiler::GetSRC(T src)
|
||||||
default:
|
default:
|
||||||
if (dst.src_attr_reg_num < sizeof(reg_table) / sizeof(reg_table[0]))
|
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
|
else
|
||||||
{
|
{
|
||||||
LOG_ERROR(RSX, "Bad src reg num: %d", fmt::by_value(dst.src_attr_reg_num));
|
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();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -425,7 +425,7 @@ void FragmentDecompiler::insertOutputs(std::stringstream & OS)
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(table) / sizeof(*table); ++i)
|
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 << " " << typeName[3] << " " << table[i].first << " : SV_TARGET" << i << ";" << std::endl;
|
||||||
}
|
}
|
||||||
OS << "};" << std::endl;
|
OS << "};" << std::endl;
|
||||||
|
@ -443,7 +443,7 @@ void FragmentDecompiler::insertConstants(std::stringstream & OS)
|
||||||
}
|
}
|
||||||
OS << "};" << std::endl;*/
|
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)
|
for (ParamItem PI : PT.items)
|
||||||
OS << PT.type << " " << PI.name << " = " << PI.value << ";" << std::endl;
|
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 << "PixelOutput main(PixelInput In)" << std::endl;
|
||||||
OS << "{" << 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)
|
for (ParamItem PI : PT.items)
|
||||||
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl;
|
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl;
|
||||||
}
|
}
|
||||||
// Declare output
|
// Declare output
|
||||||
for (ParamType PT : m_parr.params[PARAM_NONE])
|
for (ParamType PT : m_parr.params[PF_PARAM_NONE])
|
||||||
{
|
{
|
||||||
for (ParamItem PI : PT.items)
|
for (ParamItem PI : PT.items)
|
||||||
OS << " " << PT.type << " " << PI.name << " = float4(0., 0., 0., 0.);" << std::endl;
|
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;
|
OS << " PixelOutput Out;" << std::endl;
|
||||||
for (int i = 0; i < sizeof(table) / sizeof(*table); ++i)
|
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 << " Out." << table[i].first << " = " << table[i].second << ";" << std::endl;
|
||||||
}
|
}
|
||||||
OS << " return Out;" << std::endl;
|
OS << " return Out;" << std::endl;
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
|
|
||||||
enum ParamFlag
|
enum ParamFlag
|
||||||
{
|
{
|
||||||
PARAM_IN,
|
PF_PARAM_IN,
|
||||||
PARAM_OUT,
|
PF_PARAM_OUT,
|
||||||
PARAM_UNIFORM,
|
PF_PARAM_UNIFORM,
|
||||||
PARAM_CONST,
|
PF_PARAM_CONST,
|
||||||
PARAM_NONE,
|
PF_PARAM_NONE,
|
||||||
PARAM_COUNT,
|
PF_PARAM_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ParamItem
|
struct ParamItem
|
||||||
|
@ -51,7 +51,7 @@ struct ParamType
|
||||||
|
|
||||||
struct ParamArray
|
struct ParamArray
|
||||||
{
|
{
|
||||||
std::vector<ParamType> params[PARAM_COUNT];
|
std::vector<ParamType> params[PF_PARAM_COUNT];
|
||||||
|
|
||||||
ParamType* SearchParam(const ParamFlag &flag, const std::string& type)
|
ParamType* SearchParam(const ParamFlag &flag, const std::string& type)
|
||||||
{
|
{
|
||||||
|
@ -105,14 +105,14 @@ struct ParamArray
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShaderVar
|
class ShaderVariable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<std::string> swizzles;
|
std::vector<std::string> swizzles;
|
||||||
|
|
||||||
ShaderVar() = default;
|
ShaderVariable() = default;
|
||||||
ShaderVar(const std::string& var)
|
ShaderVariable(const std::string& var)
|
||||||
{
|
{
|
||||||
auto var_blocks = fmt::split(var, { "." });
|
auto var_blocks = fmt::split(var, { "." });
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ public:
|
||||||
return swizzles[swizzles.size() - 1].length();
|
return swizzles[swizzles.size() - 1].length();
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderVar& symplify()
|
ShaderVariable& symplify()
|
||||||
{
|
{
|
||||||
std::unordered_map<char, char> swizzle;
|
std::unordered_map<char, char> swizzle;
|
||||||
|
|
||||||
|
|
|
@ -52,13 +52,13 @@ std::string VertexDecompiler::GetDST(bool isSca)
|
||||||
switch (isSca ? 0x1f : d3.dst)
|
switch (isSca ? 0x1f : d3.dst)
|
||||||
{
|
{
|
||||||
case 0x1f:
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (d3.dst > 15)
|
if (d3.dst > 15)
|
||||||
LOG_ERROR(RSX, fmt::Format("dst index out of range: %u", d3.dst));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,21 +82,21 @@ std::string VertexDecompiler::GetSRC(const u32 n)
|
||||||
switch (src[n].reg_type)
|
switch (src[n].reg_type)
|
||||||
{
|
{
|
||||||
case 1: //temp
|
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;
|
break;
|
||||||
case 2: //input
|
case 2: //input
|
||||||
if (d1.input_src < (sizeof(reg_table) / sizeof(reg_table[0])))
|
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
|
else
|
||||||
{
|
{
|
||||||
LOG_ERROR(RSX, "Bad input src num: %d", fmt::by_value(d1.input_src));
|
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;
|
break;
|
||||||
case 3: //const
|
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() : "") + "]";
|
ret += std::string("vc[") + std::to_string(d1.const_src) + (d3.index_const ? " + " + AddAddrReg() : "") + "]";
|
||||||
break;
|
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)
|
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))
|
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()
|
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)
|
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());
|
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();
|
dst_var.symplify();
|
||||||
|
|
||||||
//const char *c_mask = f;
|
//const char *c_mask = f;
|
||||||
|
@ -340,7 +340,7 @@ std::string VertexDecompiler::AddAddrMask()
|
||||||
std::string VertexDecompiler::AddAddrReg()
|
std::string VertexDecompiler::AddAddrReg()
|
||||||
{
|
{
|
||||||
static const char f[] = { 'x', 'y', 'z', 'w' };
|
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()
|
u32 VertexDecompiler::GetAddr()
|
||||||
|
@ -428,11 +428,11 @@ std::string VertexDecompiler::BuildCode()
|
||||||
std::stringstream OS;
|
std::stringstream OS;
|
||||||
insertHeader(OS);
|
insertHeader(OS);
|
||||||
|
|
||||||
insertInputs(OS, m_parr.params[PARAM_IN]);
|
insertInputs(OS, m_parr.params[PF_PARAM_IN]);
|
||||||
OS << std::endl;
|
OS << std::endl;
|
||||||
insertOutputs(OS, m_parr.params[PARAM_NONE]);
|
insertOutputs(OS, m_parr.params[PF_PARAM_NONE]);
|
||||||
OS << std::endl;
|
OS << std::endl;
|
||||||
insertConstants(OS, m_parr.params[PARAM_UNIFORM]);
|
insertConstants(OS, m_parr.params[PF_PARAM_UNIFORM]);
|
||||||
OS << std::endl;
|
OS << std::endl;
|
||||||
|
|
||||||
insertMainStart(OS);
|
insertMainStart(OS);
|
||||||
|
@ -541,11 +541,11 @@ void VertexDecompiler::insertMainStart(std::stringstream & OS)
|
||||||
// Declare inside main function
|
// Declare inside main function
|
||||||
for (auto &i : reg_table)
|
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;
|
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)
|
for (const ParamItem &PI : PT.items)
|
||||||
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl;
|
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl;
|
||||||
|
@ -559,7 +559,7 @@ void VertexDecompiler::insertMainEnd(std::stringstream & OS)
|
||||||
// Declare inside main function
|
// Declare inside main function
|
||||||
for (auto &i : reg_table)
|
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;
|
OS << " Out." << i.src_reg << " = " << i.src_reg << ";" << std::endl;
|
||||||
}
|
}
|
||||||
// TODO: Find why I need to do this
|
// TODO: Find why I need to do this
|
||||||
|
@ -583,7 +583,7 @@ VertexDecompiler::VertexDecompiler(std::vector<u32>& data) :
|
||||||
|
|
||||||
std::string VertexDecompiler::Decompile()
|
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_parr.params[i].clear();
|
||||||
m_instr_count = 0;
|
m_instr_count = 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue