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 <string>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
// 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 <windows.h>
 | 
			
		||||
 | 
			
		||||
#include <shellapi.h>
 | 
			
		||||
#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 <windows.h>
 | 
			
		||||
#include <shellapi.h>
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@
 | 
			
		||||
#include <QMessageBox>
 | 
			
		||||
#include <QOffscreenSurface>
 | 
			
		||||
#include <QOpenGLContext>
 | 
			
		||||
#include <QOpenGLFunctions_4_3_Core>
 | 
			
		||||
#include <QOpenGLExtraFunctions>
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
#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<GMainWindow*>(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<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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -482,6 +482,10 @@ void Config::ReadPathValues() {
 | 
			
		||||
void Config::ReadRendererValues() {
 | 
			
		||||
    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 =
 | 
			
		||||
        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<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_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<double>(Settings::values.bg_red), 0.0);
 | 
			
		||||
    WriteSetting(QStringLiteral("bg_green"), static_cast<double>(Settings::values.bg_green), 0.0);
 | 
			
		||||
    WriteSetting(QStringLiteral("bg_blue"), static_cast<double>(Settings::values.bg_blue), 0.0);
 | 
			
		||||
 | 
			
		||||
    WriteSetting(QStringLiteral("texture_filter_name"),
 | 
			
		||||
                 QString::fromStdString(Settings::values.texture_filter_name),
 | 
			
		||||
 
 | 
			
		||||
@@ -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() {
 | 
			
		||||
 
 | 
			
		||||
@@ -114,11 +114,24 @@
 | 
			
		||||
     <layout class="QVBoxLayout" name="verticalLayout_4">
 | 
			
		||||
      <item>
 | 
			
		||||
       <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">
 | 
			
		||||
         <string>Enable CPU JIT</string>
 | 
			
		||||
        </property>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </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>
 | 
			
		||||
    </widget>
 | 
			
		||||
   </item>
 | 
			
		||||
 
 | 
			
		||||
@@ -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));
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -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<void (QSignalMapper::*)()>(&QSignalMapper::map));
 | 
			
		||||
        input_data_mapper->setMapping(input_data[i], i);
 | 
			
		||||
    }
 | 
			
		||||
    connect(input_data_mapper, static_cast<void (QSignalMapper::*)(int)>(&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"});
 | 
			
		||||
 
 | 
			
		||||
@@ -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<Config>()), emu_thread(nullptr),
 | 
			
		||||
      ui(std::make_unique<Ui::MainWindow>()) {
 | 
			
		||||
GMainWindow::GMainWindow() : ui{std::make_unique<Ui::MainWindow>()}, config{std::make_unique<Config>()}, 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<std::pair<Loader::ResultStatus, Loader::ResultStatus>>;
 | 
			
		||||
    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();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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));
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,12 +3,9 @@
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <cryptopp/osrng.h>
 | 
			
		||||
 | 
			
		||||
#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"
 | 
			
		||||
 
 | 
			
		||||
@@ -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());
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -129,6 +129,8 @@ struct LightingRegs {
 | 
			
		||||
                            "ReflectBlue, instead got %i",
 | 
			
		||||
                            config);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct LightSrc {
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -353,7 +353,8 @@ static std::array<GLfloat, 3 * 2> 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<OGLTextureMailbox>();
 | 
			
		||||
 
 | 
			
		||||
@@ -183,8 +183,9 @@ static std::array<float, 3 * 2> 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();
 | 
			
		||||
 
 | 
			
		||||
@@ -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<u32>(layers.size()),
 | 
			
		||||
        .enabledLayerCount = layer_count,
 | 
			
		||||
        .ppEnabledLayerNames = layers.data(),
 | 
			
		||||
        .enabledExtensionCount = static_cast<u32>(extensions.size()),
 | 
			
		||||
        .ppEnabledExtensionNames = extensions.data()
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user