mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	build: Add flags to toggle specific renderer backends. (#7375)
This commit is contained in:
		
							parent
							
								
									77fce3cf82
								
							
						
					
					
						commit
						82294425e3
					
				
					 18 changed files with 443 additions and 211 deletions
				
			
		|  | @ -185,10 +185,15 @@ add_executable(citra-qt | |||
|     util/spinbox.h | ||||
|     util/util.cpp | ||||
|     util/util.h | ||||
|     util/vk_device_info.cpp | ||||
|     util/vk_device_info.h | ||||
| ) | ||||
| 
 | ||||
| if (ENABLE_VULKAN) | ||||
|     target_sources(citra-qt PRIVATE | ||||
|         util/vk_device_info.cpp | ||||
|         util/vk_device_info.h | ||||
|     ) | ||||
| endif() | ||||
| 
 | ||||
| file(GLOB COMPAT_LIST | ||||
|      ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc | ||||
|      ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) | ||||
|  | @ -300,8 +305,16 @@ endif() | |||
| create_target_directory_groups(citra-qt) | ||||
| 
 | ||||
| target_link_libraries(citra-qt PRIVATE audio_core citra_common citra_core input_common network video_core) | ||||
| target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt6::Widgets Qt6::Multimedia Qt6::Concurrent) | ||||
| target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads vulkan-headers) | ||||
| target_link_libraries(citra-qt PRIVATE Boost::boost nihstro-headers Qt6::Widgets Qt6::Multimedia Qt6::Concurrent) | ||||
| target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) | ||||
| 
 | ||||
| if (ENABLE_OPENGL) | ||||
|     target_link_libraries(citra-qt PRIVATE glad) | ||||
| endif() | ||||
| 
 | ||||
| if (ENABLE_VULKAN) | ||||
|     target_link_libraries(citra-qt PRIVATE vulkan-headers) | ||||
| endif() | ||||
| 
 | ||||
