From 06c9712bc77d800877bb38d1a879536761d358c0 Mon Sep 17 00:00:00 2001 From: archshift Date: Sat, 15 Nov 2014 11:56:18 -0800 Subject: Merge Config::ReadXYZs --- src/citra_qt/config.cpp | 52 ++++++++++++++++--------------------------------- src/citra_qt/config.h | 11 ++--------- 2 files changed, 19 insertions(+), 44 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 09fce4d6f..3209e5900 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -21,7 +21,7 @@ Config::Config() { Reload(); } -void Config::ReadControls() { +void Config::ReadValues() { qt_config->beginGroup("Controls"); Settings::values.pad_a_key = qt_config->value("pad_a", Qt::Key_A).toInt(); Settings::values.pad_b_key = qt_config->value("pad_b", Qt::Key_S).toInt(); @@ -41,9 +41,22 @@ void Config::ReadControls() { Settings::values.pad_sleft_key = qt_config->value("pad_sleft", Qt::Key_Left).toInt(); Settings::values.pad_sright_key = qt_config->value("pad_sright", Qt::Key_Right).toInt(); 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", 60).toInt(); + qt_config->endGroup(); + + qt_config->beginGroup("Data Storage"); + Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool(); + qt_config->endGroup(); + + qt_config->beginGroup("Miscellaneous"); + Settings::values.enable_log = qt_config->value("enable_log", true).toBool(); + qt_config->endGroup(); } -void Config::SaveControls() { +void Config::SaveValues() { qt_config->beginGroup("Controls"); qt_config->setValue("pad_a", Settings::values.pad_a_key); qt_config->setValue("pad_b", Settings::values.pad_b_key); @@ -63,58 +76,27 @@ void Config::SaveControls() { qt_config->setValue("pad_sleft", Settings::values.pad_sleft_key); qt_config->setValue("pad_sright", Settings::values.pad_sright_key); qt_config->endGroup(); -} - -void Config::ReadCore() { - 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", 60).toInt(); - qt_config->endGroup(); -} -void Config::SaveCore() { 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->endGroup(); -} - -void Config::ReadData() { - qt_config->beginGroup("Data Storage"); - Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool(); - qt_config->endGroup(); -} -void Config::SaveData() { qt_config->beginGroup("Data Storage"); qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); qt_config->endGroup(); -} - -void Config::ReadMiscellaneous() { - qt_config->beginGroup("Miscellaneous"); - Settings::values.enable_log = qt_config->value("enable_log", true).toBool(); - qt_config->endGroup(); -} -void Config::SaveMiscellaneous() { qt_config->beginGroup("Miscellaneous"); qt_config->setValue("enable_log", Settings::values.enable_log); qt_config->endGroup(); } void Config::Reload() { - ReadControls(); - ReadCore(); - ReadData(); - ReadMiscellaneous(); + ReadValues(); } void Config::Save() { - SaveControls(); - SaveCore(); - SaveData(); - SaveMiscellaneous(); + SaveValues(); } Config::~Config() { diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h index 8c6568cb2..4c95d0cb9 100644 --- a/src/citra_qt/config.h +++ b/src/citra_qt/config.h @@ -12,15 +12,8 @@ class Config { QSettings* qt_config; std::string qt_config_loc; - void ReadControls(); - void SaveControls(); - void ReadCore(); - void SaveCore(); - void ReadData(); - void SaveData(); - - void ReadMiscellaneous(); - void SaveMiscellaneous(); + void ReadValues(); + void SaveValues(); public: Config(); ~Config(); -- cgit v1.2.3 From 8a624239703c046d89ebeaf3ea13c87af75b550f Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Wed, 3 Dec 2014 12:57:57 -0600 Subject: Change NULLs to nullptrs. --- src/citra_qt/bootmanager.cpp | 2 +- src/citra_qt/hotkeys.cpp | 4 ++-- src/citra_qt/main.cpp | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 9bf079919..9a29f974b 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -230,7 +230,7 @@ QByteArray GRenderWindow::saveGeometry() { // If we are a top-level widget, store the current geometry // otherwise, store the last backup - if (parent() == NULL) + if (parent() == nullptr) return ((QGLWidget*)this)->saveGeometry(); else return geometry; diff --git a/src/citra_qt/hotkeys.cpp b/src/citra_qt/hotkeys.cpp index bbaa4a8dc..5d0b52e4f 100644 --- a/src/citra_qt/hotkeys.cpp +++ b/src/citra_qt/hotkeys.cpp @@ -5,7 +5,7 @@ struct Hotkey { - Hotkey() : shortcut(NULL), context(Qt::WindowShortcut) {} + Hotkey() : shortcut(nullptr), context(Qt::WindowShortcut) {} QKeySequence keyseq; QShortcut* shortcut; @@ -81,7 +81,7 @@ QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widge Hotkey& hk = hotkey_groups[group][action]; if (!hk.shortcut) - hk.shortcut = new QShortcut(hk.keyseq, widget, NULL, NULL, hk.context); + hk.shortcut = new QShortcut(hk.keyseq, widget, nullptr, nullptr, hk.context); return hk.shortcut; } diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index d5554d917..430a4ece4 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -131,7 +131,7 @@ GMainWindow::GMainWindow() GMainWindow::~GMainWindow() { // will get automatically deleted otherwise - if (render_window->parent() == NULL) + if (render_window->parent() == nullptr) delete render_window; } @@ -213,14 +213,14 @@ void GMainWindow::OnOpenHotkeysDialog() void GMainWindow::ToggleWindowMode() { bool enable = ui.action_Popout_Window_Mode->isChecked(); - if (enable && render_window->parent() != NULL) + if (enable && render_window->parent() != nullptr) { ui.horizontalLayout->removeWidget(render_window); - render_window->setParent(NULL); + render_window->setParent(nullptr); render_window->setVisible(true); render_window->RestoreGeometry(); } - else if (!enable && render_window->parent() == NULL) + else if (!enable && render_window->parent() == nullptr) { render_window->BackupGeometry(); ui.horizontalLayout->addWidget(render_window); -- cgit v1.2.3 From 1aa969741dabecd3516ca79b2e7d3106cf9d3d9a Mon Sep 17 00:00:00 2001 From: ichfly Date: Sun, 7 Dec 2014 21:47:06 +0100 Subject: Loader: Add 3DSX support --- src/citra_qt/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 430a4ece4..0701decef 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -164,7 +164,7 @@ void GMainWindow::BootGame(std::string filename) void GMainWindow::OnMenuLoadFile() { - QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS executable (*.elf *.axf *.bin *.cci *.cxi)")); + QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS executable (*.3dsx *.elf *.axf *.bin *.cci *.cxi)")); if (filename.size()) BootGame(filename.toLatin1().data()); } -- cgit v1.2.3 From bf6b23f4a0ea01af2c5e87b0fcabd1aea4a51fd6 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 1 Nov 2014 15:36:59 +0100 Subject: citra-qt: Add a utility spinbox class called CSpinBox. This class has a few advantages over the regular QSpinBox: - QSpinBox stores its as signed 32 bit integers, which for instance is unsuitable for representing memory addresses. CSpinBox uses 64 bit integers instead. - QSpinBox does not provide an easy way to handle number input from bases different than 10. - QSpinBox is quite inflexible in general and almost any sort of customization requires reimplementing it anyway. --- src/citra_qt/CMakeLists.txt | 2 + src/citra_qt/util/spinbox.cpp | 303 ++++++++++++++++++++++++++++++++++++++++++ src/citra_qt/util/spinbox.hxx | 88 ++++++++++++ 3 files changed, 393 insertions(+) create mode 100644 src/citra_qt/util/spinbox.cpp create mode 100644 src/citra_qt/util/spinbox.hxx (limited to 'src/citra_qt') diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 98a48a69a..7bf44197d 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -11,6 +11,7 @@ set(SRCS debugger/graphics_cmdlists.cpp debugger/ramview.cpp debugger/registers.cpp + util/spinbox.cpp bootmanager.cpp hotkeys.cpp main.cpp @@ -26,6 +27,7 @@ set(HEADERS debugger/graphics_cmdlists.hxx debugger/ramview.hxx debugger/registers.hxx + util/spinbox.hxx bootmanager.hxx hotkeys.hxx main.hxx diff --git a/src/citra_qt/util/spinbox.cpp b/src/citra_qt/util/spinbox.cpp new file mode 100644 index 000000000..80dc67d7d --- /dev/null +++ b/src/citra_qt/util/spinbox.cpp @@ -0,0 +1,303 @@ +// Licensed under GPLv2+ +// Refer to the license.txt file included. + + +// Copyright 2014 Tony Wasserka +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the owner nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include + +#include "common/log.h" + +#include "spinbox.hxx" + +CSpinBox::CSpinBox(QWidget* parent) : QAbstractSpinBox(parent), base(10), min_value(-100), max_value(100), value(0), 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 + // invalid intermediate addresses would be read from during editing. + connect(lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(OnEditingFinished())); + + UpdateText(); +} + +void CSpinBox::SetValue(qint64 val) +{ + auto old_value = value; + value = std::max(std::min(val, max_value), min_value); + + if (old_value != value) { + UpdateText(); + emit ValueChanged(value); + } +} + +void CSpinBox::SetRange(qint64 min, qint64 max) +{ + min_value = min; + max_value = max; + + SetValue(value); + UpdateText(); +} + +void CSpinBox::stepBy(int steps) +{ + auto new_value = value; + // Scale number of steps by the currently selected digit + // TODO: Move this code elsewhere and enable it. + // TODO: Support for num_digits==0, too + // TODO: Support base!=16, too + // TODO: Make the cursor not jump back to the end of the line... + /*if (base == 16 && num_digits > 0) { + int digit = num_digits - (lineEdit()->cursorPosition() - prefix.length()) - 1; + digit = std::max(0, std::min(digit, num_digits - 1)); + steps <<= digit * 4; + }*/ + + // Increment "new_value" by "steps", and perform annoying overflow checks, too. + if (steps < 0 && new_value + steps > new_value) { + new_value = std::numeric_limits::min(); + } else if (steps > 0 && new_value + steps < new_value) { + new_value = std::numeric_limits::max(); + } else { + new_value += steps; + } + + SetValue(new_value); + UpdateText(); +} + +QAbstractSpinBox::StepEnabled CSpinBox::stepEnabled() const +{ + StepEnabled ret = StepNone; + + if (value > min_value) + ret |= StepDownEnabled; + + if (value < max_value) + ret |= StepUpEnabled; + + return ret; +} + +void CSpinBox::SetBase(int base) +{ + this->base = base; + + UpdateText(); +} + +void CSpinBox::SetNumDigits(int num_digits) +{ + this->num_digits = num_digits; + + UpdateText(); +} + +void CSpinBox::SetPrefix(const QString& prefix) +{ + this->prefix = prefix; + + UpdateText(); +} + +void CSpinBox::SetSuffix(const QString& suffix) +{ + this->suffix = suffix; + + UpdateText(); +} + +static QString StringToInputMask(const QString& input) { + QString mask = input; + + // ... replace any special characters by their escaped counterparts ... + mask.replace("\\", "\\\\"); + mask.replace("A", "\\A"); + mask.replace("a", "\\a"); + mask.replace("N", "\\N"); + mask.replace("n", "\\n"); + mask.replace("X", "\\X"); + mask.replace("x", "\\x"); + mask.replace("9", "\\9"); + mask.replace("0", "\\0"); + mask.replace("D", "\\D"); + mask.replace("d", "\\d"); + mask.replace("#", "\\#"); + mask.replace("H", "\\H"); + mask.replace("h", "\\h"); + mask.replace("B", "\\B"); + mask.replace("b", "\\b"); + mask.replace(">", "\\>"); + mask.replace("<", "\\<"); + mask.replace("!", "\\!"); + + return mask; +} + +void CSpinBox::UpdateText() +{ + // If a fixed number of digits is used, we put the line edit in insertion mode by setting an + // input mask. + QString mask; + if (num_digits != 0) { + mask += StringToInputMask(prefix); + + // For base 10 and negative range, demand a single sign character + if (HasSign()) + mask += "X"; // identified as "-" or "+" in the validator + + // Uppercase digits greater than 9. + mask += ">"; + + // The greatest signed 64-bit number has 19 decimal digits. + // TODO: Could probably make this more generic with some logarithms. + // For reference, unsigned 64-bit can have up to 20 decimal digits. + int digits = (num_digits != 0) ? num_digits + : (base == 16) ? 16 + : (base == 10) ? 19 + : 0xFF; // fallback case... + + // Match num_digits digits + // Digits irrelevant to the chosen number base are filtered in the validator + mask += QString("H").repeated(std::max(num_digits, 1)); + + // Switch off case conversion + mask += "!"; + + mask += StringToInputMask(suffix); + } + lineEdit()->setInputMask(mask); + + // Set new text without changing the cursor position. This will cause the cursor to briefly + // appear at the end of the line and then to jump back to its original position. That's + // a bit ugly, but better than having setText() move the cursor permanently all the time. + int cursor_position = lineEdit()->cursorPosition(); + lineEdit()->setText(TextFromValue()); + lineEdit()->setCursorPosition(cursor_position); +} + +QString CSpinBox::TextFromValue() +{ + return prefix + + QString(HasSign() ? ((value < 0) ? "-" : "+") : "") + + QString("%1").arg(abs(value), num_digits, base, QLatin1Char('0')).toUpper() + + suffix; +} + +qint64 CSpinBox::ValueFromText() +{ + unsigned strpos = prefix.length(); + + QString num_string = text().mid(strpos, text().length() - strpos - suffix.length()); + return num_string.toLongLong(nullptr, base); +} + +bool CSpinBox::HasSign() const +{ + return base == 10 && min_value < 0; +} + +void CSpinBox::OnEditingFinished() +{ + // Only update for valid input + QString input = lineEdit()->text(); + int pos = 0; + if (QValidator::Acceptable == validate(input, pos)) + SetValue(ValueFromText()); +} + +QValidator::State CSpinBox::validate(QString& input, int& pos) const +{ + if (!prefix.isEmpty() && input.left(prefix.length()) != prefix) + return QValidator::Invalid; + + unsigned strpos = prefix.length(); + + // Empty "numbers" allowed as intermediate values + if (strpos >= input.length() - HasSign() - suffix.length()) + return QValidator::Intermediate; + + _dbg_assert_(GUI, base <= 10 || base == 16); + QString regexp; + + // Demand sign character for negative ranges + if (HasSign()) + regexp += "[+\\-]"; + + // Match digits corresponding to the chosen number base. + regexp += QString("[0-%1").arg(std::min(base, 9)); + if (base == 16) { + regexp += "a-fA-F"; + } + regexp += "]"; + + // Specify number of digits + if (num_digits > 0) { + regexp += QString("{%1}").arg(num_digits); + } else { + regexp += "+"; + } + + // Match string + QRegExp num_regexp(regexp); + int num_pos = strpos; + QString sub_input = input.mid(strpos, input.length() - strpos - suffix.length()); + + if (!num_regexp.exactMatch(sub_input) && num_regexp.matchedLength() == 0) + return QValidator::Invalid; + + sub_input = sub_input.left(num_regexp.matchedLength()); + bool ok; + qint64 val = sub_input.toLongLong(&ok, base); + + if (!ok) + return QValidator::Invalid; + + // Outside boundaries => don't accept + if (val < min_value || val > max_value) + return QValidator::Invalid; + + // Make sure we are actually at the end of this string... + strpos += num_regexp.matchedLength(); + + if (!suffix.isEmpty() && input.mid(strpos) != suffix) { + return QValidator::Invalid; + } else { + strpos += suffix.length(); + } + + if (strpos != input.length()) + return QValidator::Invalid; + + // At this point we can say for sure that the input is fine. Let's fix it up a bit though + input.replace(num_pos, sub_input.length(), sub_input.toUpper()); + + return QValidator::Acceptable; +} diff --git a/src/citra_qt/util/spinbox.hxx b/src/citra_qt/util/spinbox.hxx new file mode 100644 index 000000000..68f5b9894 --- /dev/null +++ b/src/citra_qt/util/spinbox.hxx @@ -0,0 +1,88 @@ +// Licensed under GPLv2+ +// Refer to the license.txt file included. + + +// Copyright 2014 Tony Wasserka +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the owner nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#pragma once + +#include +#include + +class QVariant; + +/** + * A custom spin box widget with enhanced functionality over Qt's QSpinBox + */ +class CSpinBox : public QAbstractSpinBox { + Q_OBJECT + +public: + CSpinBox(QWidget* parent = nullptr); + + void stepBy(int steps) override; + StepEnabled stepEnabled() const override; + + void SetValue(qint64 val); + + void SetRange(qint64 min, qint64 max); + + void SetBase(int base); + + void SetPrefix(const QString& prefix); + void SetSuffix(const QString& suffix); + + void SetNumDigits(int num_digits); + + QValidator::State validate(QString& input, int& pos) const override; + +signals: + void ValueChanged(qint64 val); + +private slots: + void OnEditingFinished(); + +private: + void UpdateText(); + + bool HasSign() const; + + QString TextFromValue(); + qint64 ValueFromText(); + + qint64 min_value, max_value; + + qint64 value; + + QString prefix, suffix; + + int base; + + int num_digits; +}; -- cgit v1.2.3 From 706f9c5574f74b018958477813495dd6e15bd00d Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sun, 26 Oct 2014 11:40:12 +0100 Subject: citra-qt: Polish the pica tracing widget. Changed start/stop button to reflect current tracing status. Properly labeled column headers. --- src/citra_qt/debugger/graphics_cmdlists.cpp | 22 +++++++++++++++++++++- src/citra_qt/debugger/graphics_cmdlists.hxx | 5 +++++ 2 files changed, 26 insertions(+), 1 deletion(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 71dd166cd..9e53a03d0 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -49,6 +49,24 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const return QVariant(); } +QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + switch(role) { + case Qt::DisplayRole: + { + if (section == 0) { + return tr("Command Name"); + } else if (section == 1) { + return tr("Data"); + } + + break; + } + } + + return QVariant(); +} + void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace) { beginResetModel(); @@ -70,7 +88,7 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi list_widget->setFont(QFont("monospace")); list_widget->setRootIsDecorated(false); - QPushButton* toggle_tracing = new QPushButton(tr("Start Tracing")); + toggle_tracing = new QPushButton(tr("Start Tracing")); connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), @@ -88,8 +106,10 @@ void GPUCommandListWidget::OnToggleTracing() { if (!Pica::DebugUtils::IsPicaTracing()) { Pica::DebugUtils::StartPicaTracing(); + toggle_tracing->setText(tr("Stop Tracing")); } else { pica_trace = Pica::DebugUtils::FinishPicaTracing(); emit TracingFinished(*pica_trace); + toggle_tracing->setText(tr("Start Tracing")); } } diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx index 1523e724f..31bd2546d 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.hxx +++ b/src/citra_qt/debugger/graphics_cmdlists.hxx @@ -10,6 +10,8 @@ #include "video_core/gpu_debugger.h" #include "video_core/debug_utils/debug_utils.h" +class QPushButton; + class GPUCommandListModel : public QAbstractListModel { Q_OBJECT @@ -20,6 +22,7 @@ public: 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 OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace); @@ -43,4 +46,6 @@ signals: private: std::unique_ptr pica_trace; + + QPushButton* toggle_tracing; }; -- cgit v1.2.3 From 2c71ec70527abd091d69f1fdd30aaf95d815214a Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 25 Oct 2014 18:02:26 +0200 Subject: Pica/DebugUtils: Add breakpoint functionality. --- src/citra_qt/bootmanager.cpp | 13 +++++++++++-- src/citra_qt/main.cpp | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 9a29f974b..b53206be6 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -14,6 +14,8 @@ #include "core/core.h" #include "core/settings.h" +#include "video_core/debug_utils/debug_utils.h" + #include "video_core/video_core.h" #include "citra_qt/version.h" @@ -65,14 +67,21 @@ void EmuThread::Stop() } stop_run = true; + // Release emu threads from any breakpoints, so that this doesn't hang forever. + Pica::g_debug_context->ClearBreakpoints(); + //core::g_state = core::SYS_DIE; - wait(500); + // TODO: Waiting here is just a bad workaround for retarded shutdown logic. + wait(1000); if (isRunning()) { WARN_LOG(MASTER_LOG, "EmuThread still running, terminating..."); quit(); - wait(1000); + + // TODO: Waiting 50 seconds can be necessary if the logging subsystem has a lot of spam + // queued... This should be fixed. + wait(50000); if (isRunning()) { WARN_LOG(MASTER_LOG, "EmuThread STILL running, something is wrong here..."); diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 0701decef..869826e61 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -36,6 +36,8 @@ GMainWindow::GMainWindow() { LogManager::Init(); + Pica::g_debug_context = Pica::DebugContext::Construct(); + Config config; if (!Settings::values.enable_log) @@ -133,6 +135,8 @@ GMainWindow::~GMainWindow() // will get automatically deleted otherwise if (render_window->parent() == nullptr) delete render_window; + + Pica::g_debug_context.reset(); } void GMainWindow::BootGame(std::string filename) -- cgit v1.2.3 From c63a495de6f4b4729cb3c24dc65ae019a39bbb0d Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 25 Oct 2014 20:28:24 +0200 Subject: Add GUI widget for controlling pica breakpoints. --- src/citra_qt/CMakeLists.txt | 2 + src/citra_qt/debugger/graphics_breakpoints.cpp | 253 +++++++++++++++++++++++++ src/citra_qt/debugger/graphics_breakpoints.hxx | 78 ++++++++ src/citra_qt/main.cpp | 6 + 4 files changed, 339 insertions(+) create mode 100644 src/citra_qt/debugger/graphics_breakpoints.cpp create mode 100644 src/citra_qt/debugger/graphics_breakpoints.hxx (limited to 'src/citra_qt') diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 7bf44197d..999724102 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -8,6 +8,7 @@ set(SRCS debugger/callstack.cpp debugger/disassembler.cpp debugger/graphics.cpp + debugger/graphics_breakpoints.cpp debugger/graphics_cmdlists.cpp debugger/ramview.cpp debugger/registers.cpp @@ -24,6 +25,7 @@ set(HEADERS debugger/callstack.hxx debugger/disassembler.hxx debugger/graphics.hxx + debugger/graphics_breakpoints.hxx debugger/graphics_cmdlists.hxx debugger/ramview.hxx debugger/registers.hxx diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp new file mode 100644 index 000000000..2f41d5f77 --- /dev/null +++ b/src/citra_qt/debugger/graphics_breakpoints.cpp @@ -0,0 +1,253 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include + +#include "graphics_breakpoints.hxx" + +BreakPointModel::BreakPointModel(std::shared_ptr debug_context, QObject* parent) + : QAbstractListModel(parent), context_weak(debug_context), + at_breakpoint(debug_context->at_breakpoint), + active_breakpoint(debug_context->active_breakpoint) +{ + +} + +int BreakPointModel::columnCount(const QModelIndex& parent) const +{ + return 2; +} + +int BreakPointModel::rowCount(const QModelIndex& parent) const +{ + return static_cast(Pica::DebugContext::Event::NumEvents); +} + +QVariant BreakPointModel::data(const QModelIndex& index, int role) const +{ + const auto event = static_cast(index.row()); + + switch (role) { + case Qt::DisplayRole: + { + if (index.column() == 0) { + std::map map; + map.insert({Pica::DebugContext::Event::CommandLoaded, tr("Pica command loaded")}); + map.insert({Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed")}); + map.insert({Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incomming primitive batch")}); + map.insert({Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch")}); + + _dbg_assert_(GPU, map.size() == static_cast(Pica::DebugContext::Event::NumEvents)); + + return map[event]; + } else if (index.column() == 1) { + return data(index, Role_IsEnabled).toBool() ? tr("Enabled") : tr("Disabled"); + } + + break; + } + + case Qt::BackgroundRole: + { + if (at_breakpoint && index.row() == static_cast(active_breakpoint)) { + return QBrush(QColor(0xE0, 0xE0, 0x10)); + } + break; + } + + case Role_IsEnabled: + { + auto context = context_weak.lock(); + return context && context->breakpoints[event].enabled; + } + + default: + break; + } + return QVariant(); +} + +QVariant BreakPointModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + switch(role) { + case Qt::DisplayRole: + { + if (section == 0) { + return tr("Event"); + } else if (section == 1) { + return tr("Status"); + } + + break; + } + } + + return QVariant(); +} + +bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role) +{ + const auto event = static_cast(index.row()); + + switch (role) { + case Role_IsEnabled: + { + auto context = context_weak.lock(); + if (!context) + return false; + + context->breakpoints[event].enabled = value.toBool(); + QModelIndex changed_index = createIndex(index.row(), 1); + emit dataChanged(changed_index, changed_index); + return true; + } + } + + return false; +} + + +void BreakPointModel::OnBreakPointHit(Pica::DebugContext::Event event) +{ + auto context = context_weak.lock(); + if (!context) + return; + + active_breakpoint = context->active_breakpoint; + at_breakpoint = context->at_breakpoint; + emit dataChanged(createIndex(static_cast(event), 0), + createIndex(static_cast(event), 1)); +} + +void BreakPointModel::OnResumed() +{ + auto context = context_weak.lock(); + if (!context) + return; + + at_breakpoint = context->at_breakpoint; + emit dataChanged(createIndex(static_cast(active_breakpoint), 0), + createIndex(static_cast(active_breakpoint), 1)); + active_breakpoint = context->active_breakpoint; +} + + +GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr debug_context, + QWidget* parent) + : QDockWidget(tr("Pica Breakpoints"), parent), + Pica::DebugContext::BreakPointObserver(debug_context) +{ + setObjectName("PicaBreakPointsWidget"); + + status_text = new QLabel(tr("Emulation running")); + resume_button = new QPushButton(tr("Resume")); + resume_button->setEnabled(false); + + breakpoint_model = new BreakPointModel(debug_context, this); + breakpoint_list = new QTreeView; + breakpoint_list->setModel(breakpoint_model); + + toggle_breakpoint_button = new QPushButton(tr("Enable")); + toggle_breakpoint_button->setEnabled(false); + + qRegisterMetaType("Pica::DebugContext::Event"); + + connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested())); + + connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)), + this, SLOT(OnBreakPointHit(Pica::DebugContext::Event,void*)), + Qt::BlockingQueuedConnection); + connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed())); + + connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)), + breakpoint_model, SLOT(OnBreakPointHit(Pica::DebugContext::Event)), + Qt::BlockingQueuedConnection); + connect(this, SIGNAL(Resumed()), breakpoint_model, SLOT(OnResumed())); + + connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&,const QModelIndex&)), + breakpoint_model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&))); + + connect(breakpoint_list->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(OnBreakpointSelectionChanged(QModelIndex))); + + connect(toggle_breakpoint_button, SIGNAL(clicked()), this, SLOT(OnToggleBreakpointEnabled())); + + QWidget* main_widget = new QWidget; + auto main_layout = new QVBoxLayout; + { + auto sub_layout = new QHBoxLayout; + sub_layout->addWidget(status_text); + sub_layout->addWidget(resume_button); + main_layout->addLayout(sub_layout); + } + main_layout->addWidget(breakpoint_list); + main_layout->addWidget(toggle_breakpoint_button); + main_widget->setLayout(main_layout); + + setWidget(main_widget); +} + +void GraphicsBreakPointsWidget::OnPicaBreakPointHit(Event event, void* data) +{ + // Process in GUI thread + emit BreakPointHit(event, data); +} + +void GraphicsBreakPointsWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) +{ + status_text->setText(tr("Emulation halted at breakpoint")); + resume_button->setEnabled(true); +} + +void GraphicsBreakPointsWidget::OnPicaResume() +{ + // Process in GUI thread + emit Resumed(); +} + +void GraphicsBreakPointsWidget::OnResumed() +{ + status_text->setText(tr("Emulation running")); + resume_button->setEnabled(false); +} + +void GraphicsBreakPointsWidget::OnResumeRequested() +{ + if (auto context = context_weak.lock()) + context->Resume(); +} + +void GraphicsBreakPointsWidget::OnBreakpointSelectionChanged(const QModelIndex& index) +{ + if (!index.isValid()) { + toggle_breakpoint_button->setEnabled(false); + return; + } + + toggle_breakpoint_button->setEnabled(true); + UpdateToggleBreakpointButton(index); +} + +void GraphicsBreakPointsWidget::OnToggleBreakpointEnabled() +{ + QModelIndex index = breakpoint_list->selectionModel()->currentIndex(); + bool new_state = !(breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool()); + + breakpoint_model->setData(index, new_state, + BreakPointModel::Role_IsEnabled); + UpdateToggleBreakpointButton(index); +} + +void GraphicsBreakPointsWidget::UpdateToggleBreakpointButton(const QModelIndex& index) +{ + if (true == breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool()) { + toggle_breakpoint_button->setText(tr("Disable")); + } else { + toggle_breakpoint_button->setText(tr("Enable")); + } +} diff --git a/src/citra_qt/debugger/graphics_breakpoints.hxx b/src/citra_qt/debugger/graphics_breakpoints.hxx new file mode 100644 index 000000000..edc41283e --- /dev/null +++ b/src/citra_qt/debugger/graphics_breakpoints.hxx @@ -0,0 +1,78 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +#include +#include + +#include "video_core/debug_utils/debug_utils.h" + +class QLabel; +class QPushButton; +class QTreeView; + +class BreakPointModel : public QAbstractListModel { + Q_OBJECT + +public: + enum { + Role_IsEnabled = Qt::UserRole, + }; + + BreakPointModel(std::shared_ptr context, QObject* parent); + + 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; + + bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); + +public slots: + void OnBreakPointHit(Pica::DebugContext::Event event); + void OnResumed(); + +private: + bool at_breakpoint; + Pica::DebugContext::Event active_breakpoint; + std::weak_ptr context_weak; +}; + +class GraphicsBreakPointsWidget : public QDockWidget, Pica::DebugContext::BreakPointObserver { + Q_OBJECT + + using Event = Pica::DebugContext::Event; + +public: + GraphicsBreakPointsWidget(std::shared_ptr debug_context, + QWidget* parent = nullptr); + + void OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) override; + void OnPicaResume() override; + +public slots: + void OnBreakPointHit(Pica::DebugContext::Event event, void* data); + void OnResumeRequested(); + void OnResumed(); + void OnBreakpointSelectionChanged(const QModelIndex&); + void OnToggleBreakpointEnabled(); + +signals: + void Resumed(); + void BreakPointHit(Pica::DebugContext::Event event, void* data); + void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); + +private: + void UpdateToggleBreakpointButton(const QModelIndex& index); + + QLabel* status_text; + QPushButton* resume_button; + QPushButton* toggle_breakpoint_button; + + BreakPointModel* breakpoint_model; + QTreeView* breakpoint_list; +}; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 869826e61..84afe59d8 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -20,6 +20,7 @@ #include "debugger/callstack.hxx" #include "debugger/ramview.hxx" #include "debugger/graphics.hxx" +#include "debugger/graphics_breakpoints.hxx" #include "debugger/graphics_cmdlists.hxx" #include "core/settings.h" @@ -69,12 +70,17 @@ GMainWindow::GMainWindow() addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget); graphicsCommandsWidget->hide(); + auto graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(Pica::g_debug_context, this); + addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget); + graphicsBreakpointsWidget->hide(); + QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); debug_menu->addAction(disasmWidget->toggleViewAction()); debug_menu->addAction(registersWidget->toggleViewAction()); debug_menu->addAction(callstackWidget->toggleViewAction()); debug_menu->addAction(graphicsWidget->toggleViewAction()); debug_menu->addAction(graphicsCommandsWidget->toggleViewAction()); + debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction()); // Set default UI state // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half -- cgit v1.2.3 From fd194d95b0f1522b970a2b77f9ea490fb8c3ef08 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sun, 24 Aug 2014 14:39:52 +0200 Subject: citra-qt: Add texture viewer to Pica command list. The texture viewer is enabled when selecting a write command to one of the texture config registers. --- src/citra_qt/debugger/graphics_cmdlists.cpp | 64 ++++++++++++++++++++++++++++- src/citra_qt/debugger/graphics_cmdlists.hxx | 8 ++++ 2 files changed, 71 insertions(+), 1 deletion(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 9e53a03d0..dcd0ced33 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 // Refer to the license.txt file included. +#include #include #include #include @@ -9,6 +10,33 @@ #include "graphics_cmdlists.hxx" +#include "video_core/pica.h" +#include "video_core/math.h" + +#include "video_core/debug_utils/debug_utils.h" + +class TextureInfoWidget : public QWidget { +public: + TextureInfoWidget(u8* src, const Pica::DebugUtils::TextureInfo& info, QWidget* parent = nullptr) : QWidget(parent) { + QImage decoded_image(info.width, info.height, QImage::Format_ARGB32); + for (int y = 0; y < info.height; ++y) { + for (int x = 0; x < info.width; ++x) { + Math::Vec4 color = Pica::DebugUtils::LookupTexture(src, x, y, info); + decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a())); + } + } + + QLabel* image_widget = new QLabel; + QPixmap image_pixmap = QPixmap::fromImage(decoded_image); + image_pixmap = image_pixmap.scaled(200, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation); + image_widget->setPixmap(image_pixmap); + + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget(image_widget); + setLayout(layout); + } +}; + GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) { @@ -44,6 +72,8 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const } return QVariant(content); + } else if (role == CommandIdRole) { + return QVariant::fromValue(cmd.cmd_id.Value()); } return QVariant(); @@ -76,27 +106,59 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& endResetModel(); } +void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) +{ + QWidget* new_info_widget; + +#define COMMAND_IN_RANGE(cmd_id, reg_name) (cmd_id >= PICA_REG_INDEX(reg_name) && cmd_id < PICA_REG_INDEX(reg_name) + sizeof(decltype(Pica::registers.reg_name)) / 4) + const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt(); + if (COMMAND_IN_RANGE(command_id, texture0)) { + u8* src = Memory::GetPointer(Pica::registers.texture0.GetPhysicalAddress()); + Pica::DebugUtils::TextureInfo info; + info.width = Pica::registers.texture0.width; + info.height = Pica::registers.texture0.height; + info.stride = 3 * Pica::registers.texture0.width; + info.format = Pica::registers.texture0_format; + new_info_widget = new TextureInfoWidget(src, info); + } else { + new_info_widget = new QWidget; + } +#undef COMMAND_IN_RANGE + + widget()->layout()->removeWidget(command_info_widget); + delete command_info_widget; + widget()->layout()->addWidget(new_info_widget); + command_info_widget = new_info_widget; +} GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) { + setObjectName("Pica Command List"); GPUCommandListModel* model = new GPUCommandListModel(this); QWidget* main_widget = new QWidget; - QTreeView* list_widget = new QTreeView; + list_widget = new QTreeView; list_widget->setModel(model); list_widget->setFont(QFont("monospace")); list_widget->setRootIsDecorated(false); + connect(list_widget->selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)), + this, SLOT(SetCommandInfo(const QModelIndex&))); + + toggle_tracing = new QPushButton(tr("Start Tracing")); connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&))); + command_info_widget = new QWidget; + QVBoxLayout* main_layout = new QVBoxLayout; main_layout->addWidget(list_widget); main_layout->addWidget(toggle_tracing); + main_layout->addWidget(command_info_widget); main_widget->setLayout(main_layout); setWidget(main_widget); diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx index 31bd2546d..37fe19053 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.hxx +++ b/src/citra_qt/debugger/graphics_cmdlists.hxx @@ -11,12 +11,17 @@ #include "video_core/debug_utils/debug_utils.h" class QPushButton; +class QTreeView; class GPUCommandListModel : public QAbstractListModel { Q_OBJECT public: + enum { + CommandIdRole = Qt::UserRole, + }; + GPUCommandListModel(QObject* parent); int columnCount(const QModelIndex& parent = QModelIndex()) const override; @@ -40,6 +45,7 @@ public: public slots: void OnToggleTracing(); + void SetCommandInfo(const QModelIndex&); signals: void TracingFinished(const Pica::DebugUtils::PicaTrace&); @@ -47,5 +53,7 @@ signals: private: std::unique_ptr pica_trace; + QTreeView* list_widget; + QWidget* command_info_widget; QPushButton* toggle_tracing; }; -- cgit v1.2.3 From 2793619dcef9fb2f97db5f0258ca950e18fe7f13 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sun, 24 Aug 2014 17:23:02 +0200 Subject: citra_qt: Add enhanced texture debugging widgets. Double-clicking a texture parameter command in the pica command lists will spawn these as a new tab in the pica command list dock area. --- src/citra_qt/debugger/graphics_cmdlists.cpp | 173 +++++++++++++++++++++++++--- src/citra_qt/debugger/graphics_cmdlists.hxx | 24 ++++ 2 files changed, 179 insertions(+), 18 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index dcd0ced33..4f58e9a90 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -4,30 +4,39 @@ #include #include +#include #include #include #include - -#include "graphics_cmdlists.hxx" +#include +#include #include "video_core/pica.h" #include "video_core/math.h" #include "video_core/debug_utils/debug_utils.h" +#include "graphics_cmdlists.hxx" + +#include "util/spinbox.hxx" + +QImage LoadTexture(u8* src, const Pica::DebugUtils::TextureInfo& info) { + QImage decoded_image(info.width, info.height, QImage::Format_ARGB32); + for (int y = 0; y < info.height; ++y) { + for (int x = 0; x < info.width; ++x) { + Math::Vec4 color = Pica::DebugUtils::LookupTexture(src, x, y, info); + decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a())); + } + } + + return decoded_image; +} + class TextureInfoWidget : public QWidget { public: TextureInfoWidget(u8* src, const Pica::DebugUtils::TextureInfo& info, QWidget* parent = nullptr) : QWidget(parent) { - QImage decoded_image(info.width, info.height, QImage::Format_ARGB32); - for (int y = 0; y < info.height; ++y) { - for (int x = 0; x < info.width; ++x) { - Math::Vec4 color = Pica::DebugUtils::LookupTexture(src, x, y, info); - decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a())); - } - } - QLabel* image_widget = new QLabel; - QPixmap image_pixmap = QPixmap::fromImage(decoded_image); + QPixmap image_pixmap = QPixmap::fromImage(LoadTexture(src, info)); image_pixmap = image_pixmap.scaled(200, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation); image_widget->setPixmap(image_pixmap); @@ -37,6 +46,120 @@ public: } }; +TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo& info, QWidget* parent) + : QDockWidget(tr("Texture 0x%1").arg(info.address, 8, 16, QLatin1Char('0'))), + info(info) { + + QWidget* main_widget = new QWidget; + + QLabel* image_widget = new QLabel; + + connect(this, SIGNAL(UpdatePixmap(const QPixmap&)), image_widget, SLOT(setPixmap(const QPixmap&))); + + CSpinBox* phys_address_spinbox = new CSpinBox; + phys_address_spinbox->SetBase(16); + phys_address_spinbox->SetRange(0, 0xFFFFFFFF); + phys_address_spinbox->SetPrefix("0x"); + phys_address_spinbox->SetValue(info.address); + connect(phys_address_spinbox, SIGNAL(ValueChanged(qint64)), this, SLOT(OnAddressChanged(qint64))); + + QComboBox* format_choice = new QComboBox; + format_choice->addItem(tr("RGBA8")); + format_choice->addItem(tr("RGB8")); + format_choice->addItem(tr("RGBA5551")); + format_choice->addItem(tr("RGB565")); + format_choice->addItem(tr("RGBA4")); + format_choice->setCurrentIndex(static_cast(info.format)); + connect(format_choice, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFormatChanged(int))); + + QSpinBox* width_spinbox = new QSpinBox; + width_spinbox->setMaximum(65535); + width_spinbox->setValue(info.width); + connect(width_spinbox, SIGNAL(valueChanged(int)), this, SLOT(OnWidthChanged(int))); + + QSpinBox* height_spinbox = new QSpinBox; + height_spinbox->setMaximum(65535); + height_spinbox->setValue(info.height); + connect(height_spinbox, SIGNAL(valueChanged(int)), this, SLOT(OnHeightChanged(int))); + + QSpinBox* stride_spinbox = new QSpinBox; + stride_spinbox->setMaximum(65535 * 4); + stride_spinbox->setValue(info.stride); + connect(stride_spinbox, SIGNAL(valueChanged(int)), this, SLOT(OnStrideChanged(int))); + + QVBoxLayout* main_layout = new QVBoxLayout; + main_layout->addWidget(image_widget); + + { + QHBoxLayout* sub_layout = new QHBoxLayout; + sub_layout->addWidget(new QLabel(tr("Source Address:"))); + sub_layout->addWidget(phys_address_spinbox); + main_layout->addLayout(sub_layout); + } + + { + QHBoxLayout* sub_layout = new QHBoxLayout; + sub_layout->addWidget(new QLabel(tr("Format"))); + sub_layout->addWidget(format_choice); + main_layout->addLayout(sub_layout); + } + + { + QHBoxLayout* sub_layout = new QHBoxLayout; + sub_layout->addWidget(new QLabel(tr("Width:"))); + sub_layout->addWidget(width_spinbox); + sub_layout->addStretch(); + sub_layout->addWidget(new QLabel(tr("Height:"))); + sub_layout->addWidget(height_spinbox); + sub_layout->addStretch(); + sub_layout->addWidget(new QLabel(tr("Stride:"))); + sub_layout->addWidget(stride_spinbox); + main_layout->addLayout(sub_layout); + } + + main_widget->setLayout(main_layout); + + emit UpdatePixmap(ReloadPixmap()); + + setWidget(main_widget); +} + +void TextureInfoDockWidget::OnAddressChanged(qint64 value) +{ + info.address = value; + emit UpdatePixmap(ReloadPixmap()); +} + +void TextureInfoDockWidget::OnFormatChanged(int value) +{ + info.format = static_cast(value); + emit UpdatePixmap(ReloadPixmap()); +} + +void TextureInfoDockWidget::OnWidthChanged(int value) +{ + info.width = value; + emit UpdatePixmap(ReloadPixmap()); +} + +void TextureInfoDockWidget::OnHeightChanged(int value) +{ + info.height = value; + emit UpdatePixmap(ReloadPixmap()); +} + +void TextureInfoDockWidget::OnStrideChanged(int value) +{ + info.stride = value; + emit UpdatePixmap(ReloadPixmap()); +} + +QPixmap TextureInfoDockWidget::ReloadPixmap() const +{ + u8* src = Memory::GetPointer(info.address); + return QPixmap::fromImage(LoadTexture(src, info)); +} + GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) { @@ -106,30 +229,42 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& endResetModel(); } +#define COMMAND_IN_RANGE(cmd_id, reg_name) \ + (cmd_id >= PICA_REG_INDEX(reg_name) && \ + cmd_id < PICA_REG_INDEX(reg_name) + sizeof(decltype(Pica::registers.reg_name)) / 4) + +void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) +{ + + const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt(); + if (COMMAND_IN_RANGE(command_id, texture0)) { + auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(Pica::registers.texture0, + Pica::registers.texture0_format); + QMainWindow* main_window = (QMainWindow*)parent(); + main_window->tabifyDockWidget(this, new TextureInfoDockWidget(info, main_window)); + } +} + void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) { QWidget* new_info_widget; -#define COMMAND_IN_RANGE(cmd_id, reg_name) (cmd_id >= PICA_REG_INDEX(reg_name) && cmd_id < PICA_REG_INDEX(reg_name) + sizeof(decltype(Pica::registers.reg_name)) / 4) const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt(); if (COMMAND_IN_RANGE(command_id, texture0)) { u8* src = Memory::GetPointer(Pica::registers.texture0.GetPhysicalAddress()); - Pica::DebugUtils::TextureInfo info; - info.width = Pica::registers.texture0.width; - info.height = Pica::registers.texture0.height; - info.stride = 3 * Pica::registers.texture0.width; - info.format = Pica::registers.texture0_format; + auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(Pica::registers.texture0, + Pica::registers.texture0_format); new_info_widget = new TextureInfoWidget(src, info); } else { new_info_widget = new QWidget; } -#undef COMMAND_IN_RANGE widget()->layout()->removeWidget(command_info_widget); delete command_info_widget; widget()->layout()->addWidget(new_info_widget); command_info_widget = new_info_widget; } +#undef COMMAND_IN_RANGE GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) { @@ -145,6 +280,8 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi connect(list_widget->selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)), this, SLOT(SetCommandInfo(const QModelIndex&))); + connect(list_widget, SIGNAL(doubleClicked(const QModelIndex&)), + this, SLOT(OnCommandDoubleClicked(const QModelIndex&))); toggle_tracing = new QPushButton(tr("Start Tracing")); diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx index 37fe19053..a459bba64 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.hxx +++ b/src/citra_qt/debugger/graphics_cmdlists.hxx @@ -45,6 +45,8 @@ public: public slots: void OnToggleTracing(); + void OnCommandDoubleClicked(const QModelIndex&); + void SetCommandInfo(const QModelIndex&); signals: @@ -57,3 +59,25 @@ private: QWidget* command_info_widget; QPushButton* toggle_tracing; }; + +class TextureInfoDockWidget : public QDockWidget { + Q_OBJECT + +public: + TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo& info, QWidget* parent = nullptr); + +signals: + void UpdatePixmap(const QPixmap& pixmap); + +private slots: + void OnAddressChanged(qint64 value); + void OnFormatChanged(int value); + void OnWidthChanged(int value); + void OnHeightChanged(int value); + void OnStrideChanged(int value); + +private: + QPixmap ReloadPixmap() const; + + Pica::DebugUtils::TextureInfo info; +}; -- cgit v1.2.3 From 55ce9aca7149159d6ec444047355e47d70c13c3f Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sun, 26 Oct 2014 16:38:40 +0100 Subject: citra-qt: Add pica framebuffer widget. --- src/citra_qt/CMakeLists.txt | 2 + src/citra_qt/debugger/graphics_framebuffer.cpp | 282 +++++++++++++++++++++++++ src/citra_qt/debugger/graphics_framebuffer.hxx | 92 ++++++++ src/citra_qt/main.cpp | 6 + 4 files changed, 382 insertions(+) create mode 100644 src/citra_qt/debugger/graphics_framebuffer.cpp create mode 100644 src/citra_qt/debugger/graphics_framebuffer.hxx (limited to 'src/citra_qt') diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 999724102..cd4a04eac 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -10,6 +10,7 @@ set(SRCS debugger/graphics.cpp debugger/graphics_breakpoints.cpp debugger/graphics_cmdlists.cpp + debugger/graphics_framebuffer.cpp debugger/ramview.cpp debugger/registers.cpp util/spinbox.cpp @@ -27,6 +28,7 @@ set(HEADERS debugger/graphics.hxx debugger/graphics_breakpoints.hxx debugger/graphics_cmdlists.hxx + debugger/graphics_framebuffer.hxx debugger/ramview.hxx debugger/registers.hxx util/spinbox.hxx diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp new file mode 100644 index 000000000..b91db5433 --- /dev/null +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -0,0 +1,282 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include +#include + +#include "video_core/pica.h" + +#include "graphics_framebuffer.hxx" + +#include "util/spinbox.hxx" + +BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr debug_context, + const QString& title, QWidget* parent) + : QDockWidget(title, parent), BreakPointObserver(debug_context) +{ + qRegisterMetaType("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 debug_context, + QWidget* parent) + : BreakPointObserverDock(debug_context, tr("Pica Framebuffer"), parent), + framebuffer_source(Source::PicaTarget) +{ + setObjectName("PicaFramebuffer"); + + framebuffer_source_list = new QComboBox; + framebuffer_source_list->addItem(tr("Active Render Target")); + framebuffer_source_list->addItem(tr("Custom")); + framebuffer_source_list->setCurrentIndex(static_cast(framebuffer_source)); + + framebuffer_address_control = new CSpinBox; + framebuffer_address_control->SetBase(16); + framebuffer_address_control->SetRange(0, 0xFFFFFFFF); + framebuffer_address_control->SetPrefix("0x"); + + framebuffer_width_control = new QSpinBox; + framebuffer_width_control->setMinimum(1); + framebuffer_width_control->setMaximum(std::numeric_limits::max()); // TODO: Find actual maximum + + framebuffer_height_control = new QSpinBox; + framebuffer_height_control->setMinimum(1); + framebuffer_height_control->setMaximum(std::numeric_limits::max()); // TODO: Find actual maximum + + framebuffer_format_control = new QComboBox; + framebuffer_format_control->addItem(tr("RGBA8")); + framebuffer_format_control->addItem(tr("RGB8")); + framebuffer_format_control->addItem(tr("RGBA5551")); + framebuffer_format_control->addItem(tr("RGB565")); + framebuffer_format_control->addItem(tr("RGBA4")); + + // TODO: This QLabel should shrink the image to the available space rather than just expanding... + framebuffer_picture_label = new QLabel; + + auto enlarge_button = new QPushButton(tr("Enlarge")); + + // Connections + connect(this, SIGNAL(Update()), this, SLOT(OnUpdate())); + connect(framebuffer_source_list, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFramebufferSourceChanged(int))); + connect(framebuffer_address_control, SIGNAL(ValueChanged(qint64)), this, SLOT(OnFramebufferAddressChanged(qint64))); + connect(framebuffer_width_control, SIGNAL(valueChanged(int)), this, SLOT(OnFramebufferWidthChanged(int))); + connect(framebuffer_height_control, SIGNAL(valueChanged(int)), this, SLOT(OnFramebufferHeightChanged(int))); + connect(framebuffer_format_control, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFramebufferFormatChanged(int))); + + auto main_widget = new QWidget; + auto main_layout = new QVBoxLayout; + { + auto sub_layout = new QHBoxLayout; + sub_layout->addWidget(new QLabel(tr("Source:"))); + sub_layout->addWidget(framebuffer_source_list); + main_layout->addLayout(sub_layout); + } + { + auto sub_layout = new QHBoxLayout; + sub_layout->addWidget(new QLabel(tr("Virtual Address:"))); + sub_layout->addWidget(framebuffer_address_control); + main_layout->addLayout(sub_layout); + } + { + auto sub_layout = new QHBoxLayout; + sub_layout->addWidget(new QLabel(tr("Width:"))); + sub_layout->addWidget(framebuffer_width_control); + main_layout->addLayout(sub_layout); + } + { + auto sub_layout = new QHBoxLayout; + sub_layout->addWidget(new QLabel(tr("Height:"))); + sub_layout->addWidget(framebuffer_height_control); + main_layout->addLayout(sub_layout); + } + { + auto sub_layout = new QHBoxLayout; + sub_layout->addWidget(new QLabel(tr("Format:"))); + sub_layout->addWidget(framebuffer_format_control); + main_layout->addLayout(sub_layout); + } + main_layout->addWidget(framebuffer_picture_label); + main_layout->addWidget(enlarge_button); + main_widget->setLayout(main_layout); + setWidget(main_widget); + + // Load current data - TODO: Make sure this works when emulation is not running + emit Update(); + widget()->setEnabled(false); // TODO: Only enable if currently at breakpoint +} + +void GraphicsFramebufferWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) +{ + emit Update(); + widget()->setEnabled(true); +} + +void GraphicsFramebufferWidget::OnResumed() +{ + widget()->setEnabled(false); +} + +void GraphicsFramebufferWidget::OnFramebufferSourceChanged(int new_value) +{ + framebuffer_source = static_cast(new_value); + emit Update(); +} + +void GraphicsFramebufferWidget::OnFramebufferAddressChanged(qint64 new_value) +{ + if (framebuffer_address != new_value) { + framebuffer_address = static_cast(new_value); + + framebuffer_source_list->setCurrentIndex(static_cast(Source::Custom)); + emit Update(); + } +} + +void GraphicsFramebufferWidget::OnFramebufferWidthChanged(int new_value) +{ + if (framebuffer_width != new_value) { + framebuffer_width = new_value; + + framebuffer_source_list->setCurrentIndex(static_cast(Source::Custom)); + emit Update(); + } +} + +void GraphicsFramebufferWidget::OnFramebufferHeightChanged(int new_value) +{ + if (framebuffer_height != new_value) { + framebuffer_height = new_value; + + framebuffer_source_list->setCurrentIndex(static_cast(Source::Custom)); + emit Update(); + } +} + +void GraphicsFramebufferWidget::OnFramebufferFormatChanged(int new_value) +{ + if (framebuffer_format != static_cast(new_value)) { + framebuffer_format = static_cast(new_value); + + framebuffer_source_list->setCurrentIndex(static_cast(Source::Custom)); + emit Update(); + } +} + +void GraphicsFramebufferWidget::OnUpdate() +{ + QPixmap pixmap; + + switch (framebuffer_source) { + case Source::PicaTarget: + { + // TODO: Store a reference to the registers in the debug context instead of accessing them directly... + + auto framebuffer = Pica::registers.framebuffer; + using Framebuffer = decltype(framebuffer); + + framebuffer_address = framebuffer.GetColorBufferAddress(); + framebuffer_width = framebuffer.GetWidth(); + framebuffer_height = framebuffer.GetHeight(); + framebuffer_format = static_cast(framebuffer.color_format); + + break; + } + + case Source::Custom: + { + // Keep user-specified values + break; + } + + default: + qDebug() << "Unknown framebuffer source " << static_cast(framebuffer_source); + break; + } + + switch (framebuffer_format) { + case Format::RGBA8: + { + // TODO: Implement a good way to visualize the alpha component + + QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); + u32* color_buffer = (u32*)Memory::GetPointer(framebuffer_address); + for (int y = 0; y < framebuffer_height; ++y) { + for (int x = 0; x < framebuffer_width; ++x) { + u32 value = *(color_buffer + x + y * framebuffer_width); + + decoded_image.setPixel(x, y, qRgba((value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF, 255/*value >> 24*/)); + } + } + pixmap = QPixmap::fromImage(decoded_image); + break; + } + + case Format::RGB8: + { + QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); + u8* color_buffer = Memory::GetPointer(framebuffer_address); + for (int y = 0; y < framebuffer_height; ++y) { + for (int x = 0; x < framebuffer_width; ++x) { + u8* pixel_pointer = color_buffer + x * 3 + y * 3 * framebuffer_width; + + decoded_image.setPixel(x, y, qRgba(pixel_pointer[0], pixel_pointer[1], pixel_pointer[2], 255/*value >> 24*/)); + } + } + pixmap = QPixmap::fromImage(decoded_image); + break; + } + + case Format::RGBA5551: + { + QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); + u32* color_buffer = (u32*)Memory::GetPointer(framebuffer_address); + for (int y = 0; y < framebuffer_height; ++y) { + for (int x = 0; x < framebuffer_width; ++x) { + u16 value = *(u16*)(((u8*)color_buffer) + x * 2 + y * framebuffer_width * 2); + u8 r = (value >> 11) & 0x1F; + u8 g = (value >> 6) & 0x1F; + u8 b = (value >> 1) & 0x1F; + u8 a = value & 1; + + decoded_image.setPixel(x, y, qRgba(r, g, b, 255/*a*/)); + } + } + pixmap = QPixmap::fromImage(decoded_image); + break; + } + + default: + qDebug() << "Unknown fb color format " << static_cast(framebuffer_format); + break; + } + + framebuffer_address_control->SetValue(framebuffer_address); + framebuffer_width_control->setValue(framebuffer_width); + framebuffer_height_control->setValue(framebuffer_height); + framebuffer_format_control->setCurrentIndex(static_cast(framebuffer_format)); + framebuffer_picture_label->setPixmap(pixmap); +} diff --git a/src/citra_qt/debugger/graphics_framebuffer.hxx b/src/citra_qt/debugger/graphics_framebuffer.hxx new file mode 100644 index 000000000..bb73b2f72 --- /dev/null +++ b/src/citra_qt/debugger/graphics_framebuffer.hxx @@ -0,0 +1,92 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "video_core/debug_utils/debug_utils.h" + +class QComboBox; +class QLabel; +class QSpinBox; + +class CSpinBox; + +// Utility class which forwards calls to OnPicaBreakPointHit and OnPicaResume to public slots. +// This is because the Pica breakpoint callbacks will called on 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 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 + + using Event = Pica::DebugContext::Event; + + enum class Source { + PicaTarget = 0, + Custom = 1, + + // TODO: Add GPU framebuffer sources! + }; + + enum class Format { + RGBA8 = 0, + RGB8 = 1, + RGBA5551 = 2, + RGB565 = 3, + RGBA4 = 4, + }; + +public: + GraphicsFramebufferWidget(std::shared_ptr debug_context, QWidget* parent = nullptr); + +public slots: + void OnFramebufferSourceChanged(int new_value); + void OnFramebufferAddressChanged(qint64 new_value); + void OnFramebufferWidthChanged(int new_value); + void OnFramebufferHeightChanged(int new_value); + void OnFramebufferFormatChanged(int new_value); + void OnUpdate(); + +private slots: + void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override; + void OnResumed() override; + +signals: + void Update(); + +private: + + QComboBox* framebuffer_source_list; + CSpinBox* framebuffer_address_control; + QSpinBox* framebuffer_width_control; + QSpinBox* framebuffer_height_control; + QComboBox* framebuffer_format_control; + + QLabel* framebuffer_picture_label; + + Source framebuffer_source; + unsigned framebuffer_address; + unsigned framebuffer_width; + unsigned framebuffer_height; + Format framebuffer_format; +}; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 84afe59d8..b4e3ad964 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -22,6 +22,7 @@ #include "debugger/graphics.hxx" #include "debugger/graphics_breakpoints.hxx" #include "debugger/graphics_cmdlists.hxx" +#include "debugger/graphics_framebuffer.hxx" #include "core/settings.h" #include "core/system.h" @@ -74,6 +75,10 @@ GMainWindow::GMainWindow() addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget); graphicsBreakpointsWidget->hide(); + auto graphicsFramebufferWidget = new GraphicsFramebufferWidget(Pica::g_debug_context, this); + addDockWidget(Qt::RightDockWidgetArea, graphicsFramebufferWidget); + graphicsFramebufferWidget->hide(); + QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); debug_menu->addAction(disasmWidget->toggleViewAction()); debug_menu->addAction(registersWidget->toggleViewAction()); @@ -81,6 +86,7 @@ GMainWindow::GMainWindow() debug_menu->addAction(graphicsWidget->toggleViewAction()); debug_menu->addAction(graphicsCommandsWidget->toggleViewAction()); debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction()); + debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction()); // Set default UI state // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half -- cgit v1.2.3 From 0cd27a511ecd170484b672263c09192b579e31ac Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Thu, 4 Dec 2014 19:41:03 +0100 Subject: Some code cleanup. --- src/citra_qt/CMakeLists.txt | 1 + src/citra_qt/debugger/graphics_breakpoints.cpp | 3 +- src/citra_qt/debugger/graphics_breakpoints.hxx | 27 +----------- src/citra_qt/debugger/graphics_breakpoints_p.hxx | 38 +++++++++++++++++ src/citra_qt/debugger/graphics_cmdlists.cpp | 54 +++++++++--------------- src/citra_qt/debugger/graphics_framebuffer.cpp | 4 +- 6 files changed, 63 insertions(+), 64 deletions(-) create mode 100644 src/citra_qt/debugger/graphics_breakpoints_p.hxx (limited to 'src/citra_qt') diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index cd4a04eac..90e5c6aa6 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -27,6 +27,7 @@ set(HEADERS debugger/disassembler.hxx debugger/graphics.hxx debugger/graphics_breakpoints.hxx + debugger/graphics_breakpoints_p.hxx debugger/graphics_cmdlists.hxx debugger/graphics_framebuffer.hxx debugger/ramview.hxx diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp index 2f41d5f77..db98a3b05 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.cpp +++ b/src/citra_qt/debugger/graphics_breakpoints.cpp @@ -9,6 +9,7 @@ #include #include "graphics_breakpoints.hxx" +#include "graphics_breakpoints_p.hxx" BreakPointModel::BreakPointModel(std::shared_ptr debug_context, QObject* parent) : QAbstractListModel(parent), context_weak(debug_context), @@ -39,7 +40,7 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const std::map map; map.insert({Pica::DebugContext::Event::CommandLoaded, tr("Pica command loaded")}); map.insert({Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed")}); - map.insert({Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incomming primitive batch")}); + map.insert({Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch")}); map.insert({Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch")}); _dbg_assert_(GPU, map.size() == static_cast(Pica::DebugContext::Event::NumEvents)); diff --git a/src/citra_qt/debugger/graphics_breakpoints.hxx b/src/citra_qt/debugger/graphics_breakpoints.hxx index edc41283e..2142c6fa1 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.hxx +++ b/src/citra_qt/debugger/graphics_breakpoints.hxx @@ -15,32 +15,7 @@ class QLabel; class QPushButton; class QTreeView; -class BreakPointModel : public QAbstractListModel { - Q_OBJECT - -public: - enum { - Role_IsEnabled = Qt::UserRole, - }; - - BreakPointModel(std::shared_ptr context, QObject* parent); - - 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; - - bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); - -public slots: - void OnBreakPointHit(Pica::DebugContext::Event event); - void OnResumed(); - -private: - bool at_breakpoint; - Pica::DebugContext::Event active_breakpoint; - std::weak_ptr context_weak; -}; +class BreakPointModel; class GraphicsBreakPointsWidget : public QDockWidget, Pica::DebugContext::BreakPointObserver { Q_OBJECT diff --git a/src/citra_qt/debugger/graphics_breakpoints_p.hxx b/src/citra_qt/debugger/graphics_breakpoints_p.hxx new file mode 100644 index 000000000..bf5daf73d --- /dev/null +++ b/src/citra_qt/debugger/graphics_breakpoints_p.hxx @@ -0,0 +1,38 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +#include + +#include "video_core/debug_utils/debug_utils.h" + +class BreakPointModel : public QAbstractListModel { + Q_OBJECT + +public: + enum { + Role_IsEnabled = Qt::UserRole, + }; + + BreakPointModel(std::shared_ptr context, QObject* parent); + + 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; + + bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); + +public slots: + void OnBreakPointHit(Pica::DebugContext::Event event); + void OnResumed(); + +private: + std::weak_ptr context_weak; + bool at_breakpoint; + Pica::DebugContext::Event active_breakpoint; +}; diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 4f58e9a90..ed51f97f3 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -124,59 +124,49 @@ TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo setWidget(main_widget); } -void TextureInfoDockWidget::OnAddressChanged(qint64 value) -{ +void TextureInfoDockWidget::OnAddressChanged(qint64 value) { info.address = value; emit UpdatePixmap(ReloadPixmap()); } -void TextureInfoDockWidget::OnFormatChanged(int value) -{ +void TextureInfoDockWidget::OnFormatChanged(int value) { info.format = static_cast(value); emit UpdatePixmap(ReloadPixmap()); } -void TextureInfoDockWidget::OnWidthChanged(int value) -{ +void TextureInfoDockWidget::OnWidthChanged(int value) { info.width = value; emit UpdatePixmap(ReloadPixmap()); } -void TextureInfoDockWidget::OnHeightChanged(int value) -{ +void TextureInfoDockWidget::OnHeightChanged(int value) { info.height = value; emit UpdatePixmap(ReloadPixmap()); } -void TextureInfoDockWidget::OnStrideChanged(int value) -{ +void TextureInfoDockWidget::OnStrideChanged(int value) { info.stride = value; emit UpdatePixmap(ReloadPixmap()); } -QPixmap TextureInfoDockWidget::ReloadPixmap() const -{ +QPixmap TextureInfoDockWidget::ReloadPixmap() const { u8* src = Memory::GetPointer(info.address); return QPixmap::fromImage(LoadTexture(src, info)); } -GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) -{ +GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) { } -int GPUCommandListModel::rowCount(const QModelIndex& parent) const -{ +int GPUCommandListModel::rowCount(const QModelIndex& parent) const { return pica_trace.writes.size(); } -int GPUCommandListModel::columnCount(const QModelIndex& parent) const -{ +int GPUCommandListModel::columnCount(const QModelIndex& parent) const { return 2; } -QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const -{ +QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); @@ -202,8 +192,7 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const return QVariant(); } -QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientation, int role) const -{ +QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientation, int role) const { switch(role) { case Qt::DisplayRole: { @@ -220,8 +209,7 @@ QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientatio return QVariant(); } -void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace) -{ +void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace) { beginResetModel(); pica_trace = trace; @@ -233,20 +221,19 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& (cmd_id >= PICA_REG_INDEX(reg_name) && \ cmd_id < PICA_REG_INDEX(reg_name) + sizeof(decltype(Pica::registers.reg_name)) / 4) -void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) -{ - +void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) { const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt(); if (COMMAND_IN_RANGE(command_id, texture0)) { auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(Pica::registers.texture0, Pica::registers.texture0_format); - QMainWindow* main_window = (QMainWindow*)parent(); + + // TODO: Instead, emit a signal here to be caught by the main window widget. + auto main_window = static_cast(parent()); main_window->tabifyDockWidget(this, new TextureInfoDockWidget(info, main_window)); } } -void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) -{ +void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) { QWidget* new_info_widget; const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt(); @@ -266,8 +253,7 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) } #undef COMMAND_IN_RANGE -GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) -{ +GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) { setObjectName("Pica Command List"); GPUCommandListModel* model = new GPUCommandListModel(this); @@ -283,7 +269,6 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi connect(list_widget, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(OnCommandDoubleClicked(const QModelIndex&))); - toggle_tracing = new QPushButton(tr("Start Tracing")); connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); @@ -301,8 +286,7 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi setWidget(main_widget); } -void GPUCommandListWidget::OnToggleTracing() -{ +void GPUCommandListWidget::OnToggleTracing() { if (!Pica::DebugUtils::IsPicaTracing()) { Pica::DebugUtils::StartPicaTracing(); toggle_tracing->setText(tr("Stop Tracing")); diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index b91db5433..ac47f298d 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -217,11 +217,11 @@ void GraphicsFramebufferWidget::OnUpdate() break; } + // TODO: Implement a good way to visualize alpha components! + // TODO: Unify this decoding code with the texture decoder switch (framebuffer_format) { case Format::RGBA8: { - // TODO: Implement a good way to visualize the alpha component - QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); u32* color_buffer = (u32*)Memory::GetPointer(framebuffer_address); for (int y = 0; y < framebuffer_height; ++y) { -- cgit v1.2.3 From 79bb403089ff91c24b8356ad8d5bc5f7666a0d11 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Thu, 4 Dec 2014 20:41:01 +0100 Subject: More coding style fixes. --- src/citra_qt/debugger/graphics_breakpoints.cpp | 2 +- src/citra_qt/debugger/graphics_framebuffer.hxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp index db98a3b05..5973aafc8 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.cpp +++ b/src/citra_qt/debugger/graphics_breakpoints.cpp @@ -43,7 +43,7 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const map.insert({Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch")}); map.insert({Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch")}); - _dbg_assert_(GPU, map.size() == static_cast(Pica::DebugContext::Event::NumEvents)); + _dbg_assert_(GUI, map.size() == static_cast(Pica::DebugContext::Event::NumEvents)); return map[event]; } else if (index.column() == 1) { diff --git a/src/citra_qt/debugger/graphics_framebuffer.hxx b/src/citra_qt/debugger/graphics_framebuffer.hxx index bb73b2f72..1151ee7a1 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.hxx +++ b/src/citra_qt/debugger/graphics_framebuffer.hxx @@ -15,7 +15,7 @@ class QSpinBox; class CSpinBox; // Utility class which forwards calls to OnPicaBreakPointHit and OnPicaResume to public slots. -// This is because the Pica breakpoint callbacks will called on a non-GUI thread, while +// 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 -- cgit v1.2.3 From ac4d7462cb9de2038ba466f03a0241fde28ed73f Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Thu, 4 Dec 2014 20:41:45 +0100 Subject: citra-qt: Rename "Stop Tracing" to "Finish Tracing". This better reflects that no commands are supposed to show up until you hit the button a second time. --- src/citra_qt/debugger/graphics_cmdlists.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index ed51f97f3..b2b8df101 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -289,7 +289,7 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi void GPUCommandListWidget::OnToggleTracing() { if (!Pica::DebugUtils::IsPicaTracing()) { Pica::DebugUtils::StartPicaTracing(); - toggle_tracing->setText(tr("Stop Tracing")); + toggle_tracing->setText(tr("Finish Tracing")); } else { pica_trace = Pica::DebugUtils::FinishPicaTracing(); emit TracingFinished(*pica_trace); -- cgit v1.2.3 From 8b8131baecca16b46c22318b3331b2165cc74cbc Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Thu, 4 Dec 2014 21:00:06 +0100 Subject: More cleanups. --- src/citra_qt/debugger/graphics_breakpoints.cpp | 11 +++++++++-- src/citra_qt/debugger/graphics_cmdlists.cpp | 8 ++++---- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp index 5973aafc8..df5579e15 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.cpp +++ b/src/citra_qt/debugger/graphics_breakpoints.cpp @@ -36,7 +36,9 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const switch (role) { case Qt::DisplayRole: { - if (index.column() == 0) { + switch (index.column()) { + case 0: + { std::map map; map.insert({Pica::DebugContext::Event::CommandLoaded, tr("Pica command loaded")}); map.insert({Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed")}); @@ -46,8 +48,13 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const _dbg_assert_(GUI, map.size() == static_cast(Pica::DebugContext::Event::NumEvents)); return map[event]; - } else if (index.column() == 1) { + } + + case 1: return data(index, Role_IsEnabled).toBool() ? tr("Enabled") : tr("Disabled"); + + default: + break; } break; diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index b2b8df101..7f97cf143 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -177,14 +177,14 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const { if (role == Qt::DisplayRole) { QString content; if (index.column() == 0) { - content = QString::fromLatin1(Pica::Regs::GetCommandName(cmd.cmd_id).c_str()); + QString content = QString::fromLatin1(Pica::Regs::GetCommandName(cmd.cmd_id).c_str()); content.append(" "); + return content; } else if (index.column() == 1) { - content.append(QString("%1 ").arg(cmd.hex, 8, 16, QLatin1Char('0'))); + QString content = QString("%1 ").arg(cmd.hex, 8, 16, QLatin1Char('0')); content.append(QString("%1 ").arg(val, 8, 16, QLatin1Char('0'))); + return content; } - - return QVariant(content); } else if (role == CommandIdRole) { return QVariant::fromValue(cmd.cmd_id.Value()); } -- cgit v1.2.3 From 616d87444313db865c60fbeee36ebe5250ef301e Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Tue, 28 Oct 2014 05:36:00 -0200 Subject: New logging system --- src/citra_qt/main.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index b4e3ad964..2e3025295 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -5,8 +7,13 @@ #include "main.hxx" #include "common/common.h" -#include "common/platform.h" #include "common/log_manager.h" +#include "common/logging/text_formatter.h" +#include "common/logging/log.h" +#include "common/logging/backend.h" +#include "common/platform.h" +#include "common/scope_exit.h" + #if EMU_PLATFORM == PLATFORM_LINUX #include #endif @@ -33,10 +40,8 @@ #include "version.h" - GMainWindow::GMainWindow() { - LogManager::Init(); Pica::g_debug_context = Pica::DebugContext::Construct(); @@ -271,6 +276,13 @@ void GMainWindow::closeEvent(QCloseEvent* event) int __cdecl main(int argc, char* argv[]) { + std::shared_ptr logger = Log::InitGlobalLogger(); + std::thread logging_thread(Log::TextLoggingLoop, logger); + SCOPE_EXIT({ + logger->Close(); + logging_thread.join(); + }); + QApplication::setAttribute(Qt::AA_X11InitThreads); QApplication app(argc, argv); GMainWindow main_window; -- cgit v1.2.3 From 0600e2d8b5b30bd68c8b19cb1f2051e096e7caa9 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Fri, 5 Dec 2014 23:53:49 -0200 Subject: Convert old logging calls to new logging macros --- src/citra_qt/bootmanager.cpp | 8 ++++---- src/citra_qt/debugger/graphics_breakpoints.cpp | 2 +- src/citra_qt/main.cpp | 6 +++--- src/citra_qt/util/spinbox.cpp | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index b53206be6..6d08d6afc 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -62,7 +62,7 @@ void EmuThread::Stop() { if (!isRunning()) { - INFO_LOG(MASTER_LOG, "EmuThread::Stop called while emu thread wasn't running, returning..."); + LOG_WARNING(Frontend, "EmuThread::Stop called while emu thread wasn't running, returning..."); return; } stop_run = true; @@ -76,7 +76,7 @@ void EmuThread::Stop() wait(1000); if (isRunning()) { - WARN_LOG(MASTER_LOG, "EmuThread still running, terminating..."); + LOG_WARNING(Frontend, "EmuThread still running, terminating..."); quit(); // TODO: Waiting 50 seconds can be necessary if the logging subsystem has a lot of spam @@ -84,11 +84,11 @@ void EmuThread::Stop() wait(50000); if (isRunning()) { - WARN_LOG(MASTER_LOG, "EmuThread STILL running, something is wrong here..."); + LOG_CRITICAL(Frontend, "EmuThread STILL running, something is wrong here..."); terminate(); } } - INFO_LOG(MASTER_LOG, "EmuThread stopped"); + LOG_INFO(Frontend, "EmuThread stopped"); } diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp index df5579e15..53394b6e6 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.cpp +++ b/src/citra_qt/debugger/graphics_breakpoints.cpp @@ -45,7 +45,7 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const map.insert({Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch")}); map.insert({Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch")}); - _dbg_assert_(GUI, map.size() == static_cast(Pica::DebugContext::Event::NumEvents)); + _dbg_assert_(Debug_GPU, map.size() == static_cast(Pica::DebugContext::Event::NumEvents)); return map[event]; } diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 2e3025295..5293263cd 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -158,18 +158,18 @@ GMainWindow::~GMainWindow() void GMainWindow::BootGame(std::string filename) { - NOTICE_LOG(MASTER_LOG, "Citra starting...\n"); + LOG_INFO(Frontend, "Citra starting...\n"); System::Init(render_window); if (Core::Init()) { - ERROR_LOG(MASTER_LOG, "Core initialization failed, exiting..."); + LOG_CRITICAL(Frontend, "Core initialization failed, exiting..."); Core::Stop(); exit(1); } // Load a game or die... if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) { - ERROR_LOG(BOOT, "Failed to load ROM!"); + LOG_CRITICAL(Frontend, "Failed to load ROM!"); } disasmWidget->Init(); diff --git a/src/citra_qt/util/spinbox.cpp b/src/citra_qt/util/spinbox.cpp index 80dc67d7d..9672168f5 100644 --- a/src/citra_qt/util/spinbox.cpp +++ b/src/citra_qt/util/spinbox.cpp @@ -244,7 +244,7 @@ QValidator::State CSpinBox::validate(QString& input, int& pos) const if (strpos >= input.length() - HasSign() - suffix.length()) return QValidator::Intermediate; - _dbg_assert_(GUI, base <= 10 || base == 16); + _dbg_assert_(Frontend, base <= 10 || base == 16); QString regexp; // Demand sign character for negative ranges -- cgit v1.2.3 From 0e0a007a2503d468391004c8ea2faae305232345 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sat, 6 Dec 2014 20:00:08 -0200 Subject: Add configurable per-class log filtering --- src/citra_qt/config.cpp | 4 ++-- src/citra_qt/main.cpp | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 3209e5900..0ae6b8b2d 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -52,7 +52,7 @@ void Config::ReadValues() { qt_config->endGroup(); qt_config->beginGroup("Miscellaneous"); - Settings::values.enable_log = qt_config->value("enable_log", true).toBool(); + Settings::values.log_filter = qt_config->value("log_filter", "*:Info").toString().toStdString(); qt_config->endGroup(); } @@ -87,7 +87,7 @@ void Config::SaveValues() { qt_config->endGroup(); qt_config->beginGroup("Miscellaneous"); - qt_config->setValue("enable_log", Settings::values.enable_log); + qt_config->setValue("log_filter", QString::fromStdString(Settings::values.log_filter)); qt_config->endGroup(); } diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 5293263cd..817732167 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -11,6 +11,7 @@ #include "common/logging/text_formatter.h" #include "common/logging/log.h" #include "common/logging/backend.h" +#include "common/logging/filter.h" #include "common/platform.h" #include "common/scope_exit.h" @@ -42,14 +43,10 @@ GMainWindow::GMainWindow() { - Pica::g_debug_context = Pica::DebugContext::Construct(); Config config; - if (!Settings::values.enable_log) - LogManager::Shutdown(); - ui.setupUi(this); statusBar()->hide(); @@ -277,7 +274,8 @@ void GMainWindow::closeEvent(QCloseEvent* event) int __cdecl main(int argc, char* argv[]) { std::shared_ptr logger = Log::InitGlobalLogger(); - std::thread logging_thread(Log::TextLoggingLoop, logger); + Log::Filter log_filter(Log::Level::Info); + std::thread logging_thread(Log::TextLoggingLoop, logger, &log_filter); SCOPE_EXIT({ logger->Close(); logging_thread.join(); @@ -285,7 +283,11 @@ int __cdecl main(int argc, char* argv[]) QApplication::setAttribute(Qt::AA_X11InitThreads); QApplication app(argc, argv); + GMainWindow main_window; + // After settings have been loaded by GMainWindow, apply the filter + log_filter.ParseFilterString(Settings::values.log_filter); + main_window.show(); return app.exec(); } -- cgit v1.2.3 From 4d2a6f8b9b3eeb85574a5e4f93422ffd4feebcd3 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sat, 6 Dec 2014 21:14:14 -0200 Subject: Remove old logging system --- src/citra_qt/main.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 817732167..1299338ac 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -7,7 +7,6 @@ #include "main.hxx" #include "common/common.h" -#include "common/log_manager.h" #include "common/logging/text_formatter.h" #include "common/logging/log.h" #include "common/logging/backend.h" -- cgit v1.2.3 From 06f31e8b471d5b54fee80568db2583d41e81fdb0 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sat, 13 Dec 2014 20:02:22 -0200 Subject: Clean up CMake library specification The X11 libraries don't need to be specified when doing dynamic linking --- src/citra_qt/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/citra_qt') diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 90e5c6aa6..54d0a1271 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -60,6 +60,10 @@ add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS}) target_link_libraries(citra-qt core common video_core qhexedit) target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) +if (UNIX) + target_link_libraries(citra-qt -pthread) +endif() + if (APPLE) target_link_libraries(citra-qt iconv ${COREFOUNDATION_LIBRARY}) elseif (WIN32) -- cgit v1.2.3 From ca67bb7945bf358cf38242a04febfd3375760947 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 14 Dec 2014 05:55:11 -0200 Subject: HLE: Rename namespaces to match move & fix initialization order --- src/citra_qt/main.cpp | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 1299338ac..23d4925b8 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -157,12 +157,6 @@ void GMainWindow::BootGame(std::string filename) LOG_INFO(Frontend, "Citra starting...\n"); System::Init(render_window); - if (Core::Init()) { - LOG_CRITICAL(Frontend, "Core initialization failed, exiting..."); - Core::Stop(); - exit(1); - } - // Load a game or die... if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) { LOG_CRITICAL(Frontend, "Failed to load ROM!"); -- cgit v1.2.3 From e7956926147d2d2ac6741aee8a150466a5438ca3 Mon Sep 17 00:00:00 2001 From: Chin Date: Fri, 19 Dec 2014 22:16:34 -0500 Subject: Clean up some warnings --- src/citra_qt/debugger/callstack.cpp | 4 ++-- src/citra_qt/debugger/graphics_framebuffer.cpp | 12 ++++++------ src/citra_qt/util/spinbox.cpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp index 895851be3..a9ec2f7fe 100644 --- a/src/citra_qt/debugger/callstack.cpp +++ b/src/citra_qt/debugger/callstack.cpp @@ -27,10 +27,10 @@ void CallstackWidget::OnCPUStepped() ARM_Interface* app_core = Core::g_app_core; u32 sp = app_core->GetReg(13); //stack pointer - u32 addr, ret_addr, call_addr, func_addr; + u32 ret_addr, call_addr, func_addr; int counter = 0; - for (int addr = 0x10000000; addr >= sp; addr -= 4) + for (u32 addr = 0x10000000; addr >= sp; addr -= 4) { ret_addr = Memory::Read32(addr); call_addr = ret_addr - 4; //get call address??? diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index ac47f298d..61b61ef6d 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -224,8 +224,8 @@ void GraphicsFramebufferWidget::OnUpdate() { QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); u32* color_buffer = (u32*)Memory::GetPointer(framebuffer_address); - for (int y = 0; y < framebuffer_height; ++y) { - for (int x = 0; x < framebuffer_width; ++x) { + for (unsigned y = 0; y < framebuffer_height; ++y) { + for (unsigned x = 0; x < framebuffer_width; ++x) { u32 value = *(color_buffer + x + y * framebuffer_width); decoded_image.setPixel(x, y, qRgba((value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF, 255/*value >> 24*/)); @@ -239,8 +239,8 @@ void GraphicsFramebufferWidget::OnUpdate() { QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); u8* color_buffer = Memory::GetPointer(framebuffer_address); - for (int y = 0; y < framebuffer_height; ++y) { - for (int x = 0; x < framebuffer_width; ++x) { + for (unsigned y = 0; y < framebuffer_height; ++y) { + for (unsigned x = 0; x < framebuffer_width; ++x) { u8* pixel_pointer = color_buffer + x * 3 + y * 3 * framebuffer_width; decoded_image.setPixel(x, y, qRgba(pixel_pointer[0], pixel_pointer[1], pixel_pointer[2], 255/*value >> 24*/)); @@ -254,8 +254,8 @@ void GraphicsFramebufferWidget::OnUpdate() { QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); u32* color_buffer = (u32*)Memory::GetPointer(framebuffer_address); - for (int y = 0; y < framebuffer_height; ++y) { - for (int x = 0; x < framebuffer_width; ++x) { + for (unsigned y = 0; y < framebuffer_height; ++y) { + for (unsigned x = 0; x < framebuffer_width; ++x) { u16 value = *(u16*)(((u8*)color_buffer) + x * 2 + y * framebuffer_width * 2); u8 r = (value >> 11) & 0x1F; u8 g = (value >> 6) & 0x1F; diff --git a/src/citra_qt/util/spinbox.cpp b/src/citra_qt/util/spinbox.cpp index 9672168f5..24ea3a967 100644 --- a/src/citra_qt/util/spinbox.cpp +++ b/src/citra_qt/util/spinbox.cpp @@ -238,7 +238,7 @@ QValidator::State CSpinBox::validate(QString& input, int& pos) const if (!prefix.isEmpty() && input.left(prefix.length()) != prefix) return QValidator::Invalid; - unsigned strpos = prefix.length(); + int strpos = prefix.length(); // Empty "numbers" allowed as intermediate values if (strpos >= input.length() - HasSign() - suffix.length()) -- cgit v1.2.3 From 8cd0d9c000e2c3cb072ca001db13f1c12f2a07ea Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Fri, 19 Dec 2014 18:37:14 +0100 Subject: citra-qt: static-constify a map. --- src/citra_qt/debugger/graphics_breakpoints.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp index 53394b6e6..469c3e268 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.cpp +++ b/src/citra_qt/debugger/graphics_breakpoints.cpp @@ -39,15 +39,16 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const switch (index.column()) { case 0: { - std::map map; - map.insert({Pica::DebugContext::Event::CommandLoaded, tr("Pica command loaded")}); - map.insert({Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed")}); - map.insert({Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch")}); - map.insert({Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch")}); + static const std::map map = { + { Pica::DebugContext::Event::CommandLoaded, tr("Pica command loaded") }, + { Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed") }, + { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") }, + { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") }, + }; _dbg_assert_(Debug_GPU, map.size() == static_cast(Pica::DebugContext::Event::NumEvents)); - return map[event]; + return (map.find(event) != map.end()) ? map.at(event) : QString(); } case 1: -- cgit v1.2.3 From fd2539121cddd6177a964770a6985f8880ca1646 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 6 Dec 2014 19:10:08 +0100 Subject: Pica: Initial support for multitexturing. --- src/citra_qt/debugger/graphics_cmdlists.cpp | 39 +++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 7f97cf143..bdd676470 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -223,9 +223,21 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) { const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt(); - if (COMMAND_IN_RANGE(command_id, texture0)) { - auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(Pica::registers.texture0, - Pica::registers.texture0_format); + if (COMMAND_IN_RANGE(command_id, texture0) || + COMMAND_IN_RANGE(command_id, texture1) || + COMMAND_IN_RANGE(command_id, texture2)) { + + unsigned index; + if (COMMAND_IN_RANGE(command_id, texture0)) { + index = 0; + } else if (COMMAND_IN_RANGE(command_id, texture1)) { + index = 1; + } else { + index = 2; + } + auto config = Pica::registers.GetTextures()[index].config; + auto format = Pica::registers.GetTextures()[index].format; + auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format); // TODO: Instead, emit a signal here to be caught by the main window widget. auto main_window = static_cast(parent()); @@ -237,10 +249,23 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) { QWidget* new_info_widget; const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt(); - if (COMMAND_IN_RANGE(command_id, texture0)) { - u8* src = Memory::GetPointer(Pica::registers.texture0.GetPhysicalAddress()); - auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(Pica::registers.texture0, - Pica::registers.texture0_format); + if (COMMAND_IN_RANGE(command_id, texture0) || + COMMAND_IN_RANGE(command_id, texture1) || + COMMAND_IN_RANGE(command_id, texture2)) { + + unsigned index; + if (COMMAND_IN_RANGE(command_id, texture0)) { + index = 0; + } else if (COMMAND_IN_RANGE(command_id, texture1)) { + index = 1; + } else { + index = 2; + } + auto config = Pica::registers.GetTextures()[index].config; + auto format = Pica::registers.GetTextures()[index].format; + + auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format); + u8* src = Memory::GetPointer(config.GetPhysicalAddress()); new_info_widget = new TextureInfoWidget(src, info); } else { new_info_widget = new QWidget; -- cgit v1.2.3 From 782592e6d393f4e38db5db58daba3f7fbf1786b4 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Mon, 15 Dec 2014 22:09:48 +0100 Subject: citra-qt: Fix invalid memory read upon program startup. This was caused by the framebuffer display widget not checking whether we are actually in a valid emulation state or not. --- src/citra_qt/debugger/graphics_framebuffer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index 61b61ef6d..c055299a4 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -125,7 +125,8 @@ GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptrat_breakpoint) + emit Update(); widget()->setEnabled(false); // TODO: Only enable if currently at breakpoint } -- cgit v1.2.3 From 3df88d59b0ba43f1c3360cfdaaccd461cacff72c Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 6 Dec 2014 21:52:21 +0100 Subject: Pica: Merge texture lookup logic for DebugUtils and Rasterizer. This effectively adds support for a lot texture formats in the rasterizer. --- src/citra_qt/debugger/graphics_cmdlists.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index bdd676470..01ff31d44 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -24,7 +24,7 @@ QImage LoadTexture(u8* src, const Pica::DebugUtils::TextureInfo& info) { QImage decoded_image(info.width, info.height, QImage::Format_ARGB32); for (int y = 0; y < info.height; ++y) { for (int x = 0; x < info.width; ++x) { - Math::Vec4 color = Pica::DebugUtils::LookupTexture(src, x, y, info); + Math::Vec4 color = Pica::DebugUtils::LookupTexture(src, x, y, info, true); decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a())); } } -- cgit v1.2.3 From 40f123b7c0eaf1507d51f6b87192ec2f956e5d5e Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Mon, 15 Dec 2014 21:28:45 +0100 Subject: Pica: Unify ugly address translation hacks. --- src/citra_qt/debugger/graphics_cmdlists.cpp | 8 ++++---- src/citra_qt/debugger/graphics_framebuffer.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 01ff31d44..bf35f035f 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -47,7 +47,7 @@ public: }; TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo& info, QWidget* parent) - : QDockWidget(tr("Texture 0x%1").arg(info.address, 8, 16, QLatin1Char('0'))), + : QDockWidget(tr("Texture 0x%1").arg(info.physical_address, 8, 16, QLatin1Char('0'))), info(info) { QWidget* main_widget = new QWidget; @@ -60,7 +60,7 @@ TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo phys_address_spinbox->SetBase(16); phys_address_spinbox->SetRange(0, 0xFFFFFFFF); phys_address_spinbox->SetPrefix("0x"); - phys_address_spinbox->SetValue(info.address); + phys_address_spinbox->SetValue(info.physical_address); connect(phys_address_spinbox, SIGNAL(ValueChanged(qint64)), this, SLOT(OnAddressChanged(qint64))); QComboBox* format_choice = new QComboBox; @@ -125,7 +125,7 @@ TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo } void TextureInfoDockWidget::OnAddressChanged(qint64 value) { - info.address = value; + info.physical_address = value; emit UpdatePixmap(ReloadPixmap()); } @@ -150,7 +150,7 @@ void TextureInfoDockWidget::OnStrideChanged(int value) { } QPixmap TextureInfoDockWidget::ReloadPixmap() const { - u8* src = Memory::GetPointer(info.address); + u8* src = Memory::GetPointer(Pica::PAddrToVAddr(info.physical_address)); return QPixmap::fromImage(LoadTexture(src, info)); } diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index c055299a4..484be1db5 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -199,7 +199,7 @@ void GraphicsFramebufferWidget::OnUpdate() auto framebuffer = Pica::registers.framebuffer; using Framebuffer = decltype(framebuffer); - framebuffer_address = framebuffer.GetColorBufferAddress(); + framebuffer_address = framebuffer.GetColorBufferPhysicalAddress(); framebuffer_width = framebuffer.GetWidth(); framebuffer_height = framebuffer.GetHeight(); framebuffer_format = static_cast(framebuffer.color_format); @@ -224,7 +224,7 @@ void GraphicsFramebufferWidget::OnUpdate() case Format::RGBA8: { QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); - u32* color_buffer = (u32*)Memory::GetPointer(framebuffer_address); + u32* color_buffer = (u32*)Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address)); for (unsigned y = 0; y < framebuffer_height; ++y) { for (unsigned x = 0; x < framebuffer_width; ++x) { u32 value = *(color_buffer + x + y * framebuffer_width); @@ -239,7 +239,7 @@ void GraphicsFramebufferWidget::OnUpdate() case Format::RGB8: { QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); - u8* color_buffer = Memory::GetPointer(framebuffer_address); + u8* color_buffer = Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address)); for (unsigned y = 0; y < framebuffer_height; ++y) { for (unsigned x = 0; x < framebuffer_width; ++x) { u8* pixel_pointer = color_buffer + x * 3 + y * 3 * framebuffer_width; @@ -254,7 +254,7 @@ void GraphicsFramebufferWidget::OnUpdate() case Format::RGBA5551: { QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32); - u32* color_buffer = (u32*)Memory::GetPointer(framebuffer_address); + u32* color_buffer = (u32*)Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address)); for (unsigned y = 0; y < framebuffer_height; ++y) { for (unsigned x = 0; x < framebuffer_width; ++x) { u16 value = *(u16*)(((u8*)color_buffer) + x * 2 + y * framebuffer_width * 2); -- cgit v1.2.3 From 1c972ef3b93252a157ec15d0878a2be3e4b46a0e Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Wed, 10 Dec 2014 21:51:00 +0100 Subject: Add support for a ridiculous number of texture formats. --- src/citra_qt/debugger/graphics_cmdlists.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index bf35f035f..95187e54d 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -69,6 +69,13 @@ TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo format_choice->addItem(tr("RGBA5551")); format_choice->addItem(tr("RGB565")); format_choice->addItem(tr("RGBA4")); + format_choice->addItem(tr("IA8")); + format_choice->addItem(tr("UNK6")); + format_choice->addItem(tr("I8")); + format_choice->addItem(tr("A8")); + format_choice->addItem(tr("IA4")); + format_choice->addItem(tr("UNK10")); + format_choice->addItem(tr("A4")); format_choice->setCurrentIndex(static_cast(info.format)); connect(format_choice, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFormatChanged(int))); @@ -265,7 +272,7 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) { auto format = Pica::registers.GetTextures()[index].format; auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format); - u8* src = Memory::GetPointer(config.GetPhysicalAddress()); + u8* src = Memory::GetPointer(Pica::PAddrToVAddr(config.GetPhysicalAddress())); new_info_widget = new TextureInfoWidget(src, info); } else { new_info_widget = new QWidget; -- cgit v1.2.3 From 79c29243ed94fb247dfa5a60e1863a8f64f11669 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Wed, 10 Dec 2014 17:31:50 +0100 Subject: Pica/DebugUtils: Add an event triggered after loading a vertex. --- src/citra_qt/debugger/graphics_breakpoints.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp index 469c3e268..4cb41db22 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.cpp +++ b/src/citra_qt/debugger/graphics_breakpoints.cpp @@ -44,6 +44,7 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const { Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed") }, { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") }, { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") }, + { Pica::DebugContext::Event::VertexLoaded, tr("Vertex Loaded") } }; _dbg_assert_(Debug_GPU, map.size() == static_cast(Pica::DebugContext::Event::NumEvents)); -- cgit v1.2.3 From ebfd831ccba32bce097491db3d6bdff0be05935e Mon Sep 17 00:00:00 2001 From: purpasmart96 Date: Tue, 16 Dec 2014 21:38:14 -0800 Subject: License change --- src/citra_qt/config.cpp | 2 +- src/citra_qt/config.h | 2 +- src/citra_qt/debugger/graphics.cpp | 2 +- src/citra_qt/debugger/graphics.hxx | 2 +- src/citra_qt/debugger/graphics_breakpoints.cpp | 2 +- src/citra_qt/debugger/graphics_breakpoints.hxx | 2 +- src/citra_qt/debugger/graphics_breakpoints_p.hxx | 2 +- src/citra_qt/debugger/graphics_cmdlists.cpp | 2 +- src/citra_qt/debugger/graphics_cmdlists.hxx | 2 +- src/citra_qt/debugger/graphics_framebuffer.cpp | 2 +- src/citra_qt/debugger/graphics_framebuffer.hxx | 2 +- src/citra_qt/util/spinbox.cpp | 2 +- src/citra_qt/util/spinbox.hxx | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 0ae6b8b2d..0fea8e4f9 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -1,5 +1,5 @@ // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h index 4c95d0cb9..4485cae73 100644 --- a/src/citra_qt/config.h +++ b/src/citra_qt/config.h @@ -1,5 +1,5 @@ // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once diff --git a/src/citra_qt/debugger/graphics.cpp b/src/citra_qt/debugger/graphics.cpp index a86a55404..6ff4c290d 100644 --- a/src/citra_qt/debugger/graphics.cpp +++ b/src/citra_qt/debugger/graphics.cpp @@ -1,5 +1,5 @@ // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include "graphics.hxx" diff --git a/src/citra_qt/debugger/graphics.hxx b/src/citra_qt/debugger/graphics.hxx index 72656f93c..8119b4c87 100644 --- a/src/citra_qt/debugger/graphics.hxx +++ b/src/citra_qt/debugger/graphics.hxx @@ -1,5 +1,5 @@ // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp index 53394b6e6..e391f895b 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.cpp +++ b/src/citra_qt/debugger/graphics_breakpoints.cpp @@ -1,5 +1,5 @@ // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include diff --git a/src/citra_qt/debugger/graphics_breakpoints.hxx b/src/citra_qt/debugger/graphics_breakpoints.hxx index 2142c6fa1..5b9ba324e 100644 --- a/src/citra_qt/debugger/graphics_breakpoints.hxx +++ b/src/citra_qt/debugger/graphics_breakpoints.hxx @@ -1,5 +1,5 @@ // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once diff --git a/src/citra_qt/debugger/graphics_breakpoints_p.hxx b/src/citra_qt/debugger/graphics_breakpoints_p.hxx index bf5daf73d..232bfc863 100644 --- a/src/citra_qt/debugger/graphics_breakpoints_p.hxx +++ b/src/citra_qt/debugger/graphics_breakpoints_p.hxx @@ -1,5 +1,5 @@ // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 7f97cf143..83102c647 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -1,5 +1,5 @@ // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx index a459bba64..a465d044c 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.hxx +++ b/src/citra_qt/debugger/graphics_cmdlists.hxx @@ -1,5 +1,5 @@ // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index ac47f298d..fb62e8f17 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -1,5 +1,5 @@ // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include diff --git a/src/citra_qt/debugger/graphics_framebuffer.hxx b/src/citra_qt/debugger/graphics_framebuffer.hxx index 1151ee7a1..56215761e 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.hxx +++ b/src/citra_qt/debugger/graphics_framebuffer.hxx @@ -1,5 +1,5 @@ // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once diff --git a/src/citra_qt/util/spinbox.cpp b/src/citra_qt/util/spinbox.cpp index 9672168f5..3f28fdbab 100644 --- a/src/citra_qt/util/spinbox.cpp +++ b/src/citra_qt/util/spinbox.cpp @@ -1,4 +1,4 @@ -// Licensed under GPLv2+ +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/citra_qt/util/spinbox.hxx b/src/citra_qt/util/spinbox.hxx index 68f5b9894..ee7f08ec2 100644 --- a/src/citra_qt/util/spinbox.hxx +++ b/src/citra_qt/util/spinbox.hxx @@ -1,4 +1,4 @@ -// Licensed under GPLv2+ +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. -- cgit v1.2.3 From 9d90b26020af83d11ec0900117495901d445e907 Mon Sep 17 00:00:00 2001 From: Daniel Lundqvist Date: Fri, 26 Dec 2014 02:37:52 +0100 Subject: Allow focus on the Qt render widget By default widgets are set to the focus policy Qt::NoFocus which disallows manually focusing it. Changing the policy to allow clicking the widget to set focus to it allows for keyboard input when not rendering to a popout window. This commit also sets focus to the widget when showing it. Fixes issue #158. --- src/citra_qt/bootmanager.cpp | 3 +++ src/citra_qt/main.cpp | 1 + 2 files changed, 4 insertions(+) (limited to 'src/citra_qt') diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 6d08d6afc..d44ddb096 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -123,6 +123,9 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); setWindowTitle(QString::fromStdString(window_title)); + // Allow manually setting focus to the widget. + setFocusPolicy(Qt::ClickFocus); + keyboard_id = KeyMap::NewDeviceId(); ReloadSetKeymaps(); diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 23d4925b8..9fc8705e6 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -170,6 +170,7 @@ void GMainWindow::BootGame(std::string filename) render_window->GetEmuThread().start(); render_window->show(); + render_window->setFocus(); OnStartGame(); } -- cgit v1.2.3 From ba4ca041f4be1285185a56ba37ae2023c27a326b Mon Sep 17 00:00:00 2001 From: Daniel Lundqvist Date: Fri, 26 Dec 2014 19:42:27 +0100 Subject: Allow focus only when in popout mode Only allow manually setting focus to the rendering widget when in Single Window mode. Apply this behavior to when changing the mode while an app is running. --- src/citra_qt/bootmanager.cpp | 3 --- src/citra_qt/main.cpp | 11 ++++++++++- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index d44ddb096..6d08d6afc 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -123,9 +123,6 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); setWindowTitle(QString::fromStdString(window_title)); - // Allow manually setting focus to the widget. - setFocusPolicy(Qt::ClickFocus); - keyboard_id = KeyMap::NewDeviceId(); ReloadSetKeymaps(); diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 9fc8705e6..37d69ac13 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -170,7 +170,13 @@ void GMainWindow::BootGame(std::string filename) render_window->GetEmuThread().start(); render_window->show(); - render_window->setFocus(); + + // Allow manually setting focus to the render widget if not using popout mode. + if (!ui.action_Popout_Window_Mode->isChecked()) { + render_window->setFocusPolicy(Qt::ClickFocus); + render_window->setFocus(); + } + OnStartGame(); } @@ -231,12 +237,15 @@ void GMainWindow::ToggleWindowMode() render_window->setParent(nullptr); render_window->setVisible(true); render_window->RestoreGeometry(); + render_window->setFocusPolicy(Qt::NoFocus); } else if (!enable && render_window->parent() == nullptr) { render_window->BackupGeometry(); ui.horizontalLayout->addWidget(render_window); render_window->setVisible(true); + render_window->setFocusPolicy(Qt::ClickFocus); + render_window->setFocus(); } } -- cgit v1.2.3 From 7e3f62a367856ef5e6b449abeb3a7ce45e619533 Mon Sep 17 00:00:00 2001 From: Daniel Lundqvist Date: Fri, 26 Dec 2014 20:12:11 +0100 Subject: Remove duplicate work --- src/citra_qt/main.cpp | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 37d69ac13..b12e6a02b 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -170,13 +170,6 @@ void GMainWindow::BootGame(std::string filename) render_window->GetEmuThread().start(); render_window->show(); - - // Allow manually setting focus to the render widget if not using popout mode. - if (!ui.action_Popout_Window_Mode->isChecked()) { - render_window->setFocusPolicy(Qt::ClickFocus); - render_window->setFocus(); - } - OnStartGame(); } -- cgit v1.2.3 From a2005d06574885d7406b427988de25f339e4f3c7 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 26 Dec 2014 21:32:48 -0500 Subject: GPU: Change internal framerate to 30fps. --- src/citra_qt/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 0fea8e4f9..fd14686f2 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -44,7 +44,7 @@ void Config::ReadValues() { 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", 60).toInt(); + Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 30).toInt(); qt_config->endGroup(); qt_config->beginGroup("Data Storage"); -- cgit v1.2.3 From 8de09d87ab529f6f9525b784de4343b7aa4d6bf9 Mon Sep 17 00:00:00 2001 From: xdec Date: Sun, 28 Dec 2014 01:56:07 -0800 Subject: Fix crash when the disassembler pause button is pressed while no game is running. --- src/citra_qt/debugger/disassembler.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index 2ee877743..159f4d65e 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp @@ -220,7 +220,9 @@ void DisassemblerWidget::OnPause() emu_thread.SetCpuRunning(false); // TODO: By now, the CPU might not have actually stopped... - model->SetNextInstruction(Core::g_app_core->GetPC()); + if (model && Core::g_app_core) { + model->SetNextInstruction(Core::g_app_core->GetPC()); + } } void DisassemblerWidget::OnToggleStartStop() -- cgit v1.2.3 From e6162ed91e29c356af1007f9b9545d4d076570c9 Mon Sep 17 00:00:00 2001 From: xdec Date: Sun, 28 Dec 2014 10:11:51 -0800 Subject: Qt: we don't need to check if model is valid. --- src/citra_qt/debugger/disassembler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/citra_qt') diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index 159f4d65e..14745f3bb 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp @@ -220,7 +220,7 @@ void DisassemblerWidget::OnPause() emu_thread.SetCpuRunning(false); // TODO: By now, the CPU might not have actually stopped... - if (model && Core::g_app_core) { + if (Core::g_app_core) { model->SetNextInstruction(Core::g_app_core->GetPC()); } } -- cgit v1.2.3 From 3b9d181b8e0f1c3c2452497bdf65bbb65ab7c213 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 26 Dec 2014 21:40:17 -0500 Subject: GPU: Implement frameskip and remove forced framebuffer swap hack. --- src/citra_qt/config.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/citra_qt') diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index fd14686f2..1596c08d7 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -45,6 +45,7 @@ void Config::ReadValues() { 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(); qt_config->beginGroup("Data Storage"); @@ -80,6 +81,7 @@ void Config::SaveValues() { 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(); qt_config->beginGroup("Data Storage"); -- cgit v1.2.3