diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index 8f74aa627..b76d5fd8b 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp @@ -7,17 +7,8 @@ #include #include #include - // This needs to be included before getopt.h because the latter #defines symbols used by it #include "common/microprofile.h" - -#ifdef _WIN32 -// windows.h needs to be included before shellapi.h -#include - -#include -#endif - #include "citra/config.h" #include "citra/emu_window/emu_window_sdl2.h" #include "citra/lodepng_image_interface.h" @@ -25,20 +16,15 @@ #include "common/detached_tasks.h" #include "common/file_util.h" #include "common/logging/backend.h" -#include "common/logging/filter.h" #include "common/logging/log.h" #include "common/scm_rev.h" #include "common/scope_exit.h" -#include "common/string_util.h" #include "core/core.h" #include "core/dumping/backend.h" -#include "core/file_sys/cia_container.h" #include "core/frontend/applets/default_applets.h" #include "core/frontend/framebuffer_layout.h" -#include "core/gdbstub/gdbstub.h" #include "core/hle/service/am/am.h" #include "core/hle/service/cfg/cfg.h" -#include "core/loader/loader.h" #include "core/movie.h" #include "core/settings.h" #include "network/network.h" @@ -51,6 +37,10 @@ #endif #ifdef _WIN32 +// windows.h needs to be included before shellapi.h +#include +#include + extern "C" { // tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; @@ -103,35 +93,35 @@ static void OnNetworkError(const Network::RoomMember::Error& error) { break; case Network::RoomMember::Error::CouldNotConnect: LOG_ERROR(Network, "Error: Could not connect"); - exit(1); + std::exit(1); break; case Network::RoomMember::Error::NameCollision: LOG_ERROR( Network, "You tried to use the same nickname as another user that is connected to the Room"); - exit(1); + std::exit(1); break; case Network::RoomMember::Error::MacCollision: LOG_ERROR(Network, "You tried to use the same MAC-Address as another user that is " "connected to the Room"); - exit(1); + std::exit(1); break; case Network::RoomMember::Error::ConsoleIdCollision: LOG_ERROR(Network, "Your Console ID conflicted with someone else in the Room"); - exit(1); + std::exit(1); break; case Network::RoomMember::Error::WrongPassword: LOG_ERROR(Network, "Room replied with: Wrong password"); - exit(1); + std::exit(1); break; case Network::RoomMember::Error::WrongVersion: LOG_ERROR(Network, "You are using a different version than the room you are trying to connect to"); - exit(1); + std::exit(1); break; case Network::RoomMember::Error::RoomIsFull: LOG_ERROR(Network, "The room is full"); - exit(1); + std::exit(1); break; case Network::RoomMember::Error::HostKicked: 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: LOG_ERROR(Network, "You have been banned by the host"); break; + default: + LOG_ERROR(Network, "Unknown network error {}", error); } } diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index b33bce00a..b88b10322 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include "citra_qt/bootmanager.h" @@ -34,11 +33,13 @@ EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(cor EmuThread::~EmuThread() = default; static GMainWindow* GetMainWindow() { - for (QWidget* w : qApp->topLevelWidgets()) { + const auto widgets = qApp->topLevelWidgets(); + for (QWidget* w : widgets) { if (GMainWindow* main = qobject_cast(w)) { return main; } } + return nullptr; } @@ -48,7 +49,8 @@ void EmuThread::run() { 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) { emit LoadProgress(stage, value, total); }); @@ -58,18 +60,17 @@ void EmuThread::run() { 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 // we hide it immediately as we need to wait for user input to start the emulation. emit HideLoadingScreen(); - Core::System::GetInstance().frame_limiter.WaitOnce(); + system.frame_limiter.WaitOnce(); } // Holds whether the cpu was running during the last iteration, // so that the DebugModeLeft signal can be emitted before the // next execution step. bool was_active = false; - Core::System& system = Core::System::GetInstance(); while (!stop_run) { if (running) { if (!was_active) @@ -119,8 +120,20 @@ public: /// Create the original context that should be shared from explicit OpenGLSharedContext(QSurface* surface) : surface(surface) { QSurfaceFormat format; - format.setVersion(4, 4); - format.setProfile(QSurfaceFormat::CoreProfile); + + 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.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) format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior); format.setSwapInterval(0); @@ -630,14 +643,6 @@ bool GRenderWindow::InitializeOpenGL() { child->SetContext( std::make_unique(context->GetShareContext(), child->windowHandle())); - // Check for OpenGL 4.3 support - if (!QOpenGLContext::globalShareContext()->versionFunctions()) { - 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; } diff --git a/src/citra_qt/cheats.cpp b/src/citra_qt/cheats.cpp index 25e173687..4cab098b6 100644 --- a/src/citra_qt/cheats.cpp +++ b/src/citra_qt/cheats.cpp @@ -91,7 +91,7 @@ bool CheatDialog::SaveCheat(int row) { } // 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) { Cheats::GatewayCheat::CheatLine cheat_line(code_lines[i].toStdString()); if (cheat_line.valid) diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index f48609849..e9fa88508 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -482,6 +482,10 @@ void Config::ReadPathValues() { void Config::ReadRendererValues() { qt_config->beginGroup(QStringLiteral("Renderer")); + Settings::values.graphics_api = static_cast( + ReadSetting(QStringLiteral("graphics_api"), static_cast(Settings::GraphicsAPI::OpenGL)) + .toUInt()); + Settings::values.renderer_debug = ReadSetting(QStringLiteral("renderer_debug"), false).toBool(); Settings::values.use_hw_renderer = ReadSetting(QStringLiteral("use_hw_renderer"), true).toBool(); Settings::values.use_hw_shader = ReadSetting(QStringLiteral("use_hw_shader"), true).toBool(); @@ -521,7 +525,7 @@ void Config::ReadRendererValues() { void Config::ReadShortcutValues() { qt_config->beginGroup(QStringLiteral("Shortcuts")); - for (auto [name, group, shortcut] : default_hotkeys) { + for (const auto& [name, group, shortcut] : default_hotkeys) { auto [keyseq, context] = shortcut; qt_config->beginGroup(group); qt_config->beginGroup(name); @@ -556,7 +560,7 @@ void Config::ReadSystemValues() { // https://developers.google.com/media/vp9/live-encoding const QString DEFAULT_VIDEO_ENCODER_OPTIONS = 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() { qt_config->beginGroup(QStringLiteral("VideoDumping")); @@ -994,6 +998,9 @@ void Config::SavePathValues() { void Config::SaveRendererValues() { qt_config->beginGroup(QStringLiteral("Renderer")); + WriteSetting(QStringLiteral("graphics_api"), static_cast(Settings::values.graphics_api), + static_cast(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_shader"), Settings::values.use_hw_shader, true); #ifdef __APPLE__ @@ -1015,9 +1022,9 @@ void Config::SaveRendererValues() { 200); // 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_green"), (double)Settings::values.bg_green, 0.0); - WriteSetting(QStringLiteral("bg_blue"), (double)Settings::values.bg_blue, 0.0); + WriteSetting(QStringLiteral("bg_red"), static_cast(Settings::values.bg_red), 0.0); + WriteSetting(QStringLiteral("bg_green"), static_cast(Settings::values.bg_green), 0.0); + WriteSetting(QStringLiteral("bg_blue"), static_cast(Settings::values.bg_blue), 0.0); WriteSetting(QStringLiteral("texture_filter_name"), QString::fromStdString(Settings::values.texture_filter_name), diff --git a/src/citra_qt/configuration/configure_debug.cpp b/src/citra_qt/configuration/configure_debug.cpp index dcb1eedf0..5066adba2 100644 --- a/src/citra_qt/configuration/configure_debug.cpp +++ b/src/citra_qt/configuration/configure_debug.cpp @@ -8,8 +8,6 @@ #include "citra_qt/debugger/console.h" #include "citra_qt/uisettings.h" #include "common/file_util.h" -#include "common/logging/backend.h" -#include "common/logging/filter.h" #include "common/logging/log.h" #include "core/core.h" #include "core/settings.h" @@ -24,7 +22,10 @@ ConfigureDebug::ConfigureDebug(QWidget* parent) QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir)); 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; @@ -37,6 +38,7 @@ void ConfigureDebug::SetConfiguration() { ui->toggle_console->setChecked(UISettings::values.show_console); ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter)); ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit); + ui->toggle_renderer_debug->setChecked(Settings::values.renderer_debug); } void ConfigureDebug::ApplyConfiguration() { @@ -49,6 +51,7 @@ void ConfigureDebug::ApplyConfiguration() { filter.ParseFilterString(Settings::values.log_filter); Log::SetGlobalFilter(filter); Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked(); + Settings::values.renderer_debug = ui->toggle_renderer_debug->isChecked(); } void ConfigureDebug::RetranslateUI() { diff --git a/src/citra_qt/configuration/configure_debug.ui b/src/citra_qt/configuration/configure_debug.ui index 3d31d0e94..9edcfacaa 100644 --- a/src/citra_qt/configuration/configure_debug.ui +++ b/src/citra_qt/configuration/configure_debug.ui @@ -114,11 +114,24 @@ + + <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> + Enable CPU JIT + + + + <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> + + + Enable debug renderer + + + diff --git a/src/citra_qt/debugger/graphics/graphics_surface.cpp b/src/citra_qt/debugger/graphics/graphics_surface.cpp index 95a7df824..8a14af6cd 100644 --- a/src/citra_qt/debugger/graphics/graphics_surface.cpp +++ b/src/citra_qt/debugger/graphics/graphics_surface.cpp @@ -16,7 +16,6 @@ #include "citra_qt/util/spinbox.h" #include "common/color.h" #include "core/core.h" -#include "core/hw/gpu.h" #include "core/memory.h" #include "video_core/pica_state.h" #include "video_core/regs_framebuffer.h" @@ -34,12 +33,15 @@ void SurfacePicture::mousePressEvent(QMouseEvent* event) { if (!(event->buttons() & Qt::LeftButton)) return; - if (pixmap() == nullptr) + const QPixmap pixmap = this->pixmap(Qt::ReturnByValue); + if (pixmap.isNull()) { return; + } - if (surface_widget) - surface_widget->Pick(event->x() * pixmap()->width() / width(), - event->y() * pixmap()->height() / height()); + if (surface_widget) { + surface_widget->Pick(event->x() * pixmap.width() / width(), + event->y() * pixmap.height() / height()); + } } void SurfacePicture::mouseMoveEvent(QMouseEvent* event) { @@ -314,48 +316,48 @@ void GraphicsSurfaceWidget::Pick(int x, int y) { case Format::RGBA8: { auto value = Color::DecodeRGBA8(pixel) / 255.0f; return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") - .arg(QString::number(value.r(), 'f', 2)) - .arg(QString::number(value.g(), 'f', 2)) - .arg(QString::number(value.b(), 'f', 2)) - .arg(QString::number(value.a(), 'f', 2)); + .arg(QString::number(value.r(), 'f', 2), + QString::number(value.g(), 'f', 2), + QString::number(value.b(), 'f', 2), + QString::number(value.a(), 'f', 2)); } case Format::RGB8: { auto value = Color::DecodeRGB8(pixel) / 255.0f; return QStringLiteral("Red: %1, Green: %2, Blue: %3") - .arg(QString::number(value.r(), 'f', 2)) - .arg(QString::number(value.g(), 'f', 2)) - .arg(QString::number(value.b(), 'f', 2)); + .arg(QString::number(value.r(), 'f', 2), + QString::number(value.g(), 'f', 2), + QString::number(value.b(), 'f', 2)); } case Format::RGB5A1: { auto value = Color::DecodeRGB5A1(pixel) / 255.0f; return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") - .arg(QString::number(value.r(), 'f', 2)) - .arg(QString::number(value.g(), 'f', 2)) - .arg(QString::number(value.b(), 'f', 2)) - .arg(QString::number(value.a(), 'f', 2)); + .arg(QString::number(value.r(), 'f', 2), + QString::number(value.g(), 'f', 2), + QString::number(value.b(), 'f', 2), + QString::number(value.a(), 'f', 2)); } case Format::RGB565: { auto value = Color::DecodeRGB565(pixel) / 255.0f; return QStringLiteral("Red: %1, Green: %2, Blue: %3") - .arg(QString::number(value.r(), 'f', 2)) - .arg(QString::number(value.g(), 'f', 2)) - .arg(QString::number(value.b(), 'f', 2)); + .arg(QString::number(value.r(), 'f', 2), + QString::number(value.g(), 'f', 2), + QString::number(value.b(), 'f', 2)); } case Format::RGBA4: { auto value = Color::DecodeRGBA4(pixel) / 255.0f; return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") - .arg(QString::number(value.r(), 'f', 2)) - .arg(QString::number(value.g(), 'f', 2)) - .arg(QString::number(value.b(), 'f', 2)) - .arg(QString::number(value.a(), 'f', 2)); + .arg(QString::number(value.r(), 'f', 2), + QString::number(value.g(), 'f', 2), + QString::number(value.b(), 'f', 2), + QString::number(value.a(), 'f', 2)); } 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: { auto value = Color::DecodeRG8(pixel) / 255.0f; return QStringLiteral("Red: %1, Green: %2") - .arg(QString::number(value.r(), 'f', 2)) - .arg(QString::number(value.g(), 'f', 2)); + .arg(QString::number(value.r(), 'f', 2), + QString::number(value.g(), 'f', 2)); } case Format::I8: 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)); case Format::IA4: return QStringLiteral("Index: %1, Alpha: %2") - .arg(*pixel & 0xF) - .arg((*pixel & 0xF0) >> 4); + .arg(*pixel & 0xF, (*pixel & 0xF0) >> 4); case Format::I4: { u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF; return QStringLiteral("Index: %1").arg(i); @@ -390,8 +391,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) { case Format::X24S8: { auto values = Color::DecodeD24S8(pixel); return QStringLiteral("Depth: %1, Stencil: %2") - .arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4)) - .arg(values[1]); + .arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4), values[1]); } case Format::Unknown: return QStringLiteral("Unknown format"); @@ -401,8 +401,8 @@ void GraphicsSurfaceWidget::Pick(int x, int y) { }; QString nibbles; - for (unsigned i = 0; i < nibbles_per_pixel; i++) { - unsigned nibble_index = i; + for (u32 i = 0; i < nibbles_per_pixel; i++) { + u32 nibble_index = i; if (nibble_mode) { nibble_index += (offset % 2) ? 0 : 1; } @@ -412,7 +412,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) { } 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); } @@ -676,8 +676,8 @@ void GraphicsSurfaceWidget::SaveSurface() { } if (selected_filter == png_filter) { - const QPixmap* const pixmap = surface_picture_label->pixmap(); - ASSERT_MSG(pixmap != nullptr, "No pixmap set"); + const QPixmap pixmap = surface_picture_label->pixmap(Qt::ReturnByValue); + ASSERT_MSG(!pixmap.isNull(), "No pixmap set"); QFile file{filename}; if (!file.open(QIODevice::WriteOnly)) { @@ -685,7 +685,7 @@ void GraphicsSurfaceWidget::SaveSurface() { return; } - if (!pixmap->save(&file, "PNG")) { + if (!pixmap.save(&file, "PNG")) { QMessageBox::warning(this, tr("Error"), tr("Failed to save surface data to file '%1'").arg(filename)); } diff --git a/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp index 5ce5d7996..b0fe1c18d 100644 --- a/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp +++ b/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp @@ -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::Info opcode_info = opcode.GetInfo(); const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd ? instr.mad.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 " int kOpcodeColumnWidth = 8; @@ -407,8 +407,7 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget( static_cast(&QSignalMapper::map)); input_data_mapper->setMapping(input_data[i], i); } - connect(input_data_mapper, static_cast(&QSignalMapper::mapped), - this, &GraphicsVertexShaderWidget::OnInputAttributeChanged); + connect(input_data_mapper, &QSignalMapper::mappedInt, this, &GraphicsVertexShaderWidget::OnInputAttributeChanged); auto main_widget = new QWidget; auto main_layout = new QVBoxLayout; @@ -514,8 +513,10 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d info.code.push_back({instr}); int num_attributes = shader_config.max_input_attribute_index + 1; - for (auto pattern : shader_setup.swizzle_data) - info.swizzle_info.push_back({pattern}); + for (auto pattern : shader_setup.swizzle_data) { + 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; info.labels.insert({entry_point, "main"}); diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 7c7b4291d..9a5dc5c14 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -56,9 +56,7 @@ #include "common/detached_tasks.h" #include "common/file_util.h" #include "common/logging/backend.h" -#include "common/logging/filter.h" #include "common/logging/log.h" -#include "common/logging/text_formatter.h" #include "common/microprofile.h" #include "common/scm_rev.h" #include "common/scope_exit.h" @@ -70,17 +68,14 @@ #include "core/file_sys/archive_extsavedata.h" #include "core/file_sys/archive_source_sd_savedata.h" #include "core/frontend/applets/default_applets.h" -#include "core/gdbstub/gdbstub.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/nfc/nfc.h" #include "core/loader/loader.h" #include "core/movie.h" #include "core/savestate.h" #include "core/settings.h" -#include "game_list_p.h" #include "network/network_settings.h" #include "ui_main.h" -#include "video_core/renderer_base.h" #include "video_core/video_core.h" #ifdef __APPLE__ @@ -151,9 +146,7 @@ static void InitializeLogging() { #endif } -GMainWindow::GMainWindow() - : config(std::make_unique()), emu_thread(nullptr), - ui(std::make_unique()) { +GMainWindow::GMainWindow() : ui{std::make_unique()}, config{std::make_unique()}, emu_thread{nullptr} { InitializeLogging(); Debugger::ToggleConsole(); Settings::LogSettings(); @@ -263,7 +256,7 @@ void GMainWindow::InitializeWidgets() { loading_screen = new LoadingScreen(this); loading_screen->hide(); ui->horizontalLayout->addWidget(loading_screen); - connect(loading_screen, &LoadingScreen::Hidden, [&] { + connect(loading_screen, &LoadingScreen::Hidden, this, [&] { loading_screen->Clear(); if (emulation_running) { render_window->show(); @@ -432,13 +425,13 @@ void GMainWindow::InitializeSaveStateMenuActions() { 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(); if (newest_slot != 0) { 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(); actions_save_state[oldest_slot - 1]->trigger(); }); @@ -674,7 +667,7 @@ void GMainWindow::ConnectWidgetEvents() { connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this, &GMainWindow::OnGameListAddDirectory); 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()); }); 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_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie); 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] { if (emulation_running) { Core::System::GetInstance().frame_limiter.SetFrameAdvancing( @@ -1396,7 +1389,7 @@ void GMainWindow::OnGameListDumpRomFS(QString game_path, u64 program_id) { program_id | 0x0004000e00000000); using FutureWatcher = QFutureWatcher>; 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] { dialog->hide(); 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) { 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); 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.") .arg(filename)); 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: new_layout = Settings::LayoutOption::Default; break; + default: + LOG_ERROR(Frontend, "Unknown layout option {}", Settings::values.layout_option); } Settings::values.layout_option = new_layout; @@ -1959,7 +1958,7 @@ void GMainWindow::OnCaptureScreenshot() { const QString filename = game_title.remove(QRegularExpression(QStringLiteral("[\\/:?\"<>|]"))); const QString timestamp = 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); OnStartGame(); } diff --git a/src/core/settings.cpp b/src/core/settings.cpp index d3be51c21..ebb706b8b 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -21,7 +21,6 @@ namespace Settings { Values values = {}; void Apply() { - GDBStub::SetServerPort(values.gdbstub_port); GDBStub::ToggleServer(values.use_gdbstub); @@ -108,16 +107,15 @@ void LogSettings() { LogSetting("Audio_OutputDevice", values.audio_device_id); LogSetting("Audio_InputDeviceType", values.mic_input_type); LogSetting("Audio_InputDevice", values.mic_input_device); - using namespace Service::CAM; - LogSetting("Camera_OuterRightName", values.camera_name[OuterRightCamera]); - LogSetting("Camera_OuterRightConfig", values.camera_config[OuterRightCamera]); - LogSetting("Camera_OuterRightFlip", values.camera_flip[OuterRightCamera]); - LogSetting("Camera_InnerName", values.camera_name[InnerCamera]); - LogSetting("Camera_InnerConfig", values.camera_config[InnerCamera]); - LogSetting("Camera_InnerFlip", values.camera_flip[InnerCamera]); - LogSetting("Camera_OuterLeftName", values.camera_name[OuterLeftCamera]); - LogSetting("Camera_OuterLeftConfig", values.camera_config[OuterLeftCamera]); - LogSetting("Camera_OuterLeftFlip", values.camera_flip[OuterLeftCamera]); + LogSetting("Camera_OuterRightName", values.camera_name[Service::CAM::OuterRightCamera]); + LogSetting("Camera_OuterRightConfig", values.camera_config[Service::CAM::OuterRightCamera]); + LogSetting("Camera_OuterRightFlip", values.camera_flip[Service::CAM::OuterRightCamera]); + LogSetting("Camera_InnerName", values.camera_name[Service::CAM::InnerCamera]); + LogSetting("Camera_InnerConfig", values.camera_config[Service::CAM::InnerCamera]); + LogSetting("Camera_InnerFlip", values.camera_flip[Service::CAM::InnerCamera]); + LogSetting("Camera_OuterLeftName", values.camera_name[Service::CAM::OuterLeftCamera]); + LogSetting("Camera_OuterLeftConfig", values.camera_config[Service::CAM::OuterLeftCamera]); + LogSetting("Camera_OuterLeftFlip", values.camera_flip[Service::CAM::OuterLeftCamera]); LogSetting("DataStorage_UseVirtualSd", values.use_virtual_sd); LogSetting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)); LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)); diff --git a/src/core/settings.h b/src/core/settings.h index a22737ed1..ed479c322 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -168,13 +168,15 @@ struct Values { u64 init_time; // Renderer - GraphicsAPI graphics_api = GraphicsAPI::Vulkan; + GraphicsAPI graphics_api; + bool renderer_debug; bool use_hw_renderer; bool use_hw_shader; bool separable_shader; bool use_disk_shader_cache; bool shaders_accurate_mul; bool use_shader_jit; + bool use_vsync_new; u16 resolution_factor; bool use_frame_limit_alternate; u16 frame_limit; @@ -208,12 +210,11 @@ struct Values { bool filter_mode; std::string pp_shader_name; + // Custom textures bool dump_textures; bool custom_textures; bool preload_textures; - bool use_vsync_new; - // Audio bool enable_dsp_lle; bool enable_dsp_lle_multithread; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index c9f7c6841..318e3f69b 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -3,12 +3,9 @@ // Refer to the license.txt file included. #include - -#include "common/assert.h" #include "common/common_types.h" #include "common/file_util.h" #include "common/logging/log.h" -#include "common/scm_rev.h" #include "core/core.h" #include "core/settings.h" #include "core/telemetry_session.h" diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h index 95b3a40d6..30b9236ff 100644 --- a/src/video_core/gpu_debugger.h +++ b/src/video_core/gpu_debugger.h @@ -28,7 +28,7 @@ public: * @note All methods in this class are called from the GSP thread */ 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); LOG_TRACE(Debug_GPU, "Received command: id={:x}", (int)cmd.id.Value()); } diff --git a/src/video_core/regs_lighting.h b/src/video_core/regs_lighting.h index 87911f947..7520c48b9 100644 --- a/src/video_core/regs_lighting.h +++ b/src/video_core/regs_lighting.h @@ -129,6 +129,8 @@ struct LightingRegs { "ReflectBlue, instead got %i", config); } + + return false; } struct LightSrc { diff --git a/src/video_core/renderer_opengl/gl_driver.cpp b/src/video_core/renderer_opengl/gl_driver.cpp index 83dd57718..14d6c7064 100644 --- a/src/video_core/renderer_opengl/gl_driver.cpp +++ b/src/video_core/renderer_opengl/gl_driver.cpp @@ -69,7 +69,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum id, message); } -Driver::Driver(bool gles) : is_gles{gles} { +Driver::Driver(bool gles, bool enable_debug) : is_gles{gles} { #ifndef ANDROID if (!gladLoadGL()) { 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 * https://developer.qualcomm.com/comment/11845 */ - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallback(DebugHandler, nullptr); + if (enable_debug) { + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + glDebugMessageCallback(DebugHandler, nullptr); + } #endif ReportDriverInfo(); diff --git a/src/video_core/renderer_opengl/gl_driver.h b/src/video_core/renderer_opengl/gl_driver.h index 0fa18e600..b8d491b7e 100644 --- a/src/video_core/renderer_opengl/gl_driver.h +++ b/src/video_core/renderer_opengl/gl_driver.h @@ -33,31 +33,37 @@ enum class DriverBug { */ class Driver { public: - Driver(bool gles); + Driver(bool gles, bool enable_debug); /// Returns true of the driver has a particular bug stated in the DriverBug enum bool HasBug(DriverBug bug) const; + /// Returns the vendor of the currently selected physical device Vendor GetVendor() const { return vendor; } + /// Returns true if the current context is ES compatible bool IsOpenGLES() const { return is_gles; } + /// Returns true if the implementation supports ARB_buffer_storage bool HasArbBufferStorage() const { return arb_buffer_storage; } + /// Returns true if the implementation supports EXT_buffer_storage bool HasExtBufferStorage() const { return ext_buffer_storage; } + /// Returns true if the implementation supports EXT_clip_cull_distance bool HasExtClipCullDistance() const { return ext_clip_cull_distance; } + /// Returns true if the implementation supports ARB_direct_state_access bool HasArbDirectStateAccess() const { return arb_direct_state_access; } diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index d1f671df9..071599096 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -353,7 +353,8 @@ static std::array MakeOrthographicMatrix(const float width, cons } 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} { window.mailbox = std::make_unique(); diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index f8537e606..18b2a2e26 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -183,8 +183,9 @@ static std::array MakeOrthographicMatrix(float width, float height } RendererVulkan::RendererVulkan(Frontend::EmuWindow& window) - : RendererBase{window}, instance{window}, scheduler{instance, *this}, renderpass_cache{instance, scheduler}, - runtime{instance, scheduler, renderpass_cache}, swapchain{instance, renderpass_cache}, + : RendererBase{window}, instance{window, Settings::values.renderer_debug}, scheduler{instance, *this}, + renderpass_cache{instance, scheduler}, runtime{instance, scheduler, renderpass_cache}, + swapchain{instance, renderpass_cache}, vertex_buffer{instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}} { auto& telemetry_session = Core::System::GetInstance().TelemetrySession(); diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 8c9a72a97..9c7172852 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -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(); // Fetch instance independant function pointers @@ -64,9 +64,10 @@ Instance::Instance(Frontend::EmuWindow& window) { }; const std::array layers = {"VK_LAYER_KHRONOS_validation"}; + const u32 layer_count = enable_validation ? 1u : 0u; const vk::InstanceCreateInfo instance_info = { .pApplicationInfo = &application_info, - .enabledLayerCount = static_cast(layers.size()), + .enabledLayerCount = layer_count, .ppEnabledLayerNames = layers.data(), .enabledExtensionCount = static_cast(extensions.size()), .ppEnabledExtensionNames = extensions.data() diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index fec584608..f5476c7fe 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -27,7 +27,7 @@ struct FormatTraits { /// The global Vulkan instance class Instance { public: - Instance(Frontend::EmuWindow& window); + Instance(Frontend::EmuWindow& window, bool enable_validation); ~Instance(); /// Returns the FormatTraits struct for the provided pixel format