diff options
Diffstat (limited to 'src/citra_qt')
22 files changed, 627 insertions, 182 deletions
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index bbc521f8a..586bc84b0 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -8,9 +8,11 @@ set(SRCS debugger/callstack.cpp debugger/disassembler.cpp debugger/graphics.cpp + debugger/graphics_breakpoint_observer.cpp debugger/graphics_breakpoints.cpp debugger/graphics_cmdlists.cpp debugger/graphics_framebuffer.cpp + debugger/graphics_vertex_shader.cpp debugger/ramview.cpp debugger/registers.cpp util/spinbox.cpp @@ -27,10 +29,12 @@ set(HEADERS debugger/callstack.h debugger/disassembler.h debugger/graphics.h + debugger/graphics_breakpoint_observer.h debugger/graphics_breakpoints.h debugger/graphics_breakpoints_p.h debugger/graphics_cmdlists.h debugger/graphics_framebuffer.h + debugger/graphics_vertex_shader.h debugger/ramview.h debugger/registers.h util/spinbox.h diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 196380105..22a7842bf 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -268,33 +268,33 @@ QByteArray GRenderWindow::saveGeometry() void GRenderWindow::keyPressEvent(QKeyEvent* event) { EmuWindow::KeyPressed({event->key(), keyboard_id}); - HID_User::PadUpdateComplete(); + Service::HID::PadUpdateComplete(); } void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { EmuWindow::KeyReleased({event->key(), keyboard_id}); - HID_User::PadUpdateComplete(); + Service::HID::PadUpdateComplete(); } void GRenderWindow::ReloadSetKeymaps() { - KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, HID_User::PAD_A); - KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, HID_User::PAD_B); - KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, HID_User::PAD_SELECT); - KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, HID_User::PAD_START); - KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, HID_User::PAD_RIGHT); - KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, HID_User::PAD_LEFT); - KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, HID_User::PAD_UP); - KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, HID_User::PAD_DOWN); - KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, HID_User::PAD_R); - KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, HID_User::PAD_L); - KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, HID_User::PAD_X); - KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, HID_User::PAD_Y); - KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, HID_User::PAD_CIRCLE_RIGHT); - KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, HID_User::PAD_CIRCLE_LEFT); - KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP); - KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN); + KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, Service::HID::PAD_A); + KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, Service::HID::PAD_B); + KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, Service::HID::PAD_SELECT); + KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, Service::HID::PAD_START); + KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, Service::HID::PAD_RIGHT); + KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, Service::HID::PAD_LEFT); + KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, Service::HID::PAD_UP); + KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, Service::HID::PAD_DOWN); + KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, Service::HID::PAD_R); + KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, Service::HID::PAD_L); + KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, Service::HID::PAD_X); + KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, Service::HID::PAD_Y); + KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, Service::HID::PAD_CIRCLE_RIGHT); + KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, Service::HID::PAD_CIRCLE_LEFT); + KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, Service::HID::PAD_CIRCLE_UP); + KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, Service::HID::PAD_CIRCLE_DOWN); } void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 1596c08d7..76aeaedd0 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -43,7 +43,6 @@ void Config::ReadValues() { qt_config->endGroup(); qt_config->beginGroup("Core"); - Settings::values.cpu_core = qt_config->value("cpu_core", Core::CPU_Interpreter).toInt(); Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 30).toInt(); Settings::values.frame_skip = qt_config->value("frame_skip", 0).toInt(); qt_config->endGroup(); @@ -52,6 +51,10 @@ void Config::ReadValues() { Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool(); qt_config->endGroup(); + qt_config->beginGroup("System Region"); + Settings::values.region_value = qt_config->value("region_value", 1).toInt(); + qt_config->endGroup(); + qt_config->beginGroup("Miscellaneous"); Settings::values.log_filter = qt_config->value("log_filter", "*:Info").toString().toStdString(); qt_config->endGroup(); @@ -79,7 +82,6 @@ void Config::SaveValues() { qt_config->endGroup(); qt_config->beginGroup("Core"); - qt_config->setValue("cpu_core", Settings::values.cpu_core); qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate); qt_config->setValue("frame_skip", Settings::values.frame_skip); qt_config->endGroup(); @@ -88,6 +90,10 @@ void Config::SaveValues() { qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); qt_config->endGroup(); + qt_config->beginGroup("System Region"); + qt_config->setValue("region_value", Settings::values.region_value); + qt_config->endGroup(); + qt_config->beginGroup("Miscellaneous"); qt_config->setValue("log_filter", QString::fromStdString(Settings::values.log_filter)); qt_config->endGroup(); diff --git a/src/citra_qt/config/controller_config.cpp b/src/citra_qt/config/controller_config.cpp index 892995bb2..512879f1b 100644 --- a/src/citra_qt/config/controller_config.cpp +++ b/src/citra_qt/config/controller_config.cpp @@ -92,4 +92,4 @@ void GControllerConfigDialog::EnableChanges() } } -*/
\ No newline at end of file +*/ diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp index 025a5896b..9bb22ca2e 100644 --- a/src/citra_qt/debugger/callstack.cpp +++ b/src/citra_qt/debugger/callstack.cpp @@ -33,6 +33,8 @@ void CallstackWidget::OnDebugModeEntered() u32 sp = app_core->GetReg(13); //stack pointer u32 ret_addr, call_addr, func_addr; + Clear(); + int counter = 0; for (u32 addr = 0x10000000; addr >= sp; addr -= 4) { @@ -76,3 +78,12 @@ void CallstackWidget::OnDebugModeLeft() { } + +void CallstackWidget::Clear() +{ + for (int row = 0; row < callstack_model->rowCount(); row++) { + for (int column = 0; column < callstack_model->columnCount(); column++) { + callstack_model->setItem(row, column, new QStandardItem()); + } + } +} diff --git a/src/citra_qt/debugger/callstack.h b/src/citra_qt/debugger/callstack.h index fb390f5c3..1a9b6dc81 100644 --- a/src/citra_qt/debugger/callstack.h +++ b/src/citra_qt/debugger/callstack.h @@ -21,4 +21,7 @@ public slots: private: Ui::CallStack ui; QStandardItemModel* callstack_model; + + /// Clears the callstack widget while keeping the column widths the same + void Clear(); }; diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index c61ace925..54d21dc90 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp @@ -17,16 +17,9 @@ #include "core/arm/skyeye_common/armdefs.h" #include "core/arm/disassembler/arm_disasm.h" -DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractItemModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { -} - -QModelIndex DisassemblerModel::index(int row, int column, const QModelIndex& parent) const { - return createIndex(row, column); -} +DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { -QModelIndex DisassemblerModel::parent(const QModelIndex& child) const { - return QModelIndex(); } int DisassemblerModel::columnCount(const QModelIndex& parent) const { diff --git a/src/citra_qt/debugger/disassembler.h b/src/citra_qt/debugger/disassembler.h index 0deccc240..5e19d7c51 100644 --- a/src/citra_qt/debugger/disassembler.h +++ b/src/citra_qt/debugger/disassembler.h @@ -2,8 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <QAbstractItemModel> +#pragma once + +#include <QAbstractListModel> #include <QDockWidget> + #include "ui_disassembler.h" #include "common/common.h" @@ -12,15 +15,13 @@ class QAction; class EmuThread; -class DisassemblerModel : public QAbstractItemModel +class DisassemblerModel : public QAbstractListModel { Q_OBJECT public: DisassemblerModel(QObject* parent); - QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; - QModelIndex parent(const QModelIndex& child) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; diff --git a/src/citra_qt/debugger/disassembler.ui b/src/citra_qt/debugger/disassembler.ui index bd0752aa4..5ca6dc5d2 100644 --- a/src/citra_qt/debugger/disassembler.ui +++ b/src/citra_qt/debugger/disassembler.ui @@ -13,63 +13,66 @@ <property name="windowTitle"> <string>Disassembly</string> </property> - <widget class="QWidget" name="dockWidgetContents"> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QPushButton" name="button_step"> - <property name="text"> - <string>Step</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="button_pause"> - <property name="text"> - <string>Pause</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="button_continue"> - <property name="text"> - <string>Continue</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="pushButton"> - <property name="text"> - <string>Step Into</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="button_breakpoint"> - <property name="text"> - <string>Set Breakpoint</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QTreeView" name="treeView"> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - <property name="indentation"> - <number>20</number> - </property> - <property name="rootIsDecorated"> - <bool>false</bool> - </property> - <attribute name="headerVisible"> - <bool>false</bool> - </attribute> - </widget> - </item> + <widget class="QWidget" name="dockWidgetContents"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="button_step"> + <property name="text"> + <string>Step</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="button_pause"> + <property name="text"> + <string>Pause</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="button_continue"> + <property name="text"> + <string>Continue</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton"> + <property name="text"> + <string>Step Into</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="button_breakpoint"> + <property name="text"> + <string>Set Breakpoint</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QTreeView" name="treeView"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="indentation"> + <number>20</number> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="uniformRowHeights"> + <bool>true</bool> + </property> + <attribute name="headerVisible"> + <bool>false</bool> + </attribute> + </widget> + </item> </layout> </widget> </widget> diff --git a/src/citra_qt/debugger/graphics_breakpoint_observer.cpp b/src/citra_qt/debugger/graphics_breakpoint_observer.cpp new file mode 100644 index 000000000..10ac1ebad --- /dev/null +++ b/src/citra_qt/debugger/graphics_breakpoint_observer.cpp @@ -0,0 +1,32 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <QMetaType> + +#include "graphics_breakpoint_observer.h" + +BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context, + const QString& title, QWidget* parent) + : QDockWidget(title, parent), BreakPointObserver(debug_context) +{ + qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event"); + + connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed())); + + // NOTE: This signal is emitted from a non-GUI thread, but connect() takes + // care of delaying its handling to the GUI thread. + connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)), + this, SLOT(OnBreakPointHit(Pica::DebugContext::Event,void*)), + Qt::BlockingQueuedConnection); +} + +void BreakPointObserverDock::OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) +{ + emit BreakPointHit(event, data); +} + +void BreakPointObserverDock::OnPicaResume() +{ + emit Resumed(); +} diff --git a/src/citra_qt/debugger/graphics_breakpoint_observer.h b/src/citra_qt/debugger/graphics_breakpoint_observer.h new file mode 100644 index 000000000..f0d3361f8 --- /dev/null +++ b/src/citra_qt/debugger/graphics_breakpoint_observer.h @@ -0,0 +1,33 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <QDockWidget> + +#include "video_core/debug_utils/debug_utils.h" + +/** + * Utility class which forwards calls to OnPicaBreakPointHit and OnPicaResume to public slots. + * This is because the Pica breakpoint callbacks are called from a non-GUI thread, while + * the widget usually wants to perform reactions in the GUI thread. + */ +class BreakPointObserverDock : public QDockWidget, private Pica::DebugContext::BreakPointObserver { + Q_OBJECT + +public: + BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context, const QString& title, + QWidget* parent = nullptr); + + void OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) override; + void OnPicaResume() override; + +private slots: + virtual void OnBreakPointHit(Pica::DebugContext::Event event, void* data) = 0; + virtual void OnResumed() = 0; + +signals: + void Resumed(); + void BreakPointHit(Pica::DebugContext::Event event, void* data); +}; diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp index 262e2e770..92348be34 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.cpp +++ b/src/citra_qt/debugger/graphics_breakpoints.cpp @@ -47,7 +47,7 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const { Pica::DebugContext::Event::VertexLoaded, tr("Vertex loaded") } }; - _dbg_assert_(Debug_GPU, map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents)); + DEBUG_ASSERT(map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents)); return (map.find(event) != map.end()) ? map.at(event) : QString(); } diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 4a6159fdf..bd420f24a 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -76,6 +76,8 @@ TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo format_choice->addItem(tr("IA4")); format_choice->addItem(tr("UNK10")); format_choice->addItem(tr("A4")); + format_choice->addItem(tr("ETC1")); + format_choice->addItem(tr("ETC1A4")); format_choice->setCurrentIndex(static_cast<int>(info.format)); connect(format_choice, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFormatChanged(int))); diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index a9423d6c7..1ba60021f 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -6,7 +6,6 @@ #include <QComboBox> #include <QDebug> #include <QLabel> -#include <QMetaType> #include <QPushButton> #include <QSpinBox> @@ -17,32 +16,6 @@ #include "util/spinbox.h" -BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context, - const QString& title, QWidget* parent) - : QDockWidget(title, parent), BreakPointObserver(debug_context) -{ - qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event"); - - connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed())); - - // NOTE: This signal is emitted from a non-GUI thread, but connect() takes - // care of delaying its handling to the GUI thread. - connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)), - this, SLOT(OnBreakPointHit(Pica::DebugContext::Event,void*)), - Qt::BlockingQueuedConnection); -} - -void BreakPointObserverDock::OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) -{ - emit BreakPointHit(event, data); -} - -void BreakPointObserverDock::OnPicaResume() -{ - emit Resumed(); -} - - GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent) : BreakPointObserverDock(debug_context, tr("Pica Framebuffer"), parent), @@ -170,8 +143,8 @@ void GraphicsFramebufferWidget::OnFramebufferWidthChanged(int new_value) void GraphicsFramebufferWidget::OnFramebufferHeightChanged(int new_value) { - if (framebuffer_height != new_value) { - framebuffer_height = new_value; + if (framebuffer_height != static_cast<unsigned>(new_value)) { + framebuffer_height = static_cast<unsigned>(new_value); framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom)); emit Update(); diff --git a/src/citra_qt/debugger/graphics_framebuffer.h b/src/citra_qt/debugger/graphics_framebuffer.h index 56215761e..c6e293bc9 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.h +++ b/src/citra_qt/debugger/graphics_framebuffer.h @@ -6,7 +6,7 @@ #include <QDockWidget> -#include "video_core/debug_utils/debug_utils.h" +#include "graphics_breakpoint_observer.h" class QComboBox; class QLabel; @@ -14,28 +14,6 @@ class QSpinBox; class CSpinBox; -// Utility class which forwards calls to OnPicaBreakPointHit and OnPicaResume to public slots. -// This is because the Pica breakpoint callbacks are called from a non-GUI thread, while -// the widget usually wants to perform reactions in the GUI thread. -class BreakPointObserverDock : public QDockWidget, Pica::DebugContext::BreakPointObserver { - Q_OBJECT - -public: - BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context, const QString& title, - QWidget* parent = nullptr); - - void OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) override; - void OnPicaResume() override; - -private slots: - virtual void OnBreakPointHit(Pica::DebugContext::Event event, void* data) = 0; - virtual void OnResumed() = 0; - -signals: - void Resumed(); - void BreakPointHit(Pica::DebugContext::Event event, void* data); -}; - class GraphicsFramebufferWidget : public BreakPointObserverDock { Q_OBJECT diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp new file mode 100644 index 000000000..06eaf0bf0 --- /dev/null +++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp @@ -0,0 +1,298 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <iomanip> +#include <sstream> + +#include <QBoxLayout> +#include <QTreeView> + +#include "video_core/vertex_shader.h" + +#include "graphics_vertex_shader.h" + +using nihstro::Instruction; +using nihstro::SourceRegister; +using nihstro::SwizzlePattern; + +GraphicsVertexShaderModel::GraphicsVertexShaderModel(QObject* parent): QAbstractItemModel(parent) { + +} + +QModelIndex GraphicsVertexShaderModel::index(int row, int column, const QModelIndex& parent) const { + return createIndex(row, column); +} + +QModelIndex GraphicsVertexShaderModel::parent(const QModelIndex& child) const { + return QModelIndex(); +} + +int GraphicsVertexShaderModel::columnCount(const QModelIndex& parent) const { + return 3; +} + +int GraphicsVertexShaderModel::rowCount(const QModelIndex& parent) const { + return info.code.size(); +} + +QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, int role) const { + switch(role) { + case Qt::DisplayRole: + { + if (section == 0) { + return tr("Offset"); + } else if (section == 1) { + return tr("Raw"); + } else if (section == 2) { + return tr("Disassembly"); + } + + break; + } + } + + return QVariant(); +} + +QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) const { + switch (role) { + case Qt::DisplayRole: + { + switch (index.column()) { + case 0: + if (info.HasLabel(index.row())) + return QString::fromStdString(info.GetLabel(index.row())); + + return QString("%1").arg(4*index.row(), 4, 16, QLatin1Char('0')); + + case 1: + return QString("%1").arg(info.code[index.row()].hex, 8, 16, QLatin1Char('0')); + + case 2: + { + std::stringstream output; + output.flags(std::ios::hex); + + Instruction instr = info.code[index.row()]; + const SwizzlePattern& swizzle = info.swizzle_info[instr.common.operand_desc_id].pattern; + + // longest known instruction name: "setemit " + output << std::setw(8) << std::left << instr.opcode.GetInfo().name; + + // e.g. "-c92.xyzw" + static auto print_input = [](std::stringstream& output, const SourceRegister& input, + bool negate, const std::string& swizzle_mask) { + output << std::setw(4) << std::right << (negate ? "-" : "") + input.GetName(); + output << "." << swizzle_mask; + }; + + // e.g. "-c92[a0.x].xyzw" + static auto print_input_indexed = [](std::stringstream& output, const SourceRegister& input, + bool negate, const std::string& swizzle_mask, + const std::string& address_register_name) { + std::string relative_address; + if (!address_register_name.empty()) + relative_address = "[" + address_register_name + "]"; + + output << std::setw(10) << std::right << (negate ? "-" : "") + input.GetName() + relative_address; + output << "." << swizzle_mask; + }; + + // Use print_input or print_input_indexed depending on whether relative addressing is used or not. + static auto print_input_indexed_compact = [](std::stringstream& output, const SourceRegister& input, + bool negate, const std::string& swizzle_mask, + const std::string& address_register_name) { + if (address_register_name.empty()) + print_input(output, input, negate, swizzle_mask); + else + print_input_indexed(output, input, negate, swizzle_mask, address_register_name); + }; + + switch (instr.opcode.GetInfo().type) { + case Instruction::OpCodeType::Trivial: + // Nothing to do here + break; + + case Instruction::OpCodeType::Arithmetic: + { + // Use custom code for special instructions + switch (instr.opcode.EffectiveOpCode()) { + case Instruction::OpCode::CMP: + { + // NOTE: CMP always writes both cc components, so we do not consider the dest mask here. + output << std::setw(4) << std::right << "cc."; + output << "xy "; + + SourceRegister src1 = instr.common.GetSrc1(false); + SourceRegister src2 = instr.common.GetSrc2(false); + + print_input_indexed_compact(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(0,1), instr.common.AddressRegisterName()); + output << " " << instr.common.compare_op.ToString(instr.common.compare_op.x) << " "; + print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(false).substr(0,1)); + + output << ", "; + + print_input_indexed_compact(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false).substr(1,1), instr.common.AddressRegisterName()); + output << " " << instr.common.compare_op.ToString(instr.common.compare_op.y) << " "; + print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(false).substr(1,1)); + + break; + } + + default: + { + bool src_is_inverted = 0 != (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::SrcInversed); + + if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::Dest) { + // e.g. "r12.xy__" + output << std::setw(4) << std::right << instr.common.dest.GetName() + "."; + output << swizzle.DestMaskToString(); + } else if (instr.opcode.GetInfo().subtype == Instruction::OpCodeInfo::MOVA) { + output << std::setw(4) << std::right << "a0."; + output << swizzle.DestMaskToString(); + } else { + output << " "; + } + output << " "; + + if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::Src1) { + SourceRegister src1 = instr.common.GetSrc1(src_is_inverted); + print_input_indexed(output, src1, swizzle.negate_src1, swizzle.SelectorToString(false), instr.common.AddressRegisterName()); + } else { + output << " "; + } + + // TODO: In some cases, the Address Register is used as an index for SRC2 instead of SRC1 + if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::Src2) { + SourceRegister src2 = instr.common.GetSrc2(src_is_inverted); + print_input(output, src2, swizzle.negate_src2, swizzle.SelectorToString(false)); + } + break; + } + } + + break; + } + + case Instruction::OpCodeType::Conditional: + { + switch (instr.opcode.EffectiveOpCode()) { + case Instruction::OpCode::LOOP: + output << "(unknown instruction format)"; + break; + + default: + output << "if "; + + if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::HasCondition) { + const char* ops[] = { + " || ", " && ", "", "" + }; + if (instr.flow_control.op != instr.flow_control.JustY) + output << ((!instr.flow_control.refx) ? "!" : " ") << "cc.x"; + + output << ops[instr.flow_control.op]; + + if (instr.flow_control.op != instr.flow_control.JustX) + output << ((!instr.flow_control.refy) ? "!" : " ") << "cc.y"; + + output << " "; + } else if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::HasUniformIndex) { + output << "b" << instr.flow_control.bool_uniform_id << " "; + } + + u32 target_addr = instr.flow_control.dest_offset; + u32 target_addr_else = instr.flow_control.dest_offset; + + if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::HasAlternative) { + output << "else jump to 0x" << std::setw(4) << std::right << std::setfill('0') << 4 * instr.flow_control.dest_offset << " "; + } else if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::HasExplicitDest) { + output << "jump to 0x" << std::setw(4) << std::right << std::setfill('0') << 4 * instr.flow_control.dest_offset << " "; + } else { + // TODO: Handle other cases + } + + if (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::HasFinishPoint) { + output << "(return on " << std::setw(4) << std::right << std::setfill('0') + << 4 * instr.flow_control.dest_offset + 4 * instr.flow_control.num_instructions << ")"; + } + + break; + } + break; + } + + default: + output << "(unknown instruction format)"; + break; + } + + return QString::fromLatin1(output.str().c_str()); + } + + default: + break; + } + } + + case Qt::FontRole: + return QFont("monospace"); + + default: + break; + } + + return QVariant(); +} + +void GraphicsVertexShaderModel::OnUpdate() +{ + beginResetModel(); + + info.Clear(); + + for (auto instr : Pica::VertexShader::GetShaderBinary()) + info.code.push_back({instr}); + + for (auto pattern : Pica::VertexShader::GetSwizzlePatterns()) + info.swizzle_info.push_back({pattern}); + + info.labels.insert({Pica::registers.vs_main_offset, "main"}); + + endResetModel(); +} + + +GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::DebugContext > debug_context, + QWidget* parent) + : BreakPointObserverDock(debug_context, "Pica Vertex Shader", parent) { + setObjectName("PicaVertexShader"); + + auto binary_model = new GraphicsVertexShaderModel(this); + auto binary_list = new QTreeView; + binary_list->setModel(binary_model); + binary_list->setRootIsDecorated(false); + binary_list->setAlternatingRowColors(true); + + connect(this, SIGNAL(Update()), binary_model, SLOT(OnUpdate())); + + auto main_widget = new QWidget; + auto main_layout = new QVBoxLayout; + { + auto sub_layout = new QHBoxLayout; + sub_layout->addWidget(binary_list); + main_layout->addLayout(sub_layout); + } + main_widget->setLayout(main_layout); + setWidget(main_widget); +} + +void GraphicsVertexShaderWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) { + emit Update(); + widget()->setEnabled(true); +} + +void GraphicsVertexShaderWidget::OnResumed() { + widget()->setEnabled(false); +} diff --git a/src/citra_qt/debugger/graphics_vertex_shader.h b/src/citra_qt/debugger/graphics_vertex_shader.h new file mode 100644 index 000000000..38339dc05 --- /dev/null +++ b/src/citra_qt/debugger/graphics_vertex_shader.h @@ -0,0 +1,51 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <QAbstractListModel> + +#include "graphics_breakpoint_observer.h" + +#include "nihstro/parser_shbin.h" + +class GraphicsVertexShaderModel : public QAbstractItemModel { + Q_OBJECT + +public: + GraphicsVertexShaderModel(QObject* parent); + + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& child) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + +public slots: + void OnUpdate(); + +private: + nihstro::ShaderInfo info; +}; + +class GraphicsVertexShaderWidget : public BreakPointObserverDock { + Q_OBJECT + + using Event = Pica::DebugContext::Event; + +public: + GraphicsVertexShaderWidget(std::shared_ptr<Pica::DebugContext> debug_context, + QWidget* parent = nullptr); + +private slots: + void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override; + void OnResumed() override; + +signals: + void Update(); + +private: + +}; diff --git a/src/citra_qt/debugger/ramview.cpp b/src/citra_qt/debugger/ramview.cpp index 2b199bad1..88570f2cd 100644 --- a/src/citra_qt/debugger/ramview.cpp +++ b/src/citra_qt/debugger/ramview.cpp @@ -14,4 +14,4 @@ void GRamView::OnCPUStepped() { // TODO: QHexEdit doesn't show vertical scroll bars for > 10MB data streams... //setData(QByteArray((const char*)Mem_RAM,sizeof(Mem_RAM)/8)); -}
\ No newline at end of file +} diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index ece593e5d..881c7d337 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -34,6 +34,7 @@ #include "debugger/graphics_breakpoints.h" #include "debugger/graphics_cmdlists.h" #include "debugger/graphics_framebuffer.h" +#include "debugger/graphics_vertex_shader.h" #include "core/settings.h" #include "core/system.h" @@ -84,6 +85,10 @@ GMainWindow::GMainWindow() addDockWidget(Qt::RightDockWidgetArea, graphicsFramebufferWidget); graphicsFramebufferWidget->hide(); + auto graphicsVertexShaderWidget = new GraphicsVertexShaderWidget(Pica::g_debug_context, this); + addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget); + graphicsVertexShaderWidget->hide(); + QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); debug_menu->addAction(disasmWidget->toggleViewAction()); debug_menu->addAction(registersWidget->toggleViewAction()); @@ -92,6 +97,7 @@ GMainWindow::GMainWindow() debug_menu->addAction(graphicsCommandsWidget->toggleViewAction()); debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction()); debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction()); + debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction()); // Set default UI state // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half @@ -114,6 +120,9 @@ GMainWindow::GMainWindow() ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", true).toBool()); ToggleWindowMode(); + ui.actionDisplay_widget_title_bars->setChecked(settings.value("displayTitleBars", true).toBool()); + OnDisplayTitleBars(ui.actionDisplay_widget_title_bars->isChecked()); + // Setup connections connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile())); connect(ui.action_Load_Symbol_Map, SIGNAL(triggered()), this, SLOT(OnMenuLoadSymbolMap())); @@ -160,6 +169,27 @@ GMainWindow::~GMainWindow() Pica::g_debug_context.reset(); } +void GMainWindow::OnDisplayTitleBars(bool show) +{ + QList<QDockWidget*> widgets = findChildren<QDockWidget*>(); + + if (show) { + for (QDockWidget* widget: widgets) { + QWidget* old = widget->titleBarWidget(); + widget->setTitleBarWidget(nullptr); + if (old != nullptr) + delete old; + } + } else { + for (QDockWidget* widget: widgets) { + QWidget* old = widget->titleBarWidget(); + widget->setTitleBarWidget(new QWidget()); + if (old != nullptr) + delete old; + } + } +} + void GMainWindow::BootGame(std::string filename) { LOG_INFO(Frontend, "Citra starting...\n"); @@ -263,6 +293,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) settings.setValue("state", saveState()); settings.setValue("geometryRenderWindow", render_window->saveGeometry()); settings.setValue("singleWindowMode", ui.action_Single_Window_Mode->isChecked()); + settings.setValue("displayTitleBars", ui.actionDisplay_widget_title_bars->isChecked()); settings.setValue("firstStart", false); SaveHotkeys(settings); diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 72df17c50..dd53489dd 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -46,6 +46,7 @@ private slots: void OnMenuLoadSymbolMap(); void OnOpenHotkeysDialog(); void OnConfigure(); + void OnDisplayTitleBars(bool); void ToggleWindowMode(); private: diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index d06c207a0..a3752ac1e 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -32,7 +32,7 @@ <x>0</x> <y>0</y> <width>1081</width> - <height>20</height> + <height>21</height> </rect> </property> <widget class="QMenu" name="menu_File"> @@ -59,6 +59,7 @@ <string>&View</string> </property> <addaction name="action_Single_Window_Mode"/> + <addaction name="actionDisplay_widget_title_bars"/> <addaction name="action_Hotkeys"/> </widget> <widget class="QMenu" name="menu_Help"> @@ -73,17 +74,17 @@ <addaction name="menu_Help"/> </widget> <widget class="QStatusBar" name="statusbar"/> - <action name="action_Load_File"> - <property name="text"> - <string>Load File...</string> - </property> - </action> - <action name="action_Load_Symbol_Map"> - <property name="text"> - <string>Load Symbol Map...</string> - </property> - </action> - <action name="action_Exit"> + <action name="action_Load_File"> + <property name="text"> + <string>Load File...</string> + </property> + </action> + <action name="action_Load_Symbol_Map"> + <property name="text"> + <string>Load Symbol Map...</string> + </property> + </action> + <action name="action_Exit"> <property name="text"> <string>E&xit</string> </property> @@ -101,28 +102,28 @@ <string>&Pause</string> </property> </action> - <action name="action_Stop"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>&Stop</string> - </property> - </action> - <action name="action_About"> - <property name="text"> - <string>About Citra</string> - </property> - </action> - <action name="action_Single_Window_Mode"> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="text"> - <string>Single Window Mode</string> - </property> - </action> - <action name="action_Hotkeys"> + <action name="action_Stop"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>&Stop</string> + </property> + </action> + <action name="action_About"> + <property name="text"> + <string>About Citra</string> + </property> + </action> + <action name="action_Single_Window_Mode"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Single Window Mode</string> + </property> + </action> + <action name="action_Hotkeys"> <property name="text"> <string>Configure &Hotkeys ...</string> </property> @@ -132,6 +133,14 @@ <string>Configure ...</string> </property> </action> + <action name="actionDisplay_widget_title_bars"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Display Dock Widget Headers</string> + </property> + </action> </widget> <resources/> <connections> @@ -167,8 +176,25 @@ </hint> </hints> </connection> + <connection> + <sender>actionDisplay_widget_title_bars</sender> + <signal>triggered(bool)</signal> + <receiver>MainWindow</receiver> + <slot>OnDisplayTitleBars(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>540</x> + <y>364</y> + </hint> + </hints> + </connection> </connections> <slots> <slot>OnConfigure()</slot> + <slot>OnDisplayTitleBars(bool)</slot> </slots> </ui> diff --git a/src/citra_qt/util/spinbox.cpp b/src/citra_qt/util/spinbox.cpp index 54f628e4c..2e2076a27 100644 --- a/src/citra_qt/util/spinbox.cpp +++ b/src/citra_qt/util/spinbox.cpp @@ -32,11 +32,10 @@ #include <QLineEdit> #include <QRegExpValidator> -#include "common/log.h" - +#include "common/assert.h" #include "spinbox.h" -CSpinBox::CSpinBox(QWidget* parent) : QAbstractSpinBox(parent), base(10), min_value(-100), max_value(100), value(0), num_digits(0) +CSpinBox::CSpinBox(QWidget* parent) : QAbstractSpinBox(parent), min_value(-100), max_value(100), value(0), base(10), num_digits(0) { // TODO: Might be nice to not immediately call the slot. // Think of an address that is being replaced by a different one, in which case a lot @@ -244,7 +243,7 @@ QValidator::State CSpinBox::validate(QString& input, int& pos) const if (strpos >= input.length() - HasSign() - suffix.length()) return QValidator::Intermediate; - _dbg_assert_(Frontend, base <= 10 || base == 16); + DEBUG_ASSERT(base <= 10 || base == 16); QString regexp; // Demand sign character for negative ranges |
