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:
GPUCode
2022-10-02 18:54:00 +03:00
parent 62e88fbeb3
commit eea914ba84
16 changed files with 56 additions and 40 deletions

View File

@ -7,10 +7,8 @@
#include <regex> #include <regex>
#include <string> #include <string>
#include <thread> #include <thread>
// This needs to be included before getopt.h because the latter #defines symbols used by it // This needs to be included before getopt.h because the latter #defines symbols used by it
#include "common/microprofile.h" #include "common/microprofile.h"
#include "citra/config.h" #include "citra/config.h"
#include "citra/emu_window/emu_window_sdl2.h" #include "citra/emu_window/emu_window_sdl2.h"
#include "citra/lodepng_image_interface.h" #include "citra/lodepng_image_interface.h"
@ -18,7 +16,6 @@
#include "common/detached_tasks.h" #include "common/detached_tasks.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/backend.h" #include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/scm_rev.h" #include "common/scm_rev.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
@ -26,13 +23,10 @@
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h" #include "core/core.h"
#include "core/dumping/backend.h" #include "core/dumping/backend.h"
#include "core/file_sys/cia_container.h"
#include "core/frontend/applets/default_applets.h" #include "core/frontend/applets/default_applets.h"
#include "core/frontend/framebuffer_layout.h" #include "core/frontend/framebuffer_layout.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/service/am/am.h" #include "core/hle/service/am/am.h"
#include "core/hle/service/cfg/cfg.h" #include "core/hle/service/cfg/cfg.h"
#include "core/loader/loader.h"
#include "core/movie.h" #include "core/movie.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "network/network.h" #include "network/network.h"
@ -47,7 +41,6 @@
#ifdef _WIN32 #ifdef _WIN32
// windows.h needs to be included before shellapi.h // windows.h needs to be included before shellapi.h
#include <windows.h> #include <windows.h>
#include <shellapi.h> #include <shellapi.h>
extern "C" { extern "C" {

View File

@ -9,7 +9,6 @@
#include <QMessageBox> #include <QMessageBox>
#include <QOffscreenSurface> #include <QOffscreenSurface>
#include <QOpenGLContext> #include <QOpenGLContext>
#include <QOpenGLFunctions_4_3_Core>
#include <QOpenGLExtraFunctions> #include <QOpenGLExtraFunctions>
#include <fmt/format.h> #include <fmt/format.h>
#include "citra_qt/bootmanager.h" #include "citra_qt/bootmanager.h"
@ -121,8 +120,20 @@ public:
/// Create the original context that should be shared from /// Create the original context that should be shared from
explicit OpenGLSharedContext(QSurface* surface) : surface(surface) { explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
QSurfaceFormat format; QSurfaceFormat format;
if (Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES) {
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
format.setVersion(3, 2);
} else {
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
format.setVersion(4, 4); format.setVersion(4, 4);
format.setProfile(QSurfaceFormat::CoreProfile); format.setProfile(QSurfaceFormat::CoreProfile);
}
if (Settings::values.renderer_debug) {
format.setOption(QSurfaceFormat::FormatOption::DebugContext);
}
// TODO: expose a setting for buffer value (ie default/single/double/triple) // TODO: expose a setting for buffer value (ie default/single/double/triple)
format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior); format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
format.setSwapInterval(0); format.setSwapInterval(0);
@ -637,14 +648,6 @@ bool GRenderWindow::InitializeOpenGL() {
child->SetContext( child->SetContext(
std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle())); std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle()));
// Check for OpenGL 4.3 support
if (!QOpenGLContext::globalShareContext()->versionFunctions<QOpenGLFunctions_4_3_Core>()) {
QMessageBox::critical(this, tr("OpenGL 4.3 Unsupported"),
tr("Your GPU may not support OpenGL 4.3, or you do not "
"have the latest graphics driver."));
return false;
}
return true; return true;
} }

View File

