diff --git a/rpcs3/Emu/GS/GL/GLGSRender.cpp b/rpcs3/Emu/GS/GL/GLGSRender.cpp index 9bfaccc8dc..98cb204231 100644 --- a/rpcs3/Emu/GS/GL/GLGSRender.cpp +++ b/rpcs3/Emu/GS/GL/GLGSRender.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "GLGSRender.h" #include "Emu/Cell/PPCInstrTable.h" +#include "Gui/RSXDebugger.h" #define CMD_DEBUG 0 #define DUMP_VERTEX_DATA 0 @@ -428,6 +429,34 @@ bool GLGSRender::LoadProgram() if(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. + glDetachShader(m_program.id, m_vertex_prog.id); + glDetachShader(m_program.id, m_shader_prog.id); + m_vertex_prog.shader = program.vp_shader; + m_shader_prog.shader = program.fp_shader; + m_vertex_prog.Wait(); + m_vertex_prog.Compile(); + checkForGlError("m_vertex_prog.Compile"); + m_shader_prog.Wait(); + m_shader_prog.Compile(); + checkForGlError("m_shader_prog.Compile"); + glAttachShader(m_program.id, m_vertex_prog.id); + glAttachShader(m_program.id, m_shader_prog.id); + glLinkProgram(m_program.id); + checkForGlError("glLinkProgram"); + program.vp_id = m_vertex_prog.id; + program.fp_id = m_shader_prog.id; + program.modified = false; + } + } + } m_program.Use(); } else @@ -437,6 +466,18 @@ bool GLGSRender::LoadProgram() m_prog_buffer.Add(m_program, m_shader_prog, *m_cur_shader_prog, m_vertex_prog, *m_cur_vertex_prog); checkForGlError("m_prog_buffer.Add"); m_program.Use(); + + // RSX Debugger + if (Ini.GSLogPrograms.GetValue()) + { + RSXDebuggerProgram program = RSXDebuggerProgram(); + program.id = m_program.id; + program.vp_id = m_vertex_prog.id; + program.fp_id = m_shader_prog.id; + program.vp_shader = m_vertex_prog.shader; + program.fp_shader = m_shader_prog.shader; + m_debug_programs.push_back(program); + } } return true; diff --git a/rpcs3/Emu/GS/GL/GLProcTable.tbl b/rpcs3/Emu/GS/GL/GLProcTable.tbl index ebeb72cff0..265eda6154 100644 --- a/rpcs3/Emu/GS/GL/GLProcTable.tbl +++ b/rpcs3/Emu/GS/GL/GLProcTable.tbl @@ -20,6 +20,7 @@ OPENGL_PROC(PFNGLGETSHADERINFOLOGPROC, GetShaderInfoLog); OPENGL_PROC(PFNGLCREATEPROGRAMPROC, CreateProgram); OPENGL_PROC(PFNGLDELETEPROGRAMPROC, DeleteProgram); OPENGL_PROC(PFNGLATTACHSHADERPROC, AttachShader); +OPENGL_PROC(PFNGLDETACHSHADERPROC, DetachShader); OPENGL_PROC(PFNGLGETATTRIBLOCATIONPROC, GetAttribLocation); OPENGL_PROC(PFNGLLINKPROGRAMPROC, LinkProgram); //OPENGL_PROC(PFNGLBINDFRAGDATALOCATIONPROC, BindFragDataLocation); diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index 344ccb1592..16d9e2ff00 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -375,6 +375,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxComboBox* cbox_audio_out = new wxComboBox(&diag, wxID_ANY); wxCheckBox* chbox_cpu_ignore_rwerrors = new wxCheckBox(&diag, wxID_ANY, "Ignore Read/Write errors"); + wxCheckBox* chbox_gs_log_prog = new wxCheckBox(&diag, wxID_ANY, "Log vertex/fragment programs"); wxCheckBox* chbox_gs_dump_depth = new wxCheckBox(&diag, wxID_ANY, "Dump Depth Buffer"); wxCheckBox* chbox_gs_dump_color = new wxCheckBox(&diag, wxID_ANY, "Dump Color Buffers"); wxCheckBox* chbox_gs_vsync = new wxCheckBox(&diag, wxID_ANY, "VSync"); @@ -411,6 +412,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) cbox_audio_out->Append("Null"); chbox_cpu_ignore_rwerrors->SetValue(Ini.CPUIgnoreRWErrors.GetValue()); + chbox_gs_log_prog->SetValue(Ini.GSLogPrograms.GetValue()); chbox_gs_dump_depth->SetValue(Ini.GSDumpDepthBuffer.GetValue()); chbox_gs_dump_color->SetValue(Ini.GSDumpColorBuffers.GetValue()); chbox_gs_vsync->SetValue(Ini.GSVSyncEnable.GetValue()); @@ -435,6 +437,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) s_round_gs->Add(s_round_gs_render, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs->Add(s_round_gs_res, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs->Add(s_round_gs_aspect, wxSizerFlags().Border(wxALL, 5).Expand()); + s_round_gs->Add(chbox_gs_log_prog, wxSizerFlags().Border(wxALL, 5)); s_round_gs->Add(chbox_gs_dump_depth, wxSizerFlags().Border(wxALL, 5)); s_round_gs->Add(chbox_gs_dump_color, wxSizerFlags().Border(wxALL, 5)); s_round_gs->Add(chbox_gs_vsync, wxSizerFlags().Border(wxALL, 5)); @@ -478,6 +481,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) Ini.GSResolution.SetValue(ResolutionNumToId(cbox_gs_resolution->GetSelection() + 1)); Ini.GSAspectRatio.SetValue(cbox_gs_aspect->GetSelection() + 1); Ini.GSVSyncEnable.SetValue(chbox_gs_vsync->GetValue()); + Ini.GSLogPrograms.SetValue(chbox_gs_log_prog->GetValue()); Ini.GSDumpDepthBuffer.SetValue(chbox_gs_dump_depth->GetValue()); Ini.GSDumpColorBuffers.SetValue(chbox_gs_dump_color->GetValue()); Ini.PadHandlerMode.SetValue(cbox_pad_handler->GetSelection()); @@ -805,7 +809,7 @@ void MainFrame::OnKeyDown(wxKeyEvent& event) { switch(event.GetKeyCode()) { - case 'C': case 'c': if(Emu.IsPaused()) Emu.Resume(); else if(Emu.IsReady()) Emu.Run(); return; + case 'E': case 'e': if(Emu.IsPaused()) Emu.Resume(); else if(Emu.IsReady()) Emu.Run(); return; case 'P': case 'p': if(Emu.IsRunning()) Emu.Pause(); return; case 'S': case 's': if(!Emu.IsStopped()) Emu.Stop(); return; case 'R': case 'r': if(!Emu.m_path.IsEmpty()) {Emu.Stop(); Emu.Run();} return; diff --git a/rpcs3/Gui/RSXDebugger.cpp b/rpcs3/Gui/RSXDebugger.cpp index db0f1341ba..e49614c029 100644 --- a/rpcs3/Gui/RSXDebugger.cpp +++ b/rpcs3/Gui/RSXDebugger.cpp @@ -5,6 +5,9 @@ #include "MemoryViewer.h" +// TODO: Clear the object when restarting the emulator +std::vector m_debug_programs; + enum GCMEnumTypes { CELL_GCM_ENUM, @@ -68,12 +71,14 @@ RSXDebugger::RSXDebugger(wxWindow* parent) wxNotebook* nb_rsx = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxSize(482,475)); wxPanel* p_commands = 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_flags, wxT("Flags")); + nb_rsx->AddPage(p_programs, wxT("Programs")); nb_rsx->AddPage(p_lightning, wxT("Lightning")); nb_rsx->AddPage(p_texture, wxT("Texture")); nb_rsx->AddPage(p_settings, wxT("Settings")); @@ -81,6 +86,7 @@ RSXDebugger::RSXDebugger(wxWindow* parent) //Tabs: Lists m_list_commands = new wxListView(p_commands, wxID_ANY, wxPoint(1,3), wxSize(470,444)); m_list_flags = new wxListView(p_flags, wxID_ANY, wxPoint(1,3), wxSize(470,444)); + m_list_programs = new wxListView(p_programs, wxID_ANY, wxPoint(1,3), wxSize(470,444)); m_list_lightning = new wxListView(p_lightning, wxID_ANY, wxPoint(1,3), wxSize(470,444)); m_list_texture = new wxListView(p_texture, wxID_ANY, wxPoint(1,3), wxSize(470,444)); m_list_settings = new wxListView(p_settings, wxID_ANY, wxPoint(1,3), wxSize(470,444)); @@ -88,6 +94,7 @@ RSXDebugger::RSXDebugger(wxWindow* parent) //Tabs: List Style m_list_commands ->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)); @@ -99,6 +106,11 @@ RSXDebugger::RSXDebugger(wxWindow* parent) m_list_commands->InsertColumn(3, "Count", 0, 40); 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); @@ -131,10 +143,10 @@ RSXDebugger::RSXDebugger(wxWindow* parent) //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_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"); @@ -207,6 +219,7 @@ RSXDebugger::RSXDebugger(wxWindow* parent) m_list_commands->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(RSXDebugger::OnScrollMemory), nullptr, this); m_list_flags->Connect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(RSXDebugger::SetFlags), nullptr, this); + m_list_programs->Connect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(RSXDebugger::SetPrograms), nullptr, this); m_list_texture->Connect(wxID_ANY, wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(RSXDebugger::OnSelectTexture), nullptr, this); @@ -331,6 +344,7 @@ void RSXDebugger::UpdateInformation() GetMemory(); GetBuffers(); GetFlags(); + GetPrograms(); GetLightning(); GetTexture(); GetSettings(); @@ -476,6 +490,23 @@ void RSXDebugger::GetFlags() #undef LIST_FLAGS_ADD } +void RSXDebugger::GetPrograms() +{ + if (!RSXReady()) return; + m_list_programs->DeleteAllItems(); + + int i=0; + for (auto& program : m_debug_programs) + { + m_list_programs->InsertItem(i, wxString::Format("%d", program.id)); + m_list_programs->SetItem(i, 1, wxString::Format("%d", program.vp_id)); + m_list_programs->SetItem(i, 2, wxString::Format("%d", program.fp_id)); + m_list_programs->SetItem(i, 3, wxString::Format("%d", program.vp_shader.length())); + m_list_programs->SetItem(i, 4, wxString::Format("%d", program.fp_shader.length())); + i++; + } +} + void RSXDebugger::GetLightning() { if (!RSXReady()) return; @@ -615,6 +646,44 @@ void RSXDebugger::SetFlags(wxListEvent& event) UpdateInformation(); } +void RSXDebugger::SetPrograms(wxListEvent& event) +{ + if (!RSXReady()) return; + GSRender& render = Emu.GetGSManager().GetRender(); + RSXDebuggerProgram& program = m_debug_programs[event.m_itemIndex]; + + // Program Editor + wxString title = wxString::Format("Program ID: %d (VP:%d, FP:%d)", program.id, program.vp_id, program.fp_id); + wxDialog* d_editor = new wxDialog(this, wxID_ANY, title, wxDefaultPosition, wxSize(800,500), + wxDEFAULT_DIALOG_STYLE | wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxRESIZE_BORDER); + + wxBoxSizer& s_panel = *new wxBoxSizer(wxHORIZONTAL); + wxStaticBoxSizer& s_vp_box = *new wxStaticBoxSizer(wxHORIZONTAL, d_editor, "Vertex Program"); + wxStaticBoxSizer& s_fp_box = *new wxStaticBoxSizer(wxHORIZONTAL, d_editor, "Fragment Program"); + wxTextCtrl* t_vp_edit = new wxTextCtrl(d_editor, -1, program.vp_shader, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); + wxTextCtrl* t_fp_edit = new wxTextCtrl(d_editor, -1, program.fp_shader, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); + t_vp_edit->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + t_fp_edit->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + s_vp_box.Add(t_vp_edit, 1, wxEXPAND); + s_fp_box.Add(t_fp_edit, 1, wxEXPAND); + s_panel.Add(&s_vp_box, 1, wxEXPAND); + s_panel.Add(&s_fp_box, 1, wxEXPAND); + d_editor->SetSizer(&s_panel); + + // Show editor and open Save Dialog when closing + if (d_editor->ShowModal()) + { + wxMessageDialog* d_save = new wxMessageDialog(d_editor, "Save changes and compile shaders?", title, wxYES_NO|wxCENTRE); + if(d_save->ShowModal() == wxID_YES) + { + program.modified = true; + program.vp_shader = t_vp_edit->GetValue(); + program.fp_shader = t_fp_edit->GetValue(); + } + } + UpdateInformation(); +} + void RSXDebugger::OnSelectTexture(wxListEvent& event) { if(event.GetIndex() >= 0) diff --git a/rpcs3/Gui/RSXDebugger.h b/rpcs3/Gui/RSXDebugger.h index 4d69e67947..8877016974 100644 --- a/rpcs3/Gui/RSXDebugger.h +++ b/rpcs3/Gui/RSXDebugger.h @@ -2,6 +2,23 @@ #include +struct RSXDebuggerProgram +{ + u32 id; + u32 vp_id; + u32 fp_id; + std::string vp_shader; + std::string fp_shader; + bool modified; + + RSXDebuggerProgram() + : modified(false) + { + } +}; + +extern std::vector m_debug_programs; + class RSXDebugger : public wxFrame { AppConnector m_app_connector; @@ -18,6 +35,7 @@ class RSXDebugger : public wxFrame u32 m_item_count; wxListView* m_list_commands; wxListView* m_list_flags; + wxListView* m_list_programs; wxListView* m_list_lightning; wxListView* m_list_texture; wxListView* m_list_settings; @@ -52,11 +70,13 @@ public: virtual void GetMemory(); virtual void GetBuffers(); virtual void GetFlags(); + virtual void GetPrograms(); virtual void GetLightning(); virtual void GetTexture(); virtual void GetSettings(); virtual void SetFlags(wxListEvent& event); + virtual void SetPrograms(wxListEvent& event); virtual void OnSelectTexture(wxListEvent& event); wxString ParseGCMEnum(u32 value, u32 type); diff --git a/rpcs3/Ini.h b/rpcs3/Ini.h index 1924aca8d9..4542a6a525 100644 --- a/rpcs3/Ini.h +++ b/rpcs3/Ini.h @@ -98,6 +98,7 @@ public: IniEntry GSResolution; IniEntry GSAspectRatio; IniEntry GSVSyncEnable; + IniEntry GSLogPrograms; IniEntry GSDumpColorBuffers; IniEntry GSDumpDepthBuffer; IniEntry PadHandlerMode; @@ -137,6 +138,7 @@ public: GSResolution.Init("Resolution", path); GSAspectRatio.Init("AspectRatio", path); GSVSyncEnable.Init("VSyncEnable", path); + GSLogPrograms.Init("LogPrograms", path); GSDumpColorBuffers.Init("DumpColorBuffers", path); GSDumpDepthBuffer.Init("DumpDepthBuffer", path); @@ -178,6 +180,7 @@ public: GSResolution.Load(4); GSAspectRatio.Load(2); GSVSyncEnable.Load(false); + GSLogPrograms.Load(false); GSDumpColorBuffers.Load(true); GSDumpDepthBuffer.Load(true); PadHandlerMode.Load(1); @@ -212,6 +215,7 @@ public: GSResolution.Save(); GSAspectRatio.Save(); GSVSyncEnable.Save(); + GSLogPrograms.Save(); GSDumpColorBuffers.Save(); GSDumpDepthBuffer.Save(); PadHandlerMode.Save();