diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index 4cb34e7545..f9b456ea1d 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -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 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); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index 2b2cffa755..bbc86c13be 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -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 m_vdata; // std::vector 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(); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp new file mode 100644 index 0000000000..5c6052bcf3 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -0,0 +1,315 @@ +#include "stdafx.h" +#if defined (DX12_SUPPORT) + +#include "D3D12PipelineState.h" +#include "Emu/Memory/vm.h" +#include "Utilities/Log.h" +#include +#include +#include + +#pragma comment (lib, "d3dcompiler.lib") + +std::unordered_map > CachedShader; + +struct GLBufferInfo +{ + ID3D12PipelineState *prog_id; + u32 fp_id; + u32 vp_id; + std::vector fp_data; + std::vector vp_data; + std::string fp_shader; + std::string vp_shader; + Microsoft::WRL::ComPtr fp_bytecode; + Microsoft::WRL::ComPtr 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 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 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 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(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(rsx_fp.addr), vm::get_ptr(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 \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h new file mode 100644 index 0000000000..1916f1768c --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h @@ -0,0 +1,17 @@ +#pragma once +#if defined (DX12_SUPPORT) + +#include +#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 \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/DefaultPixelShader.hlsl b/rpcs3/Emu/RSX/D3D12/DefaultPixelShader.hlsl new file mode 100644 index 0000000000..68075ef0c2 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/DefaultPixelShader.hlsl @@ -0,0 +1,4 @@ +float4 main() : SV_TARGET +{ + return float4(1.0f, 1.0f, 1.0f, 1.0f); +} \ No newline at end of file