#include "stdafx_gui.h" #include "rpcs3/Ini.h" #include "Utilities/rPlatform.h" #include "Utilities/Log.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "RSXDebugger.h" #include "Emu/SysCalls/Modules/cellVideoOut.h" #include "Emu/RSX/GSManager.h" #include "Emu/RSX/GSRender.h" //#include "Emu/RSX/GCM.h" #include "MemoryViewer.h" #include // TODO: Clear the object when restarting the emulator std::vector m_debug_programs; enum GCMEnumTypes { CELL_GCM_ENUM, CELL_GCM_PRIMITIVE_ENUM, }; RSXDebugger::RSXDebugger(wxWindow* parent) : wxFrame(parent, wxID_ANY, "RSX Debugger", wxDefaultPosition, wxSize(700, 450)) , m_item_count(37) , m_addr(0x0) , m_cur_texture(0) , exit(false) { this->SetBackgroundColour(wxColour(240,240,240)); //This fix the ugly background color under Windows wxBoxSizer* s_panel = new wxBoxSizer(wxHORIZONTAL); //Tools wxBoxSizer* s_tools = new wxBoxSizer(wxVERTICAL); // Controls wxStaticBoxSizer* s_controls = new wxStaticBoxSizer(wxHORIZONTAL, this, "RSX Debugger Controls"); // Controls: Address wxStaticBoxSizer* s_controls_addr = new wxStaticBoxSizer(wxHORIZONTAL, this, "Address:"); t_addr = new wxTextCtrl(this, wxID_ANY, "00000000", wxDefaultPosition, wxSize(60,-1)); t_addr->SetMaxLength(8); s_controls_addr->Add(t_addr); // Controls: Go to wxStaticBoxSizer* s_controls_goto = new wxStaticBoxSizer(wxHORIZONTAL, this, "Go to:"); wxButton* b_goto_get = new wxButton(this, wxID_ANY, "Get", wxDefaultPosition, wxSize(40,-1)); wxButton* b_goto_put = new wxButton(this, wxID_ANY, "Put", wxDefaultPosition, wxSize(40,-1)); s_controls_goto->Add(b_goto_get); s_controls_goto->Add(b_goto_put); // Controls: Breaks wxStaticBoxSizer* s_controls_breaks = new wxStaticBoxSizer(wxHORIZONTAL, this, "Break on:"); wxButton* b_break_frame = new wxButton(this, wxID_ANY, "Frame", wxDefaultPosition, wxSize(60,-1)); wxButton* b_break_text = new wxButton(this, wxID_ANY, "Texture", wxDefaultPosition, wxSize(60,-1)); wxButton* b_break_draw = new wxButton(this, wxID_ANY, "Draw", wxDefaultPosition, wxSize(60,-1)); wxButton* b_break_prim = new wxButton(this, wxID_ANY, "Primitive", wxDefaultPosition, wxSize(60,-1)); wxButton* b_break_inst = new wxButton(this, wxID_ANY, "Command", wxDefaultPosition, wxSize(60,-1)); s_controls_breaks->Add(b_break_frame); s_controls_breaks->Add(b_break_text); s_controls_breaks->Add(b_break_draw); s_controls_breaks->Add(b_break_prim); s_controls_breaks->Add(b_break_inst); // TODO: This feature is not yet implemented b_break_frame->Disable(); b_break_text->Disable(); b_break_draw->Disable(); b_break_prim->Disable(); b_break_inst->Disable(); s_controls->Add(s_controls_addr); 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)); 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")); //Tabs: Lists m_list_commands = new wxListView(p_commands, 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)); //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)); //Tabs: List Columns m_list_commands->InsertColumn(0, "Address", 0, 80); m_list_commands->InsertColumn(1, "Value", 0, 80); m_list_commands->InsertColumn(2, "Command", 0, 500); 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); m_list_texture->InsertColumn(0, "Index"); m_list_texture->InsertColumn(1, "Address"); m_list_texture->InsertColumn(2, "Cubemap"); m_list_texture->InsertColumn(3, "Dimension"); m_list_texture->InsertColumn(4, "Enabled"); m_list_texture->InsertColumn(5, "Format"); m_list_texture->InsertColumn(6, "Mipmap"); m_list_texture->InsertColumn(7, "Pitch"); m_list_texture->InsertColumn(8, "Size"); m_list_settings->InsertColumn(0, "Name", 0, 170); m_list_settings->InsertColumn(1, "Value", 0, 270); // Fill list for(u32 i=0; iInsertItem(m_list_commands->GetItemCount(), wxEmptyString); } //Tools: Tools = Controls + Notebook Tabs s_tools->AddSpacer(10); s_tools->Add(s_controls); s_tools->AddSpacer(10); s_tools->Add(nb_rsx); s_tools->AddSpacer(10); //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"); //Buffers and textures CellVideoOutResolution res = ResolutionTable[ResolutionIdToNum(Ini.GSResolution.GetValue())]; m_panel_width = (res.width*108)/res.height; m_panel_height = 108; m_text_width = 108; 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)); s_buffers_colorA->Add(p_buffer_colorA); s_buffers_colorB->Add(p_buffer_colorB); s_buffers_colorC->Add(p_buffer_colorC); s_buffers_colorD->Add(p_buffer_colorD); s_buffers_depth->Add(p_buffer_depth); s_buffers_stencil->Add(p_buffer_stencil); s_buffers_text->Add(p_buffer_tex); //Merge and display everything s_buffers1->AddSpacer(10); s_buffers1->Add(s_buffers_colorA); s_buffers1->AddSpacer(10); s_buffers1->Add(s_buffers_colorC); s_buffers1->AddSpacer(10); s_buffers1->Add(s_buffers_depth); s_buffers1->AddSpacer(10); s_buffers1->Add(s_buffers_text); s_buffers1->AddSpacer(10); s_buffers2->AddSpacer(10); s_buffers2->Add(s_buffers_colorB); s_buffers2->AddSpacer(10); s_buffers2->Add(s_buffers_colorD); s_buffers2->AddSpacer(10); s_buffers2->Add(s_buffers_stencil); s_buffers2->AddSpacer(10); 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->AddSpacer(10); SetSizerAndFit(s_panel); //Events Bind(wxEVT_KEY_DOWN, &RSXDebugger::OnKeyDown, this); t_addr->Bind(wxEVT_TEXT_ENTER, &RSXDebugger::OnChangeToolsAddr, this); b_goto_get->Bind(wxEVT_BUTTON, &RSXDebugger::GoToGet, this); b_goto_put->Bind(wxEVT_BUTTON, &RSXDebugger::GoToPut, this); p_buffer_colorA->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this); p_buffer_colorB->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this); p_buffer_colorC->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this); p_buffer_colorD->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this); //p_buffer_depth->Bind(wxEVT_BUTTON, &RSXDebugger::OnClickBuffer, this); //p_buffer_stencil->Bind(wxEVT_BUTTON, &RSXDebugger::OnClickBuffer, this); p_buffer_tex->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this); 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); //Fill the frame UpdateInformation(); }; void RSXDebugger::OnKeyDown(wxKeyEvent& event) { if(wxGetActiveWindow() == wxGetTopLevelParent(this)) { switch(event.GetKeyCode()) { case WXK_F5: UpdateInformation(); return; } } event.Skip(); } void RSXDebugger::OnChangeToolsAddr(wxCommandEvent& event) { t_addr->GetValue().ToULong((unsigned long *)&m_addr, 16); t_addr->SetValue(wxString::Format("%08x", m_addr)); UpdateInformation(); event.Skip(); } void RSXDebugger::OnScrollMemory(wxMouseEvent& event) { if(vm::check_addr(m_addr)) { int items = event.ControlDown() ? m_item_count : 1; for(int i=0; i> 18) & 0x7ff; offset = 1 + count; } else { offset = 1; } m_addr -= 4 * offset * (event.GetWheelRotation() / event.GetWheelDelta()); } } else { m_addr -= (event.ControlDown() ? m_item_count : 1) * 4 * (event.GetWheelRotation() / event.GetWheelDelta()); } UpdateInformation(); event.Skip(); } void RSXDebugger::OnClickBuffer(wxMouseEvent& event) { if (!RSXReady()) return; const GSRender& render = Emu.GetGSManager().GetRender(); const auto buffers = vm::ps3::ptr::make(render.m_gcm_buffers_addr); if(!buffers) return; // TODO: Is there any better way to choose the color buffers #define SHOW_BUFFER(id) \ { \ u32 addr = render.local_mem_addr + buffers[id].offset; \ if (vm::check_addr(addr) && buffers[id].width && buffers[id].height) \ MemoryViewerPanel::ShowImage(this, addr, 3, buffers[id].width, buffers[id].height, true); \ return; \ } \ if (event.GetId() == p_buffer_colorA->GetId()) SHOW_BUFFER(0); if (event.GetId() == p_buffer_colorB->GetId()) SHOW_BUFFER(1); if (event.GetId() == p_buffer_colorC->GetId()) SHOW_BUFFER(2); if (event.GetId() == p_buffer_colorD->GetId()) SHOW_BUFFER(3); if (event.GetId() == p_buffer_tex->GetId()) { u8 location = render.textures[m_cur_texture].location(); if(location <= 1 && vm::check_addr(rsx::get_address(render.textures[m_cur_texture].offset(), location)) && render.textures[m_cur_texture].width() && render.textures[m_cur_texture].height()) MemoryViewerPanel::ShowImage(this, rsx::get_address(render.textures[m_cur_texture].offset(), location), 1, render.textures[m_cur_texture].width(), render.textures[m_cur_texture].height(), false); } #undef SHOW_BUFFER } void RSXDebugger::GoToGet(wxCommandEvent& event) { if (!RSXReady()) return; auto ctrl = vm::get_ptr(Emu.GetGSManager().GetRender().m_ctrlAddress); u32 realAddr; if (RSXIOMem.getRealAddr(ctrl->get.load(), realAddr)) { m_addr = realAddr; t_addr->SetValue(wxString::Format("%08x", m_addr)); UpdateInformation(); event.Skip(); } // TODO: We should probably throw something? } void RSXDebugger::GoToPut(wxCommandEvent& event) { if (!RSXReady()) return; auto ctrl = vm::get_ptr(Emu.GetGSManager().GetRender().m_ctrlAddress); u32 realAddr; if (RSXIOMem.getRealAddr(ctrl->put.load(), realAddr)) { m_addr = realAddr; t_addr->SetValue(wxString::Format("%08x", m_addr)); UpdateInformation(); event.Skip(); } // TODO: We should probably throw something? } void RSXDebugger::UpdateInformation() { t_addr->SetValue(wxString::Format("%08x", m_addr)); GetMemory(); GetBuffers(); GetFlags(); GetPrograms(); GetLightning(); GetTexture(); GetSettings(); } void RSXDebugger::GetMemory() { // Clean commands column for(u32 i=0; iSetItem(i, 2, wxEmptyString); bool isReady = RSXReady(); // Write information for(u32 i=0, addr = m_addr; iSetItem(i, 0, wxString::Format("%08x", addr)); if (isReady && vm::check_addr(addr)) { u32 cmd = vm::ps3::read32(addr); u32 count = (cmd >> 18) & 0x7ff; m_list_commands->SetItem(i, 1, wxString::Format("%08x", cmd)); m_list_commands->SetItem(i, 3, wxString::Format("%d", count)); m_list_commands->SetItem(i, 2, DisAsmCommand(cmd, count, addr, 0)); if(!(cmd & (CELL_GCM_METHOD_FLAG_JUMP | CELL_GCM_METHOD_FLAG_CALL)) && cmd != CELL_GCM_METHOD_FLAG_RETURN) { addr += 4 * count; } } else { m_list_commands->SetItem(i, 1, "????????"); } } } void RSXDebugger::GetBuffers() { if (!RSXReady()) return; const GSRender& render = Emu.GetGSManager().GetRender(); // Draw Buffers // TODO: Currently it only supports color buffers for (u32 bufferId=0; bufferId < render.gcm_buffers_count; bufferId++) { if(!vm::check_addr(render.m_gcm_buffers_addr)) continue; auto buffers = vm::get_ptr(render.m_gcm_buffers_addr); u32 RSXbuffer_addr = render.local_mem_addr + buffers[bufferId].offset; if(!vm::check_addr(RSXbuffer_addr)) continue; auto RSXbuffer = vm::get_ptr(RSXbuffer_addr); u32 width = buffers[bufferId].width; u32 height = buffers[bufferId].height; unsigned char* buffer = (unsigned char*)malloc(width * height * 3); // ABGR to RGB and flip vertically for (u32 y=0; y 1) return; u32 TexBuffer_addr = rsx::get_address(offset, location); if(!vm::check_addr(TexBuffer_addr)) return; unsigned char* TexBuffer = vm::get_ptr(TexBuffer_addr); u32 width = render.textures[m_cur_texture].width(); u32 height = render.textures[m_cur_texture].height(); unsigned char* buffer = (unsigned char*)malloc(width * height * 3); memcpy(buffer, TexBuffer, width * height * 3); wxImage img(width, height, buffer); wxClientDC dc_canvas(p_buffer_tex); dc_canvas.DrawBitmap(img.Scale(m_text_width, m_text_height), 0, 0, false); } void RSXDebugger::GetFlags() { if (!RSXReady()) return; const GSRender& render = Emu.GetGSManager().GetRender(); m_list_flags->DeleteAllItems(); int i=0; #define LIST_FLAGS_ADD(name, value) \ m_list_flags->InsertItem(i, name); m_list_flags->SetItem(i, 1, value ? "Enabled" : "Disabled"); i++; LIST_FLAGS_ADD("Alpha test", rsx::method_registers[NV4097_SET_ALPHA_TEST_ENABLE]); LIST_FLAGS_ADD("Blend", rsx::method_registers[NV4097_SET_BLEND_ENABLE]); LIST_FLAGS_ADD("Scissor", render.m_set_scissor_horizontal && render.m_set_scissor_vertical); LIST_FLAGS_ADD("Cull face", rsx::method_registers[NV4097_SET_CULL_FACE]); LIST_FLAGS_ADD("Depth bounds test", render.m_set_depth_bounds_test); // LIST_FLAGS_ADD("Depth test", render.m_set_depth_test); LIST_FLAGS_ADD("Dither", render.m_set_dither); LIST_FLAGS_ADD("Line smooth", render.m_set_line_smooth); // LIST_FLAGS_ADD("Logic op", render.m_set_logic_op); LIST_FLAGS_ADD("Poly smooth", render.m_set_poly_smooth); LIST_FLAGS_ADD("Poly offset fill", render.m_set_poly_offset_fill); LIST_FLAGS_ADD("Poly offset line", render.m_set_poly_offset_line); LIST_FLAGS_ADD("Poly offset point", render.m_set_poly_offset_point); // LIST_FLAGS_ADD("Stencil test", render.m_set_stencil_test); LIST_FLAGS_ADD("Primitive restart", render.m_set_restart_index); LIST_FLAGS_ADD("Two sided lighting", render.m_set_two_side_light_enable); LIST_FLAGS_ADD("Point Sprite", render.m_set_point_sprite_control); LIST_FLAGS_ADD("Lighting ", render.m_set_specular); #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; const GSRender& render = Emu.GetGSManager().GetRender(); m_list_lightning->DeleteAllItems(); int i=0; #define LIST_LIGHTNING_ADD(name, value) \ m_list_lightning->InsertItem(i, name); m_list_lightning->SetItem(i, 1, value); i++; LIST_LIGHTNING_ADD("Shade model", (render.m_shade_mode == 0x1D00) ? "Flat" : "Smooth"); #undef LIST_LIGHTNING_ADD } void RSXDebugger::GetTexture() { if (!RSXReady()) return; const GSRender& render = Emu.GetGSManager().GetRender(); m_list_texture->DeleteAllItems(); for(uint i=0; iInsertItem(i, wxString::Format("%d", i)); u8 location = render.textures[i].location(); if(location > 1) { m_list_texture->SetItem(i, 1, wxString::Format("Bad address (offset=0x%x, location=%d)", render.textures[i].offset(), location)); } else { m_list_texture->SetItem(i, 1, wxString::Format("0x%x", rsx::get_address(render.textures[i].offset(), location))); } m_list_texture->SetItem(i, 2, render.textures[i].cubemap() ? "True" : "False"); m_list_texture->SetItem(i, 3, wxString::Format("%dD", render.textures[i].dimension())); m_list_texture->SetItem(i, 4, render.textures[i].enabled() ? "True" : "False"); m_list_texture->SetItem(i, 5, wxString::Format("0x%x", render.textures[i].format())); m_list_texture->SetItem(i, 6, wxString::Format("0x%x", render.textures[i].mipmap())); m_list_texture->SetItem(i, 7, wxString::Format("0x%x", render.textures[i].pitch())); m_list_texture->SetItem(i, 8, wxString::Format("%dx%d", render.textures[i].width(), render.textures[i].height())); m_list_texture->SetItemBackgroundColour(i, wxColour(m_cur_texture == i ? "Wheat" : "White")); } } } void RSXDebugger::GetSettings() { if (!RSXReady()) return; const GSRender& render = Emu.GetGSManager().GetRender(); m_list_settings->DeleteAllItems(); int i=0; #define LIST_SETTINGS_ADD(name, value) \ m_list_settings->InsertItem(i, name); m_list_settings->SetItem(i, 1, value); i++; LIST_SETTINGS_ADD("Alpha func", !(rsx::method_registers[NV4097_SET_ALPHA_FUNC]) ? "(none)" : wxString::Format("0x%x (%s)", rsx::method_registers[NV4097_SET_ALPHA_FUNC], ParseGCMEnum(rsx::method_registers[NV4097_SET_ALPHA_FUNC], CELL_GCM_ENUM))); LIST_SETTINGS_ADD("Blend color", !(rsx::method_registers[NV4097_SET_BLEND_COLOR]) ? "(none)" : wxString::Format("R:%d, G:%d, B:%d, A:%d", rsx::method_registers[NV4097_SET_BLEND_COLOR] & 0xFF, (rsx::method_registers[NV4097_SET_BLEND_COLOR] >> 8) & 0xFF, (rsx::method_registers[NV4097_SET_BLEND_COLOR] >> 16) & 0xFF, (rsx::method_registers[NV4097_SET_BLEND_COLOR] >> 24) & 0xFF)); LIST_SETTINGS_ADD("Clipping", wxString::Format("Min:%f, Max:%f", render.m_clip_min, render.m_clip_max)); LIST_SETTINGS_ADD("Color mask", !(rsx::method_registers[NV4097_SET_COLOR_MASK]) ? "(none)" : wxString::Format("R:%d, G:%d, B:%d, A:%d", (rsx::method_registers[NV4097_SET_COLOR_MASK] >> 16) & 0xff, (rsx::method_registers[NV4097_SET_COLOR_MASK] >> 8) & 0xff, (rsx::method_registers[NV4097_SET_COLOR_MASK]) & 0xff, (rsx::method_registers[NV4097_SET_COLOR_MASK] >> 24) & 0xff)); LIST_SETTINGS_ADD("Context DMA Color A", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_A])); LIST_SETTINGS_ADD("Context DMA Color B", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_B])); LIST_SETTINGS_ADD("Context DMA Color C", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_C])); LIST_SETTINGS_ADD("Context DMA Color D", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_D])); LIST_SETTINGS_ADD("Context DMA Zeta", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA])); LIST_SETTINGS_ADD("Depth bounds", wxString::Format("Min:%f, Max:%f", render.m_depth_bounds_min, render.m_depth_bounds_max)); // LIST_SETTINGS_ADD("Depth func", !(render.m_set_depth_func) ? "(none)" : wxString::Format("0x%x (%s)", // render.m_depth_func, // ParseGCMEnum(render.m_depth_func, CELL_GCM_ENUM))); LIST_SETTINGS_ADD("Draw mode", wxString::Format("%d (%s)", render.draw_mode, ParseGCMEnum(render.draw_mode, CELL_GCM_PRIMITIVE_ENUM))); LIST_SETTINGS_ADD("Scissor", wxString::Format("X:%d, Y:%d, W:%d, H:%d", render.m_scissor_x, render.m_scissor_y, render.m_scissor_w, render.m_scissor_h)); // LIST_SETTINGS_ADD("Stencil func", !(render.m_set_stencil_func) ? "(none)" : wxString::Format("0x%x (%s)", // render.m_stencil_func, // ParseGCMEnum(render.m_stencil_func, CELL_GCM_ENUM))); LIST_SETTINGS_ADD("Surface Pitch A", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_SURFACE_PITCH_A])); LIST_SETTINGS_ADD("Surface Pitch B", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_SURFACE_PITCH_B])); LIST_SETTINGS_ADD("Surface Pitch C", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_SURFACE_PITCH_C])); LIST_SETTINGS_ADD("Surface Pitch D", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_SURFACE_PITCH_D])); LIST_SETTINGS_ADD("Surface Pitch Z", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_SURFACE_PITCH_Z])); LIST_SETTINGS_ADD("Surface Offset A", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_SURFACE_COLOR_AOFFSET])); LIST_SETTINGS_ADD("Surface Offset B", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_SURFACE_COLOR_BOFFSET])); LIST_SETTINGS_ADD("Surface Offset C", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_SURFACE_COLOR_COFFSET])); LIST_SETTINGS_ADD("Surface Offset D", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_SURFACE_COLOR_DOFFSET])); LIST_SETTINGS_ADD("Surface Offset Z", wxString::Format("0x%x", rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET])); LIST_SETTINGS_ADD("Viewport", wxString::Format("X:%d, Y:%d, W:%d, H:%d", rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] & 0xFFFF, rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] & 0xFFFF, rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16, rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16)); #undef LIST_SETTINGS_ADD } void RSXDebugger::SetFlags(wxListEvent& event) { if (!RSXReady()) return; GSRender& render = Emu.GetGSManager().GetRender(); switch(event.m_itemIndex) { case 0: rsx::method_registers[NV4097_SET_ALPHA_TEST_ENABLE] ^= true; break; case 1: rsx::method_registers[NV4097_SET_BLEND_ENABLE] ^= true; break; case 2: rsx::method_registers[NV4097_SET_CULL_FACE] ^= true; break; case 3: render.m_set_depth_bounds_test ^= true; break; // case 4: render.m_set_depth_test ^= true; break; case 5: render.m_set_dither ^= true; break; case 6: render.m_set_line_smooth ^= true; break; // case 7: render.m_set_logic_op ^= true; break; case 8: render.m_set_poly_smooth ^= true; break; case 9: render.m_set_poly_offset_fill ^= true; break; case 10: render.m_set_poly_offset_line ^= true; break; case 11: render.m_set_poly_offset_point ^= true; break; // case 12: render.m_set_stencil_test ^= true; break; case 13: render.m_set_point_sprite_control ^= true; break; case 14: render.m_set_restart_index ^= true; break; case 15: render.m_set_specular ^= true; break; case 16: render.m_set_scissor_horizontal ^= true; break; case 17: render.m_set_scissor_vertical ^= true; break; } 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(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, wxID_ANY, program.vp_shader, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); wxTextCtrl* t_fp_edit = new wxTextCtrl(&d_editor, wxID_ANY, 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(&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) m_cur_texture = event.GetIndex(); UpdateInformation(); } const char* RSXDebugger::ParseGCMEnum(u32 value, u32 type) { switch(type) { case CELL_GCM_ENUM: { switch(value) { case 0x0200: return "Never"; case 0x0201: return "Less"; case 0x0202: return "Equal"; case 0x0203: return "Less or Equal"; case 0x0204: return "Greater"; case 0x0205: return "Not Equal"; case 0x0206: return "Greater or Equal"; case 0x0207: return "Always"; case 0x0: return "Zero"; case 0x1: return "One"; case 0x0300: return "SRC_COLOR"; case 0x0301: return "1 - SRC_COLOR"; case 0x0302: return "SRC_ALPHA"; case 0x0303: return "1 - SRC_ALPHA"; case 0x0304: return "DST_ALPHA"; case 0x0305: return "1 - DST_ALPHA"; case 0x0306: return "DST_COLOR"; case 0x0307: return "1 - DST_COLOR"; case 0x0308: return "SRC_ALPHA_SATURATE"; case 0x8001: return "CONSTANT_COLOR"; case 0x8002: return "1 - CONSTANT_COLOR"; case 0x8003: return "CONSTANT_ALPHA"; case 0x8004: return "1 - CONSTANT_ALPHA"; case 0x8006: return "Add"; case 0x8007: return "Min"; case 0x8008: return "Max"; case 0x800A: return "Substract"; case 0x800B: return "Reverse Substract"; case 0xF005: return "Reverse Substract Signed"; case 0xF006: return "Add Signed"; case 0xF007: return "Reverse Add Signed"; default: return "Wrong Value!"; } } case CELL_GCM_PRIMITIVE_ENUM: { switch(value) { case 1: return "POINTS"; case 2: return "LINES"; case 3: return "LINE_LOOP"; case 4: return "LINE_STRIP"; case 5: return "TRIANGLES"; case 6: return "TRIANGLE_STRIP"; case 7: return "TRIANGLE_FAN"; case 8: return "QUADS"; case 9: return "QUAD_STRIP"; case 10: return "POLYGON"; default: return "Wrong Value!"; } } default: return "Unknown!"; } } #define case_16(a, m) \ case a + m: \ case a + m * 2: \ case a + m * 3: \ case a + m * 4: \ case a + m * 5: \ case a + m * 6: \ case a + m * 7: \ case a + m * 8: \ case a + m * 9: \ case a + m * 10: \ case a + m * 11: \ case a + m * 12: \ case a + m * 13: \ case a + m * 14: \ case a + m * 15: \ index = (cmd - a) / m; \ case a \ wxString RSXDebugger::DisAsmCommand(u32 cmd, u32 count, u32 currentAddr, u32 ioAddr) { wxString disasm = wxEmptyString; #define DISASM(string, ...) { if(disasm.IsEmpty()) disasm = wxString::Format((string), ##__VA_ARGS__); else disasm += (wxString(' ') + wxString::Format((string), ##__VA_ARGS__)); } if(cmd & CELL_GCM_METHOD_FLAG_JUMP) { u32 jumpAddr = cmd & ~(CELL_GCM_METHOD_FLAG_JUMP | CELL_GCM_METHOD_FLAG_NON_INCREMENT); DISASM("JUMP: %08x -> %08x", currentAddr, ioAddr+jumpAddr); } else if(cmd & CELL_GCM_METHOD_FLAG_CALL) { u32 callAddr = cmd & ~CELL_GCM_METHOD_FLAG_CALL; DISASM("CALL: %08x -> %08x", currentAddr, ioAddr+callAddr); } if(cmd == CELL_GCM_METHOD_FLAG_RETURN) { DISASM("RETURN"); } if(cmd == 0) { DISASM("Null cmd"); } else if(!(cmd & (CELL_GCM_METHOD_FLAG_JUMP | CELL_GCM_METHOD_FLAG_CALL)) && cmd != CELL_GCM_METHOD_FLAG_RETURN) { auto args = vm::ps3::ptr::make(currentAddr + 4); u32 index = 0; switch(cmd & 0x3ffff) { case NV406E_SEMAPHORE_OFFSET: DISASM("PFIFO: Semaphore offset 0x%x", (u32)args[0]); break; case NV406E_SEMAPHORE_ACQUIRE: DISASM("PFIFO: Semaphore acquire at 0x%x", (u32)args[0]); break; case NV406E_SEMAPHORE_RELEASE: DISASM("PFIFO: Semaphore release value 0x%x", (u32)args[0]); break; case NV4097_SET_SURFACE_FORMAT: { const u32 a0 = (u32)args[0]; const u32 surface_format = a0 & 0x1f; const u32 surface_depth_format = (a0 >> 5) & 0x7; const char *depth_type_name, *color_type_name; switch (surface_depth_format) { case CELL_GCM_SURFACE_Z16: depth_type_name = "CELL_GCM_SURFACE_Z16"; break; case CELL_GCM_SURFACE_Z24S8: depth_type_name = "CELL_GCM_SURFACE_Z24S8"; break; default: depth_type_name = ""; break; } switch (surface_format) { case CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5: color_type_name = "CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5"; break; case CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5: color_type_name = "CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5"; break; case CELL_GCM_SURFACE_R5G6B5: color_type_name = "CELL_GCM_SURFACE_R5G6B5"; break; case CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8: color_type_name = "CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8"; break; case CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8: color_type_name = "CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8"; break; case CELL_GCM_SURFACE_A8R8G8B8: color_type_name = "CELL_GCM_SURFACE_A8R8G8B8"; break; case CELL_GCM_SURFACE_B8: color_type_name = "CELL_GCM_SURFACE_B8"; break; case CELL_GCM_SURFACE_G8B8: color_type_name = "CELL_GCM_SURFACE_G8B8"; break; case CELL_GCM_SURFACE_F_W16Z16Y16X16: color_type_name = "CELL_GCM_SURFACE_F_W16Z16Y16X16"; break; case CELL_GCM_SURFACE_F_W32Z32Y32X32: color_type_name = "CELL_GCM_SURFACE_F_W32Z32Y32X32"; break; case CELL_GCM_SURFACE_F_X32: color_type_name = "CELL_GCM_SURFACE_F_X32"; break; case CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8: color_type_name = "CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8"; break; case CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8: color_type_name = "CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8"; break; case CELL_GCM_SURFACE_A8B8G8R8: color_type_name = "CELL_GCM_SURFACE_A8B8G8R8"; break; default: color_type_name = ""; break; } DISASM("Set surface format : C %s Z %s", color_type_name, depth_type_name); } break; case NV4097_SET_SURFACE_COLOR_TARGET: DISASM("Set surface color target"); break; case NV4097_SET_SHADER_WINDOW: DISASM("Set shader windows"); break; case NV4097_SET_DEPTH_TEST_ENABLE: DISASM("Set depth test enable"); break; case NV4097_SET_DEPTH_FUNC: DISASM("Set depth func"); break; case NV4097_SET_ZSTENCIL_CLEAR_VALUE: DISASM("Set ZSTENCIL clear value"); break; case NV4097_CLEAR_SURFACE: DISASM("Clear surface"); break; case NV4097_SET_TRANSFORM_CONSTANT_LOAD: DISASM("Set transform constant load"); break; case NV4097_SET_VERTEX_DATA_ARRAY_FORMAT: DISASM("Set vertex data array format"); break; case NV4097_SET_VERTEX_DATA_ARRAY_OFFSET: DISASM("Set vertex data array offset"); break; case NV4097_SET_SHADER_PROGRAM: DISASM("Set shader program"); break; case NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK: DISASM("Set vertex attrib output mask"); break; case NV4097_SET_TEX_COORD_CONTROL: DISASM("Set tex coord control"); break; case NV4097_SET_TRANSFORM_PROGRAM_LOAD: DISASM("Set transform program load"); break; case NV4097_SET_TRANSFORM_PROGRAM: DISASM("Set transform program"); break; case NV4097_SET_VERTEX_ATTRIB_INPUT_MASK: DISASM("Set vertex attrib input mask"); break; case NV4097_SET_TRANSFORM_TIMEOUT: DISASM("Set transform timeout"); break; case NV4097_INVALIDATE_VERTEX_CACHE_FILE: DISASM("Invalidate vertex cache file"); break; case NV4097_SET_SHADER_CONTROL: DISASM("Set shader control"); break; case NV4097_SET_SEMAPHORE_OFFSET: DISASM("PGRAPH: Set semaphore offset 0x%x", (u32)args[0]); break; case NV4097_BACK_END_WRITE_SEMAPHORE_RELEASE: DISASM("PGRAPH: Back end write semaphore release %x", (u32)args[0]); break; case NV4097_SET_COLOR_MASK_MRT: DISASM("Set color mask MRT"); break; case NV4097_SET_TEXTURE_IMAGE_RECT: DISASM("Set texture image rect"); break; case NV4097_SET_TEXTURE_CONTROL3: DISASM("Set texture control 3"); break; case NV4097_SET_TEXTURE_CONTROL1: DISASM("Set texture control 1"); break; case NV4097_SET_TEXTURE_CONTROL0: DISASM("Set texture control 0"); break; case NV4097_SET_TEXTURE_ADDRESS: DISASM("Set texture address"); break; case NV4097_SET_TEXTURE_FILTER: DISASM("Set texture filter"); break; case NV4097_SET_BLEND_FUNC_SFACTOR: DISASM("Set blend func sfactor"); break; case NV4097_SET_FRONT_POLYGON_MODE: DISASM("Set front polygon mode"); break; case NV4097_SET_VIEWPORT_HORIZONTAL: { u32 m_viewport_x = (u32)args[0] & 0xffff; u32 m_viewport_w = (u32)args[0] >> 16; if (count == 2) { u32 m_viewport_y = (u32)args[1] & 0xffff; u32 m_viewport_h = (u32)args[1] >> 16; DISASM("Set viewport horizontal %d %d", m_viewport_w, m_viewport_h); } else DISASM("Set viewport horizontal %d", m_viewport_w); break; } case NV4097_SET_CLIP_MIN: DISASM("Set clip min"); break; case NV4097_SET_VIEWPORT_OFFSET: DISASM("Set viewport offset"); break; case NV4097_SET_SCISSOR_HORIZONTAL: DISASM("Set scissor horizontal"); break; case NV4097_INVALIDATE_L2: DISASM("Invalidate L2"); break; case NV4097_INVALIDATE_VERTEX_FILE: DISASM("Invalidate vertex file"); break; case NV4097_SET_BEGIN_END: DISASM("Set BEGIN END"); break; case NV4097_DRAW_ARRAYS: DISASM("Draw arrays"); break; case NV4097_SET_WINDOW_OFFSET: DISASM("Set window offset"); break; case NV4097_SET_SURFACE_CLIP_HORIZONTAL: { const u32 a0 = (u32)args[0]; u32 clip_x = a0; u32 clip_w = a0 >> 16; if (count == 2) { const u32 a1 = (u32)args[1]; u32 clip_y = a1; u32 clip_h = a1 >> 16; DISASM("Set surface clip horizontal : %d %d", clip_w, clip_h); } else DISASM("Set surface clip horizontal : %d", clip_w); break; } break; case 0x3fead: DISASM("Flip and change current buffer: %d", (u32)args[0]); break; case NV4097_NO_OPERATION: DISASM("NOP"); break; case NV406E_SET_REFERENCE: DISASM("Set reference: 0x%x", (u32)args[0]); break; case_16(NV4097_SET_TEXTURE_OFFSET, 0x20): DISASM("Texture Offset[%d]: %08x", index, (u32)args[0]); switch ((args[1] & 0x3) - 1) { case CELL_GCM_LOCATION_LOCAL: DISASM("(Local memory);"); break; case CELL_GCM_LOCATION_MAIN: DISASM("(Main memory);"); break; default: DISASM("(Bad location!);"); break; } DISASM(" Cubemap:%s; Dimension:0x%x; Format:0x%x; Mipmap:0x%x", (((args[1] >> 2) & 0x1) ? "True" : "False"), ((args[1] >> 4) & 0xf), ((args[1] >> 8) & 0xff), ((args[1] >> 16) & 0xffff)); break; case NV4097_SET_COLOR_MASK: DISASM(" Color mask: True (A:%c, R:%c, G:%c, B:%c)", args[0] & 0x1000000 ? '1' : '0', args[0] & 0x0010000 ? '1' : '0', args[0] & 0x0000100 ? '1' : '0', args[0] & 0x0000001 ? '1' : '0'); break; case NV4097_SET_ALPHA_TEST_ENABLE: DISASM(args[0] ? "Alpha test: Enable" : "Alpha test: Disable"); break; case NV4097_SET_BLEND_ENABLE: DISASM(args[0] ? "Blend: Enable" : "Blend: Disable"); break; case NV4097_SET_DEPTH_BOUNDS_TEST_ENABLE: DISASM(args[0] ? "Depth bounds test: Enable" : "Depth bounds test: Disable"); break; case NV4097_SET_CONTEXT_DMA_COLOR_A: DISASM("Context DMA Color A: 0x%x", (u32)args[0]); break; case NV4097_SET_CONTEXT_DMA_COLOR_B: DISASM("Context DMA Color B: 0x%x", (u32)args[0]); break; case NV4097_SET_CONTEXT_DMA_COLOR_C: DISASM("Context DMA Color C: 0x%x", (u32)args[0]); if(count > 1) DISASM("0x%x", (u32)args[1]); break; case NV4097_SET_CONTEXT_DMA_ZETA: DISASM("Context DMA Zeta: 0x%x", (u32)args[0]); break; case NV4097_SET_SURFACE_PITCH_C: DISASM("Surface Pitch C: 0x%x;", (u32)args[0]); DISASM("Surface Pitch D: 0x%x;", (u32)args[1]); DISASM("Surface Offset C: 0x%x;", (u32)args[2]); DISASM("Surface Offset D: 0x%x", (u32)args[3]); break; case NV4097_SET_SURFACE_PITCH_Z: DISASM("Surface Pitch Z: 0x%x;", (u32)args[0]); break; default: break; } if(cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT) { DISASM("Non Increment cmd"); } DISASM("[0x%08x(", cmd); for(uint i=0; i