citra_qt: Improve graphics API intergration
* Add renderer debug option which toggles debug output in OpenGL/validation layers in Vulkan * Fix many warnings and replace deprecated Qt functionailty with newer alternatives
This commit is contained in:
@ -7,17 +7,8 @@
|
|||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
// This needs to be included before getopt.h because the latter #defines symbols used by it
|
// This needs to be included before getopt.h because the latter #defines symbols used by it
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
// windows.h needs to be included before shellapi.h
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#include <shellapi.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "citra/config.h"
|
#include "citra/config.h"
|
||||||
#include "citra/emu_window/emu_window_sdl2.h"
|
#include "citra/emu_window/emu_window_sdl2.h"
|
||||||
#include "citra/lodepng_image_interface.h"
|
#include "citra/lodepng_image_interface.h"
|
||||||
@ -25,20 +16,15 @@
|
|||||||
#include "common/detached_tasks.h"
|
#include "common/detached_tasks.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/backend.h"
|
#include "common/logging/backend.h"
|
||||||
#include "common/logging/filter.h"
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scm_rev.h"
|
#include "common/scm_rev.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "common/string_util.h"
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/dumping/backend.h"
|
#include "core/dumping/backend.h"
|
||||||
#include "core/file_sys/cia_container.h"
|
|
||||||
#include "core/frontend/applets/default_applets.h"
|
#include "core/frontend/applets/default_applets.h"
|
||||||
#include "core/frontend/framebuffer_layout.h"
|
#include "core/frontend/framebuffer_layout.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
|
||||||
#include "core/hle/service/am/am.h"
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/cfg/cfg.h"
|
#include "core/hle/service/cfg/cfg.h"
|
||||||
#include "core/loader/loader.h"
|
|
||||||
#include "core/movie.h"
|
#include "core/movie.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
@ -51,6 +37,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
// windows.h needs to be included before shellapi.h
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
// tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics
|
// tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics
|
||||||
__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
|
__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
|
||||||
@ -103,35 +93,35 @@ static void OnNetworkError(const Network::RoomMember::Error& error) {
|
|||||||
break;
|
break;
|
||||||
case Network::RoomMember::Error::CouldNotConnect:
|
case Network::RoomMember::Error::CouldNotConnect:
|
||||||
LOG_ERROR(Network, "Error: Could not connect");
|
LOG_ERROR(Network, "Error: Could not connect");
|
||||||
exit(1);
|
std::exit(1);
|
||||||
break;
|
break;
|
||||||
case Network::RoomMember::Error::NameCollision:
|
case Network::RoomMember::Error::NameCollision:
|
||||||
LOG_ERROR(
|
LOG_ERROR(
|
||||||
Network,
|
Network,
|
||||||
"You tried to use the same nickname as another user that is connected to the Room");
|
"You tried to use the same nickname as another user that is connected to the Room");
|
||||||
exit(1);
|
std::exit(1);
|
||||||
break;
|
break;
|
||||||
case Network::RoomMember::Error::MacCollision:
|
case Network::RoomMember::Error::MacCollision:
|
||||||
LOG_ERROR(Network, "You tried to use the same MAC-Address as another user that is "
|
LOG_ERROR(Network, "You tried to use the same MAC-Address as another user that is "
|
||||||
"connected to the Room");
|
"connected to the Room");
|
||||||
exit(1);
|
std::exit(1);
|
||||||
break;
|
break;
|
||||||
case Network::RoomMember::Error::ConsoleIdCollision:
|
case Network::RoomMember::Error::ConsoleIdCollision:
|
||||||
LOG_ERROR(Network, "Your Console ID conflicted with someone else in the Room");
|
LOG_ERROR(Network, "Your Console ID conflicted with someone else in the Room");
|
||||||
exit(1);
|
std::exit(1);
|
||||||
break;
|
break;
|
||||||
case Network::RoomMember::Error::WrongPassword:
|
case Network::RoomMember::Error::WrongPassword:
|
||||||
LOG_ERROR(Network, "Room replied with: Wrong password");
|
LOG_ERROR(Network, "Room replied with: Wrong password");
|
||||||
exit(1);
|
std::exit(1);
|
||||||
break;
|
break;
|
||||||
case Network::RoomMember::Error::WrongVersion:
|
case Network::RoomMember::Error::WrongVersion:
|
||||||
LOG_ERROR(Network,
|
LOG_ERROR(Network,
|
||||||
"You are using a different version than the room you are trying to connect to");
|
"You are using a different version than the room you are trying to connect to");
|
||||||
exit(1);
|
std::exit(1);
|
||||||
break;
|
break;
|
||||||
case Network::RoomMember::Error::RoomIsFull:
|
case Network::RoomMember::Error::RoomIsFull:
|
||||||
LOG_ERROR(Network, "The room is full");
|
LOG_ERROR(Network, "The room is full");
|
||||||
exit(1);
|
std::exit(1);
|
||||||
break;
|
break;
|
||||||
case Network::RoomMember::Error::HostKicked:
|
case Network::RoomMember::Error::HostKicked:
|
||||||
LOG_ERROR(Network, "You have been kicked by the host");
|
LOG_ERROR(Network, "You have been kicked by the host");
|
||||||
@ -139,6 +129,8 @@ static void OnNetworkError(const Network::RoomMember::Error& error) {
|
|||||||
case Network::RoomMember::Error::HostBanned:
|
case Network::RoomMember::Error::HostBanned:
|
||||||
LOG_ERROR(Network, "You have been banned by the host");
|
LOG_ERROR(Network, "You have been banned by the host");
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR(Network, "Unknown network error {}", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QOffscreenSurface>
|
#include <QOffscreenSurface>
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
#include <QOpenGLFunctions_4_3_Core>
|
|
||||||
#include <QOpenGLExtraFunctions>
|
#include <QOpenGLExtraFunctions>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include "citra_qt/bootmanager.h"
|
#include "citra_qt/bootmanager.h"
|
||||||
@ -34,11 +33,13 @@ EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(cor
|
|||||||
EmuThread::~EmuThread() = default;
|
EmuThread::~EmuThread() = default;
|
||||||
|
|
||||||
static GMainWindow* GetMainWindow() {
|
static GMainWindow* GetMainWindow() {
|
||||||
for (QWidget* w : qApp->topLevelWidgets()) {
|
const auto widgets = qApp->topLevelWidgets();
|
||||||
|
for (QWidget* w : widgets) {
|
||||||
if (GMainWindow* main = qobject_cast<GMainWindow*>(w)) {
|
if (GMainWindow* main = qobject_cast<GMainWindow*>(w)) {
|
||||||
return main;
|
return main;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +49,8 @@ void EmuThread::run() {
|
|||||||
|
|
||||||
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
|
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
|
||||||
|
|
||||||
Core::System::GetInstance().Renderer().Rasterizer()->LoadDiskResources(
|
Core::System& system = Core::System::GetInstance();
|
||||||
|
system.Renderer().Rasterizer()->LoadDiskResources(
|
||||||
stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
|
stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
|
||||||
emit LoadProgress(stage, value, total);
|
emit LoadProgress(stage, value, total);
|
||||||
});
|
});
|
||||||
@ -58,18 +60,17 @@ void EmuThread::run() {
|
|||||||
|
|
||||||
core_context.MakeCurrent();
|
core_context.MakeCurrent();
|
||||||
|
|
||||||
if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) {
|
if (system.frame_limiter.IsFrameAdvancing()) {
|
||||||
// Usually the loading screen is hidden after the first frame is drawn. In this case
|
// Usually the loading screen is hidden after the first frame is drawn. In this case
|
||||||
// we hide it immediately as we need to wait for user input to start the emulation.
|
// we hide it immediately as we need to wait for user input to start the emulation.
|
||||||
emit HideLoadingScreen();
|
emit HideLoadingScreen();
|
||||||
Core::System::GetInstance().frame_limiter.WaitOnce();
|
system.frame_limiter.WaitOnce();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Holds whether the cpu was running during the last iteration,
|
// Holds whether the cpu was running during the last iteration,
|
||||||
// so that the DebugModeLeft signal can be emitted before the
|
// so that the DebugModeLeft signal can be emitted before the
|
||||||
// next execution step.
|
// next execution step.
|
||||||
bool was_active = false;
|
bool was_active = false;
|
||||||
Core::System& system = Core::System::GetInstance();
|
|
||||||
while (!stop_run) {
|
while (!stop_run) {
|
||||||
if (running) {
|
if (running) {
|
||||||
if (!was_active)
|
if (!was_active)
|
||||||
@ -119,8 +120,20 @@ public:
|
|||||||
/// Create the original context that should be shared from
|
/// Create the original context that should be shared from
|
||||||
explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
|
explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
|
||||||
QSurfaceFormat format;
|
QSurfaceFormat format;
|
||||||
|
|
||||||
|
if (Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES) {
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||||
|
format.setVersion(3, 2);
|
||||||
|
} else {
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
|
||||||
format.setVersion(4, 4);
|
format.setVersion(4, 4);
|
||||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Settings::values.renderer_debug) {
|
||||||
|
format.setOption(QSurfaceFormat::FormatOption::DebugContext);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: expose a setting for buffer value (ie default/single/double/triple)
|
// TODO: expose a setting for buffer value (ie default/single/double/triple)
|
||||||
format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
|
format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
|
||||||
format.setSwapInterval(0);
|
format.setSwapInterval(0);
|
||||||
@ -630,14 +643,6 @@ bool GRenderWindow::InitializeOpenGL() {
|
|||||||
child->SetContext(
|
child->SetContext(
|
||||||
std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle()));
|
std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle()));
|
||||||
|
|
||||||
// Check for OpenGL 4.3 support
|
|
||||||
if (!QOpenGLContext::globalShareContext()->versionFunctions<QOpenGLFunctions_4_3_Core>()) {
|
|
||||||
QMessageBox::critical(this, tr("OpenGL 4.3 Unsupported"),
|
|
||||||
tr("Your GPU may not support OpenGL 4.3, or you do not "
|
|
||||||
"have the latest graphics driver."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ bool CheatDialog::SaveCheat(int row) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the cheat lines are valid
|
// Check if the cheat lines are valid
|
||||||
auto code_lines = ui->textCode->toPlainText().split(QLatin1Char{'\n'}, QString::SkipEmptyParts);
|
auto code_lines = ui->textCode->toPlainText().split(QLatin1Char{'\n'}, Qt::SkipEmptyParts);
|
||||||
for (int i = 0; i < code_lines.size(); ++i) {
|
for (int i = 0; i < code_lines.size(); ++i) {
|
||||||
Cheats::GatewayCheat::CheatLine cheat_line(code_lines[i].toStdString());
|
Cheats::GatewayCheat::CheatLine cheat_line(code_lines[i].toStdString());
|
||||||
if (cheat_line.valid)
|
if (cheat_line.valid)
|
||||||
|
@ -482,6 +482,10 @@ void Config::ReadPathValues() {
|
|||||||
void Config::ReadRendererValues() {
|
void Config::ReadRendererValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("Renderer"));
|
qt_config->beginGroup(QStringLiteral("Renderer"));
|
||||||
|
|
||||||
|
Settings::values.graphics_api = static_cast<Settings::GraphicsAPI>(
|
||||||
|
ReadSetting(QStringLiteral("graphics_api"), static_cast<u32>(Settings::GraphicsAPI::OpenGL))
|
||||||
|
.toUInt());
|
||||||
|
Settings::values.renderer_debug = ReadSetting(QStringLiteral("renderer_debug"), false).toBool();
|
||||||
Settings::values.use_hw_renderer =
|
Settings::values.use_hw_renderer =
|
||||||
ReadSetting(QStringLiteral("use_hw_renderer"), true).toBool();
|
ReadSetting(QStringLiteral("use_hw_renderer"), true).toBool();
|
||||||
Settings::values.use_hw_shader = ReadSetting(QStringLiteral("use_hw_shader"), true).toBool();
|
Settings::values.use_hw_shader = ReadSetting(QStringLiteral("use_hw_shader"), true).toBool();
|
||||||
@ -521,7 +525,7 @@ void Config::ReadRendererValues() {
|
|||||||
void Config::ReadShortcutValues() {
|
void Config::ReadShortcutValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("Shortcuts"));
|
qt_config->beginGroup(QStringLiteral("Shortcuts"));
|
||||||
|
|
||||||
for (auto [name, group, shortcut] : default_hotkeys) {
|
for (const auto& [name, group, shortcut] : default_hotkeys) {
|
||||||
auto [keyseq, context] = shortcut;
|
auto [keyseq, context] = shortcut;
|
||||||
qt_config->beginGroup(group);
|
qt_config->beginGroup(group);
|
||||||
qt_config->beginGroup(name);
|
qt_config->beginGroup(name);
|
||||||
@ -556,7 +560,7 @@ void Config::ReadSystemValues() {
|
|||||||
// https://developers.google.com/media/vp9/live-encoding
|
// https://developers.google.com/media/vp9/live-encoding
|
||||||
const QString DEFAULT_VIDEO_ENCODER_OPTIONS =
|
const QString DEFAULT_VIDEO_ENCODER_OPTIONS =
|
||||||
QStringLiteral("quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1");
|
QStringLiteral("quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1");
|
||||||
const QString DEFAULT_AUDIO_ENCODER_OPTIONS = QString{};
|
const QString DEFAULT_AUDIO_ENCODER_OPTIONS = QStringLiteral("");
|
||||||
|
|
||||||
void Config::ReadVideoDumpingValues() {
|
void Config::ReadVideoDumpingValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("VideoDumping"));
|
qt_config->beginGroup(QStringLiteral("VideoDumping"));
|
||||||
@ -994,6 +998,9 @@ void Config::SavePathValues() {
|
|||||||
void Config::SaveRendererValues() {
|
void Config::SaveRendererValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("Renderer"));
|
qt_config->beginGroup(QStringLiteral("Renderer"));
|
||||||
|
|
||||||
|
WriteSetting(QStringLiteral("graphics_api"), static_cast<u32>(Settings::values.graphics_api),
|
||||||
|
static_cast<u32>(Settings::GraphicsAPI::OpenGL));
|
||||||
|
WriteSetting(QStringLiteral("renderer_debug"), Settings::values.renderer_debug, false);
|
||||||
WriteSetting(QStringLiteral("use_hw_renderer"), Settings::values.use_hw_renderer, true);
|
WriteSetting(QStringLiteral("use_hw_renderer"), Settings::values.use_hw_renderer, true);
|
||||||
WriteSetting(QStringLiteral("use_hw_shader"), Settings::values.use_hw_shader, true);
|
WriteSetting(QStringLiteral("use_hw_shader"), Settings::values.use_hw_shader, true);
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
@ -1015,9 +1022,9 @@ void Config::SaveRendererValues() {
|
|||||||
200);
|
200);
|
||||||
|
|
||||||
// Cast to double because Qt's written float values are not human-readable
|
// Cast to double because Qt's written float values are not human-readable
|
||||||
WriteSetting(QStringLiteral("bg_red"), (double)Settings::values.bg_red, 0.0);
|
WriteSetting(QStringLiteral("bg_red"), static_cast<double>(Settings::values.bg_red), 0.0);
|
||||||
WriteSetting(QStringLiteral("bg_green"), (double)Settings::values.bg_green, 0.0);
|
WriteSetting(QStringLiteral("bg_green"), static_cast<double>(Settings::values.bg_green), 0.0);
|
||||||
WriteSetting(QStringLiteral("bg_blue"), (double)Settings::values.bg_blue, 0.0);
|
WriteSetting(QStringLiteral("bg_blue"), static_cast<double>(Settings::values.bg_blue), 0.0);
|
||||||
|
|
||||||
WriteSetting(QStringLiteral("texture_filter_name"),
|
WriteSetting(QStringLiteral("texture_filter_name"),
|
||||||
QString::fromStdString(Settings::values.texture_filter_name),
|
QString::fromStdString(Settings::values.texture_filter_name),
|
||||||
|
@ -8,8 +8,6 @@
|
|||||||
#include "citra_qt/debugger/console.h"
|
#include "citra_qt/debugger/console.h"
|
||||||
#include "citra_qt/uisettings.h"
|
#include "citra_qt/uisettings.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/backend.h"
|
|
||||||
#include "common/logging/filter.h"
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
@ -24,7 +22,10 @@ ConfigureDebug::ConfigureDebug(QWidget* parent)
|
|||||||
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
|
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
|
||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||||
});
|
});
|
||||||
ui->toggle_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
|
||||||
|
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
|
||||||
|
ui->toggle_cpu_jit->setEnabled(!is_powered_on);
|
||||||
|
ui->toggle_renderer_debug->setEnabled(!is_powered_on);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigureDebug::~ConfigureDebug() = default;
|
ConfigureDebug::~ConfigureDebug() = default;
|
||||||
@ -37,6 +38,7 @@ void ConfigureDebug::SetConfiguration() {
|
|||||||
ui->toggle_console->setChecked(UISettings::values.show_console);
|
ui->toggle_console->setChecked(UISettings::values.show_console);
|
||||||
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
|
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
|
||||||
ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit);
|
ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit);
|
||||||
|
ui->toggle_renderer_debug->setChecked(Settings::values.renderer_debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureDebug::ApplyConfiguration() {
|
void ConfigureDebug::ApplyConfiguration() {
|
||||||
@ -49,6 +51,7 @@ void ConfigureDebug::ApplyConfiguration() {
|
|||||||
filter.ParseFilterString(Settings::values.log_filter);
|
filter.ParseFilterString(Settings::values.log_filter);
|
||||||
Log::SetGlobalFilter(filter);
|
Log::SetGlobalFilter(filter);
|
||||||
Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked();
|
Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked();
|
||||||
|
Settings::values.renderer_debug = ui->toggle_renderer_debug->isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureDebug::RetranslateUI() {
|
void ConfigureDebug::RetranslateUI() {
|
||||||
|
@ -114,11 +114,24 @@
|
|||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="toggle_cpu_jit">
|
<widget class="QCheckBox" name="toggle_cpu_jit">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Enables the use of the ARM JIT compiler for emulating the 3DS CPUs. Don't disable unless for debugging purposes</p></body></html></string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Enable CPU JIT</string>
|
<string>Enable CPU JIT</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="toggle_renderer_debug">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Enables debug reporting in the currently selected graphics API. Causes measurable performance loss, don't enable unless for debugging purposes</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable debug renderer</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#include "citra_qt/util/spinbox.h"
|
#include "citra_qt/util/spinbox.h"
|
||||||
#include "common/color.h"
|
#include "common/color.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hw/gpu.h"
|
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
#include "video_core/regs_framebuffer.h"
|
#include "video_core/regs_framebuffer.h"
|
||||||
@ -34,12 +33,15 @@ void SurfacePicture::mousePressEvent(QMouseEvent* event) {
|
|||||||
if (!(event->buttons() & Qt::LeftButton))
|
if (!(event->buttons() & Qt::LeftButton))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (pixmap() == nullptr)
|
const QPixmap pixmap = this->pixmap(Qt::ReturnByValue);
|
||||||
|
if (pixmap.isNull()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (surface_widget)
|
if (surface_widget) {
|
||||||
surface_widget->Pick(event->x() * pixmap()->width() / width(),
|
surface_widget->Pick(event->x() * pixmap.width() / width(),
|
||||||
event->y() * pixmap()->height() / height());
|
event->y() * pixmap.height() / height());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfacePicture::mouseMoveEvent(QMouseEvent* event) {
|
void SurfacePicture::mouseMoveEvent(QMouseEvent* event) {
|
||||||
@ -314,48 +316,48 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
|||||||
case Format::RGBA8: {
|
case Format::RGBA8: {
|
||||||
auto value = Color::DecodeRGBA8(pixel) / 255.0f;
|
auto value = Color::DecodeRGBA8(pixel) / 255.0f;
|
||||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
||||||
.arg(QString::number(value.r(), 'f', 2))
|
.arg(QString::number(value.r(), 'f', 2),
|
||||||
.arg(QString::number(value.g(), 'f', 2))
|
QString::number(value.g(), 'f', 2),
|
||||||
.arg(QString::number(value.b(), 'f', 2))
|
QString::number(value.b(), 'f', 2),
|
||||||
.arg(QString::number(value.a(), 'f', 2));
|
QString::number(value.a(), 'f', 2));
|
||||||
}
|
}
|
||||||
case Format::RGB8: {
|
case Format::RGB8: {
|
||||||
auto value = Color::DecodeRGB8(pixel) / 255.0f;
|
auto value = Color::DecodeRGB8(pixel) / 255.0f;
|
||||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
|
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
|
||||||
.arg(QString::number(value.r(), 'f', 2))
|
.arg(QString::number(value.r(), 'f', 2),
|
||||||
.arg(QString::number(value.g(), 'f', 2))
|
QString::number(value.g(), 'f', 2),
|
||||||
.arg(QString::number(value.b(), 'f', 2));
|
QString::number(value.b(), 'f', 2));
|
||||||
}
|
}
|
||||||
case Format::RGB5A1: {
|
case Format::RGB5A1: {
|
||||||
auto value = Color::DecodeRGB5A1(pixel) / 255.0f;
|
auto value = Color::DecodeRGB5A1(pixel) / 255.0f;
|
||||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
||||||
.arg(QString::number(value.r(), 'f', 2))
|
.arg(QString::number(value.r(), 'f', 2),
|
||||||
.arg(QString::number(value.g(), 'f', 2))
|
QString::number(value.g(), 'f', 2),
|
||||||
.arg(QString::number(value.b(), 'f', 2))
|
QString::number(value.b(), 'f', 2),
|
||||||
.arg(QString::number(value.a(), 'f', 2));
|
QString::number(value.a(), 'f', 2));
|
||||||
}
|
}
|
||||||
case Format::RGB565: {
|
case Format::RGB565: {
|
||||||
auto value = Color::DecodeRGB565(pixel) / 255.0f;
|
auto value = Color::DecodeRGB565(pixel) / 255.0f;
|
||||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
|
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
|
||||||
.arg(QString::number(value.r(), 'f', 2))
|
.arg(QString::number(value.r(), 'f', 2),
|
||||||
.arg(QString::number(value.g(), 'f', 2))
|
QString::number(value.g(), 'f', 2),
|
||||||
.arg(QString::number(value.b(), 'f', 2));
|
QString::number(value.b(), 'f', 2));
|
||||||
}
|
}
|
||||||
case Format::RGBA4: {
|
case Format::RGBA4: {
|
||||||
auto value = Color::DecodeRGBA4(pixel) / 255.0f;
|
auto value = Color::DecodeRGBA4(pixel) / 255.0f;
|
||||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
||||||
.arg(QString::number(value.r(), 'f', 2))
|
.arg(QString::number(value.r(), 'f', 2),
|
||||||
.arg(QString::number(value.g(), 'f', 2))
|
QString::number(value.g(), 'f', 2),
|
||||||
.arg(QString::number(value.b(), 'f', 2))
|
QString::number(value.b(), 'f', 2),
|
||||||
.arg(QString::number(value.a(), 'f', 2));
|
QString::number(value.a(), 'f', 2));
|
||||||
}
|
}
|
||||||
case Format::IA8:
|
case Format::IA8:
|
||||||
return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0]).arg(pixel[1]);
|
return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0], pixel[1]);
|
||||||
case Format::RG8: {
|
case Format::RG8: {
|
||||||
auto value = Color::DecodeRG8(pixel) / 255.0f;
|
auto value = Color::DecodeRG8(pixel) / 255.0f;
|
||||||
return QStringLiteral("Red: %1, Green: %2")
|
return QStringLiteral("Red: %1, Green: %2")
|
||||||
.arg(QString::number(value.r(), 'f', 2))
|
.arg(QString::number(value.r(), 'f', 2),
|
||||||
.arg(QString::number(value.g(), 'f', 2));
|
QString::number(value.g(), 'f', 2));
|
||||||
}
|
}
|
||||||
case Format::I8:
|
case Format::I8:
|
||||||
return QStringLiteral("Index: %1").arg(*pixel);
|
return QStringLiteral("Index: %1").arg(*pixel);
|
||||||
@ -363,8 +365,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
|||||||
return QStringLiteral("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2));
|
return QStringLiteral("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2));
|
||||||
case Format::IA4:
|
case Format::IA4:
|
||||||
return QStringLiteral("Index: %1, Alpha: %2")
|
return QStringLiteral("Index: %1, Alpha: %2")
|
||||||
.arg(*pixel & 0xF)
|
.arg(*pixel & 0xF, (*pixel & 0xF0) >> 4);
|
||||||
.arg((*pixel & 0xF0) >> 4);
|
|
||||||
case Format::I4: {
|
case Format::I4: {
|
||||||
u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF;
|
u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF;
|
||||||
return QStringLiteral("Index: %1").arg(i);
|
return QStringLiteral("Index: %1").arg(i);
|
||||||
@ -390,8 +391,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
|||||||
case Format::X24S8: {
|
case Format::X24S8: {
|
||||||
auto values = Color::DecodeD24S8(pixel);
|
auto values = Color::DecodeD24S8(pixel);
|
||||||
return QStringLiteral("Depth: %1, Stencil: %2")
|
return QStringLiteral("Depth: %1, Stencil: %2")
|
||||||
.arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4))
|
.arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4), values[1]);
|
||||||
.arg(values[1]);
|
|
||||||
}
|
}
|
||||||
case Format::Unknown:
|
case Format::Unknown:
|
||||||
return QStringLiteral("Unknown format");
|
return QStringLiteral("Unknown format");
|
||||||
@ -401,8 +401,8 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
QString nibbles;
|
QString nibbles;
|
||||||
for (unsigned i = 0; i < nibbles_per_pixel; i++) {
|
for (u32 i = 0; i < nibbles_per_pixel; i++) {
|
||||||
unsigned nibble_index = i;
|
u32 nibble_index = i;
|
||||||
if (nibble_mode) {
|
if (nibble_mode) {
|
||||||
nibble_index += (offset % 2) ? 0 : 1;
|
nibble_index += (offset % 2) ? 0 : 1;
|
||||||
}
|
}
|
||||||
@ -412,7 +412,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
surface_info_label->setText(
|
surface_info_label->setText(
|
||||||
QStringLiteral("Raw: 0x%3\n(%4)").arg(nibbles).arg(GetText(surface_format, pixel)));
|
QStringLiteral("Raw: 0x%3\n(%4)").arg(nibbles, GetText(surface_format, pixel)));
|
||||||
surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,8 +676,8 @@ void GraphicsSurfaceWidget::SaveSurface() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (selected_filter == png_filter) {
|
if (selected_filter == png_filter) {
|
||||||
const QPixmap* const pixmap = surface_picture_label->pixmap();
|
const QPixmap pixmap = surface_picture_label->pixmap(Qt::ReturnByValue);
|
||||||
ASSERT_MSG(pixmap != nullptr, "No pixmap set");
|
ASSERT_MSG(!pixmap.isNull(), "No pixmap set");
|
||||||
|
|
||||||
QFile file{filename};
|
QFile file{filename};
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
@ -685,7 +685,7 @@ void GraphicsSurfaceWidget::SaveSurface() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pixmap->save(&file, "PNG")) {
|
if (!pixmap.save(&file, "PNG")) {
|
||||||
QMessageBox::warning(this, tr("Error"),
|
QMessageBox::warning(this, tr("Error"),
|
||||||
tr("Failed to save surface data to file '%1'").arg(filename));
|
tr("Failed to save surface data to file '%1'").arg(filename));
|
||||||
}
|
}
|
||||||
|
@ -111,13 +111,13 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Instruction instr = par->info.code[index.row()];
|
const Instruction& instr = par->info.code[index.row()];
|
||||||
const OpCode opcode = instr.opcode;
|
const OpCode opcode = instr.opcode;
|
||||||
const OpCode::Info opcode_info = opcode.GetInfo();
|
const OpCode::Info opcode_info = opcode.GetInfo();
|
||||||
const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd
|
const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd
|
||||||
? instr.mad.operand_desc_id.Value()
|
? instr.mad.operand_desc_id.Value()
|
||||||
: instr.common.operand_desc_id.Value();
|
: instr.common.operand_desc_id.Value();
|
||||||
const SwizzlePattern swizzle = par->info.swizzle_info[operand_desc_id].pattern;
|
const SwizzlePattern& swizzle = par->info.swizzle_info[operand_desc_id].pattern;
|
||||||
|
|
||||||
// longest known instruction name: "setemit "
|
// longest known instruction name: "setemit "
|
||||||
int kOpcodeColumnWidth = 8;
|
int kOpcodeColumnWidth = 8;
|
||||||
@ -407,8 +407,7 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
|
|||||||
static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
|
static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
|
||||||
input_data_mapper->setMapping(input_data[i], i);
|
input_data_mapper->setMapping(input_data[i], i);
|
||||||
}
|
}
|
||||||
connect(input_data_mapper, static_cast<void (QSignalMapper::*)(int)>(&QSignalMapper::mapped),
|
connect(input_data_mapper, &QSignalMapper::mappedInt, this, &GraphicsVertexShaderWidget::OnInputAttributeChanged);
|
||||||
this, &GraphicsVertexShaderWidget::OnInputAttributeChanged);
|
|
||||||
|
|
||||||
auto main_widget = new QWidget;
|
auto main_widget = new QWidget;
|
||||||
auto main_layout = new QVBoxLayout;
|
auto main_layout = new QVBoxLayout;
|
||||||
@ -514,8 +513,10 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
|
|||||||
info.code.push_back({instr});
|
info.code.push_back({instr});
|
||||||
int num_attributes = shader_config.max_input_attribute_index + 1;
|
int num_attributes = shader_config.max_input_attribute_index + 1;
|
||||||
|
|
||||||
for (auto pattern : shader_setup.swizzle_data)
|
for (auto pattern : shader_setup.swizzle_data) {
|
||||||
info.swizzle_info.push_back({pattern});
|
const nihstro::SwizzleInfo swizzle_info = { .pattern = nihstro::SwizzlePattern{pattern} };
|
||||||
|
info.swizzle_info.push_back(swizzle_info);
|
||||||
|
}
|
||||||
|
|
||||||
u32 entry_point = Pica::g_state.regs.vs.main_offset;
|
u32 entry_point = Pica::g_state.regs.vs.main_offset;
|
||||||
info.labels.insert({entry_point, "main"});
|
info.labels.insert({entry_point, "main"});
|
||||||
|
@ -56,9 +56,7 @@
|
|||||||
#include "common/detached_tasks.h"
|
#include "common/detached_tasks.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/backend.h"
|
#include "common/logging/backend.h"
|
||||||
#include "common/logging/filter.h"
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/logging/text_formatter.h"
|
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
#include "common/scm_rev.h"
|
#include "common/scm_rev.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
@ -70,17 +68,14 @@
|
|||||||
#include "core/file_sys/archive_extsavedata.h"
|
#include "core/file_sys/archive_extsavedata.h"
|
||||||
#include "core/file_sys/archive_source_sd_savedata.h"
|
#include "core/file_sys/archive_source_sd_savedata.h"
|
||||||
#include "core/frontend/applets/default_applets.h"
|
#include "core/frontend/applets/default_applets.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
|
||||||
#include "core/hle/service/fs/archive.h"
|
#include "core/hle/service/fs/archive.h"
|
||||||
#include "core/hle/service/nfc/nfc.h"
|
#include "core/hle/service/nfc/nfc.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
#include "core/movie.h"
|
#include "core/movie.h"
|
||||||
#include "core/savestate.h"
|
#include "core/savestate.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "game_list_p.h"
|
|
||||||
#include "network/network_settings.h"
|
#include "network/network_settings.h"
|
||||||
#include "ui_main.h"
|
#include "ui_main.h"
|
||||||
#include "video_core/renderer_base.h"
|
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
@ -151,9 +146,7 @@ static void InitializeLogging() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
GMainWindow::GMainWindow()
|
GMainWindow::GMainWindow() : ui{std::make_unique<Ui::MainWindow>()}, config{std::make_unique<Config>()}, emu_thread{nullptr} {
|
||||||
: config(std::make_unique<Config>()), emu_thread(nullptr),
|
|
||||||
ui(std::make_unique<Ui::MainWindow>()) {
|
|
||||||
InitializeLogging();
|
InitializeLogging();
|
||||||
Debugger::ToggleConsole();
|
Debugger::ToggleConsole();
|
||||||
Settings::LogSettings();
|
Settings::LogSettings();
|
||||||
@ -263,7 +256,7 @@ void GMainWindow::InitializeWidgets() {
|
|||||||
loading_screen = new LoadingScreen(this);
|
loading_screen = new LoadingScreen(this);
|
||||||
loading_screen->hide();
|
loading_screen->hide();
|
||||||
ui->horizontalLayout->addWidget(loading_screen);
|
ui->horizontalLayout->addWidget(loading_screen);
|
||||||
connect(loading_screen, &LoadingScreen::Hidden, [&] {
|
connect(loading_screen, &LoadingScreen::Hidden, this, [&] {
|
||||||
loading_screen->Clear();
|
loading_screen->Clear();
|
||||||
if (emulation_running) {
|
if (emulation_running) {
|
||||||
render_window->show();
|
render_window->show();
|
||||||
@ -432,13 +425,13 @@ void GMainWindow::InitializeSaveStateMenuActions() {
|
|||||||
ui->menu_Save_State->addAction(actions_save_state[i]);
|
ui->menu_Save_State->addAction(actions_save_state[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(ui->action_Load_from_Newest_Slot, &QAction::triggered, [this] {
|
connect(ui->action_Load_from_Newest_Slot, &QAction::triggered, this, [this] {
|
||||||
UpdateSaveStates();
|
UpdateSaveStates();
|
||||||
if (newest_slot != 0) {
|
if (newest_slot != 0) {
|
||||||
actions_load_state[newest_slot - 1]->trigger();
|
actions_load_state[newest_slot - 1]->trigger();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(ui->action_Save_to_Oldest_Slot, &QAction::triggered, [this] {
|
connect(ui->action_Save_to_Oldest_Slot, &QAction::triggered, this, [this] {
|
||||||
UpdateSaveStates();
|
UpdateSaveStates();
|
||||||
actions_save_state[oldest_slot - 1]->trigger();
|
actions_save_state[oldest_slot - 1]->trigger();
|
||||||
});
|
});
|
||||||
@ -674,7 +667,7 @@ void GMainWindow::ConnectWidgetEvents() {
|
|||||||
connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this,
|
connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this,
|
||||||
&GMainWindow::OnGameListAddDirectory);
|
&GMainWindow::OnGameListAddDirectory);
|
||||||
connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList);
|
connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList);
|
||||||
connect(game_list, &GameList::PopulatingCompleted,
|
connect(game_list, &GameList::PopulatingCompleted, this,
|
||||||
[this] { multiplayer_state->UpdateGameList(game_list->GetModel()); });
|
[this] { multiplayer_state->UpdateGameList(game_list->GetModel()); });
|
||||||
|
|
||||||
connect(this, &GMainWindow::EmulationStarting, render_window,
|
connect(this, &GMainWindow::EmulationStarting, render_window,
|
||||||
@ -765,7 +758,7 @@ void GMainWindow::ConnectMenuEvents() {
|
|||||||
connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie);
|
connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie);
|
||||||
connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie);
|
connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie);
|
||||||
connect(ui->action_Movie_Read_Only_Mode, &QAction::toggled, this,
|
connect(ui->action_Movie_Read_Only_Mode, &QAction::toggled, this,
|
||||||
[this](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); });
|
[](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); });
|
||||||
connect(ui->action_Enable_Frame_Advancing, &QAction::triggered, this, [this] {
|
connect(ui->action_Enable_Frame_Advancing, &QAction::triggered, this, [this] {
|
||||||
if (emulation_running) {
|
if (emulation_running) {
|
||||||
Core::System::GetInstance().frame_limiter.SetFrameAdvancing(
|
Core::System::GetInstance().frame_limiter.SetFrameAdvancing(
|
||||||
@ -1396,7 +1389,7 @@ void GMainWindow::OnGameListDumpRomFS(QString game_path, u64 program_id) {
|
|||||||
program_id | 0x0004000e00000000);
|
program_id | 0x0004000e00000000);
|
||||||
using FutureWatcher = QFutureWatcher<std::pair<Loader::ResultStatus, Loader::ResultStatus>>;
|
using FutureWatcher = QFutureWatcher<std::pair<Loader::ResultStatus, Loader::ResultStatus>>;
|
||||||
auto* future_watcher = new FutureWatcher(this);
|
auto* future_watcher = new FutureWatcher(this);
|
||||||
connect(future_watcher, &FutureWatcher::finished,
|
connect(future_watcher, &FutureWatcher::finished, this,
|
||||||
[this, dialog, base_path, update_path, future_watcher] {
|
[this, dialog, base_path, update_path, future_watcher] {
|
||||||
dialog->hide();
|
dialog->hide();
|
||||||
const auto& [base, update] = future_watcher->result();
|
const auto& [base, update] = future_watcher->result();
|
||||||
@ -1498,7 +1491,7 @@ void GMainWindow::InstallCIA(QStringList filepaths) {
|
|||||||
const auto cia_progress = [&](std::size_t written, std::size_t total) {
|
const auto cia_progress = [&](std::size_t written, std::size_t total) {
|
||||||
emit UpdateProgress(written, total);
|
emit UpdateProgress(written, total);
|
||||||
};
|
};
|
||||||
for (const auto current_path : filepaths) {
|
for (const auto& current_path : filepaths) {
|
||||||
status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress);
|
status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress);
|
||||||
emit CIAInstallReport(status, current_path);
|
emit CIAInstallReport(status, current_path);
|
||||||
}
|
}
|
||||||
@ -1536,6 +1529,10 @@ void GMainWindow::OnCIAInstallReport(Service::AM::InstallStatus status, QString
|
|||||||
"before being used with Citra. A real 3DS is required.")
|
"before being used with Citra. A real 3DS is required.")
|
||||||
.arg(filename));
|
.arg(filename));
|
||||||
break;
|
break;
|
||||||
|
case Service::AM::InstallStatus::ErrorFileNotFound:
|
||||||
|
QMessageBox::critical(this, tr("Unable to find File"),
|
||||||
|
tr("Could not find %1").arg(filename));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1713,6 +1710,8 @@ void GMainWindow::ToggleScreenLayout() {
|
|||||||
case Settings::LayoutOption::SideScreen:
|
case Settings::LayoutOption::SideScreen:
|
||||||
new_layout = Settings::LayoutOption::Default;
|
new_layout = Settings::LayoutOption::Default;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR(Frontend, "Unknown layout option {}", Settings::values.layout_option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::values.layout_option = new_layout;
|
Settings::values.layout_option = new_layout;
|
||||||
@ -1959,7 +1958,7 @@ void GMainWindow::OnCaptureScreenshot() {
|
|||||||
const QString filename = game_title.remove(QRegularExpression(QStringLiteral("[\\/:?\"<>|]")));
|
const QString filename = game_title.remove(QRegularExpression(QStringLiteral("[\\/:?\"<>|]")));
|
||||||
const QString timestamp =
|
const QString timestamp =
|
||||||
QDateTime::currentDateTime().toString(QStringLiteral("dd.MM.yy_hh.mm.ss.z"));
|
QDateTime::currentDateTime().toString(QStringLiteral("dd.MM.yy_hh.mm.ss.z"));
|
||||||
path.append(QStringLiteral("/%1_%2.png").arg(filename).arg(timestamp));
|
path.append(QStringLiteral("/%1_%2.png").arg(filename, timestamp));
|
||||||
render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path);
|
render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path);
|
||||||
OnStartGame();
|
OnStartGame();
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ namespace Settings {
|
|||||||
Values values = {};
|
Values values = {};
|
||||||
|
|
||||||
void Apply() {
|
void Apply() {
|
||||||
|
|
||||||
GDBStub::SetServerPort(values.gdbstub_port);
|
GDBStub::SetServerPort(values.gdbstub_port);
|
||||||
GDBStub::ToggleServer(values.use_gdbstub);
|
GDBStub::ToggleServer(values.use_gdbstub);
|
||||||
|
|
||||||
@ -108,16 +107,15 @@ void LogSettings() {
|
|||||||
LogSetting("Audio_OutputDevice", values.audio_device_id);
|
LogSetting("Audio_OutputDevice", values.audio_device_id);
|
||||||
LogSetting("Audio_InputDeviceType", values.mic_input_type);
|
LogSetting("Audio_InputDeviceType", values.mic_input_type);
|
||||||
LogSetting("Audio_InputDevice", values.mic_input_device);
|
LogSetting("Audio_InputDevice", values.mic_input_device);
|
||||||
using namespace Service::CAM;
|
LogSetting("Camera_OuterRightName", values.camera_name[Service::CAM::OuterRightCamera]);
|
||||||
LogSetting("Camera_OuterRightName", values.camera_name[OuterRightCamera]);
|
LogSetting("Camera_OuterRightConfig", values.camera_config[Service::CAM::OuterRightCamera]);
|
||||||
LogSetting("Camera_OuterRightConfig", values.camera_config[OuterRightCamera]);
|
LogSetting("Camera_OuterRightFlip", values.camera_flip[Service::CAM::OuterRightCamera]);
|
||||||
LogSetting("Camera_OuterRightFlip", values.camera_flip[OuterRightCamera]);
|
LogSetting("Camera_InnerName", values.camera_name[Service::CAM::InnerCamera]);
|
||||||
LogSetting("Camera_InnerName", values.camera_name[InnerCamera]);
|
LogSetting("Camera_InnerConfig", values.camera_config[Service::CAM::InnerCamera]);
|
||||||
LogSetting("Camera_InnerConfig", values.camera_config[InnerCamera]);
|
LogSetting("Camera_InnerFlip", values.camera_flip[Service::CAM::InnerCamera]);
|
||||||
LogSetting("Camera_InnerFlip", values.camera_flip[InnerCamera]);
|
LogSetting("Camera_OuterLeftName", values.camera_name[Service::CAM::OuterLeftCamera]);
|
||||||
LogSetting("Camera_OuterLeftName", values.camera_name[OuterLeftCamera]);
|
LogSetting("Camera_OuterLeftConfig", values.camera_config[Service::CAM::OuterLeftCamera]);
|
||||||
LogSetting("Camera_OuterLeftConfig", values.camera_config[OuterLeftCamera]);
|
LogSetting("Camera_OuterLeftFlip", values.camera_flip[Service::CAM::OuterLeftCamera]);
|
||||||
LogSetting("Camera_OuterLeftFlip", values.camera_flip[OuterLeftCamera]);
|
|
||||||
LogSetting("DataStorage_UseVirtualSd", values.use_virtual_sd);
|
LogSetting("DataStorage_UseVirtualSd", values.use_virtual_sd);
|
||||||
LogSetting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
|
LogSetting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
|
||||||
LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
|
LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
|
||||||
|
@ -168,13 +168,15 @@ struct Values {
|
|||||||
u64 init_time;
|
u64 init_time;
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
GraphicsAPI graphics_api = GraphicsAPI::Vulkan;
|
GraphicsAPI graphics_api;
|
||||||
|
bool renderer_debug;
|
||||||
bool use_hw_renderer;
|
bool use_hw_renderer;
|
||||||
bool use_hw_shader;
|
bool use_hw_shader;
|
||||||
bool separable_shader;
|
bool separable_shader;
|
||||||
bool use_disk_shader_cache;
|
bool use_disk_shader_cache;
|
||||||
bool shaders_accurate_mul;
|
bool shaders_accurate_mul;
|
||||||
bool use_shader_jit;
|
bool use_shader_jit;
|
||||||
|
bool use_vsync_new;
|
||||||
u16 resolution_factor;
|
u16 resolution_factor;
|
||||||
bool use_frame_limit_alternate;
|
bool use_frame_limit_alternate;
|
||||||
u16 frame_limit;
|
u16 frame_limit;
|
||||||
@ -208,12 +210,11 @@ struct Values {
|
|||||||
bool filter_mode;
|
bool filter_mode;
|
||||||
std::string pp_shader_name;
|
std::string pp_shader_name;
|
||||||
|
|
||||||
|
// Custom textures
|
||||||
bool dump_textures;
|
bool dump_textures;
|
||||||
bool custom_textures;
|
bool custom_textures;
|
||||||
bool preload_textures;
|
bool preload_textures;
|
||||||
|
|
||||||
bool use_vsync_new;
|
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
bool enable_dsp_lle;
|
bool enable_dsp_lle;
|
||||||
bool enable_dsp_lle_multithread;
|
bool enable_dsp_lle_multithread;
|
||||||
|
@ -3,12 +3,9 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <cryptopp/osrng.h>
|
#include <cryptopp/osrng.h>
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scm_rev.h"
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "core/telemetry_session.h"
|
#include "core/telemetry_session.h"
|
||||||
|
@ -28,7 +28,7 @@ public:
|
|||||||
* @note All methods in this class are called from the GSP thread
|
* @note All methods in this class are called from the GSP thread
|
||||||
*/
|
*/
|
||||||
virtual void GXCommandProcessed(int total_command_count) {
|
virtual void GXCommandProcessed(int total_command_count) {
|
||||||
const Service::GSP::Command& cmd =
|
[[maybe_unused]] const Service::GSP::Command& cmd =
|
||||||
observed->ReadGXCommandHistory(total_command_count - 1);
|
observed->ReadGXCommandHistory(total_command_count - 1);
|
||||||
LOG_TRACE(Debug_GPU, "Received command: id={:x}", (int)cmd.id.Value());
|
LOG_TRACE(Debug_GPU, "Received command: id={:x}", (int)cmd.id.Value());
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,8 @@ struct LightingRegs {
|
|||||||
"ReflectBlue, instead got %i",
|
"ReflectBlue, instead got %i",
|
||||||
config);
|
config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LightSrc {
|
struct LightSrc {
|
||||||
|
@ -69,7 +69,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
|
|||||||
id, message);
|
id, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
Driver::Driver(bool gles) : is_gles{gles} {
|
Driver::Driver(bool gles, bool enable_debug) : is_gles{gles} {
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
if (!gladLoadGL()) {
|
if (!gladLoadGL()) {
|
||||||
return;
|
return;
|
||||||
@ -79,8 +79,10 @@ Driver::Driver(bool gles) : is_gles{gles} {
|
|||||||
* Qualcomm has some spammy info messages that are marked as errors but not important
|
* Qualcomm has some spammy info messages that are marked as errors but not important
|
||||||
* https://developer.qualcomm.com/comment/11845
|
* https://developer.qualcomm.com/comment/11845
|
||||||
*/
|
*/
|
||||||
|
if (enable_debug) {
|
||||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||||
glDebugMessageCallback(DebugHandler, nullptr);
|
glDebugMessageCallback(DebugHandler, nullptr);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ReportDriverInfo();
|
ReportDriverInfo();
|
||||||
|
@ -33,31 +33,37 @@ enum class DriverBug {
|
|||||||
*/
|
*/
|
||||||
class Driver {
|
class Driver {
|
||||||
public:
|
public:
|
||||||
Driver(bool gles);
|
Driver(bool gles, bool enable_debug);
|
||||||
|
|
||||||
/// Returns true of the driver has a particular bug stated in the DriverBug enum
|
/// Returns true of the driver has a particular bug stated in the DriverBug enum
|
||||||
bool HasBug(DriverBug bug) const;
|
bool HasBug(DriverBug bug) const;
|
||||||
|
|
||||||
|
/// Returns the vendor of the currently selected physical device
|
||||||
Vendor GetVendor() const {
|
Vendor GetVendor() const {
|
||||||
return vendor;
|
return vendor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the current context is ES compatible
|
||||||
bool IsOpenGLES() const {
|
bool IsOpenGLES() const {
|
||||||
return is_gles;
|
return is_gles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the implementation supports ARB_buffer_storage
|
||||||
bool HasArbBufferStorage() const {
|
bool HasArbBufferStorage() const {
|
||||||
return arb_buffer_storage;
|
return arb_buffer_storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the implementation supports EXT_buffer_storage
|
||||||
bool HasExtBufferStorage() const {
|
bool HasExtBufferStorage() const {
|
||||||
return ext_buffer_storage;
|
return ext_buffer_storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the implementation supports EXT_clip_cull_distance
|
||||||
bool HasExtClipCullDistance() const {
|
bool HasExtClipCullDistance() const {
|
||||||
return ext_clip_cull_distance;
|
return ext_clip_cull_distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the implementation supports ARB_direct_state_access
|
||||||
bool HasArbDirectStateAccess() const {
|
bool HasArbDirectStateAccess() const {
|
||||||
return arb_direct_state_access;
|
return arb_direct_state_access;
|
||||||
}
|
}
|
||||||
|
@ -353,7 +353,8 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
RendererOpenGL::RendererOpenGL(Frontend::EmuWindow& window)
|
RendererOpenGL::RendererOpenGL(Frontend::EmuWindow& window)
|
||||||
: RendererBase{window}, driver{Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES},
|
: RendererBase{window}, driver{Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES,
|
||||||
|
Settings::values.renderer_debug},
|
||||||
frame_dumper{Core::System::GetInstance().VideoDumper(), window} {
|
frame_dumper{Core::System::GetInstance().VideoDumper(), window} {
|
||||||
|
|
||||||
window.mailbox = std::make_unique<OGLTextureMailbox>();
|
window.mailbox = std::make_unique<OGLTextureMailbox>();
|
||||||
|
@ -183,8 +183,9 @@ static std::array<float, 3 * 2> MakeOrthographicMatrix(float width, float height
|
|||||||
}
|
}
|
||||||
|
|
||||||
RendererVulkan::RendererVulkan(Frontend::EmuWindow& window)
|
RendererVulkan::RendererVulkan(Frontend::EmuWindow& window)
|
||||||
: RendererBase{window}, instance{window}, scheduler{instance, *this}, renderpass_cache{instance, scheduler},
|
: RendererBase{window}, instance{window, Settings::values.renderer_debug}, scheduler{instance, *this},
|
||||||
runtime{instance, scheduler, renderpass_cache}, swapchain{instance, renderpass_cache},
|
renderpass_cache{instance, scheduler}, runtime{instance, scheduler, renderpass_cache},
|
||||||
|
swapchain{instance, renderpass_cache},
|
||||||
vertex_buffer{instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}} {
|
vertex_buffer{instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}} {
|
||||||
|
|
||||||
auto& telemetry_session = Core::System::GetInstance().TelemetrySession();
|
auto& telemetry_session = Core::System::GetInstance().TelemetrySession();
|
||||||
|
@ -38,7 +38,7 @@ vk::Format ToVkFormat(VideoCore::PixelFormat format) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Instance::Instance(Frontend::EmuWindow& window) {
|
Instance::Instance(Frontend::EmuWindow& window, bool enable_validation) {
|
||||||
auto window_info = window.GetWindowInfo();
|
auto window_info = window.GetWindowInfo();
|
||||||
|
|
||||||
// Fetch instance independant function pointers
|
// Fetch instance independant function pointers
|
||||||
@ -64,9 +64,10 @@ Instance::Instance(Frontend::EmuWindow& window) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const std::array layers = {"VK_LAYER_KHRONOS_validation"};
|
const std::array layers = {"VK_LAYER_KHRONOS_validation"};
|
||||||
|
const u32 layer_count = enable_validation ? 1u : 0u;
|
||||||
const vk::InstanceCreateInfo instance_info = {
|
const vk::InstanceCreateInfo instance_info = {
|
||||||
.pApplicationInfo = &application_info,
|
.pApplicationInfo = &application_info,
|
||||||
.enabledLayerCount = static_cast<u32>(layers.size()),
|
.enabledLayerCount = layer_count,
|
||||||
.ppEnabledLayerNames = layers.data(),
|
.ppEnabledLayerNames = layers.data(),
|
||||||
.enabledExtensionCount = static_cast<u32>(extensions.size()),
|
.enabledExtensionCount = static_cast<u32>(extensions.size()),
|
||||||
.ppEnabledExtensionNames = extensions.data()
|
.ppEnabledExtensionNames = extensions.data()
|
||||||
|
@ -27,7 +27,7 @@ struct FormatTraits {
|
|||||||
/// The global Vulkan instance
|
/// The global Vulkan instance
|
||||||
class Instance {
|
class Instance {
|
||||||
public:
|
public:
|
||||||
Instance(Frontend::EmuWindow& window);
|
Instance(Frontend::EmuWindow& window, bool enable_validation);
|
||||||
~Instance();
|
~Instance();
|
||||||
|
|
||||||
/// Returns the FormatTraits struct for the provided pixel format
|
/// Returns the FormatTraits struct for the provided pixel format
|
||||||
|
Reference in New Issue
Block a user