| if (NOT WIN32) | ||||
|     target_include_directories(citra-qt PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ | |||
| #include "video_core/renderer_base.h" | ||||
| #include "video_core/renderer_software/renderer_software.h" | ||||
| 
 | ||||
| #ifdef HAS_OPENGL | ||||
| #ifdef ENABLE_OPENGL | ||||
| #include <glad/glad.h> | ||||
| 
 | ||||
| #include <QOffscreenSurface> | ||||
|  | @ -137,7 +137,7 @@ void EmuThread::run() { | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| #ifdef HAS_OPENGL | ||||
| #ifdef ENABLE_OPENGL | ||||
| static std::unique_ptr<QOpenGLContext> CreateQOpenGLContext(bool gles) { | ||||
|     QSurfaceFormat format; | ||||
|     if (gles) { | ||||
|  | @ -258,7 +258,7 @@ public: | |||
|     virtual ~RenderWidget() = default; | ||||
| }; | ||||
| 
 | ||||
| #ifdef HAS_OPENGL | ||||
| #ifdef ENABLE_OPENGL | ||||
| class OpenGLRenderWidget : public RenderWidget { | ||||
| public: | ||||
|     explicit OpenGLRenderWidget(GRenderWindow* parent, Core::System& system_, bool is_secondary) | ||||
|  | @ -305,6 +305,7 @@ private: | |||
| }; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef ENABLE_VULKAN | ||||
| class VulkanRenderWidget : public RenderWidget { | ||||
| public: | ||||
|     explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) { | ||||
|  | @ -324,7 +325,9 @@ public: | |||
|         return nullptr; | ||||
|     } | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef ENABLE_SOFTWARE_RENDERER | ||||
| struct SoftwareRenderWidget : public RenderWidget { | ||||
|     explicit SoftwareRenderWidget(GRenderWindow* parent, Core::System& system_) | ||||
|         : RenderWidget(parent), system(system_) {} | ||||
|  | @ -377,6 +380,7 @@ struct SoftwareRenderWidget : public RenderWidget { | |||
| private: | ||||
|     Core::System& system; | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| static Frontend::WindowSystemType GetWindowSystemType() { | ||||
|     // Determine WSI type based on Qt platform.
 | ||||
|  | @ -636,17 +640,40 @@ bool GRenderWindow::InitRenderTarget() { | |||
| 
 | ||||
|     const auto graphics_api = Settings::values.graphics_api.GetValue(); | ||||
|     switch (graphics_api) { | ||||
| #ifdef ENABLE_SOFTWARE_RENDERER | ||||
|     case Settings::GraphicsAPI::Software: | ||||
|         InitializeSoftware(); | ||||
|         break; | ||||
| #endif | ||||
| #ifdef ENABLE_OPENGL | ||||
|     case Settings::GraphicsAPI::OpenGL: | ||||
|         if (!InitializeOpenGL() || !LoadOpenGL()) { | ||||
|             return false; | ||||
|         } | ||||
|         break; | ||||
| #endif | ||||
| #ifdef ENABLE_VULKAN | ||||
|     case Settings::GraphicsAPI::Vulkan: | ||||
|         InitializeVulkan(); | ||||
|         break; | ||||
| #endif | ||||
|     default: | ||||
|         LOG_CRITICAL(Frontend, | ||||
|                      "Unknown or unsupported graphics API {}, falling back to available default", | ||||
|                      graphics_api); | ||||
| #ifdef ENABLE_OPENGL | ||||
|         if (!InitializeOpenGL() || !LoadOpenGL()) { | ||||
|             return false; | ||||
|         } | ||||
| #elif ENABLE_VULKAN | ||||
|         InitializeVulkan(); | ||||
| #elif ENABLE_SOFTWARE_RENDERER | ||||
|         InitializeSoftware(); | ||||
| #else | ||||
| // TODO: Add a null renderer backend for this, perhaps.
 | ||||
| #error "At least one renderer must be enabled." | ||||
| #endif | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     // Update the Window System information with the new render target
 | ||||
|  | @ -700,8 +727,8 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal | |||
|     setMinimumSize(minimal_size.first, minimal_size.second); | ||||
| } | ||||
| 
 | ||||
| #ifdef ENABLE_OPENGL | ||||
| bool GRenderWindow::InitializeOpenGL() { | ||||
| #ifdef HAS_OPENGL | ||||
|     if (!QOpenGLContext::supportsThreadedOpenGL()) { | ||||
|         QMessageBox::warning(this, tr("OpenGL not available!"), | ||||
|                              tr("OpenGL shared contexts are not supported.")); | ||||
|  | @ -726,33 +753,13 @@ bool GRenderWindow::InitializeOpenGL() { | |||
|     child_widget->windowHandle()->setFormat(format); | ||||
| 
 | ||||
|     return true; | ||||
| #else | ||||
|     QMessageBox::warning(this, tr("OpenGL not available!"), | ||||
|                          tr("Citra has not been compiled with OpenGL support.")); | ||||
|     return false; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void GRenderWindow::InitializeVulkan() { | ||||
|     auto child = new VulkanRenderWidget(this); | ||||
|     child_widget = child; | ||||
|     child_widget->windowHandle()->create(); | ||||
|     main_context = std::make_unique<DummyContext>(); | ||||
| } | ||||
| 
 | ||||
| void GRenderWindow::InitializeSoftware() { | ||||
|     child_widget = new SoftwareRenderWidget(this, system); | ||||
|     main_context = std::make_unique<DummyContext>(); | ||||
| } | ||||
| 
 | ||||
| #ifdef HAS_OPENGL | ||||
| static void* GetProcAddressGL(const char* name) { | ||||
|     return reinterpret_cast<void*>(QOpenGLContext::currentContext()->getProcAddress(name)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| bool GRenderWindow::LoadOpenGL() { | ||||
| #ifdef HAS_OPENGL | ||||
|     auto context = CreateSharedContext(); | ||||
|     auto scope = context->Acquire(); | ||||
|     const auto gles = context->IsGLES(); | ||||
|  | @ -785,12 +792,24 @@ bool GRenderWindow::LoadOpenGL() { | |||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| #else | ||||
|     QMessageBox::warning(this, tr("OpenGL not available!"), | ||||
|                          tr("Citra has not been compiled with OpenGL support.")); | ||||
|     return false; | ||||
| #endif | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef ENABLE_VULKAN | ||||
| void GRenderWindow::InitializeVulkan() { | ||||
|     auto child = new VulkanRenderWidget(this); | ||||
|     child_widget = child; | ||||
|     child_widget->windowHandle()->create(); | ||||
|     main_context = std::make_unique<DummyContext>(); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef ENABLE_SOFTWARE_RENDERER | ||||
| void GRenderWindow::InitializeSoftware() { | ||||
|     child_widget = new SoftwareRenderWidget(this, system); | ||||
|     main_context = std::make_unique<DummyContext>(); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) { | ||||
|     this->emu_thread = emu_thread; | ||||
|  | @ -805,7 +824,7 @@ void GRenderWindow::showEvent(QShowEvent* event) { | |||
| } | ||||
| 
 | ||||
| std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const { | ||||
| #ifdef HAS_OPENGL | ||||
| #ifdef ENABLE_OPENGL | ||||
|     const auto graphics_api = Settings::values.graphics_api.GetValue(); | ||||
|     if (graphics_api == Settings::GraphicsAPI::OpenGL) { | ||||
|         auto gl_context = static_cast<OpenGLSharedContext*>(main_context.get()); | ||||
|  |  | |||
|  | @ -186,10 +186,16 @@ private: | |||
| 
 | ||||
|     void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override; | ||||
| 
 | ||||
| #ifdef ENABLE_OPENGL | ||||
|     bool InitializeOpenGL(); | ||||
|     void InitializeVulkan(); | ||||
|     void InitializeSoftware(); | ||||
|     bool LoadOpenGL(); | ||||
| #endif | ||||
| #ifdef ENABLE_VULKAN | ||||
|     void InitializeVulkan(); | ||||
| #endif | ||||
| #ifdef ENABLE_SOFTWARE_RENDERER | ||||
|     void InitializeSoftware(); | ||||
| #endif | ||||
| 
 | ||||
|     QWidget* child_widget = nullptr; | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,7 +13,9 @@ | |||
| #include "common/logging/backend.h" | ||||
| #include "common/settings.h" | ||||
| #include "ui_configure_debug.h" | ||||
| #ifdef ENABLE_VULKAN | ||||
| #include "video_core/renderer_vulkan/vk_instance.h" | ||||
| #endif | ||||
| 
 | ||||
| // The QSlider doesn't have an easy way to set a custom step amount,
 | ||||
| // so we can just convert from the sliders range (0 - 79) to the expected
 | ||||
|  | @ -36,6 +38,7 @@ ConfigureDebug::ConfigureDebug(bool is_powered_on_, QWidget* parent) | |||
|         QDesktopServices::openUrl(QUrl::fromLocalFile(path)); | ||||
|     }); | ||||
| 
 | ||||
| #ifdef ENABLE_VULKAN | ||||
|     connect(ui->toggle_renderer_debug, &QCheckBox::clicked, this, [this](bool checked) { | ||||
|         if (checked && Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::Vulkan) { | ||||
|             try { | ||||
|  | @ -65,6 +68,7 @@ ConfigureDebug::ConfigureDebug(bool is_powered_on_, QWidget* parent) | |||
|             } | ||||
|         } | ||||
|     }); | ||||
| #endif | ||||
| 
 | ||||
|     ui->toggle_cpu_jit->setEnabled(!is_powered_on); | ||||
|     ui->toggle_renderer_debug->setEnabled(!is_powered_on); | ||||
|  |  | |||
|  | @ -7,7 +7,9 @@ | |||
| #include "citra_qt/configuration/configure_enhancements.h" | ||||
| #include "common/settings.h" | ||||
| #include "ui_configure_enhancements.h" | ||||
| #ifdef ENABLE_OPENGL | ||||
| #include "video_core/renderer_opengl/post_processing_opengl.h" | ||||
| #endif | ||||
| 
 | ||||
| ConfigureEnhancements::ConfigureEnhancements(QWidget* parent) | ||||
|     : QWidget(parent), ui(std::make_unique<Ui::ConfigureEnhancements>()) { | ||||
|  | @ -117,12 +119,14 @@ void ConfigureEnhancements::updateShaders(Settings::StereoRenderOption stereo_op | |||
| 
 | ||||
|     ui->shader_combobox->setCurrentIndex(0); | ||||
| 
 | ||||
| #ifdef ENABLE_OPENGL | ||||
|     for (const auto& shader : OpenGL::GetPostProcessingShaderList( | ||||
|              stereo_option == Settings::StereoRenderOption::Anaglyph)) { | ||||
|         ui->shader_combobox->addItem(QString::fromStdString(shader)); | ||||
|         if (current_shader == shader) | ||||
|             ui->shader_combobox->setCurrentIndex(ui->shader_combobox->count() - 1); | ||||
|     } | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void ConfigureEnhancements::RetranslateUI() { | ||||
|  |  | |||
|  | @ -3,11 +3,14 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <QColorDialog> | ||||
| #include <QStandardItemModel> | ||||
| #include "citra_qt/configuration/configuration_shared.h" | ||||
| #include "citra_qt/configuration/configure_graphics.h" | ||||
| #include "common/settings.h" | ||||
| #include "ui_configure_graphics.h" | ||||
| #ifdef ENABLE_VULKAN | ||||
| #include "video_core/renderer_vulkan/vk_instance.h" | ||||
| #endif | ||||
| 
 | ||||
| ConfigureGraphics::ConfigureGraphics(std::span<const QString> physical_devices, bool is_powered_on, | ||||
|                                      QWidget* parent) | ||||
|  | @ -27,12 +30,32 @@ ConfigureGraphics::ConfigureGraphics(std::span<const QString> physical_devices, | |||
|     // Set the index to -1 to ensure the below lambda is called with setCurrentIndex
 | ||||
|     ui->graphics_api_combo->setCurrentIndex(-1); | ||||
| 
 | ||||
|     auto graphics_api_combo_model = | ||||
|         qobject_cast<QStandardItemModel*>(ui->graphics_api_combo->model()); | ||||
| #ifndef ENABLE_SOFTWARE_RENDERER | ||||
|     const auto software_item = | ||||
|         graphics_api_combo_model->item(static_cast<u32>(Settings::GraphicsAPI::Software)); | ||||
|     software_item->setFlags(software_item->flags() & ~Qt::ItemIsEnabled); | ||||
| #endif | ||||
| #ifndef ENABLE_OPENGL | ||||
|     const auto opengl_item = | ||||
|         graphics_api_combo_model->item(static_cast<u32>(Settings::GraphicsAPI::OpenGL)); | ||||
|     opengl_item->setFlags(opengl_item->flags() & ~Qt::ItemIsEnabled); | ||||
| #endif | ||||
| #ifndef ENABLE_VULKAN | ||||
|     const auto vulkan_item = | ||||
|         graphics_api_combo_model->item(static_cast<u32>(Settings::GraphicsAPI::Vulkan)); | ||||
|     vulkan_item->setFlags(vulkan_item->flags() & ~Qt::ItemIsEnabled); | ||||
| #else | ||||
|     if (physical_devices.empty()) { | ||||
|         const u32 index = static_cast<u32>(Settings::GraphicsAPI::Vulkan); | ||||
|         ui->graphics_api_combo->removeItem(index); | ||||
|         const auto vulkan_item = | ||||
|             graphics_api_combo_model->item(static_cast<u32>(Settings::GraphicsAPI::Vulkan)); | ||||
|         vulkan_item->setFlags(vulkan_item->flags() & ~Qt::ItemIsEnabled); | ||||
| 
 | ||||
|         ui->physical_device_combo->setVisible(false); | ||||
|         ui->spirv_shader_gen->setVisible(false); | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|     connect(ui->graphics_api_combo, qOverload<int>(&QComboBox::currentIndexChanged), this, | ||||
|             [this](int index) { | ||||
|  |  | |||
|  | @ -519,6 +519,7 @@ void GameList::UpdateColumnVisibility() { | |||
|     tree_view->setColumnHidden(COLUMN_SIZE, !UISettings::values.show_size_column); | ||||
| } | ||||
| 
 | ||||
| #ifdef ENABLE_OPENGL | ||||
| void ForEachOpenGLCacheFile(u64 program_id, auto func) { | ||||
|     for (const std::string_view cache_type : {"separable", "conventional"}) { | ||||
|         const std::string path = fmt::format("{}opengl/precompiled/{}/{:016X}.bin", | ||||
|  | @ -528,6 +529,7 @@ void ForEachOpenGLCacheFile(u64 program_id, auto func) { | |||
|         func(file); | ||||
|     } | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QString& name, | ||||
|                             u64 program_id, u64 extdata_id, Service::FS::MediaType media_type) { | ||||
|  | @ -545,8 +547,10 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr | |||
|     QMenu* shader_menu = context_menu.addMenu(tr("Disk Shader Cache")); | ||||
|     QAction* open_shader_cache_location = shader_menu->addAction(tr("Open Shader Cache Location")); | ||||
|     shader_menu->addSeparator(); | ||||
| #ifdef ENABLE_OPENGL | ||||
|     QAction* delete_opengl_disk_shader_cache = | ||||
|         shader_menu->addAction(tr("Delete OpenGL Shader Cache")); | ||||
| #endif | ||||
| 
 | ||||
|     QMenu* uninstall_menu = context_menu.addMenu(tr("Uninstall")); | ||||
|     QAction* uninstall_all = uninstall_menu->addAction(tr("Everything")); | ||||
|  | @ -564,9 +568,11 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr | |||
|     const bool is_application = program_id_high == 0x00040000 || program_id_high == 0x00040002 || | ||||
|                                 program_id_high == 0x00040010; | ||||
| 
 | ||||
| #ifdef ENABLE_OPENGL | ||||
|     bool opengl_cache_exists = false; | ||||
|     ForEachOpenGLCacheFile( | ||||
|         program_id, [&opengl_cache_exists](QFile& file) { opengl_cache_exists |= file.exists(); }); | ||||
| #endif | ||||
| 
 | ||||
|     std::string sdmc_dir = FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir); | ||||
|     open_save_location->setEnabled( | ||||
|  | @ -603,7 +609,9 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr | |||
|     open_mods_location->setEnabled(is_application); | ||||
|     dump_romfs->setEnabled(is_application); | ||||
| 
 | ||||
| #ifdef ENABLE_OPENGL | ||||
|     delete_opengl_disk_shader_cache->setEnabled(opengl_cache_exists); | ||||
| #endif | ||||
| 
 | ||||
|     uninstall_all->setEnabled(is_installed || has_update || has_dlc); | ||||
|     uninstall_game->setEnabled(is_installed); | ||||
|  | @ -669,9 +677,11 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr | |||
|             emit OpenFolderRequested(program_id, GameListOpenTarget::SHADER_CACHE); | ||||
|         } | ||||
|     }); | ||||
| #ifdef ENABLE_OPENGL | ||||
|     connect(delete_opengl_disk_shader_cache, &QAction::triggered, this, [program_id] { | ||||
|         ForEachOpenGLCacheFile(program_id, [](QFile& file) { file.remove(); }); | ||||
|     }); | ||||
| #endif | ||||
|     connect(uninstall_all, &QAction::triggered, this, [=, this] { | ||||
|         QMessageBox::StandardButton answer = QMessageBox::question( | ||||
|             this, tr("Citra"), | ||||
|  |  | |||
|  | @ -270,6 +270,7 @@ GMainWindow::GMainWindow(Core::System& system_) | |||
|     connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor); | ||||
|     connect(ui->menubar, &QMenuBar::hovered, this, &GMainWindow::OnMouseActivity); | ||||
| 
 | ||||
| #ifdef ENABLE_VULKAN | ||||
|     physical_devices = GetVulkanPhysicalDevices(); | ||||
|     if (physical_devices.empty()) { | ||||
|         QMessageBox::warning(this, tr("No Suitable Vulkan Devices Detected"), | ||||
|  | @ -277,6 +278,7 @@ GMainWindow::GMainWindow(Core::System& system_) | |||
|                                 "Your GPU may not support Vulkan 1.1, or you do not " | ||||
|                                 "have the latest graphics driver.")); | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
| #if ENABLE_QT_UPDATER | ||||
|     if (UISettings::values.check_for_update_on_start) { | ||||
|  | @ -2689,6 +2691,22 @@ void GMainWindow::UpdateAPIIndicator(bool update) { | |||
|     u32 api_index = static_cast<u32>(Settings::values.graphics_api.GetValue()); | ||||
|     if (update) { | ||||
|         api_index = (api_index + 1) % graphics_apis.size(); | ||||
|         // Skip past any disabled renderers.
 | ||||
| #ifndef ENABLE_SOFTWARE_RENDERER | ||||
|         if (api_index == static_cast<u32>(Settings::GraphicsAPI::Software)) { | ||||
|             api_index = (api_index + 1) % graphics_apis.size(); | ||||
|         } | ||||
| #endif | ||||
| #ifndef ENABLE_OPENGL | ||||
|         if (api_index == static_cast<u32>(Settings::GraphicsAPI::OpenGL)) { | ||||
|             api_index = (api_index + 1) % graphics_apis.size(); | ||||
|         } | ||||
| #endif | ||||
| #ifndef ENABLE_VULKAN | ||||
|         if (api_index == static_cast<u32>(Settings::GraphicsAPI::Vulkan)) { | ||||
|             api_index = (api_index + 1) % graphics_apis.size(); | ||||
|         } | ||||
| #endif | ||||
|         Settings::values.graphics_api = static_cast<Settings::GraphicsAPI>(api_index); | ||||
|     } | ||||
| 
 | ||||
|  | @ -3164,8 +3182,11 @@ int main(int argc, char* argv[]) { | |||
|     chdir(bin_path.c_str()); | ||||
| #endif | ||||
| 
 | ||||
| #ifdef ENABLE_OPENGL | ||||
|     QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); | ||||
|     QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); | ||||
| #endif | ||||
| 
 | ||||
|     QApplication app(argc, argv); | ||||
| 
 | ||||
|     // Qt changes the locale and causes issues in float conversion using std::to_string() when
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue