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;
|
||||
|
||||
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
|
||||
*/
|
||||
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