A new debugger.
Lots of bugs/rough edges/etc - issues will be filed. Old-style debugging still works (just use --emit_source_annotations to get the helpful movs back and --break_on_instruction will still fire).
This commit is contained in:
@@ -1,88 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/debug/ui/application.h"
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/debug/ui/main_window.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
|
||||
Application* current_application_ = nullptr;
|
||||
|
||||
Application* Application::current() {
|
||||
assert_not_null(current_application_);
|
||||
return current_application_;
|
||||
}
|
||||
|
||||
Application::Application() {
|
||||
current_application_ = this;
|
||||
loop_ = xe::ui::Loop::Create();
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
assert_true(current_application_ == this);
|
||||
current_application_ = nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Application> Application::Create() {
|
||||
std::unique_ptr<Application> app(new Application());
|
||||
|
||||
xe::threading::Fence fence;
|
||||
app->loop()->Post([&app, &fence]() {
|
||||
xe::threading::set_name("Win32 Loop");
|
||||
xe::Profiler::ThreadEnter("Win32 Loop");
|
||||
|
||||
if (!app->Initialize()) {
|
||||
xe::FatalError("Failed to initialize application");
|
||||
return;
|
||||
}
|
||||
|
||||
fence.Signal();
|
||||
});
|
||||
fence.Wait();
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
bool Application::Initialize() {
|
||||
// Bind the object model to the client so it'll maintain state.
|
||||
system_ = std::make_unique<model::System>(loop(), &client_);
|
||||
|
||||
// TODO(benvanik): flags and such.
|
||||
if (!client_.Connect("localhost", 9002)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
main_window_ = std::make_unique<MainWindow>(this);
|
||||
if (!main_window_->Initialize()) {
|
||||
XELOGE("Unable to initialize main window");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::Quit() {
|
||||
loop_->Quit();
|
||||
|
||||
// TODO(benvanik): proper exit.
|
||||
XELOGI("User-initiated death!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_APPLICATION_H_
|
||||
#define XENIA_DEBUG_UI_APPLICATION_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "xenia/debug/debug_client.h"
|
||||
#include "xenia/debug/ui/model/system.h"
|
||||
#include "xenia/ui/loop.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
|
||||
class MainWindow;
|
||||
|
||||
class Application {
|
||||
public:
|
||||
~Application();
|
||||
|
||||
static std::unique_ptr<Application> Create();
|
||||
static Application* current();
|
||||
|
||||
xe::ui::Loop* loop() { return loop_.get(); }
|
||||
MainWindow* main_window() const { return main_window_.get(); }
|
||||
DebugClient* client() { return &client_; }
|
||||
model::System* system() const { return system_.get(); }
|
||||
|
||||
void Quit();
|
||||
|
||||
private:
|
||||
Application();
|
||||
|
||||
bool Initialize();
|
||||
|
||||
std::unique_ptr<xe::ui::Loop> loop_;
|
||||
std::unique_ptr<MainWindow> main_window_;
|
||||
DebugClient client_;
|
||||
|
||||
std::unique_ptr<model::System> system_;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_APPLICATION_H_
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_CONTROL_H_
|
||||
#define XENIA_DEBUG_UI_CONTROL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "el/elements.h"
|
||||
#include "el/event_handler.h"
|
||||
#include "xenia/debug/ui/application.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
|
||||
class Control {
|
||||
public:
|
||||
virtual ~Control() = default;
|
||||
|
||||
el::LayoutBox* root_element() { return &root_element_; }
|
||||
xe::ui::Loop* loop() const { return Application::current()->loop(); }
|
||||
DebugClient* client() const { return client_; }
|
||||
model::System* system() const { return Application::current()->system(); }
|
||||
|
||||
virtual el::Element* BuildUI() = 0;
|
||||
|
||||
virtual void Setup(xe::debug::DebugClient* client) = 0;
|
||||
|
||||
protected:
|
||||
Control() = default;
|
||||
|
||||
el::LayoutBox root_element_;
|
||||
std::unique_ptr<el::EventHandler> handler_;
|
||||
xe::debug::DebugClient* client_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_CONTROL_H_
|
||||
1683
src/xenia/debug/ui/debug_window.cc
Normal file
1683
src/xenia/debug/ui/debug_window.cc
Normal file
File diff suppressed because it is too large
Load Diff
153
src/xenia/debug/ui/debug_window.h
Normal file
153
src/xenia/debug/ui/debug_window.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_DEBUG_WINDOW_H_
|
||||
#define XENIA_DEBUG_UI_DEBUG_WINDOW_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/x64_context.h"
|
||||
#include "xenia/debug/debugger.h"
|
||||
#include "xenia/emulator.h"
|
||||
#include "xenia/ui/loop.h"
|
||||
#include "xenia/ui/menu_item.h"
|
||||
#include "xenia/ui/window.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
|
||||
class ImGuiRenderer;
|
||||
|
||||
class DebugWindow : public DebugListener {
|
||||
public:
|
||||
~DebugWindow();
|
||||
|
||||
static std::unique_ptr<DebugWindow> Create(Emulator* emulator,
|
||||
xe::ui::Loop* loop);
|
||||
|
||||
Emulator* emulator() const { return emulator_; }
|
||||
xe::ui::Loop* loop() const { return loop_; }
|
||||
xe::ui::Window* window() const { return window_.get(); }
|
||||
|
||||
void OnFocus() override;
|
||||
void OnDetached() override;
|
||||
void OnExecutionPaused() override;
|
||||
void OnExecutionContinued() override;
|
||||
void OnExecutionEnded() override;
|
||||
void OnStepCompleted(xe::kernel::XThread* thread) override;
|
||||
void OnBreakpointHit(Breakpoint* breakpoint,
|
||||
xe::kernel::XThread* thread) override;
|
||||
|
||||
private:
|
||||
explicit DebugWindow(Emulator* emulator, xe::ui::Loop* loop);
|
||||
bool Initialize();
|
||||
|
||||
void DrawFrame();
|
||||
void DrawToolbar();
|
||||
void DrawFunctionsPane();
|
||||
void DrawSourcePane();
|
||||
void DrawGuestFunctionSource();
|
||||
void DrawMachineCodeSource(const uint8_t* ptr, size_t length);
|
||||
void DrawBreakpointGutterButton(bool has_breakpoint,
|
||||
CodeBreakpoint::AddressType address_type,
|
||||
uint64_t address);
|
||||
void ScrollToSourceIfPcChanged();
|
||||
void DrawRegistersPane();
|
||||
bool DrawRegisterTextBox(int id, uint32_t* value);
|
||||
bool DrawRegisterTextBox(int id, uint64_t* value);
|
||||
bool DrawRegisterTextBox(int id, double* value);
|
||||
bool DrawRegisterTextBoxes(int id, float* value);
|
||||
void DrawThreadsPane();
|
||||
void DrawMemoryPane();
|
||||
void DrawBreakpointsPane();
|
||||
void DrawLogPane();
|
||||
|
||||
void SelectThreadStackFrame(kernel::XThread* thread, size_t stack_frame_index,
|
||||
bool always_navigate);
|
||||
void NavigateToFunction(cpu::Function* function, uint32_t guest_pc = 0,
|
||||
uint64_t host_pc = 0);
|
||||
// void NavigateToMemory(uint64_t address, uint64_t length = 0);
|
||||
// void ToggleLogThreadFocus(thread | nullptr);
|
||||
|
||||
void UpdateCache();
|
||||
|
||||
void CreateCodeBreakpoint(CodeBreakpoint::AddressType address_type,
|
||||
uint64_t address);
|
||||
void DeleteCodeBreakpoint(CodeBreakpoint* breakpoint);
|
||||
void DeleteBreakpoint(Breakpoint* breakpoint);
|
||||
CodeBreakpoint* LookupBreakpointAtAddress(
|
||||
CodeBreakpoint::AddressType address_type, uint64_t address);
|
||||
|
||||
Emulator* emulator_ = nullptr;
|
||||
Debugger* debugger_ = nullptr;
|
||||
xe::ui::Loop* loop_ = nullptr;
|
||||
std::unique_ptr<xe::ui::Window> window_;
|
||||
std::unique_ptr<ImGuiRenderer> imgui_renderer_;
|
||||
uint64_t last_draw_tick_count_ = 0;
|
||||
|
||||
uintptr_t capstone_handle_ = 0;
|
||||
|
||||
// Cached debugger data, updated on every break before a frame is drawn.
|
||||
// Prefer putting stuff here that will be queried either each frame or
|
||||
// multiple times per frame to avoid expensive redundant work.
|
||||
struct ImDataCache {
|
||||
bool is_running = false;
|
||||
std::vector<kernel::object_ref<kernel::XModule>> modules;
|
||||
std::vector<ThreadExecutionInfo*> thread_execution_infos;
|
||||
} cache_;
|
||||
|
||||
enum class RegisterGroup {
|
||||
kGuestGeneral,
|
||||
kGuestFloat,
|
||||
kGuestVector,
|
||||
kHostGeneral,
|
||||
kHostVector,
|
||||
};
|
||||
|
||||
// The current state of the UI. Use this to synchronize multiple parts of the
|
||||
// UI.
|
||||
struct ImState {
|
||||
static const int kRightPaneThreads = 0;
|
||||
static const int kRightPaneMemory = 1;
|
||||
int right_pane_tab = kRightPaneThreads;
|
||||
|
||||
xe::kernel::XThread* thread = nullptr;
|
||||
ThreadExecutionInfo* thread_info = nullptr;
|
||||
size_t thread_stack_frame_index = 0;
|
||||
bool has_changed_thread = false;
|
||||
|
||||
xe::cpu::Function* function = nullptr;
|
||||
uint64_t last_host_pc = 0;
|
||||
bool has_changed_pc = false;
|
||||
int source_display_mode = 3;
|
||||
|
||||
RegisterGroup register_group = RegisterGroup::kGuestGeneral;
|
||||
bool register_input_hex = true;
|
||||
|
||||
struct {
|
||||
char kernel_call_filter[64] = {0};
|
||||
std::vector<std::unique_ptr<Breakpoint>> all_breakpoints;
|
||||
std::unordered_map<uint32_t, CodeBreakpoint*>
|
||||
code_breakpoints_by_guest_address;
|
||||
std::unordered_map<uintptr_t, CodeBreakpoint*>
|
||||
code_breakpoints_by_host_address;
|
||||
} breakpoints;
|
||||
|
||||
xe::kernel::XThread* isolated_log_thread = nullptr;
|
||||
} state_;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_DEBUG_WINDOW_H_
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "xenia/base/main.h"
|
||||
#include "xenia/debug/ui/application.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
|
||||
int main(const std::vector<std::wstring>& args) {
|
||||
auto app = Application::Create();
|
||||
app->loop()->AwaitQuit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
DEFINE_ENTRY_POINT(L"xenia-debug-ui", L"xenia-debug-ui ??",
|
||||
xe::debug::ui::main);
|
||||
@@ -1,6 +0,0 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
|
||||
#include "third_party\\elemental-forms\\resources.rc"
|
||||
|
||||
//IDR_xe_debug_ui_resources_skin_bg_tile_png RCDATA ".\\resources\\skin\\bg_tile.png"
|
||||
IDR_xe_debug_ui_resources_smaller_skin_skin_tb_txt RCDATA ".\\resources\\smaller_skin\\skin.tb.txt"
|
||||
341
src/xenia/debug/ui/imgui_renderer.cc
Normal file
341
src/xenia/debug/ui/imgui_renderer.cc
Normal file
File diff suppressed because one or more lines are too long
55
src/xenia/debug/ui/imgui_renderer.h
Normal file
55
src/xenia/debug/ui/imgui_renderer.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_IMGUI_RENDERER_H_
|
||||
#define XENIA_DEBUG_UI_IMGUI_RENDERER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "third_party/imgui/imgui.h"
|
||||
#include "xenia/base/clock.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/ui/gl/circular_buffer.h"
|
||||
#include "xenia/ui/gl/gl_context.h"
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
|
||||
class ImGuiRenderer {
|
||||
public:
|
||||
ImGuiRenderer(xe::ui::Window* window, xe::ui::GraphicsContext* context);
|
||||
~ImGuiRenderer();
|
||||
|
||||
private:
|
||||
static ImGuiRenderer* global_renderer_;
|
||||
|
||||
void Initialize();
|
||||
void InitializeShaders();
|
||||
void InitializeFontTextures();
|
||||
void Shutdown();
|
||||
|
||||
void RenderDrawLists(ImDrawData* data);
|
||||
|
||||
xe::ui::Window* window_ = nullptr;
|
||||
xe::ui::GraphicsContext* context_ = nullptr;
|
||||
|
||||
GLuint program_ = 0;
|
||||
GLuint vao_ = 0;
|
||||
xe::ui::gl::CircularBuffer vertex_buffer_;
|
||||
xe::ui::gl::CircularBuffer index_buffer_;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_IMGUI_RENDERER_H_
|
||||
@@ -1,197 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/debug/ui/main_window.h"
|
||||
|
||||
#include "el/animation_manager.h"
|
||||
#include "el/io/file_manager.h"
|
||||
#include "el/util/debug.h"
|
||||
#include "xenia/base/clock.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/ui/gl/gl_context.h"
|
||||
|
||||
#if XE_PLATFORM_WIN32
|
||||
#include "el/io/win32_res_file_system_win.h"
|
||||
#endif // XE_PLATFORM_WIN32
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
|
||||
using xe::ui::MenuItem;
|
||||
|
||||
const std::wstring kBaseTitle = L"xenia debugger";
|
||||
|
||||
MainWindow::MainWindow(Application* app) : app_(app) {}
|
||||
|
||||
MainWindow::~MainWindow() = default;
|
||||
|
||||
bool MainWindow::Initialize() {
|
||||
client_ = app_->client();
|
||||
|
||||
window_ = xe::ui::Window::Create(app()->loop(), kBaseTitle);
|
||||
if (!window_) {
|
||||
return false;
|
||||
}
|
||||
window_->Initialize();
|
||||
window_->set_context(xe::ui::gl::GLContext::Create(window_.get()));
|
||||
|
||||
#if XE_PLATFORM_WIN32
|
||||
el::io::FileManager::RegisterFileSystem(
|
||||
std::make_unique<el::io::Win32ResFileSystem>(
|
||||
"IDR_xe_debug_ui_resources_"));
|
||||
#endif // XE_PLATFORM_WIN32
|
||||
window_->LoadSkin("smaller_skin/skin.tb.txt");
|
||||
|
||||
window_->on_closed.AddListener(std::bind(&MainWindow::OnClose, this));
|
||||
|
||||
window_->on_key_down.AddListener([this](xe::ui::KeyEvent* e) {
|
||||
bool handled = true;
|
||||
switch (e->key_code()) {
|
||||
case 0x1B: { // VK_ESCAPE
|
||||
// Allow users to escape fullscreen (but not enter it).
|
||||
if (window_->is_fullscreen()) {
|
||||
window_->ToggleFullscreen(false);
|
||||
}
|
||||
} break;
|
||||
|
||||
case 0x70: { // VK_F1
|
||||
LaunchBrowser("http://xenia.jp");
|
||||
} break;
|
||||
|
||||
default: { handled = false; } break;
|
||||
}
|
||||
e->set_handled(handled);
|
||||
});
|
||||
|
||||
// Main menu.
|
||||
auto main_menu = MenuItem::Create(MenuItem::Type::kNormal);
|
||||
auto file_menu = MenuItem::Create(MenuItem::Type::kPopup, L"&File");
|
||||
{
|
||||
file_menu->AddChild(MenuItem::Create(MenuItem::Type::kString, L"E&xit",
|
||||
L"Alt+F4",
|
||||
[this]() { window_->Close(); }));
|
||||
}
|
||||
main_menu->AddChild(std::move(file_menu));
|
||||
|
||||
// Help menu.
|
||||
auto help_menu = MenuItem::Create(MenuItem::Type::kPopup, L"&Help");
|
||||
{
|
||||
help_menu->AddChild(
|
||||
MenuItem::Create(MenuItem::Type::kString, L"&Website...", L"F1",
|
||||
[]() { LaunchBrowser("http://xenia.jp"); }));
|
||||
help_menu->AddChild(
|
||||
MenuItem::Create(MenuItem::Type::kString, L"&About...",
|
||||
[]() { LaunchBrowser("http://xenia.jp/about/"); }));
|
||||
}
|
||||
main_menu->AddChild(std::move(help_menu));
|
||||
|
||||
window_->set_main_menu(std::move(main_menu));
|
||||
|
||||
window_->Resize(1440, 1200);
|
||||
|
||||
BuildUI();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::BuildUI() {
|
||||
using namespace el::dsl; // NOLINT(build/namespaces)
|
||||
el::AnimationBlocker animation_blocker;
|
||||
|
||||
auto root_element = window_->root_element();
|
||||
form_ = std::make_unique<el::Form>();
|
||||
form_->set_settings(el::FormSettings::kFullScreen);
|
||||
root_element->AddChild(form_.get());
|
||||
|
||||
auto root_node =
|
||||
LayoutBoxNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.distribution(LayoutDistribution::kAvailable)
|
||||
.axis(Axis::kY)
|
||||
.child(
|
||||
LayoutBoxNode()
|
||||
.id("toolbar_box")
|
||||
.gravity(Gravity::kTop | Gravity::kLeftRight)
|
||||
.distribution(LayoutDistribution::kGravity)
|
||||
.distribution_position(LayoutDistributionPosition::kLeftTop)
|
||||
.child(ButtonNode("Pause").id("pause_button"))
|
||||
.child(ButtonNode("Continue").id("resume_button")))
|
||||
.child(
|
||||
SplitContainerNode()
|
||||
.id("split_container")
|
||||
.gravity(Gravity::kAll)
|
||||
.axis(Axis::kX)
|
||||
.fixed_pane(FixedPane::kSecond)
|
||||
.min(128)
|
||||
.value(250)
|
||||
.pane(TabContainerNode()
|
||||
.id("tab_container")
|
||||
.gravity(Gravity::kAll)
|
||||
.align(Align::kTop))
|
||||
.pane(LayoutBoxNode().id("log_box").gravity(Gravity::kAll)));
|
||||
|
||||
form_->LoadNodeTree(root_node);
|
||||
form_->GetElementsById({
|
||||
{TBIDC("split_container"), &ui_.split_container},
|
||||
{TBIDC("toolbar_box"), &ui_.toolbar_box},
|
||||
{TBIDC("tab_container"), &ui_.tab_container},
|
||||
});
|
||||
|
||||
handler_ = std::make_unique<el::EventHandler>(form_.get());
|
||||
handler_->Listen(el::EventType::kClick, TBIDC("pause_button"),
|
||||
[this](const el::Event& ev) {
|
||||
client_->Interrupt();
|
||||
return true;
|
||||
});
|
||||
handler_->Listen(el::EventType::kClick, TBIDC("resume_button"),
|
||||
[this](const el::Event& ev) {
|
||||
client_->Continue();
|
||||
return true;
|
||||
});
|
||||
|
||||
system()->on_execution_state_changed.AddListener(
|
||||
[this]() { UpdateElementState(); });
|
||||
|
||||
ui_.tab_container->tab_bar()->LoadNodeTree(ButtonNode(cpu_view_.name()));
|
||||
ui_.tab_container->content_root()->AddChild(cpu_view_.BuildUI());
|
||||
cpu_view_.Setup(Application::current()->client());
|
||||
|
||||
ui_.tab_container->tab_bar()->LoadNodeTree(ButtonNode(gpu_view_.name()));
|
||||
ui_.tab_container->content_root()->AddChild(gpu_view_.BuildUI());
|
||||
gpu_view_.Setup(Application::current()->client());
|
||||
|
||||
UpdateElementState();
|
||||
|
||||
el::util::ShowDebugInfoSettingsForm(root_element);
|
||||
}
|
||||
|
||||
void MainWindow::UpdateElementState() {
|
||||
bool is_running = client_->execution_state() == ExecutionState::kRunning;
|
||||
|
||||
el::TabContainer* tab_container;
|
||||
el::Button* pause_button;
|
||||
el::Button* resume_button;
|
||||
form_->GetElementsById({
|
||||
{TBIDC("tab_container"), &tab_container},
|
||||
{TBIDC("pause_button"), &pause_button},
|
||||
{TBIDC("resume_button"), &resume_button},
|
||||
});
|
||||
tab_container->set_enabled(!is_running);
|
||||
pause_button->set_enabled(is_running);
|
||||
resume_button->set_enabled(!is_running);
|
||||
}
|
||||
|
||||
void MainWindow::OnClose() { app_->Quit(); }
|
||||
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_MAIN_WINDOW_H_
|
||||
#define XENIA_DEBUG_UI_MAIN_WINDOW_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "el/elements.h"
|
||||
#include "xenia/debug/ui/application.h"
|
||||
#include "xenia/debug/ui/views/cpu/cpu_view.h"
|
||||
#include "xenia/debug/ui/views/gpu/gpu_view.h"
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
|
||||
class MainWindow {
|
||||
public:
|
||||
explicit MainWindow(Application* app);
|
||||
~MainWindow();
|
||||
|
||||
Application* app() const { return app_; }
|
||||
xe::ui::Loop* loop() const { return app_->loop(); }
|
||||
model::System* system() const { return app_->system(); }
|
||||
|
||||
bool Initialize();
|
||||
|
||||
// void NavigateToCpuView(uint32_t address);
|
||||
|
||||
private:
|
||||
void BuildUI();
|
||||
void UpdateElementState();
|
||||
|
||||
void OnClose();
|
||||
|
||||
Application* app_ = nullptr;
|
||||
xe::debug::DebugClient* client_ = nullptr;
|
||||
|
||||
std::unique_ptr<xe::ui::Window> window_;
|
||||
std::unique_ptr<el::Form> form_;
|
||||
struct {
|
||||
el::SplitContainer* split_container;
|
||||
el::LayoutBox* toolbar_box;
|
||||
el::TabContainer* tab_container;
|
||||
} ui_ = {0};
|
||||
std::unique_ptr<el::EventHandler> handler_;
|
||||
views::cpu::CpuView cpu_view_;
|
||||
views::gpu::GpuView gpu_view_;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_MAIN_WINDOW_H_
|
||||
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/debug/ui/model/function.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace model {
|
||||
|
||||
//
|
||||
|
||||
} // namespace model
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_MODEL_FUNCTION_H_
|
||||
#define XENIA_DEBUG_UI_MODEL_FUNCTION_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace model {
|
||||
|
||||
class Function {
|
||||
public:
|
||||
};
|
||||
|
||||
} // namespace model
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_MODEL_FUNCTION_H_
|
||||
@@ -1,26 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/debug/ui/model/module.h"
|
||||
|
||||
#include "xenia/debug/ui/model/system.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace model {
|
||||
|
||||
void Module::Update(const proto::ModuleListEntry* entry) {
|
||||
std::memcpy(&entry_, entry, sizeof(entry_));
|
||||
}
|
||||
|
||||
} // namespace model
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_MODEL_MODULE_H_
|
||||
#define XENIA_DEBUG_UI_MODEL_MODULE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/debug/proto/xdp_protocol.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace model {
|
||||
|
||||
class System;
|
||||
|
||||
class Module {
|
||||
public:
|
||||
explicit Module(System* system) : system_(system) {}
|
||||
|
||||
bool is_dead() const { return is_dead_; }
|
||||
void set_dead(bool is_dead) { is_dead_ = is_dead; }
|
||||
|
||||
uint32_t module_handle() const { return entry_.module_handle; }
|
||||
bool is_kernel_module() const { return entry_.is_kernel_module; }
|
||||
std::string name() const { return entry_.name; }
|
||||
const proto::ModuleListEntry* entry() const { return &entry_; }
|
||||
|
||||
void Update(const proto::ModuleListEntry* entry);
|
||||
|
||||
private:
|
||||
System* system_ = nullptr;
|
||||
bool is_dead_ = false;
|
||||
proto::ModuleListEntry entry_ = {0};
|
||||
};
|
||||
|
||||
} // namespace model
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_MODEL_MODULE_H_
|
||||
@@ -1,128 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/debug/ui/model/system.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace model {
|
||||
|
||||
using namespace xe::debug::proto; // NOLINT(build/namespaces)
|
||||
|
||||
System::System(xe::ui::Loop* loop, DebugClient* client)
|
||||
: loop_(loop), client_(client) {
|
||||
client_->set_listener(this);
|
||||
client_->set_loop(loop);
|
||||
}
|
||||
|
||||
System::~System() { client_->set_listener(nullptr); }
|
||||
|
||||
ExecutionState System::execution_state() { return client_->execution_state(); }
|
||||
|
||||
std::vector<Module*> System::modules() {
|
||||
std::vector<Module*> result;
|
||||
for (auto& module : modules_) {
|
||||
result.push_back(module.get());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Thread*> System::threads() {
|
||||
std::vector<Thread*> result;
|
||||
for (auto& thread : threads_) {
|
||||
result.push_back(thread.get());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Module* System::GetModuleByHandle(uint32_t module_handle) {
|
||||
auto it = modules_by_handle_.find(module_handle);
|
||||
return it != modules_by_handle_.end() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
Thread* System::GetThreadByHandle(uint32_t thread_handle) {
|
||||
auto it = threads_by_handle_.find(thread_handle);
|
||||
return it != threads_by_handle_.end() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
void System::OnExecutionStateChanged(ExecutionState execution_state) {
|
||||
on_execution_state_changed();
|
||||
}
|
||||
|
||||
void System::OnModulesUpdated(std::vector<const ModuleListEntry*> entries) {
|
||||
std::unordered_set<uint32_t> extra_modules;
|
||||
for (size_t i = 0; i < modules_.size(); ++i) {
|
||||
extra_modules.emplace(modules_[i]->module_handle());
|
||||
}
|
||||
for (auto entry : entries) {
|
||||
auto existing_module = modules_by_handle_.find(entry->module_handle);
|
||||
if (existing_module == modules_by_handle_.end()) {
|
||||
auto module = std::make_unique<Module>(this);
|
||||
module->Update(entry);
|
||||
modules_by_handle_.emplace(entry->module_handle, module.get());
|
||||
modules_.emplace_back(std::move(module));
|
||||
} else {
|
||||
existing_module->second->Update(entry);
|
||||
extra_modules.erase(existing_module->first);
|
||||
}
|
||||
}
|
||||
for (auto module_handle : extra_modules) {
|
||||
auto module = modules_by_handle_.find(module_handle);
|
||||
if (module != modules_by_handle_.end()) {
|
||||
module->second->set_dead(true);
|
||||
}
|
||||
}
|
||||
|
||||
on_modules_updated();
|
||||
}
|
||||
|
||||
void System::OnThreadsUpdated(std::vector<const ThreadListEntry*> entries) {
|
||||
std::unordered_set<uint32_t> extra_threads;
|
||||
for (size_t i = 0; i < threads_.size(); ++i) {
|
||||
extra_threads.emplace(threads_[i]->thread_handle());
|
||||
}
|
||||
for (auto entry : entries) {
|
||||
auto existing_thread = threads_by_handle_.find(entry->thread_handle);
|
||||
if (existing_thread == threads_by_handle_.end()) {
|
||||
auto thread = std::make_unique<Thread>(this);
|
||||
thread->Update(entry);
|
||||
threads_by_handle_.emplace(entry->thread_handle, thread.get());
|
||||
threads_.emplace_back(std::move(thread));
|
||||
} else {
|
||||
existing_thread->second->Update(entry);
|
||||
extra_threads.erase(existing_thread->first);
|
||||
}
|
||||
}
|
||||
for (auto thread_handle : extra_threads) {
|
||||
auto thread = threads_by_handle_.find(thread_handle);
|
||||
if (thread != threads_by_handle_.end()) {
|
||||
thread->second->set_dead(true);
|
||||
}
|
||||
}
|
||||
|
||||
on_threads_updated();
|
||||
}
|
||||
|
||||
void System::OnThreadStateUpdated(
|
||||
uint32_t thread_handle, const ThreadStateEntry* entry,
|
||||
std::vector<const ThreadCallStackFrame*> frames) {
|
||||
auto thread = threads_by_handle_[thread_handle];
|
||||
if (thread != nullptr) {
|
||||
thread->UpdateState(entry, std::move(frames));
|
||||
on_thread_state_updated(thread);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace model
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_MODEL_SYSTEM_H_
|
||||
#define XENIA_DEBUG_UI_MODEL_SYSTEM_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/delegate.h"
|
||||
#include "xenia/debug/debug_client.h"
|
||||
#include "xenia/debug/ui/model/function.h"
|
||||
#include "xenia/debug/ui/model/module.h"
|
||||
#include "xenia/debug/ui/model/thread.h"
|
||||
#include "xenia/ui/loop.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace model {
|
||||
|
||||
class System : public DebugClientListener {
|
||||
public:
|
||||
System(xe::ui::Loop* loop, DebugClient* client);
|
||||
~System() override;
|
||||
|
||||
xe::ui::Loop* loop() const { return loop_; }
|
||||
DebugClient* client() const { return client_; }
|
||||
|
||||
ExecutionState execution_state();
|
||||
|
||||
std::vector<Module*> modules();
|
||||
std::vector<Thread*> threads();
|
||||
|
||||
Module* GetModuleByHandle(uint32_t module_handle);
|
||||
Thread* GetThreadByHandle(uint32_t thread_handle);
|
||||
|
||||
Delegate<void> on_execution_state_changed;
|
||||
Delegate<void> on_modules_updated;
|
||||
Delegate<void> on_threads_updated;
|
||||
Delegate<Thread*> on_thread_state_updated;
|
||||
|
||||
private:
|
||||
void OnExecutionStateChanged(ExecutionState execution_state) override;
|
||||
void OnModulesUpdated(
|
||||
std::vector<const proto::ModuleListEntry*> entries) override;
|
||||
void OnThreadsUpdated(
|
||||
std::vector<const proto::ThreadListEntry*> entries) override;
|
||||
void OnThreadStateUpdated(
|
||||
uint32_t thread_handle, const ThreadStateEntry* entry,
|
||||
std::vector<const ThreadCallStackFrame*> frames) override;
|
||||
|
||||
xe::ui::Loop* loop_ = nullptr;
|
||||
DebugClient* client_ = nullptr;
|
||||
|
||||
std::vector<std::unique_ptr<Module>> modules_;
|
||||
std::unordered_map<uint32_t, Module*> modules_by_handle_;
|
||||
std::vector<std::unique_ptr<Thread>> threads_;
|
||||
std::unordered_map<uint32_t, Thread*> threads_by_handle_;
|
||||
};
|
||||
|
||||
} // namespace model
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_MODEL_SYSTEM_H_
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/debug/ui/model/thread.h"
|
||||
|
||||
#include "xenia/debug/ui/model/system.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace model {
|
||||
|
||||
Thread::Thread(System* system) : system_(system) {
|
||||
state_ = memory::AlignedAlloc<proto::ThreadStateEntry>(64);
|
||||
}
|
||||
|
||||
Thread::~Thread() { memory::AlignedFree(state_); }
|
||||
|
||||
std::string Thread::to_string() {
|
||||
std::string value = entry_.name;
|
||||
if (is_host_thread()) {
|
||||
value += " (host)";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void Thread::Update(const proto::ThreadListEntry* entry) {
|
||||
std::memcpy(&entry_, entry, sizeof(entry_));
|
||||
}
|
||||
|
||||
void Thread::UpdateState(
|
||||
const proto::ThreadStateEntry* entry,
|
||||
std::vector<const proto::ThreadCallStackFrame*> frames) {
|
||||
std::memcpy(state_, entry, sizeof(*state_));
|
||||
call_stack_.resize(frames.size());
|
||||
for (size_t i = 0; i < frames.size(); ++i) {
|
||||
std::memcpy(call_stack_.data() + i, frames[i], sizeof(Frame));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace model
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_MODEL_THREAD_H_
|
||||
#define XENIA_DEBUG_UI_MODEL_THREAD_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/debug/proto/xdp_protocol.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace model {
|
||||
|
||||
class System;
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
using Frame = proto::ThreadCallStackFrame;
|
||||
|
||||
explicit Thread(System* system);
|
||||
~Thread();
|
||||
|
||||
bool is_dead() const { return is_dead_; }
|
||||
void set_dead(bool is_dead) { is_dead_ = is_dead; }
|
||||
|
||||
const proto::ThreadListEntry* entry() const { return &entry_; }
|
||||
const proto::ThreadStateEntry* state() const { return state_; }
|
||||
|
||||
uint32_t thread_handle() const { return entry_.thread_handle; }
|
||||
uint32_t thread_id() const { return entry_.thread_id; }
|
||||
bool is_host_thread() const { return entry_.is_host_thread; }
|
||||
std::string name() const { return entry_.name; }
|
||||
|
||||
const cpu::frontend::PPCContext* guest_context() const {
|
||||
return &state_->guest_context;
|
||||
}
|
||||
const cpu::X64Context* host_context() const { return &state_->host_context; }
|
||||
const std::vector<Frame>& call_stack() const { return call_stack_; }
|
||||
|
||||
std::string to_string();
|
||||
|
||||
void Update(const proto::ThreadListEntry* entry);
|
||||
void UpdateState(const proto::ThreadStateEntry* entry,
|
||||
std::vector<const proto::ThreadCallStackFrame*> frames);
|
||||
|
||||
private:
|
||||
System* system_ = nullptr;
|
||||
bool is_dead_ = false;
|
||||
proto::ThreadListEntry entry_ = {0};
|
||||
proto::ThreadStateEntry* state_ = nullptr;
|
||||
std::vector<Frame> call_stack_;
|
||||
};
|
||||
|
||||
} // namespace model
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_MODEL_THREAD_H_
|
||||
@@ -3,56 +3,25 @@ include(project_root.."/build_tools")
|
||||
|
||||
group("src")
|
||||
project("xenia-debug-ui")
|
||||
uuid("ed128630-8b4e-4dd7-afc9-ef00052fe3a7")
|
||||
kind("WindowedApp")
|
||||
uuid("9193a274-f4c2-4746-bd85-93fcfc5c3e38")
|
||||
kind("StaticLib")
|
||||
language("C++")
|
||||
links({
|
||||
"elemental-forms",
|
||||
"gflags",
|
||||
"xenia-apu",
|
||||
"xenia-apu-nop",
|
||||
"xenia-apu-xaudio2",
|
||||
"glew",
|
||||
"imgui",
|
||||
"xenia-base",
|
||||
"xenia-core",
|
||||
"xenia-cpu",
|
||||
"xenia-cpu-backend-x64",
|
||||
"xenia-debug",
|
||||
"xenia-gpu",
|
||||
"xenia-gpu-gl4",
|
||||
"xenia-hid-nop",
|
||||
"xenia-hid-winkey",
|
||||
"xenia-hid-xinput",
|
||||
"xenia-kernel",
|
||||
"xenia-ui",
|
||||
"xenia-ui-gl",
|
||||
"xenia-vfs",
|
||||
})
|
||||
flags({
|
||||
"WinMain", -- Use WinMain instead of main.
|
||||
})
|
||||
defines({
|
||||
"GLEW_STATIC=1",
|
||||
"GLEW_MX=1",
|
||||
})
|
||||
includedirs({
|
||||
project_root.."/third_party/elemental-forms/src",
|
||||
project_root.."/build_tools/third_party/gflags/src",
|
||||
project_root.."/third_party/elemental-forms/src",
|
||||
})
|
||||
recursive_platform_files()
|
||||
files({
|
||||
"debugger_main.cc",
|
||||
"../../base/main_"..platform_suffix..".cc",
|
||||
})
|
||||
files({
|
||||
"debugger_resources.rc",
|
||||
})
|
||||
resincludedirs({
|
||||
project_root,
|
||||
project_root.."/third_party/elemental-forms",
|
||||
})
|
||||
|
||||
filter("platforms:Windows")
|
||||
debugdir(project_root)
|
||||
debugargs({
|
||||
"--flagfile=scratch/flags.txt",
|
||||
"2>&1",
|
||||
"1>scratch/stdout-debugger.txt",
|
||||
})
|
||||
local_platform_files()
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
elements
|
||||
Button
|
||||
padding 3 4
|
||||
Button.flat
|
||||
padding 3 4
|
||||
ButtonInGroup
|
||||
padding 3 4
|
||||
Box
|
||||
padding 5
|
||||
ListItem
|
||||
padding 1 4
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_VIEW_H_
|
||||
#define XENIA_DEBUG_UI_VIEW_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "el/elements.h"
|
||||
#include "el/event_handler.h"
|
||||
#include "xenia/debug/ui/application.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
|
||||
class View {
|
||||
public:
|
||||
virtual ~View() = default;
|
||||
|
||||
std::string name() const { return name_; }
|
||||
el::LayoutBox* root_element() { return &root_element_; }
|
||||
xe::ui::Loop* loop() const { return Application::current()->loop(); }
|
||||
DebugClient* client() const { return client_; }
|
||||
model::System* system() const { return Application::current()->system(); }
|
||||
|
||||
virtual el::Element* BuildUI() = 0;
|
||||
|
||||
virtual void Setup(xe::debug::DebugClient* client) = 0;
|
||||
|
||||
protected:
|
||||
explicit View(std::string name) : name_(name) {}
|
||||
|
||||
std::string name_;
|
||||
el::LayoutBox root_element_;
|
||||
std::unique_ptr<el::EventHandler> handler_;
|
||||
xe::debug::DebugClient* client_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_VIEW_H_
|
||||
@@ -1,152 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/debug/ui/views/cpu/call_stack_control.h"
|
||||
|
||||
#include "el/animation_manager.h"
|
||||
#include "xenia/base/string_buffer.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace views {
|
||||
namespace cpu {
|
||||
|
||||
class CallStackItem : public el::GenericStringItem {
|
||||
public:
|
||||
CallStackItem(size_t ordinal, const ThreadCallStackFrame* frame)
|
||||
: GenericStringItem(""), ordinal_(ordinal), frame_(frame) {
|
||||
StringBuffer sb;
|
||||
if (frame_->guest_pc) {
|
||||
sb.AppendFormat(" %.2lld %.16llX %.8X %s", ordinal_, frame_->host_pc,
|
||||
frame_->guest_pc, frame_->name);
|
||||
} else {
|
||||
sb.AppendFormat(" %.2lld %.16llX %s", ordinal_, frame_->host_pc,
|
||||
frame_->name);
|
||||
}
|
||||
str = sb.to_string();
|
||||
}
|
||||
|
||||
private:
|
||||
size_t ordinal_ = 0;
|
||||
const ThreadCallStackFrame* frame_ = nullptr;
|
||||
};
|
||||
|
||||
class CallStackItemElement : public el::LayoutBox {
|
||||
public:
|
||||
CallStackItemElement(CallStackItem* item, CallStackItemSource* source,
|
||||
el::ListItemObserver* source_viewer, size_t index)
|
||||
: item_(item),
|
||||
source_(source),
|
||||
source_viewer_(source_viewer),
|
||||
index_(index) {
|
||||
set_background_skin(TBIDC("ListItem"));
|
||||
set_axis(el::Axis::kY);
|
||||
set_gravity(el::Gravity::kAll);
|
||||
set_layout_position(el::LayoutPosition::kLeftTop);
|
||||
set_layout_distribution(el::LayoutDistribution::kAvailable);
|
||||
set_layout_distribution_position(el::LayoutDistributionPosition::kLeftTop);
|
||||
set_layout_size(el::LayoutSize::kAvailable);
|
||||
set_paint_overflow_fadeout(false);
|
||||
|
||||
using namespace el::dsl; // NOLINT(build/namespaces)
|
||||
el::AnimationBlocker animation_blocker;
|
||||
|
||||
auto node = LabelNode(item_->str.c_str())
|
||||
.gravity(Gravity::kLeft)
|
||||
.ignore_input(true)
|
||||
.text_align(el::TextAlign::kLeft);
|
||||
content_root()->LoadNodeTree(node);
|
||||
}
|
||||
|
||||
bool OnEvent(const el::Event& ev) override {
|
||||
return el::LayoutBox::OnEvent(ev);
|
||||
}
|
||||
|
||||
private:
|
||||
CallStackItem* item_ = nullptr;
|
||||
CallStackItemSource* source_ = nullptr;
|
||||
el::ListItemObserver* source_viewer_ = nullptr;
|
||||
size_t index_ = 0;
|
||||
};
|
||||
|
||||
class CallStackItemSource : public el::ListItemSourceList<CallStackItem> {
|
||||
public:
|
||||
el::Element* CreateItemElement(size_t index,
|
||||
el::ListItemObserver* viewer) override {
|
||||
return new CallStackItemElement(at(index), this, viewer, index);
|
||||
}
|
||||
};
|
||||
|
||||
CallStackControl::CallStackControl()
|
||||
: item_source_(new CallStackItemSource()) {}
|
||||
|
||||
CallStackControl::~CallStackControl() = default;
|
||||
|
||||
el::Element* CallStackControl::BuildUI() {
|
||||
using namespace el::dsl; // NOLINT(build/namespaces)
|
||||
el::AnimationBlocker animation_blocker;
|
||||
|
||||
auto node =
|
||||
LayoutBoxNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.distribution(LayoutDistribution::kAvailable)
|
||||
.child(ListBoxNode().id("stack_listbox").gravity(Gravity::kAll));
|
||||
|
||||
root_element_.set_gravity(Gravity::kAll);
|
||||
root_element_.set_layout_distribution(LayoutDistribution::kAvailable);
|
||||
root_element_.LoadNodeTree(node);
|
||||
|
||||
auto stack_listbox =
|
||||
root_element_.GetElementById<el::ListBox>(TBIDC("stack_listbox"));
|
||||
stack_listbox->set_source(item_source_.get());
|
||||
stack_listbox->scroll_container()->set_scroll_mode(
|
||||
el::ScrollMode::kAutoXAutoY);
|
||||
|
||||
handler_ = std::make_unique<el::EventHandler>(&root_element_);
|
||||
|
||||
return &root_element_;
|
||||
}
|
||||
|
||||
void CallStackControl::Setup(DebugClient* client) {
|
||||
client_ = client;
|
||||
|
||||
system()->on_thread_state_updated.AddListener([this](model::Thread* thread) {
|
||||
if (thread == thread_) {
|
||||
InvalidateCallStack();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CallStackControl::set_thread(model::Thread* thread) {
|
||||
thread_ = thread;
|
||||
InvalidateCallStack();
|
||||
}
|
||||
|
||||
void CallStackControl::InvalidateCallStack() {
|
||||
item_source_->clear();
|
||||
if (!thread_) {
|
||||
return;
|
||||
}
|
||||
auto& call_stack = thread_->call_stack();
|
||||
for (size_t i = 0; i < call_stack.size(); ++i) {
|
||||
auto& frame = call_stack[i];
|
||||
size_t ordinal = call_stack.size() - i - 1;
|
||||
auto item = std::make_unique<CallStackItem>(ordinal, &frame);
|
||||
item->tag.set_integer(static_cast<int>(i));
|
||||
item_source_->push_back(std::move(item));
|
||||
}
|
||||
item_source_->InvokeAllItemsRemoved();
|
||||
}
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace views
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_VIEWS_CPU_CALL_STACK_CONTROL_H_
|
||||
#define XENIA_DEBUG_UI_VIEWS_CPU_CALL_STACK_CONTROL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/debug/ui/control.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace views {
|
||||
namespace cpu {
|
||||
|
||||
class CallStackItemSource;
|
||||
|
||||
class CallStackControl : public Control {
|
||||
public:
|
||||
CallStackControl();
|
||||
~CallStackControl() override;
|
||||
|
||||
el::Element* BuildUI() override;
|
||||
|
||||
void Setup(xe::debug::DebugClient* client) override;
|
||||
|
||||
model::Thread* thread() const { return thread_; }
|
||||
void set_thread(model::Thread* thread);
|
||||
|
||||
private:
|
||||
void InvalidateCallStack();
|
||||
|
||||
model::Thread* thread_ = nullptr;
|
||||
std::unique_ptr<CallStackItemSource> item_source_;
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace views
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_VIEWS_CPU_CALL_STACK_CONTROL_H_
|
||||
@@ -1,278 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/debug/ui/views/cpu/cpu_view.h"
|
||||
|
||||
#include "el/animation_manager.h"
|
||||
#include "xenia/base/string_buffer.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace views {
|
||||
namespace cpu {
|
||||
|
||||
CpuView::CpuView()
|
||||
: View("CPU"),
|
||||
gr_registers_control_(RegisterSet::kGeneral),
|
||||
fr_registers_control_(RegisterSet::kFloat),
|
||||
vr_registers_control_(RegisterSet::kVector),
|
||||
host_registers_control_(RegisterSet::kHost) {}
|
||||
|
||||
CpuView::~CpuView() = default;
|
||||
|
||||
el::Element* CpuView::BuildUI() {
|
||||
using namespace el::dsl; // NOLINT(build/namespaces)
|
||||
el::AnimationBlocker animation_blocker;
|
||||
|
||||
auto functions_node =
|
||||
LayoutBoxNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.distribution(LayoutDistribution::kAvailable)
|
||||
.axis(Axis::kY)
|
||||
.child(LayoutBoxNode()
|
||||
.gravity(Gravity::kTop | Gravity::kLeftRight)
|
||||
.distribution(LayoutDistribution::kAvailable)
|
||||
.axis(Axis::kX)
|
||||
.skin("button_group")
|
||||
.child(DropDownButtonNode().id("module_dropdown")))
|
||||
.child(ListBoxNode().id("function_listbox").gravity(Gravity::kAll))
|
||||
.child(LayoutBoxNode()
|
||||
.gravity(Gravity::kBottom | Gravity::kLeftRight)
|
||||
.distribution(LayoutDistribution::kAvailable)
|
||||
.axis(Axis::kX)
|
||||
.child(TextBoxNode()
|
||||
.type(EditType::kSearch)
|
||||
.placeholder("Filter")));
|
||||
|
||||
auto register_list_node = ListBoxNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.item("A")
|
||||
.item("A")
|
||||
.item("A")
|
||||
.item("A");
|
||||
auto source_registers_node =
|
||||
TabContainerNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.tab(ButtonNode("GR"), LabelNode("<register list control>")
|
||||
.id("gr_registers_placeholder"))
|
||||
.tab(ButtonNode("FR"), LabelNode("<register list control>")
|
||||
.id("fr_registers_placeholder"))
|
||||
.tab(ButtonNode("VR"), LabelNode("<register list control>")
|
||||
.id("vr_registers_placeholder"))
|
||||
.tab(ButtonNode("X64"), LabelNode("<register list control>")
|
||||
.id("host_registers_placeholder"));
|
||||
|
||||
auto source_tools_node =
|
||||
TabContainerNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.align(Align::kLeft)
|
||||
.tab(ButtonNode("Stack"),
|
||||
LabelNode("<callstack control>").id("call_stack_placeholder"))
|
||||
.tab(ButtonNode("BPs"), LabelNode("BREAKPOINTS"));
|
||||
|
||||
auto source_pane_node =
|
||||
LayoutBoxNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.distribution(LayoutDistribution::kAvailable)
|
||||
.axis(Axis::kY)
|
||||
.child(
|
||||
LayoutBoxNode()
|
||||
.id("source_toolbar")
|
||||
.gravity(Gravity::kTop | Gravity::kLeftRight)
|
||||
.distribution(LayoutDistribution::kGravity)
|
||||
.distribution_position(LayoutDistributionPosition::kLeftTop)
|
||||
.axis(Axis::kX)
|
||||
.child(DropDownButtonNode().id("thread_dropdown")))
|
||||
.child(LayoutBoxNode()
|
||||
.id("source_content")
|
||||
.gravity(Gravity::kAll)
|
||||
.distribution(LayoutDistribution::kAvailable)
|
||||
.child(SplitContainerNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.axis(Axis::kX)
|
||||
.fixed_pane(FixedPane::kSecond)
|
||||
.value(250)
|
||||
.pane(SplitContainerNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.axis(Axis::kY)
|
||||
.fixed_pane(FixedPane::kSecond)
|
||||
.value(240)
|
||||
.pane(LabelNode("<source control>")
|
||||
.id("source_placeholder"))
|
||||
.pane(source_registers_node))
|
||||
.pane(source_tools_node)));
|
||||
|
||||
auto memory_pane_node = LabelNode("MEMORY");
|
||||
|
||||
auto node = SplitContainerNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.axis(Axis::kY)
|
||||
.min(128)
|
||||
.max(512)
|
||||
.value(128)
|
||||
.pane(functions_node)
|
||||
.pane(SplitContainerNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.axis(Axis::kY)
|
||||
.value(800)
|
||||
.pane(source_pane_node)
|
||||
.pane(memory_pane_node));
|
||||
|
||||
root_element_.set_gravity(Gravity::kAll);
|
||||
root_element_.set_layout_distribution(LayoutDistribution::kAvailable);
|
||||
root_element_.LoadNodeTree(node);
|
||||
|
||||
el::Label* source_placeholder;
|
||||
el::Label* gr_registers_placeholder;
|
||||
el::Label* fr_registers_placeholder;
|
||||
el::Label* vr_registers_placeholder;
|
||||
el::Label* host_registers_placeholder;
|
||||
el::Label* call_stack_placeholder;
|
||||
root_element_.GetElementsById({
|
||||
{TBIDC("source_placeholder"), &source_placeholder},
|
||||
{TBIDC("gr_registers_placeholder"), &gr_registers_placeholder},
|
||||
{TBIDC("fr_registers_placeholder"), &fr_registers_placeholder},
|
||||
{TBIDC("vr_registers_placeholder"), &vr_registers_placeholder},
|
||||
{TBIDC("host_registers_placeholder"), &host_registers_placeholder},
|
||||
{TBIDC("call_stack_placeholder"), &call_stack_placeholder},
|
||||
});
|
||||
source_placeholder->parent()->ReplaceChild(source_placeholder,
|
||||
source_control_.BuildUI());
|
||||
source_control_.Setup(client_);
|
||||
gr_registers_placeholder->parent()->ReplaceChild(
|
||||
gr_registers_placeholder, gr_registers_control_.BuildUI());
|
||||
gr_registers_control_.Setup(client_);
|
||||
fr_registers_placeholder->parent()->ReplaceChild(
|
||||
fr_registers_placeholder, fr_registers_control_.BuildUI());
|
||||
fr_registers_control_.Setup(client_);
|
||||
vr_registers_placeholder->parent()->ReplaceChild(
|
||||
vr_registers_placeholder, vr_registers_control_.BuildUI());
|
||||
vr_registers_control_.Setup(client_);
|
||||
host_registers_placeholder->parent()->ReplaceChild(
|
||||
host_registers_placeholder, host_registers_control_.BuildUI());
|
||||
host_registers_control_.Setup(client_);
|
||||
call_stack_placeholder->parent()->ReplaceChild(call_stack_placeholder,
|
||||
call_stack_control_.BuildUI());
|
||||
call_stack_control_.Setup(client_);
|
||||
|
||||
handler_ = std::make_unique<el::EventHandler>(&root_element_);
|
||||
|
||||
handler_->Listen(el::EventType::kChanged, TBIDC("module_dropdown"),
|
||||
[this](const el::Event& ev) {
|
||||
UpdateFunctionList();
|
||||
return true;
|
||||
});
|
||||
handler_->Listen(
|
||||
el::EventType::kChanged, TBIDC("thread_dropdown"),
|
||||
[this](const el::Event& ev) {
|
||||
auto thread_dropdown = root_element_.GetElementById<el::DropDownButton>(
|
||||
TBIDC("thread_dropdown"));
|
||||
auto thread_handle = uint32_t(thread_dropdown->selected_item_id());
|
||||
if (thread_handle) {
|
||||
current_thread_ = system()->GetThreadByHandle(thread_handle);
|
||||
} else {
|
||||
current_thread_ = nullptr;
|
||||
}
|
||||
SwitchCurrentThread(current_thread_);
|
||||
return true;
|
||||
});
|
||||
|
||||
return &root_element_;
|
||||
}
|
||||
|
||||
void CpuView::Setup(DebugClient* client) {
|
||||
client_ = client;
|
||||
|
||||
system()->on_execution_state_changed.AddListener(
|
||||
[this]() { UpdateElementState(); });
|
||||
system()->on_modules_updated.AddListener([this]() { UpdateModuleList(); });
|
||||
system()->on_threads_updated.AddListener([this]() { UpdateThreadList(); });
|
||||
}
|
||||
|
||||
void CpuView::UpdateElementState() {
|
||||
root_element_.GetElementsById({
|
||||
//
|
||||
});
|
||||
}
|
||||
|
||||
void CpuView::UpdateModuleList() {
|
||||
el::DropDownButton* module_dropdown;
|
||||
root_element_.GetElementsById({
|
||||
{TBIDC("module_dropdown"), &module_dropdown},
|
||||
});
|
||||
auto module_items = module_dropdown->default_source();
|
||||
auto modules = system()->modules();
|
||||
bool is_first = module_items->size() == 0;
|
||||
for (size_t i = module_items->size(); i < modules.size(); ++i) {
|
||||
auto module = modules[i];
|
||||
auto item = std::make_unique<el::GenericStringItem>(module->name());
|
||||
item->id = module->module_handle();
|
||||
module_items->push_back(std::move(item));
|
||||
}
|
||||
if (is_first) {
|
||||
module_dropdown->set_value(static_cast<int>(module_items->size() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
void CpuView::UpdateFunctionList() {
|
||||
el::DropDownButton* module_dropdown;
|
||||
el::ListBox* function_listbox;
|
||||
root_element_.GetElementsById({
|
||||
{TBIDC("module_dropdown"), &module_dropdown},
|
||||
{TBIDC("function_listbox"), &function_listbox},
|
||||
});
|
||||
auto module_handle = module_dropdown->selected_item_id();
|
||||
auto module = system()->GetModuleByHandle(module_handle);
|
||||
if (!module) {
|
||||
function_listbox->default_source()->clear();
|
||||
return;
|
||||
}
|
||||
// TODO(benvanik): fetch list.
|
||||
}
|
||||
|
||||
void CpuView::UpdateThreadList() {
|
||||
el::DropDownButton* thread_dropdown;
|
||||
root_element_.GetElementsById({
|
||||
{TBIDC("thread_dropdown"), &thread_dropdown},
|
||||
});
|
||||
auto thread_items = thread_dropdown->default_source();
|
||||
auto threads = system()->threads();
|
||||
bool is_first = thread_items->size() == 0;
|
||||
for (size_t i = 0; i < thread_items->size(); ++i) {
|
||||
auto thread = threads[i];
|
||||
auto item = thread_items->at(i);
|
||||
item->str = thread->to_string();
|
||||
}
|
||||
for (size_t i = thread_items->size(); i < threads.size(); ++i) {
|
||||
auto thread = threads[i];
|
||||
auto item = std::make_unique<el::GenericStringItem>(thread->to_string());
|
||||
item->id = thread->thread_handle();
|
||||
thread_items->push_back(std::move(item));
|
||||
}
|
||||
if (is_first) {
|
||||
thread_dropdown->set_value(static_cast<int>(thread_items->size() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
void CpuView::SwitchCurrentThread(model::Thread* thread) {
|
||||
current_thread_ = thread;
|
||||
source_control_.set_thread(thread);
|
||||
gr_registers_control_.set_thread(thread);
|
||||
fr_registers_control_.set_thread(thread);
|
||||
vr_registers_control_.set_thread(thread);
|
||||
host_registers_control_.set_thread(thread);
|
||||
call_stack_control_.set_thread(thread);
|
||||
}
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace views
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_VIEWS_CPU_CPU_VIEW_H_
|
||||
#define XENIA_DEBUG_UI_VIEWS_CPU_CPU_VIEW_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/debug/ui/view.h"
|
||||
#include "xenia/debug/ui/views/cpu/call_stack_control.h"
|
||||
#include "xenia/debug/ui/views/cpu/register_list_control.h"
|
||||
#include "xenia/debug/ui/views/cpu/source_control.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace views {
|
||||
namespace cpu {
|
||||
|
||||
class CpuView : public View {
|
||||
public:
|
||||
CpuView();
|
||||
~CpuView() override;
|
||||
|
||||
el::Element* BuildUI() override;
|
||||
|
||||
void Setup(xe::debug::DebugClient* client) override;
|
||||
|
||||
protected:
|
||||
void UpdateElementState();
|
||||
void UpdateModuleList();
|
||||
void UpdateFunctionList();
|
||||
void UpdateThreadList();
|
||||
|
||||
void SwitchCurrentThread(model::Thread* thread);
|
||||
|
||||
// TODO(benvanik): better state machine.
|
||||
model::Thread* current_thread_ = nullptr;
|
||||
|
||||
SourceControl source_control_;
|
||||
RegisterListControl gr_registers_control_;
|
||||
RegisterListControl fr_registers_control_;
|
||||
RegisterListControl vr_registers_control_;
|
||||
RegisterListControl host_registers_control_;
|
||||
CallStackControl call_stack_control_;
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace views
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_VIEWS_CPU_CPU_VIEW_H_
|
||||
@@ -1,325 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/debug/ui/views/cpu/register_list_control.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "el/animation_manager.h"
|
||||
#include "xenia/base/string_buffer.h"
|
||||
#include "xenia/base/string_util.h"
|
||||
#include "xenia/cpu/x64_context.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace views {
|
||||
namespace cpu {
|
||||
|
||||
using xe::cpu::frontend::PPCRegister;
|
||||
using xe::cpu::X64Register;
|
||||
|
||||
enum class RegisterType {
|
||||
kControl,
|
||||
kInteger,
|
||||
kFloat,
|
||||
kVector,
|
||||
};
|
||||
|
||||
class RegisterItem : public el::GenericStringItem {
|
||||
public:
|
||||
const char* name() { return name_.c_str(); }
|
||||
|
||||
virtual void set_thread(model::Thread* thread) { thread_ = thread; }
|
||||
|
||||
protected:
|
||||
RegisterItem(RegisterSet set, RegisterType type, int ordinal)
|
||||
: GenericStringItem(""), set_(set), type_(type), ordinal_(ordinal) {
|
||||
tag.set_integer(ordinal);
|
||||
}
|
||||
|
||||
RegisterSet set_;
|
||||
RegisterType type_;
|
||||
int ordinal_;
|
||||
model::Thread* thread_ = nullptr;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
class GuestRegisterItem : public RegisterItem {
|
||||
public:
|
||||
GuestRegisterItem(RegisterSet set, RegisterType type, PPCRegister reg)
|
||||
: RegisterItem(set, type, static_cast<int>(reg)), reg_(reg) {
|
||||
name_ = xe::cpu::frontend::PPCContext::GetRegisterName(reg_);
|
||||
}
|
||||
|
||||
void set_thread(model::Thread* thread) override {
|
||||
RegisterItem::set_thread(thread);
|
||||
if (thread_) {
|
||||
str = thread_->guest_context()->GetStringFromValue(reg_);
|
||||
} else {
|
||||
str = "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
PPCRegister reg_;
|
||||
};
|
||||
|
||||
class HostRegisterItem : public RegisterItem {
|
||||
public:
|
||||
HostRegisterItem(RegisterSet set, RegisterType type, X64Register reg)
|
||||
: RegisterItem(set, type, static_cast<int>(reg)), reg_(reg) {
|
||||
name_ = xe::cpu::X64Context::GetRegisterName(reg_);
|
||||
}
|
||||
|
||||
void set_thread(model::Thread* thread) override {
|
||||
RegisterItem::set_thread(thread);
|
||||
if (thread_) {
|
||||
str = thread_->host_context()->GetStringFromValue(reg_);
|
||||
} else {
|
||||
str = "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
X64Register reg_;
|
||||
};
|
||||
|
||||
class RegisterItemElement : public el::LayoutBox {
|
||||
public:
|
||||
RegisterItemElement(RegisterItem* item, RegisterItemSource* source,
|
||||
el::ListItemObserver* source_viewer, size_t index)
|
||||
: item_(item),
|
||||
source_(source),
|
||||
source_viewer_(source_viewer),
|
||||
index_(index) {
|
||||
set_background_skin(TBIDC("ListItem"));
|
||||
set_axis(el::Axis::kY);
|
||||
set_gravity(el::Gravity::kAll);
|
||||
set_layout_position(el::LayoutPosition::kLeftTop);
|
||||
set_layout_distribution(el::LayoutDistribution::kAvailable);
|
||||
set_layout_distribution_position(el::LayoutDistributionPosition::kLeftTop);
|
||||
set_layout_size(el::LayoutSize::kAvailable);
|
||||
set_paint_overflow_fadeout(false);
|
||||
|
||||
using namespace el::dsl; // NOLINT(build/namespaces)
|
||||
el::AnimationBlocker animation_blocker;
|
||||
|
||||
auto node = LayoutBoxNode()
|
||||
.axis(Axis::kX)
|
||||
.gravity(Gravity::kLeft)
|
||||
.distribution(LayoutDistribution::kAvailable)
|
||||
.child(LabelNode(item_->name())
|
||||
.ignore_input(true)
|
||||
.width(45_px)
|
||||
.gravity(Gravity::kLeft))
|
||||
.child(TextBoxNode(item_->str.c_str())
|
||||
.gravity(Gravity::kLeftRight));
|
||||
content_root()->LoadNodeTree(node);
|
||||
}
|
||||
|
||||
bool OnEvent(const el::Event& ev) override {
|
||||
return el::LayoutBox::OnEvent(ev);
|
||||
}
|
||||
|
||||
private:
|
||||
RegisterItem* item_ = nullptr;
|
||||
RegisterItemSource* source_ = nullptr;
|
||||
el::ListItemObserver* source_viewer_ = nullptr;
|
||||
size_t index_ = 0;
|
||||
};
|
||||
|
||||
class RegisterItemSource : public el::ListItemSourceList<RegisterItem> {
|
||||
public:
|
||||
el::Element* CreateItemElement(size_t index,
|
||||
el::ListItemObserver* viewer) override {
|
||||
return new RegisterItemElement(at(index), this, viewer, index);
|
||||
}
|
||||
};
|
||||
|
||||
void DefineRegisterItem(RegisterItemSource* item_source, RegisterSet set,
|
||||
RegisterType type, PPCRegister reg) {
|
||||
auto item = std::make_unique<GuestRegisterItem>(set, type, reg);
|
||||
item->tag.set_integer(static_cast<int>(reg));
|
||||
item_source->push_back(std::move(item));
|
||||
}
|
||||
void DefineRegisterItem(RegisterItemSource* item_source, RegisterSet set,
|
||||
RegisterType type, X64Register reg) {
|
||||
auto item = std::make_unique<HostRegisterItem>(set, type, reg);
|
||||
item->tag.set_integer(static_cast<int>(reg));
|
||||
item_source->push_back(std::move(item));
|
||||
}
|
||||
|
||||
RegisterListControl::RegisterListControl(RegisterSet set)
|
||||
: set_(set), item_source_(new RegisterItemSource()) {
|
||||
switch (set_) {
|
||||
case RegisterSet::kGeneral: {
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
PPCRegister::kLR);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
PPCRegister::kCTR);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kControl,
|
||||
PPCRegister::kXER);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kControl,
|
||||
PPCRegister::kCR);
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
static_cast<PPCRegister>(
|
||||
static_cast<size_t>(PPCRegister::kR0) + i));
|
||||
}
|
||||
} break;
|
||||
case RegisterSet::kFloat: {
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kControl,
|
||||
PPCRegister::kFPSCR);
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kFloat,
|
||||
static_cast<PPCRegister>(
|
||||
static_cast<size_t>(PPCRegister::kFR0) + i));
|
||||
}
|
||||
} break;
|
||||
case RegisterSet::kVector: {
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kControl,
|
||||
PPCRegister::kVSCR);
|
||||
for (size_t i = 0; i < 128; ++i) {
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
static_cast<PPCRegister>(
|
||||
static_cast<size_t>(PPCRegister::kVR0) + i));
|
||||
}
|
||||
} break;
|
||||
case RegisterSet::kHost: {
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kRip);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kControl,
|
||||
X64Register::kEflags);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kRax);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kRcx);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kRdx);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kRbx);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kRsp);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kRbp);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kRsi);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kRdi);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kR8);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kR9);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kR10);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kR11);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kR12);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kR13);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kR14);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kInteger,
|
||||
X64Register::kR15);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm0);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm1);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm2);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm3);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm4);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm5);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm6);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm7);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm8);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm9);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm10);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm11);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm12);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm13);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm14);
|
||||
DefineRegisterItem(item_source_.get(), set_, RegisterType::kVector,
|
||||
X64Register::kXmm15);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
RegisterListControl::~RegisterListControl() = default;
|
||||
|
||||
el::Element* RegisterListControl::BuildUI() {
|
||||
using namespace el::dsl; // NOLINT(build/namespaces)
|
||||
el::AnimationBlocker animation_blocker;
|
||||
|
||||
auto node =
|
||||
LayoutBoxNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.distribution(LayoutDistribution::kAvailable)
|
||||
.child(ListBoxNode().id("register_listbox").gravity(Gravity::kAll));
|
||||
|
||||
root_element_.set_gravity(Gravity::kAll);
|
||||
root_element_.set_layout_distribution(LayoutDistribution::kAvailable);
|
||||
root_element_.LoadNodeTree(node);
|
||||
|
||||
auto register_listbox =
|
||||
root_element_.GetElementById<el::ListBox>(TBIDC("register_listbox"));
|
||||
register_listbox->set_source(item_source_.get());
|
||||
register_listbox->scroll_container()->set_scroll_mode(
|
||||
el::ScrollMode::kAutoXAutoY);
|
||||
|
||||
handler_ = std::make_unique<el::EventHandler>(&root_element_);
|
||||
|
||||
return &root_element_;
|
||||
}
|
||||
|
||||
void RegisterListControl::Setup(DebugClient* client) {
|
||||
client_ = client;
|
||||
|
||||
system()->on_thread_state_updated.AddListener([this](model::Thread* thread) {
|
||||
if (thread == thread_) {
|
||||
InvalidateRegisters();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterListControl::set_thread(model::Thread* thread) {
|
||||
thread_ = thread;
|
||||
InvalidateRegisters();
|
||||
}
|
||||
|
||||
void RegisterListControl::InvalidateRegisters() {
|
||||
for (size_t i = 0; i < item_source_->size(); ++i) {
|
||||
item_source_->at(i)->set_thread(thread_);
|
||||
}
|
||||
|
||||
auto register_listbox =
|
||||
root_element_.GetElementById<el::ListBox>(TBIDC("register_listbox"));
|
||||
register_listbox->InvalidateList();
|
||||
}
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace views
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_VIEWS_CPU_REGISTER_LIST_CONTROL_H_
|
||||
#define XENIA_DEBUG_UI_VIEWS_CPU_REGISTER_LIST_CONTROL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/debug/ui/control.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace views {
|
||||
namespace cpu {
|
||||
|
||||
class RegisterItemSource;
|
||||
|
||||
enum class RegisterSet {
|
||||
kGeneral,
|
||||
kFloat,
|
||||
kVector,
|
||||
kHost,
|
||||
};
|
||||
|
||||
class RegisterListControl : public Control {
|
||||
public:
|
||||
explicit RegisterListControl(RegisterSet set);
|
||||
~RegisterListControl() override;
|
||||
|
||||
el::Element* BuildUI() override;
|
||||
|
||||
void Setup(xe::debug::DebugClient* client) override;
|
||||
|
||||
model::Thread* thread() const { return thread_; }
|
||||
void set_thread(model::Thread* thread);
|
||||
|
||||
private:
|
||||
void InvalidateRegisters();
|
||||
|
||||
RegisterSet set_;
|
||||
model::Thread* thread_ = nullptr;
|
||||
std::unique_ptr<RegisterItemSource> item_source_;
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace views
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_VIEWS_CPU_REGISTER_LIST_CONTROL_H_
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/debug/ui/views/cpu/source_control.h"
|
||||
|
||||
#include "el/animation_manager.h"
|
||||
#include "xenia/base/string_buffer.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace views {
|
||||
namespace cpu {
|
||||
|
||||
SourceControl::SourceControl() = default;
|
||||
|
||||
SourceControl::~SourceControl() = default;
|
||||
|
||||
el::Element* SourceControl::BuildUI() {
|
||||
using namespace el::dsl; // NOLINT(build/namespaces)
|
||||
el::AnimationBlocker animation_blocker;
|
||||
|
||||
auto node = LayoutBoxNode()
|
||||
.gravity(Gravity::kAll)
|
||||
.distribution(LayoutDistribution::kAvailable)
|
||||
.axis(Axis::kY)
|
||||
.child(LayoutBoxNode()
|
||||
.gravity(Gravity::kTop | Gravity::kLeftRight)
|
||||
.distribution(LayoutDistribution::kGravity)
|
||||
.distribution_position(
|
||||
LayoutDistributionPosition::kLeftTop)
|
||||
.axis(Axis::kX)
|
||||
.child(ButtonNode("A")))
|
||||
.child(TextBoxNode("source!")
|
||||
.id("source_textbox")
|
||||
.gravity(Gravity::kAll)
|
||||
.is_multiline(true)
|
||||
.is_read_only(true));
|
||||
|
||||
root_element_.set_gravity(Gravity::kAll);
|
||||
root_element_.set_layout_distribution(LayoutDistribution::kAvailable);
|
||||
root_element_.LoadNodeTree(node);
|
||||
|
||||
handler_ = std::make_unique<el::EventHandler>(&root_element_);
|
||||
|
||||
return &root_element_;
|
||||
}
|
||||
|
||||
void SourceControl::Setup(DebugClient* client) {
|
||||
client_ = client;
|
||||
|
||||
// system()->on_thread_state_updated.AddListener([this](model::Thread* thread)
|
||||
// {
|
||||
// if (thread == thread_) {
|
||||
// InvalidateCallStack();
|
||||
// }
|
||||
//});
|
||||
}
|
||||
|
||||
void SourceControl::set_thread(model::Thread* thread) {
|
||||
thread_ = thread;
|
||||
// InvalidateCallStack();
|
||||
}
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace views
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
@@ -1,46 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_VIEWS_CPU_SOURCE_CONTROL_H_
|
||||
#define XENIA_DEBUG_UI_VIEWS_CPU_SOURCE_CONTROL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/debug/ui/control.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace views {
|
||||
namespace cpu {
|
||||
|
||||
class SourceControl : public Control {
|
||||
public:
|
||||
SourceControl();
|
||||
~SourceControl() override;
|
||||
|
||||
el::Element* BuildUI() override;
|
||||
|
||||
void Setup(xe::debug::DebugClient* client) override;
|
||||
|
||||
model::Thread* thread() const { return thread_; }
|
||||
void set_thread(model::Thread* thread);
|
||||
|
||||
private:
|
||||
model::Thread* thread_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace views
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_VIEWS_CPU_SOURCE_CONTROL_H_
|
||||
@@ -1,47 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "el/animation_manager.h"
|
||||
#include "xenia/debug/ui/views/gpu/gpu_view.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace views {
|
||||
namespace gpu {
|
||||
|
||||
GpuView::GpuView() : View("GPU") {}
|
||||
|
||||
GpuView::~GpuView() = default;
|
||||
|
||||
el::Element* GpuView::BuildUI() {
|
||||
using namespace el::dsl; // NOLINT(build/namespaces)
|
||||
el::AnimationBlocker animation_blocker;
|
||||
|
||||
auto node = LabelNode("TODO");
|
||||
|
||||
root_element_.set_gravity(Gravity::kAll);
|
||||
root_element_.set_layout_distribution(LayoutDistribution::kAvailable);
|
||||
root_element_.LoadNodeTree(node);
|
||||
root_element_.GetElementsById({
|
||||
//
|
||||
});
|
||||
handler_ = std::make_unique<el::EventHandler>(&root_element_);
|
||||
return &root_element_;
|
||||
}
|
||||
|
||||
void GpuView::Setup(xe::debug::DebugClient* client) {
|
||||
//
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
} // namespace views
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_DEBUG_UI_VIEWS_GPU_GPU_VIEW_H_
|
||||
#define XENIA_DEBUG_UI_VIEWS_GPU_GPU_VIEW_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/debug/ui/view.h"
|
||||
|
||||
namespace xe {
|
||||
namespace debug {
|
||||
namespace ui {
|
||||
namespace views {
|
||||
namespace gpu {
|
||||
|
||||
class GpuView : public View {
|
||||
public:
|
||||
GpuView();
|
||||
~GpuView() override;
|
||||
|
||||
el::Element* BuildUI() override;
|
||||
|
||||
void Setup(xe::debug::DebugClient* client) override;
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
} // namespace gpu
|
||||
} // namespace views
|
||||
} // namespace ui
|
||||
} // namespace debug
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_DEBUG_UI_VIEWS_GPU_GPU_VIEW_H_
|
||||
@@ -1,101 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{C5BA52F0-C86B-4817-921C-CCA257FC04BE}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>xedebugui</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\build\Xenia.Cpp.$(Platform).Common.props" />
|
||||
<Import Project="..\..\..\..\build\Xenia.Cpp.$(Platform).$(Configuration).props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\build\Xenia.Cpp.$(Platform).Common.props" />
|
||||
<Import Project="..\..\..\..\build\Xenia.Cpp.$(Platform).$(Configuration).props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libgflags.lib;libglew.lib;libxenia.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libgflags.lib;libglew.lib;libxenia.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\base\main.h" />
|
||||
<ClInclude Include="application.h" />
|
||||
<ClInclude Include="main_window.h" />
|
||||
<ClInclude Include="view.h" />
|
||||
<ClInclude Include="views\cpu\cpu_view.h" />
|
||||
<ClInclude Include="views\gpu\gpu_view.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\base\main_win.cc" />
|
||||
<ClCompile Include="application.cc" />
|
||||
<ClCompile Include="main_window.cc" />
|
||||
<ClCompile Include="views\cpu\cpu_view.cc" />
|
||||
<ClCompile Include="views\gpu\gpu_view.cc" />
|
||||
<ClCompile Include="xe-debug-ui.cc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="resources.rc">
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)third_party/elemental-forms;$(SolutionDir);.</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)third_party/elemental-forms;$(SolutionDir);.</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -1,77 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{52d1c314-7464-4640-bee4-59b30d2b2df4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\xenia">
|
||||
<UniqueIdentifier>{f8d1867c-424d-4942-ba97-a7b29fa8c87c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\xenia\debug">
|
||||
<UniqueIdentifier>{1b70e26e-0024-410f-b27f-ceaba190d5a9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\xenia\debug\ui">
|
||||
<UniqueIdentifier>{9b5a4bce-210a-4488-863a-9175f0543d00}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\xenia\base">
|
||||
<UniqueIdentifier>{9a5724c2-5473-4d53-93b4-26531201f38d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\xenia\debug\ui\elements">
|
||||
<UniqueIdentifier>{f0ac4999-4700-4b41-b73d-c6dc8b23c5e6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\xenia\debug\ui\views">
|
||||
<UniqueIdentifier>{5601b0a2-a720-4d89-9fca-df1637fce0b1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\xenia\debug\ui\views\cpu">
|
||||
<UniqueIdentifier>{5b186e9a-1fef-42f5-b06b-2ac0b10a8a5b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\xenia\debug\ui\views\gpu">
|
||||
<UniqueIdentifier>{c66e9a6b-0947-4610-9b2b-29db99c08e91}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\base\main.h">
|
||||
<Filter>src\xenia\base</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="main_window.h">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="application.h">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="view.h">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="views\gpu\gpu_view.h">
|
||||
<Filter>src\xenia\debug\ui\views\gpu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="views\cpu\cpu_view.h">
|
||||
<Filter>src\xenia\debug\ui\views\cpu</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\base\main_win.cc">
|
||||
<Filter>src\xenia\base</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="xe-debug-ui.cc">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main_window.cc">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="application.cc">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="views\gpu\gpu_view.cc">
|
||||
<Filter>src\xenia\debug\ui\views\gpu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="views\cpu\cpu_view.cc">
|
||||
<Filter>src\xenia\debug\ui\views\cpu</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="resources.rc">
|
||||
<Filter>src\xenia\debug\ui</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user