@ -601,6 +601,7 @@ void Config::ReadPathValues() {
void Config::ReadRendererValues() { void Config::ReadRendererValues() {
qt_config->beginGroup(QStringLiteral("Renderer")); qt_config->beginGroup(QStringLiteral("Renderer"));
ReadGlobalSetting(Settings::values.graphics_api);
ReadGlobalSetting(Settings::values.use_hw_renderer); ReadGlobalSetting(Settings::values.use_hw_renderer);
ReadGlobalSetting(Settings::values.use_hw_shader); ReadGlobalSetting(Settings::values.use_hw_shader);
#ifdef __APPLE__ #ifdef __APPLE__
@ -622,6 +623,7 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.texture_filter_name); ReadGlobalSetting(Settings::values.texture_filter_name);
if (global) { if (global) {
ReadBasicSetting(Settings::values.renderer_debug);
ReadBasicSetting(Settings::values.use_shader_jit); ReadBasicSetting(Settings::values.use_shader_jit);
} }
@ -1077,6 +1079,7 @@ void Config::SavePathValues() {
void Config::SaveRendererValues() { void Config::SaveRendererValues() {
qt_config->beginGroup(QStringLiteral("Renderer")); qt_config->beginGroup(QStringLiteral("Renderer"));
WriteGlobalSetting(Settings::values.graphics_api);
WriteGlobalSetting(Settings::values.use_hw_renderer); WriteGlobalSetting(Settings::values.use_hw_renderer);
WriteGlobalSetting(Settings::values.use_hw_shader); WriteGlobalSetting(Settings::values.use_hw_shader);
#ifdef __APPLE__ #ifdef __APPLE__
@ -1097,6 +1100,7 @@ void Config::SaveRendererValues() {
WriteGlobalSetting(Settings::values.texture_filter_name); WriteGlobalSetting(Settings::values.texture_filter_name);
if (global) { if (global) {
WriteBasicSetting(Settings::values.renderer_debug);
WriteSetting(QStringLiteral("use_shader_jit"), Settings::values.use_shader_jit.GetValue(), WriteSetting(QStringLiteral("use_shader_jit"), Settings::values.use_shader_jit.GetValue(),
true); true);
} }

View File

@ -25,6 +25,7 @@ ConfigureDebug::ConfigureDebug(QWidget* parent)
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn(); const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
ui->toggle_cpu_jit->setEnabled(!is_powered_on); ui->toggle_cpu_jit->setEnabled(!is_powered_on);
ui->toggle_renderer_debug->setEnabled(!is_powered_on);
} }
ConfigureDebug::~ConfigureDebug() = default; ConfigureDebug::~ConfigureDebug() = default;
@ -37,6 +38,7 @@ void ConfigureDebug::SetConfiguration() {
ui->toggle_console->setChecked(UISettings::values.show_console.GetValue()); ui->toggle_console->setChecked(UISettings::values.show_console.GetValue());
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue())); ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue()));
ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit.GetValue()); ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit.GetValue());
ui->toggle_renderer_debug->setChecked(Settings::values.renderer_debug.GetValue());
} }
void ConfigureDebug::ApplyConfiguration() { void ConfigureDebug::ApplyConfiguration() {
@ -49,6 +51,7 @@ void ConfigureDebug::ApplyConfiguration() {
filter.ParseFilterString(Settings::values.log_filter.GetValue()); filter.ParseFilterString(Settings::values.log_filter.GetValue());
Log::SetGlobalFilter(filter); Log::SetGlobalFilter(filter);
Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked(); Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked();
Settings::values.renderer_debug = ui->toggle_renderer_debug->isChecked();
} }
void ConfigureDebug::RetranslateUI() { void ConfigureDebug::RetranslateUI() {

View File

@ -122,6 +122,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="toggle_renderer_debug">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enables debug reporting in the currently selected graphics API. Causes measurable performance loss, don't enable unless for debugging purposes&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable debug renderer</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -16,7 +16,6 @@
#include "citra_qt/util/spinbox.h" #include "citra_qt/util/spinbox.h"
#include "common/color.h" #include "common/color.h"
#include "core/core.h" #include "core/core.h"
#include "core/hw/gpu.h"
#include "core/memory.h" #include "core/memory.h"
#include "video_core/pica_state.h" #include "video_core/pica_state.h"
#include "video_core/regs_framebuffer.h" #include "video_core/regs_framebuffer.h"

View File

@ -407,8 +407,7 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map)); static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
input_data_mapper->setMapping(input_data[i], i); input_data_mapper->setMapping(input_data[i], i);
} }
connect(input_data_mapper, &QSignalMapper::mappedInt, this, connect(input_data_mapper, &QSignalMapper::mappedInt, this, &GraphicsVertexShaderWidget::OnInputAttributeChanged);
&GraphicsVertexShaderWidget::OnInputAttributeChanged);
auto main_widget = new QWidget; auto main_widget = new QWidget;
auto main_layout = new QVBoxLayout; auto main_layout = new QVBoxLayout;

