diff --git a/rpcs3/Emu/RSX/Common/ProgramStateCache.h b/rpcs3/Emu/RSX/Common/ProgramStateCache.h index cfb07ff44d..af85971c80 100644 --- a/rpcs3/Emu/RSX/Common/ProgramStateCache.h +++ b/rpcs3/Emu/RSX/Common/ProgramStateCache.h @@ -294,6 +294,22 @@ public: clear(); } + const typename BackendTraits::VertexProgramData* get_transform_program(const RSXVertexProgram& rsx_vp) const noexcept + { + typename binary2VS::const_iterator It = m_cacheVS.find(rsx_vp.data); + if (It == m_cacheVS.end()) + return nullptr; + return &It->second; + } + + const typename BackendTraits::FragmentProgramData* get_shader_program(const RSXFragmentProgram& rsx_fp) const noexcept + { + typename binary2FS::const_iterator It = m_cacheFS.find(vm::base(rsx_fp.addr)); + if (It == m_cacheFS.end()) + return nullptr; + return &It->second; + } + void clear() { for (auto pair : m_cachePSO) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index d81af97d40..c306d9ee56 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -66,6 +66,7 @@ private: rsx::surface_info m_surface; + RSXVertexProgram vertex_program; RSXFragmentProgram fragment_program; PipelineStateObjectCache m_pso_cache; std::tuple, size_t> *m_current_pso; @@ -215,4 +216,5 @@ protected: virtual void copy_render_targets_to_memory(void *buffer, u8 rtt) override; virtual void copy_depth_buffer_to_memory(void *buffer) override; virtual void copy_stencil_buffer_to_memory(void *buffer) override; + virtual std::pair get_programs() const override; }; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp index 857433d895..360c8abba0 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -11,6 +11,7 @@ extern pD3DCompile wrapD3DCompile; void Shader::Compile(const std::string &code, SHADER_TYPE st) { + content = code; HRESULT hr; ComPtr errorBlob; UINT compileFlags; @@ -35,7 +36,6 @@ void Shader::Compile(const std::string &code, SHADER_TYPE st) bool D3D12GSRender::load_program() { - RSXVertexProgram vertex_program; u32 transform_program_start = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START]; vertex_program.data.reserve((512 - transform_program_start) * 4); @@ -246,4 +246,9 @@ bool D3D12GSRender::load_program() m_current_pso = m_pso_cache.getGraphicPipelineState(&vertex_program, &fragment_program, prop, std::make_pair(m_device.Get(), m_root_signatures)); return m_current_pso != nullptr; } + +std::pair D3D12GSRender::get_programs() const +{ + return std::make_pair(m_pso_cache.get_transform_program(vertex_program)->content, m_pso_cache.get_shader_program(fragment_program)->content); +} #endif diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h index f0766bfc4c..e496501984 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h @@ -91,6 +91,8 @@ public: u32 id; ComPtr bytecode; + // For debugging + std::string content; std::vector vertex_shader_inputs; std::vector FragmentConstantOffsetCache; size_t m_textureCount; diff --git a/rpcs3/Emu/RSX/GCM.h b/rpcs3/Emu/RSX/GCM.h index 4220ee85c6..bee004a1e9 100644 --- a/rpcs3/Emu/RSX/GCM.h +++ b/rpcs3/Emu/RSX/GCM.h @@ -1798,6 +1798,7 @@ namespace rsx { switch (target) { + case CELL_GCM_SURFACE_TARGET_NONE: return "none"; case CELL_GCM_SURFACE_TARGET_0: return "surface A"; case CELL_GCM_SURFACE_TARGET_1: return "surface B"; case CELL_GCM_SURFACE_TARGET_MRT1: return "surfaces A and B"; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index f766137a56..60913cc382 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -646,7 +646,7 @@ namespace rsx if (rsx->domethod(id, arg)) { if (rsx->capture_current_frame && id == NV4097_CLEAR_SURFACE) - rsx->capture_frame(); + rsx->capture_frame("clear"); return; } @@ -895,7 +895,7 @@ namespace rsx } } - void thread::capture_frame() + void thread::capture_frame(const std::string &name) { frame_capture_data::draw_state draw_state = {}; @@ -939,6 +939,8 @@ namespace rsx draw_state.stencil.data.resize(clip_w * clip_h * 4); copy_stencil_buffer_to_memory(draw_state.stencil.data.data()); } + draw_state.programs = get_programs(); + draw_state.name = name; frame_debug.draw_calls.push_back(draw_state); } @@ -956,7 +958,7 @@ namespace rsx transform_constants.clear(); if (capture_current_frame) - capture_frame(); + capture_frame("Draw " + std::to_string(vertex_draw_count)); } void thread::task() diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 44e92d96a1..e7ecc9a970 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -23,6 +23,8 @@ struct frame_capture_data struct draw_state { + std::string name; + std::pair programs; buffer color_buffer[4]; buffer depth; buffer stencil; @@ -200,7 +202,7 @@ namespace rsx virtual void load_vertex_index_data(u32 first, u32 count); bool capture_current_frame = false; - void capture_frame(); + void capture_frame(const std::string &name); public: u32 ioAddress, ioSize; int flip_status; @@ -283,6 +285,8 @@ namespace rsx * TODO: It's more efficient to combine multiple call of this function into one. */ virtual void copy_stencil_buffer_to_memory(void *buffer) {}; + + virtual std::pair get_programs() const { return std::make_pair("", ""); }; public: void reset(); void init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress); diff --git a/rpcs3/Gui/RSXDebugger.cpp b/rpcs3/Gui/RSXDebugger.cpp index 522dce6360..d50b74dd8c 100644 --- a/rpcs3/Gui/RSXDebugger.cpp +++ b/rpcs3/Gui/RSXDebugger.cpp @@ -16,6 +16,7 @@ #include "MemoryViewer.h" #include +#include // TODO: Clear the object when restarting the emulator std::vector m_debug_programs; @@ -79,32 +80,32 @@ RSXDebugger::RSXDebugger(wxWindow* parent) s_controls->Add(s_controls_goto); s_controls->Add(s_controls_breaks); - //Tabs + wxNotebook* nb_rsx = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxSize(732, 732)); + + //Tabs wxPanel* p_commands = new wxPanel(nb_rsx, wxID_ANY); wxPanel* p_captured_frame = new wxPanel(nb_rsx, wxID_ANY); wxPanel* p_captured_draw_calls = new wxPanel(nb_rsx, wxID_ANY); wxPanel* p_flags = new wxPanel(nb_rsx, wxID_ANY); - wxPanel* p_programs = new wxPanel(nb_rsx, wxID_ANY); wxPanel* p_lightning = new wxPanel(nb_rsx, wxID_ANY); wxPanel* p_texture = new wxPanel(nb_rsx, wxID_ANY); wxPanel* p_settings = new wxPanel(nb_rsx, wxID_ANY); - nb_rsx->AddPage(p_commands, wxT("RSX Commands")); + nb_rsx->AddPage(p_commands, wxT("RSX Commands")); nb_rsx->AddPage(p_captured_frame, wxT("Captured Frame")); nb_rsx->AddPage(p_captured_draw_calls, wxT("Captured Draw Calls")); - nb_rsx->AddPage(p_flags, wxT("Flags")); - nb_rsx->AddPage(p_programs, wxT("Programs")); + nb_rsx->AddPage(p_flags, wxT("Flags")); + nb_rsx->AddPage(p_lightning, wxT("Lightning")); - nb_rsx->AddPage(p_texture, wxT("Texture")); - nb_rsx->AddPage(p_settings, wxT("Settings")); + nb_rsx->AddPage(p_texture, wxT("Texture")); + nb_rsx->AddPage(p_settings, wxT("Settings")); //Tabs: Lists m_list_commands = new wxListView(p_commands, wxID_ANY, wxPoint(1,3), wxSize(720, 720)); m_list_captured_frame = new wxListView(p_captured_frame, wxID_ANY, wxPoint(1, 3), wxSize(720, 720)); m_list_captured_draw_calls = new wxListView(p_captured_draw_calls, wxID_ANY, wxPoint(1, 3), wxSize(720, 720)); m_list_flags = new wxListView(p_flags, wxID_ANY, wxPoint(1,3), wxSize(720, 720)); - m_list_programs = new wxListView(p_programs, wxID_ANY, wxPoint(1,3), wxSize(720, 720)); m_list_lightning = new wxListView(p_lightning, wxID_ANY, wxPoint(1,3), wxSize(720, 720)); m_list_texture = new wxListView(p_texture, wxID_ANY, wxPoint(1,3), wxSize(720, 720)); m_list_settings = new wxListView(p_settings, wxID_ANY, wxPoint(1,3), wxSize(720, 720)); @@ -114,7 +115,6 @@ RSXDebugger::RSXDebugger(wxWindow* parent) m_list_captured_frame->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); m_list_captured_draw_calls->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); m_list_flags ->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); - m_list_programs ->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); m_list_lightning->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); m_list_texture ->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); m_list_settings ->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); @@ -128,11 +128,6 @@ RSXDebugger::RSXDebugger(wxWindow* parent) m_list_captured_draw_calls->InsertColumn(0, "Draw calls", 0, 720); m_list_flags->InsertColumn(0, "Name", 0, 170); m_list_flags->InsertColumn(1, "Value", 0, 270); - m_list_programs->InsertColumn(0, "ID", 0, 70); - m_list_programs->InsertColumn(1, "VP ID", 0, 70); - m_list_programs->InsertColumn(2, "FP ID", 0, 70); - m_list_programs->InsertColumn(3, "VP Length", 0, 110); - m_list_programs->InsertColumn(4, "FP Length", 0, 110); m_list_lightning->InsertColumn(0, "Name", 0, 170); m_list_lightning->InsertColumn(1, "Value", 0, 270); @@ -164,17 +159,35 @@ RSXDebugger::RSXDebugger(wxWindow* parent) s_tools->Add(nb_rsx); s_tools->AddSpacer(10); + // State explorer + wxBoxSizer* s_state_explorer = new wxBoxSizer(wxHORIZONTAL); + wxNotebook* state_rsx = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxSize(732, 732)); + + wxPanel* p_buffers = new wxPanel(state_rsx, wxID_ANY); + wxPanel* p_transform_program = new wxPanel(state_rsx, wxID_ANY); + wxPanel* p_shader_program = new wxPanel(state_rsx, wxID_ANY); + + state_rsx->AddPage(p_buffers, wxT("RTTs and DS")); + state_rsx->AddPage(p_transform_program, wxT("Transform program")); + state_rsx->AddPage(p_shader_program, wxT("Shader program")); + + m_text_transform_program = new wxTextCtrl(p_transform_program, wxID_ANY, "", wxPoint(1, 3), wxSize(720, 720), wxTE_MULTILINE | wxTE_READONLY); + m_text_transform_program->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + + m_text_shader_program = new wxTextCtrl(p_shader_program, wxID_ANY, "", wxPoint(1, 3), wxSize(720, 720), wxTE_MULTILINE | wxTE_READONLY); + m_text_shader_program->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + //Buffers wxBoxSizer* s_buffers1 = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s_buffers2 = new wxBoxSizer(wxVERTICAL); - wxStaticBoxSizer* s_buffers_colorA = new wxStaticBoxSizer(wxHORIZONTAL, this, "Color Buffer A"); - wxStaticBoxSizer* s_buffers_colorB = new wxStaticBoxSizer(wxHORIZONTAL, this, "Color Buffer B"); - wxStaticBoxSizer* s_buffers_colorC = new wxStaticBoxSizer(wxHORIZONTAL, this, "Color Buffer C"); - wxStaticBoxSizer* s_buffers_colorD = new wxStaticBoxSizer(wxHORIZONTAL, this, "Color Buffer D"); - wxStaticBoxSizer* s_buffers_depth = new wxStaticBoxSizer(wxHORIZONTAL, this, "Depth Buffer"); - wxStaticBoxSizer* s_buffers_stencil = new wxStaticBoxSizer(wxHORIZONTAL, this, "Stencil Buffer"); - wxStaticBoxSizer* s_buffers_text = new wxStaticBoxSizer(wxHORIZONTAL, this, "Texture"); - + wxStaticBoxSizer* s_buffers_colorA = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Color Buffer A"); + wxStaticBoxSizer* s_buffers_colorB = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Color Buffer B"); + wxStaticBoxSizer* s_buffers_colorC = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Color Buffer C"); + wxStaticBoxSizer* s_buffers_colorD = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Color Buffer D"); + wxStaticBoxSizer* s_buffers_depth = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Depth Buffer"); + wxStaticBoxSizer* s_buffers_stencil = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Stencil Buffer"); + wxStaticBoxSizer* s_buffers_text = new wxStaticBoxSizer(wxHORIZONTAL, p_buffers, "Texture"); + //Buffers and textures CellVideoOutResolution res = ResolutionTable[ResolutionIdToNum((u32)rpcs3::state.config.rsx.resolution.value())]; m_panel_width = (res.width*108)/res.height; @@ -183,13 +196,13 @@ RSXDebugger::RSXDebugger(wxWindow* parent) m_text_height = 108; //Panels for displaying the buffers - p_buffer_colorA = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(m_panel_width, m_panel_height)); - p_buffer_colorB = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(m_panel_width, m_panel_height)); - p_buffer_colorC = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(m_panel_width, m_panel_height)); - p_buffer_colorD = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(m_panel_width, m_panel_height)); - p_buffer_depth = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(m_panel_width, m_panel_height)); - p_buffer_stencil = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(m_panel_width, m_panel_height)); - p_buffer_tex = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(m_text_width, m_text_height)); + p_buffer_colorA = new wxPanel(p_buffers, wxID_ANY, wxDefaultPosition, wxSize(m_panel_width, m_panel_height)); + p_buffer_colorB = new wxPanel(p_buffers, wxID_ANY, wxDefaultPosition, wxSize(m_panel_width, m_panel_height)); + p_buffer_colorC = new wxPanel(p_buffers, wxID_ANY, wxDefaultPosition, wxSize(m_panel_width, m_panel_height)); + p_buffer_colorD = new wxPanel(p_buffers, wxID_ANY, wxDefaultPosition, wxSize(m_panel_width, m_panel_height)); + p_buffer_depth = new wxPanel(p_buffers, wxID_ANY, wxDefaultPosition, wxSize(m_panel_width, m_panel_height)); + p_buffer_stencil = new wxPanel(p_buffers, wxID_ANY, wxDefaultPosition, wxSize(m_panel_width, m_panel_height)); + p_buffer_tex = new wxPanel(p_buffers, wxID_ANY, wxDefaultPosition, wxSize(m_text_width, m_text_height)); s_buffers_colorA->Add(p_buffer_colorA); s_buffers_colorB->Add(p_buffer_colorB); s_buffers_colorC->Add(p_buffer_colorC); @@ -217,12 +230,16 @@ RSXDebugger::RSXDebugger(wxWindow* parent) s_buffers2->Add(s_buffers_stencil); s_buffers2->AddSpacer(10); + s_state_explorer->Add(s_buffers1); + s_state_explorer->AddSpacer(10); + s_state_explorer->Add(s_buffers2); + + p_buffers->SetSizerAndFit(s_state_explorer); + s_panel->AddSpacer(10); s_panel->Add(s_tools); s_panel->AddSpacer(10); - s_panel->Add(s_buffers1); - s_panel->AddSpacer(10); - s_panel->Add(s_buffers2); + s_panel->Add(state_rsx); s_panel->AddSpacer(10); SetSizerAndFit(s_panel); @@ -244,7 +261,6 @@ RSXDebugger::RSXDebugger(wxWindow* parent) m_list_commands->Bind(wxEVT_MOUSEWHEEL, &RSXDebugger::OnScrollMemory, this); m_list_flags->Bind(wxEVT_LIST_ITEM_ACTIVATED, &RSXDebugger::SetFlags, this); - m_list_programs->Bind(wxEVT_LIST_ITEM_ACTIVATED, &RSXDebugger::SetPrograms, this); m_list_texture->Bind(wxEVT_LIST_ITEM_ACTIVATED, &RSXDebugger::OnSelectTexture, this); @@ -442,6 +458,12 @@ void RSXDebugger::OnClickDrawCalls(wxMouseEvent& event) dc_canvas.DrawBitmap(img.Scale(m_panel_width, m_panel_height), 0, 0, false); } } + + // Programs + m_text_transform_program->Clear(); + m_text_transform_program->AppendText(frame_debug.draw_calls[draw_id].programs.first); + m_text_shader_program->Clear(); + m_text_shader_program->AppendText(frame_debug.draw_calls[draw_id].programs.second); } void RSXDebugger::GoToGet(wxCommandEvent& event) @@ -478,7 +500,6 @@ void RSXDebugger::UpdateInformation() GetMemory(); GetBuffers(); GetFlags(); - GetPrograms(); GetLightning(); GetTexture(); GetSettings(); @@ -515,15 +536,20 @@ void RSXDebugger::GetMemory() m_list_commands->SetItem(i, 1, "????????"); } } - + std::ofstream command_dump; + command_dump.open("command_dump.log"); for (u32 i = 0; i < frame_debug.command_queue.size(); i++) { std::string str = rsx::get_pretty_printing_function(frame_debug.command_queue[i].first)(frame_debug.command_queue[i].second); m_list_captured_frame->SetItem(i, 0, str); + command_dump << str << "\n"; } + command_dump.close(); for (u32 i = 0;i < frame_debug.draw_calls.size(); i++) - m_list_captured_draw_calls->InsertItem(0, std::to_string(frame_debug.draw_calls.size() - i - 1)); + m_list_captured_draw_calls->InsertItem(i, frame_debug.draw_calls[i].name); + + } void RSXDebugger::GetBuffers() @@ -641,21 +667,6 @@ void RSXDebugger::GetFlags() #undef LIST_FLAGS_ADD } -void RSXDebugger::GetPrograms() -{ - if (!RSXReady()) return; - m_list_programs->DeleteAllItems(); - - for (auto& program : m_debug_programs) - { - const int i = m_list_programs->InsertItem(m_list_programs->GetItemCount(), wxString::Format("%u", program.id)); - m_list_programs->SetItem(i, 1, wxString::Format("%u", program.vp_id)); - m_list_programs->SetItem(i, 2, wxString::Format("%u", program.fp_id)); - m_list_programs->SetItem(i, 3, wxString::Format("%llu", (u64)program.vp_shader.length())); - m_list_programs->SetItem(i, 4, wxString::Format("%llu", (u64)program.fp_shader.length())); - } -} - void RSXDebugger::GetLightning() { if (!RSXReady()) return; diff --git a/rpcs3/Gui/RSXDebugger.h b/rpcs3/Gui/RSXDebugger.h index 82f22ec05e..d8a5da934a 100644 --- a/rpcs3/Gui/RSXDebugger.h +++ b/rpcs3/Gui/RSXDebugger.h @@ -18,7 +18,6 @@ class RSXDebugger : public wxFrame wxListView* m_list_captured_frame; wxListView* m_list_captured_draw_calls; wxListView* m_list_flags; - wxListView* m_list_programs; wxListView* m_list_lightning; wxListView* m_list_texture; wxListView* m_list_settings; @@ -31,6 +30,9 @@ class RSXDebugger : public wxFrame wxPanel* p_buffer_stencil; wxPanel* p_buffer_tex; + wxTextCtrl* m_text_transform_program; + wxTextCtrl *m_text_shader_program; + uint m_cur_texture; public: @@ -54,7 +56,6 @@ public: virtual void GetMemory(); virtual void GetBuffers(); virtual void GetFlags(); - virtual void GetPrograms(); virtual void GetLightning(); virtual void GetTexture(); virtual void GetSettings();