mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 12:05:23 +00:00
d3d12: Start caching shaders
This commit is contained in:
parent
728736ccdd
commit
d5b4a31c37
5 changed files with 369 additions and 27 deletions
|
@ -18,7 +18,7 @@ static void check(HRESULT hr)
|
|||
}
|
||||
|
||||
D3D12GSRender::D3D12GSRender()
|
||||
: GSRender(), m_fbo(nullptr)
|
||||
: GSRender(), m_fbo(nullptr), m_PSO(nullptr)
|
||||
{
|
||||
// Enable d3d debug layer
|
||||
Microsoft::WRL::ComPtr<ID3D12Debug> debugInterface;
|
||||
|
@ -132,7 +132,6 @@ void D3D12GSRender::ExecCMD(u32 cmd)
|
|||
check(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator, nullptr, IID_PPV_ARGS(&commandList)));
|
||||
m_inflightCommandList.push_back(commandList);
|
||||
|
||||
|
||||
/* if (m_set_color_mask)
|
||||
{
|
||||
glColorMask(m_color_mask_r, m_color_mask_g, m_color_mask_b, m_color_mask_a);
|
||||
|
@ -143,9 +142,7 @@ void D3D12GSRender::ExecCMD(u32 cmd)
|
|||
{
|
||||
glScissor(m_scissor_x, m_scissor_y, m_scissor_w, m_scissor_h);
|
||||
checkForGlError("glScissor");
|
||||
}
|
||||
|
||||
GLbitfield f = 0;*/
|
||||
}*/
|
||||
|
||||
// TODO: Merge depth and stencil clear when possible
|
||||
if (m_clear_surface_mask & 0x1)
|
||||
|
@ -191,26 +188,36 @@ void D3D12GSRender::ExecCMD(u32 cmd)
|
|||
default:
|
||||
LOG_ERROR(RSX, "Bad surface color target: %d", m_surface_color_target);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// transition.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
// transition.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||
|
||||
// commandList->ResourceBarrier(1, &transition);
|
||||
|
||||
check(commandList->Close());
|
||||
m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**) &commandList);
|
||||
}
|
||||
|
||||
|
||||
bool D3D12GSRender::LoadProgram()
|
||||
{
|
||||
if (!m_cur_fragment_prog)
|
||||
{
|
||||
LOG_WARNING(RSX, "LoadProgram: m_cur_shader_prog == NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_cur_fragment_prog->ctrl = m_shader_ctrl;
|
||||
|
||||
if (!m_cur_vertex_prog)
|
||||
{
|
||||
LOG_WARNING(RSX, "LoadProgram: m_cur_vertex_prog == NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_PSO = new D3D12PipelineState(m_device, m_cur_vertex_prog, m_cur_fragment_prog);
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D12GSRender::ExecCMD()
|
||||
{
|
||||
ID3D12CommandList *commandList;
|
||||
// m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator, nullptr, IID_PPV_ARGS(&commandList));
|
||||
|
||||
|
||||
//return;
|
||||
/* if (!LoadProgram())
|
||||
if (!LoadProgram())
|
||||
{
|
||||
LOG_ERROR(RSX, "LoadProgram failed.");
|
||||
Emu.Pause();
|
||||
|
@ -219,7 +226,10 @@ void D3D12GSRender::ExecCMD()
|
|||
|
||||
InitDrawBuffers();
|
||||
|
||||
if (m_set_color_mask)
|
||||
ID3D12CommandList *commandList;
|
||||
// m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator, nullptr, IID_PPV_ARGS(&commandList));
|
||||
|
||||
/* if (m_set_color_mask)
|
||||
{
|
||||
glColorMask(m_color_mask_r, m_color_mask_g, m_color_mask_b, m_color_mask_a);
|
||||
checkForGlError("glColorMask");
|
||||
|
@ -262,11 +272,6 @@ void D3D12GSRender::ExecCMD()
|
|||
Enable(m_set_line_stipple, GL_LINE_STIPPLE);
|
||||
Enable(m_set_polygon_stipple, GL_POLYGON_STIPPLE);
|
||||
|
||||
if (!is_intel_vendor)
|
||||
{
|
||||
Enable(m_set_depth_bounds_test, GL_DEPTH_BOUNDS_TEST_EXT);
|
||||
}
|
||||
|
||||
if (m_set_clip_plane)
|
||||
{
|
||||
Enable(m_clip_plane_0, GL_CLIP_PLANE0);
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
#include "Emu/RSX/GSRender.h"
|
||||
|
||||
#include "D3D12RenderTargetSets.h"
|
||||
#include "D3D12PipelineState.h"
|
||||
|
||||
#pragma comment (lib, "d3d12.lib")
|
||||
#pragma comment (lib, "dxgi.lib")
|
||||
#pragma comment (lib, "d3dcompiler.lib")
|
||||
|
||||
class GSFrameBase2
|
||||
{
|
||||
|
@ -47,7 +47,7 @@ private:
|
|||
// std::vector<u8> m_vdata;
|
||||
// std::vector<PostDrawObj> m_post_draw_objs;
|
||||
|
||||
// GLProgram m_program;
|
||||
D3D12PipelineState *m_PSO;
|
||||
int m_fp_buf_num;
|
||||
int m_vp_buf_num;
|
||||
// GLProgramBuffer m_prog_buffer;
|
||||
|
@ -60,7 +60,6 @@ private:
|
|||
|
||||
// GLvao m_vao;
|
||||
// GLvbo m_vbo;
|
||||
// GLrbo m_rbo;
|
||||
D3D12RenderTargetSets *m_fbo;
|
||||
ID3D12Device* m_device;
|
||||
ID3D12CommandQueue *m_commandQueueCopy;
|
||||
|
@ -86,6 +85,8 @@ public:
|
|||
|
||||
private:
|
||||
virtual void Close() override;
|
||||
|
||||
bool LoadProgram();
|
||||
/* void EnableVertexData(bool indexed_draw = false);
|
||||
void DisableVertexData();
|
||||
void InitVertexData();
|
||||
|
@ -93,7 +94,7 @@ private:
|
|||
|
||||
void Enable(bool enable, const u32 cap);
|
||||
|
||||
bool LoadProgram();
|
||||
|
||||
void WriteBuffers();
|
||||
void WriteDepthBuffer();
|
||||
void WriteColorBuffers();
|
||||
|
|
315
rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp
Normal file
315
rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp
Normal file
|
@ -0,0 +1,315 @@
|
|||
#include "stdafx.h"
|
||||
#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>
|
||||
|
||||
#pragma comment (lib, "d3dcompiler.lib")
|
||||
|
||||
std::unordered_map<std::string, Microsoft::WRL::ComPtr<ID3DBlob> > CachedShader;
|
||||
|
||||
struct GLBufferInfo
|
||||
{
|
||||
ID3D12PipelineState *prog_id;
|
||||
u32 fp_id;
|
||||
u32 vp_id;
|
||||
std::vector<u8> fp_data;
|
||||
std::vector<u32> vp_data;
|
||||
std::string fp_shader;
|
||||
std::string vp_shader;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> fp_bytecode;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> vp_bytecode;
|
||||
};
|
||||
|
||||
// Copied from GL implementation
|
||||
|
||||
enum class SHADER_TYPE
|
||||
{
|
||||
SHADER_TYPE_VERTEX,
|
||||
SHADER_TYPE_FRAGMENT
|
||||
};
|
||||
|
||||
/** Storage for a shader
|
||||
* Embeds the D3DBlob corresponding to
|
||||
*/
|
||||
class Shader
|
||||
{
|
||||
public:
|
||||
Shader() : bytecode(nullptr) {}
|
||||
~Shader() {}
|
||||
|
||||
// GLParamArray parr;
|
||||
u32 id;
|
||||
std::string shader;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> bytecode;
|
||||
|
||||
/**
|
||||
* Decompile a fragment shader located in the PS3's Memory. This function operates synchronously.
|
||||
* @param prog RSXShaderProgram specifying the location and size of the shader in memory
|
||||
*/
|
||||
// void Decompile(RSXFragmentProgram& prog);
|
||||
|
||||
/**
|
||||
* Asynchronously decompile a fragment shader located in the PS3's Memory.
|
||||
* When this function is called you must call Wait() before GetShaderText() will return valid data.
|
||||
* @param prog RSXShaderProgram specifying the location and size of the shader in memory
|
||||
*/
|
||||
// void DecompileAsync(RSXFragmentProgram& prog);
|
||||
|
||||
/** Wait for the decompiler task to complete decompilation. */
|
||||
// void Wait();
|
||||
|
||||
/** Compile the decompiled fragment shader into a format we can use with OpenGL. */
|
||||
void Compile(SHADER_TYPE st)
|
||||
{
|
||||
static const char VSstring[] =
|
||||
"float4 main(float4 pos : POSITION) : SV_POSITION"
|
||||
"{"
|
||||
" return pos;"
|
||||
"}";
|
||||
static const char FSstring[] =
|
||||
"float4 main() : SV_TARGET"
|
||||
"{"
|
||||
"return float4(1.0f, 1.0f, 1.0f, 1.0f);"
|
||||
"}";
|
||||
HRESULT hr;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob;
|
||||
switch (st)
|
||||
{
|
||||
case SHADER_TYPE::SHADER_TYPE_VERTEX:
|
||||
hr = D3DCompile(VSstring, sizeof(VSstring), "test", nullptr, nullptr, "main", "vs_5_0", 0, 0, bytecode.GetAddressOf(), errorBlob.GetAddressOf());
|
||||
if (hr != S_OK)
|
||||
LOG_ERROR(RSX, "VS build failed:%s", errorBlob->GetBufferPointer());
|
||||
break;
|
||||
case SHADER_TYPE::SHADER_TYPE_FRAGMENT:
|
||||
hr = D3DCompile(FSstring, sizeof(FSstring), "test", nullptr, nullptr, "main", "ps_5_0", 0, 0, bytecode.GetAddressOf(), errorBlob.GetAddressOf());
|
||||
if (hr != S_OK)
|
||||
LOG_ERROR(RSX, "FS build failed:%s", errorBlob->GetBufferPointer());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/** Threaded fragment shader decompiler responsible for decompiling this program */
|
||||
// GLFragmentDecompilerThread* m_decompiler_thread;
|
||||
|
||||
/** Deletes the shader and any stored information */
|
||||
// void Delete();
|
||||
};
|
||||
|
||||
// Could be improved with an (un)ordered map ?
|
||||
class ProgramBuffer
|
||||
{
|
||||
std::vector<GLBufferInfo> m_buf;
|
||||
public:
|
||||
int SearchFp(const RSXFragmentProgram& rsx_fp, Shader& shader)
|
||||
{
|
||||
int n = m_buf.size();
|
||||
for (int i = 0; i < m_buf.size(); ++i)
|
||||
{
|
||||
if (memcmp(&m_buf[i].fp_data[0], vm::get_ptr<void>(rsx_fp.addr), m_buf[i].fp_data.size()) != 0) continue;
|
||||
|
||||
shader.id = m_buf[i].fp_id;
|
||||
shader.shader = m_buf[i].fp_shader.c_str();
|
||||
shader.bytecode = m_buf[i].fp_bytecode;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SearchVp(const RSXVertexProgram& rsx_vp, Shader& shader)
|
||||
{
|
||||
for (u32 i = 0; i < m_buf.size(); ++i)
|
||||
{
|
||||
if (m_buf[i].vp_data.size() != rsx_vp.data.size()) continue;
|
||||
if (memcmp(m_buf[i].vp_data.data(), rsx_vp.data.data(), rsx_vp.data.size() * 4) != 0) continue;
|
||||
|
||||
shader.id = m_buf[i].vp_id;
|
||||
shader.shader = m_buf[i].vp_shader.c_str();
|
||||
shader.bytecode = m_buf[i].vp_bytecode;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ID3D12PipelineState *GetProg(u32 fp, u32 vp) const
|
||||
{
|
||||
if (fp == vp)
|
||||
{
|
||||
/*
|
||||
LOG_NOTICE(RSX, "Get program (%d):", fp);
|
||||
LOG_NOTICE(RSX, "*** prog id = %d", m_buf[fp].prog_id);
|
||||
LOG_NOTICE(RSX, "*** vp id = %d", m_buf[fp].vp_id);
|
||||
LOG_NOTICE(RSX, "*** fp id = %d", m_buf[fp].fp_id);
|
||||
|
||||
LOG_NOTICE(RSX, "*** vp shader = \n%s", m_buf[fp].vp_shader.wx_str());
|
||||
LOG_NOTICE(RSX, "*** fp shader = \n%s", m_buf[fp].fp_shader.wx_str());
|
||||
*/
|
||||
return m_buf[fp].prog_id;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i<m_buf.size(); ++i)
|
||||
{
|
||||
if (i == fp || i == vp) continue;
|
||||
|
||||
// if (CmpVP(vp, i) && CmpFP(fp, i))
|
||||
{
|
||||
/*
|
||||
LOG_NOTICE(RSX, "Get program (%d):", i);
|
||||
LOG_NOTICE(RSX, "*** prog id = %d", m_buf[i].prog_id);
|
||||
LOG_NOTICE(RSX, "*** vp id = %d", m_buf[i].vp_id);
|
||||
LOG_NOTICE(RSX, "*** fp id = %d", m_buf[i].fp_id);
|
||||
|
||||
LOG_NOTICE(RSX, "*** vp shader = \n%s", m_buf[i].vp_shader.wx_str());
|
||||
LOG_NOTICE(RSX, "*** fp shader = \n%s", m_buf[i].fp_shader.wx_str());
|
||||
*/
|
||||
return m_buf[i].prog_id;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Add(ID3D12PipelineState *prog, Shader& fp, RSXFragmentProgram& rsx_fp, Shader& vp, RSXVertexProgram& rsx_vp)
|
||||
{
|
||||
GLBufferInfo new_buf = {};
|
||||
|
||||
LOG_NOTICE(RSX, "Add program (%d):", m_buf.size());
|
||||
LOG_NOTICE(RSX, "*** prog id = %x", prog);
|
||||
LOG_NOTICE(RSX, "*** vp id = %d", vp.id);
|
||||
LOG_NOTICE(RSX, "*** fp id = %d", fp.id);
|
||||
LOG_NOTICE(RSX, "*** vp data size = %d", rsx_vp.data.size() * 4);
|
||||
LOG_NOTICE(RSX, "*** fp data size = %d", rsx_fp.size);
|
||||
|
||||
LOG_NOTICE(RSX, "*** vp shader = \n%s", vp.shader.c_str());
|
||||
LOG_NOTICE(RSX, "*** fp shader = \n%s", fp.shader.c_str());
|
||||
|
||||
|
||||
new_buf.prog_id = prog;
|
||||
new_buf.vp_id = vp.id;
|
||||
new_buf.fp_id = fp.id;
|
||||
new_buf.fp_bytecode = fp.bytecode;
|
||||
|
||||
new_buf.fp_data.insert(new_buf.fp_data.end(), vm::get_ptr<u8>(rsx_fp.addr), vm::get_ptr<u8>(rsx_fp.addr + rsx_fp.size));
|
||||
new_buf.vp_data = rsx_vp.data;
|
||||
new_buf.vp_bytecode = vp.bytecode;
|
||||
|
||||
new_buf.vp_shader = vp.shader;
|
||||
new_buf.fp_shader = fp.shader;
|
||||
|
||||
m_buf.resize(m_buf.size() + 1);
|
||||
m_buf.push_back(new_buf);
|
||||
}
|
||||
};
|
||||
|
||||
static ProgramBuffer g_cachedProgram;
|
||||
|
||||
D3D12PipelineState::D3D12PipelineState(ID3D12Device *device, RSXVertexProgram *vertexShader, RSXFragmentProgram *fragmentShader)
|
||||
{
|
||||
Shader m_vertex_prog, m_fragment_prog;
|
||||
int m_fp_buf_num = g_cachedProgram.SearchFp(*fragmentShader, m_fragment_prog);
|
||||
int m_vp_buf_num = g_cachedProgram.SearchVp(*vertexShader, m_vertex_prog);
|
||||
|
||||
if (m_fp_buf_num == -1)
|
||||
{
|
||||
LOG_WARNING(RSX, "FP not found in buffer!");
|
||||
// m_fragment_prog.Decompile(*fragmentShader);
|
||||
m_fragment_prog.Compile(SHADER_TYPE::SHADER_TYPE_FRAGMENT);
|
||||
|
||||
// TODO: This shouldn't use current dir
|
||||
// fs::file("./FragmentProgram.txt", o_write | o_create | o_trunc).write(m_fragment_prog.shader.c_str(), m_fragment_prog.shader.size());
|
||||
}
|
||||
|
||||
if (m_vp_buf_num == -1)
|
||||
{
|
||||
LOG_WARNING(RSX, "VP not found in buffer!");
|
||||
// m_vertex_prog.Decompile(*vertexShader);
|
||||
m_vertex_prog.Compile(SHADER_TYPE::SHADER_TYPE_VERTEX);
|
||||
|
||||
// TODO: This shouldn't use current dir
|
||||
// fs::file("./VertexProgram.txt", o_write | o_create | o_trunc).write(m_vertex_prog.shader.c_str(), m_vertex_prog.shader.size());
|
||||
}
|
||||
|
||||
if (m_fp_buf_num != -1 && m_vp_buf_num != -1)
|
||||
{
|
||||
// m_program.id = m_prog_buffer.GetProg(m_fp_buf_num, m_vp_buf_num);
|
||||
}
|
||||
|
||||
if (false)//m_program.id)
|
||||
{
|
||||
/* // 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
|
||||
{
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC graphicPipelineStateDesc = {};
|
||||
|
||||
graphicPipelineStateDesc.VS.BytecodeLength = m_vertex_prog.bytecode->GetBufferSize();
|
||||
graphicPipelineStateDesc.VS.pShaderBytecode = m_vertex_prog.bytecode->GetBufferPointer();
|
||||
graphicPipelineStateDesc.PS.BytecodeLength = m_fragment_prog.bytecode->GetBufferSize();
|
||||
graphicPipelineStateDesc.PS.pShaderBytecode = m_fragment_prog.bytecode->GetBufferPointer();
|
||||
device->CreateGraphicsPipelineState(&graphicPipelineStateDesc, IID_PPV_ARGS(&m_pipelineStateObject));
|
||||
g_cachedProgram.Add(m_pipelineStateObject, m_fragment_prog, *fragmentShader, m_vertex_prog, *vertexShader);
|
||||
/*m_program.Create(m_vertex_prog.id, m_fragment_prog.id);
|
||||
checkForGlError("m_program.Create");
|
||||
m_prog_buffer.Add(m_program, m_fragment_prog, *m_cur_fragment_prog, m_vertex_prog, *m_cur_vertex_prog);
|
||||
checkForGlError("m_prog_buffer.Add");
|
||||
m_program.Use();
|
||||
|
||||
// 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);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
D3D12PipelineState::~D3D12PipelineState()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
17
rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h
Normal file
17
rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#if defined (DX12_SUPPORT)
|
||||
|
||||
#include <d3d12.h>
|
||||
#include "Emu/RSX/RSXFragmentProgram.h"
|
||||
#include "Emu/RSX/RSXVertexProgram.h"
|
||||
|
||||
class D3D12PipelineState
|
||||
{
|
||||
ID3D12PipelineState *m_pipelineStateObject;
|
||||
ID3D12RootSignature *m_rootSignature;
|
||||
public:
|
||||
D3D12PipelineState(ID3D12Device *device, RSXVertexProgram *vertexShader, RSXFragmentProgram *fragmentShader);
|
||||
~D3D12PipelineState();
|
||||
};
|
||||
|
||||
#endif
|
4
rpcs3/Emu/RSX/D3D12/DefaultPixelShader.hlsl
Normal file
4
rpcs3/Emu/RSX/D3D12/DefaultPixelShader.hlsl
Normal file
|
@ -0,0 +1,4 @@
|
|||
float4 main() : SV_TARGET
|
||||
{
|
||||
return float4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
Loading…
Add table
Reference in a new issue