View File

@ -59,10 +59,7 @@
#include "common/file_util.h" #include "common/file_util.h"
#include "common/literals.h" #include "common/literals.h"
#include "common/logging/backend.h" #include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/logging/text_formatter.h"
#include "common/memory_detect.h"
#include "common/microprofile.h" #include "common/microprofile.h"
#include "common/scm_rev.h" #include "common/scm_rev.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
@ -76,7 +73,6 @@
#include "core/file_sys/archive_extsavedata.h" #include "core/file_sys/archive_extsavedata.h"
#include "core/file_sys/archive_source_sd_savedata.h" #include "core/file_sys/archive_source_sd_savedata.h"
#include "core/frontend/applets/default_applets.h" #include "core/frontend/applets/default_applets.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/archive.h"
#include "core/hle/service/nfc/nfc.h" #include "core/hle/service/nfc/nfc.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
@ -86,7 +82,6 @@
#include "input_common/main.h" #include "input_common/main.h"
#include "network/network_settings.h" #include "network/network_settings.h"
#include "ui_main.h" #include "ui_main.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
#ifdef __APPLE__ #ifdef __APPLE__

View File

@ -446,7 +446,8 @@ struct Values {
Setting<bool> allow_plugin_loader{true, "allow_plugin_loader"}; Setting<bool> allow_plugin_loader{true, "allow_plugin_loader"};
// Renderer // Renderer
SwitchableSetting<GraphicsAPI> graphics_api{GraphicsAPI::Vulkan, "graphics_api"}; SwitchableSetting<GraphicsAPI> graphics_api{GraphicsAPI::OpenGL, "graphics_api"};
Setting<bool> renderer_debug{false, "renderer_debug"};
SwitchableSetting<bool> use_hw_renderer{true, "use_hw_renderer"}; SwitchableSetting<bool> use_hw_renderer{true, "use_hw_renderer"};
SwitchableSetting<bool> use_hw_shader{true, "use_hw_shader"}; SwitchableSetting<bool> use_hw_shader{true, "use_hw_shader"};
SwitchableSetting<bool> separable_shader{false, "use_separable_shader"}; SwitchableSetting<bool> separable_shader{false, "use_separable_shader"};

View File

@ -3,8 +3,6 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <cryptopp/osrng.h> #include <cryptopp/osrng.h>
#include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"

View File

@ -69,7 +69,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
id, message); id, message);
} }
Driver::Driver(bool gles) : is_gles{gles} { Driver::Driver(bool gles, bool enable_debug) : is_gles{gles} {
#ifndef ANDROID #ifndef ANDROID
if (!gladLoadGL()) { if (!gladLoadGL()) {
return; return;
@ -79,8 +79,10 @@ Driver::Driver(bool gles) : is_gles{gles} {
* Qualcomm has some spammy info messages that are marked as errors but not important * Qualcomm has some spammy info messages that are marked as errors but not important
* https://developer.qualcomm.com/comment/11845 * https://developer.qualcomm.com/comment/11845
*/ */
if (enable_debug) {
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(DebugHandler, nullptr); glDebugMessageCallback(DebugHandler, nullptr);
}
#endif #endif
ReportDriverInfo(); ReportDriverInfo();

View File

@ -33,31 +33,37 @@ enum class DriverBug {
*/ */
class Driver { class Driver {
public: public:
Driver(bool gles); Driver(bool gles, bool enable_debug);
/// Returns true of the driver has a particular bug stated in the DriverBug enum /// Returns true of the driver has a particular bug stated in the DriverBug enum
bool HasBug(DriverBug bug) const; bool HasBug(DriverBug bug) const;
/// Returns the vendor of the currently selected physical device
Vendor GetVendor() const { Vendor GetVendor() const {
return vendor; return vendor;
} }
/// Returns true if the current context is ES compatible
bool IsOpenGLES() const { bool IsOpenGLES() const {
return is_gles; return is_gles;
} }
/// Returns true if the implementation supports ARB_buffer_storage
bool HasArbBufferStorage() const { bool HasArbBufferStorage() const {
return arb_buffer_storage; return arb_buffer_storage;
} }
/// Returns true if the implementation supports EXT_buffer_storage
bool HasExtBufferStorage() const { bool HasExtBufferStorage() const {
return ext_buffer_storage; return ext_buffer_storage;
} }
/// Returns true if the implementation supports EXT_clip_cull_distance
bool HasExtClipCullDistance() const { bool HasExtClipCullDistance() const {
return ext_clip_cull_distance; return ext_clip_cull_distance;
} }
/// Returns true if the implementation supports ARB_direct_state_access
bool HasArbDirectStateAccess() const { bool HasArbDirectStateAccess() const {
return arb_direct_state_access; return arb_direct_state_access;
} }

View File

@ -353,7 +353,8 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
} }
RendererOpenGL::RendererOpenGL(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window) RendererOpenGL::RendererOpenGL(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window)
: RendererBase{window, secondary_window}, driver{Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES}, : RendererBase{window, secondary_window}, driver{Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES,
Settings::values.renderer_debug},
frame_dumper(Core::System::GetInstance().VideoDumper(), window) { frame_dumper(Core::System::GetInstance().VideoDumper(), window) {
window.mailbox = std::make_unique<OGLTextureMailbox>(); window.mailbox = std::make_unique<OGLTextureMailbox>();
if (secondary_window) { if (secondary_window) {

View File

@ -183,8 +183,9 @@ static std::array<float, 3 * 2> MakeOrthographicMatrix(float width, float height
} }
RendererVulkan::RendererVulkan(Frontend::EmuWindow& window) RendererVulkan::RendererVulkan(Frontend::EmuWindow& window)
: RendererBase{window}, instance{window}, scheduler{instance, *this}, renderpass_cache{instance, scheduler}, : RendererBase{window}, instance{window, Settings::values.renderer_debug}, scheduler{instance, *this},
runtime{instance, scheduler, renderpass_cache}, swapchain{instance, renderpass_cache}, renderpass_cache{instance, scheduler}, runtime{instance, scheduler, renderpass_cache},
swapchain{instance, renderpass_cache},
vertex_buffer{instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}} { vertex_buffer{instance, scheduler, VERTEX_BUFFER_SIZE, vk::BufferUsageFlagBits::eVertexBuffer, {}} {
auto& telemetry_session = Core::System::GetInstance().TelemetrySession(); auto& telemetry_session = Core::System::GetInstance().TelemetrySession();

View File

@ -38,7 +38,7 @@ vk::Format ToVkFormat(VideoCore::PixelFormat format) {
} }
} }
Instance::Instance(Frontend::EmuWindow& window) { Instance::Instance(Frontend::EmuWindow& window, bool enable_validation) {
auto window_info = window.GetWindowInfo(); auto window_info = window.GetWindowInfo();
// Fetch instance independant function pointers // Fetch instance independant function pointers
@ -64,9 +64,10 @@ Instance::Instance(Frontend::EmuWindow& window) {
}; };
const std::array layers = {"VK_LAYER_KHRONOS_validation"}; const std::array layers = {"VK_LAYER_KHRONOS_validation"};
const u32 layer_count = enable_validation ? 1u : 0u;
const vk::InstanceCreateInfo instance_info = { const vk::InstanceCreateInfo instance_info = {
.pApplicationInfo = &application_info, .pApplicationInfo = &application_info,
.enabledLayerCount = static_cast<u32>(layers.size()), .enabledLayerCount = layer_count,
.ppEnabledLayerNames = layers.data(), .ppEnabledLayerNames = layers.data(),
.enabledExtensionCount = static_cast<u32>(extensions.size()), .enabledExtensionCount = static_cast<u32>(extensions.size()),
.ppEnabledExtensionNames = extensions.data() .ppEnabledExtensionNames = extensions.data()

View File

@ -27,7 +27,7 @@ struct FormatTraits {
/// The global Vulkan instance /// The global Vulkan instance
class Instance { class Instance {
public: public:
Instance(Frontend::EmuWindow& window); Instance(Frontend::EmuWindow& window, bool enable_validation);
~Instance(); ~Instance();
/// Returns the FormatTraits struct for the provided pixel format /// Returns the FormatTraits struct for the provided pixel format