diff --git a/Source/Core/Common/GL/GLExtensions/GLExtensions.cpp b/Source/Core/Common/GL/GLExtensions/GLExtensions.cpp index d43e898ca5..e761f9e05a 100644 --- a/Source/Core/Common/GL/GLExtensions/GLExtensions.cpp +++ b/Source/Core/Common/GL/GLExtensions/GLExtensions.cpp @@ -1674,7 +1674,7 @@ const GLFunc gl_function_array[] = { GLFUNC_REQUIRES(glDrawArraysInstancedBaseInstance, "VERSION_4_2"), GLFUNC_REQUIRES(glDrawElementsInstancedBaseInstance, "VERSION_4_2"), GLFUNC_REQUIRES(glDrawElementsInstancedBaseVertexBaseInstance, "VERSION_4_2"), - GLFUNC_REQUIRES(glGetInternalformativ, "VERSION_4_2"), + GLFUNC_REQUIRES(glGetInternalformativ, "VERSION_4_2 |VERSION_GLES_3"), GLFUNC_REQUIRES(glGetActiveAtomicCounterBufferiv, "VERSION_4_2"), GLFUNC_REQUIRES(glBindImageTexture, "VERSION_4_2"), GLFUNC_REQUIRES(glMemoryBarrier, "VERSION_4_2"), diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index fb97379411..dbcca8a687 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -261,7 +261,7 @@ bool Init(std::unique_ptr boot, const WindowSystemInfo& wsi) Host_UpdateMainFrame(); // Disable any menus or buttons at boot // Manually reactivate the video backend in case a GameINI overrides the video backend setting. - VideoBackendBase::PopulateBackendInfo(); + VideoBackendBase::PopulateBackendInfo(wsi); // Issue any API calls which must occur on the main thread for the graphics backend. WindowSystemInfo prepared_wsi(wsi); @@ -579,7 +579,7 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi system.GetPowerPC().GetDebugInterface().Clear(guard); }}; - VideoBackendBase::PopulateBackendInfo(); + VideoBackendBase::PopulateBackendInfo(wsi); if (!g_video_backend->Initialize(wsi)) { diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 05142ae672..ec9ac2065a 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -534,7 +534,6 @@ - @@ -1160,7 +1159,6 @@ - diff --git a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp index 113c9fe835..c5889d2ad4 100644 --- a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp @@ -23,8 +23,6 @@ #include "DolphinQt/QtUtils/NonDefaultQPushButton.h" #include "DolphinQt/Settings.h" -#include "UICommon/VideoUtils.h" - #include "VideoCommon/PostProcessing.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoCommon.h" @@ -260,18 +258,38 @@ void EnhancementsWidget::LoadSettings() m_block_save = true; // Anti-Aliasing - const int aa_selection = Config::Get(Config::GFX_MSAA); + const u32 aa_selection = Config::Get(Config::GFX_MSAA); const bool ssaa = Config::Get(Config::GFX_SSAA); const int aniso = Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY); const TextureFilteringMode tex_filter_mode = Config::Get(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING); m_aa_combo->clear(); - for (const auto& option : VideoUtils::GetAvailableAntialiasingModes(m_msaa_modes)) - m_aa_combo->addItem(option == "None" ? tr("None") : QString::fromStdString(option)); - m_aa_combo->setCurrentText( - QString::fromStdString(std::to_string(aa_selection) + "x " + (ssaa ? "SSAA" : "MSAA"))); + for (const u32 aa_mode : g_Config.backend_info.AAModes) + { + if (aa_mode == 1) + m_aa_combo->addItem(tr("None"), 1); + else + m_aa_combo->addItem(tr("%1x MSAA").arg(aa_mode), static_cast(aa_mode)); + + if (aa_mode == aa_selection && !ssaa) + m_aa_combo->setCurrentIndex(m_aa_combo->count() - 1); + } + if (g_Config.backend_info.bSupportsSSAA) + { + for (const u32 aa_mode : g_Config.backend_info.AAModes) + { + if (aa_mode != 1) // don't show "None" twice + { + // Mark SSAA using negative values in the variant + m_aa_combo->addItem(tr("%1x SSAA").arg(aa_mode), -static_cast(aa_mode)); + if (aa_mode == aa_selection && ssaa) + m_aa_combo->setCurrentIndex(m_aa_combo->count() - 1); + } + } + } + m_aa_combo->setEnabled(m_aa_combo->count() > 1); switch (tex_filter_mode) @@ -310,22 +328,10 @@ void EnhancementsWidget::SaveSettings() if (m_block_save) return; - bool is_ssaa = m_aa_combo->currentText().endsWith(QStringLiteral("SSAA")); - - int aa_value = m_aa_combo->currentIndex(); - - if (aa_value == 0) - { - aa_value = 1; - } - else - { - if (aa_value > m_msaa_modes) - aa_value -= m_msaa_modes; - aa_value = std::pow(2, aa_value); - } - Config::SetBaseOrCurrent(Config::GFX_MSAA, static_cast(aa_value)); + const u32 aa_value = static_cast(std::abs(m_aa_combo->currentData().toInt())); + const bool is_ssaa = m_aa_combo->currentData().toInt() < 0; + Config::SetBaseOrCurrent(Config::GFX_MSAA, aa_value); Config::SetBaseOrCurrent(Config::GFX_SSAA, is_ssaa); const int texture_filtering_selection = m_texture_filtering_combo->currentData().toInt(); diff --git a/Source/Core/DolphinQt/Config/Graphics/GraphicsWindow.cpp b/Source/Core/DolphinQt/Config/Graphics/GraphicsWindow.cpp index 535458685c..7b31cc7f6e 100644 --- a/Source/Core/DolphinQt/Config/Graphics/GraphicsWindow.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/GraphicsWindow.cpp @@ -24,7 +24,7 @@ #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoConfig.h" -GraphicsWindow::GraphicsWindow(MainWindow* parent) : QDialog(parent) +GraphicsWindow::GraphicsWindow(MainWindow* parent) : QDialog(parent), m_main_window(parent) { CreateMainLayout(); @@ -68,7 +68,7 @@ void GraphicsWindow::CreateMainLayout() void GraphicsWindow::OnBackendChanged(const QString& backend_name) { Config::SetBase(Config::MAIN_GFX_BACKEND, backend_name.toStdString()); - VideoBackendBase::PopulateBackendInfoFromUI(); + VideoBackendBase::PopulateBackendInfoFromUI(m_main_window->GetWindowSystemInfo()); setWindowTitle( tr("%1 Graphics Configuration").arg(tr(g_video_backend->GetDisplayName().c_str()))); diff --git a/Source/Core/DolphinQt/Config/Graphics/GraphicsWindow.h b/Source/Core/DolphinQt/Config/Graphics/GraphicsWindow.h index c345de3fef..5949a2dda3 100644 --- a/Source/Core/DolphinQt/Config/Graphics/GraphicsWindow.h +++ b/Source/Core/DolphinQt/Config/Graphics/GraphicsWindow.h @@ -28,4 +28,6 @@ signals: private: void CreateMainLayout(); void OnBackendChanged(const QString& backend); + + MainWindow* const m_main_window; }; diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 8262c8f01e..42a6a04603 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -343,12 +343,17 @@ MainWindow::~MainWindow() Config::Save(); } +WindowSystemInfo MainWindow::GetWindowSystemInfo() const +{ + return ::GetWindowSystemInfo(m_render_widget->windowHandle()); +} + void MainWindow::InitControllers() { if (g_controller_interface.IsInit()) return; - UICommon::InitControllers(GetWindowSystemInfo(windowHandle())); + UICommon::InitControllers(::GetWindowSystemInfo(windowHandle())); m_hotkey_scheduler = new HotkeyScheduler(); m_hotkey_scheduler->Start(); @@ -1098,7 +1103,7 @@ void MainWindow::StartGame(std::unique_ptr&& parameters) // Boot up, show an error if it fails to load the game. if (!BootManager::BootCore(std::move(parameters), - GetWindowSystemInfo(m_render_widget->windowHandle()))) + ::GetWindowSystemInfo(m_render_widget->windowHandle()))) { ModalMessageBox::critical(this, tr("Error"), tr("Failed to init core"), QMessageBox::Ok); HideRenderWidget(); @@ -1206,7 +1211,7 @@ void MainWindow::HideRenderWidget(bool reinit, bool is_exit) // The controller interface will still be registered to the old render widget, if the core // has booted. Therefore, we should re-bind it to the main window for now. When the core // is next started, it will be swapped back to the new render widget. - g_controller_interface.ChangeWindow(GetWindowSystemInfo(windowHandle()).render_window, + g_controller_interface.ChangeWindow(::GetWindowSystemInfo(windowHandle()).render_window, is_exit ? ControllerInterface::WindowChangeReason::Exit : ControllerInterface::WindowChangeReason::Other); } diff --git a/Source/Core/DolphinQt/MainWindow.h b/Source/Core/DolphinQt/MainWindow.h index fa3a274bfc..4654202ed7 100644 --- a/Source/Core/DolphinQt/MainWindow.h +++ b/Source/Core/DolphinQt/MainWindow.h @@ -50,6 +50,7 @@ class ThreadWidget; class ToolBar; class WatchWidget; class WiiTASInputWindow; +struct WindowSystemInfo; namespace DiscIO { @@ -76,6 +77,7 @@ public: ~MainWindow(); void Show(); + WindowSystemInfo GetWindowSystemInfo() const; bool eventFilter(QObject* object, QEvent* event) override; diff --git a/Source/Core/UICommon/CMakeLists.txt b/Source/Core/UICommon/CMakeLists.txt index f2ffbd0821..947aeae346 100644 --- a/Source/Core/UICommon/CMakeLists.txt +++ b/Source/Core/UICommon/CMakeLists.txt @@ -23,8 +23,6 @@ add_library(uicommon UICommon.h USBUtils.cpp USBUtils.h - VideoUtils.cpp - VideoUtils.h ) target_link_libraries(uicommon diff --git a/Source/Core/UICommon/VideoUtils.cpp b/Source/Core/UICommon/VideoUtils.cpp deleted file mode 100644 index 17947e81b2..0000000000 --- a/Source/Core/UICommon/VideoUtils.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "UICommon/VideoUtils.h" - -#include "Common/Assert.h" -#include "VideoCommon/VideoConfig.h" - -namespace VideoUtils -{ -std::vector GetAvailableAntialiasingModes(int& msaa_modes) -{ - std::vector modes; - const auto& aa_modes = g_Config.backend_info.AAModes; - const bool supports_ssaa = g_Config.backend_info.bSupportsSSAA; - msaa_modes = 0; - - for (const auto mode : aa_modes) - { - if (mode == 1) - { - modes.push_back("None"); - ASSERT_MSG(VIDEO, !supports_ssaa || msaa_modes == 0, "SSAA setting won't work correctly"); - } - else - { - modes.push_back(std::to_string(mode) + "x MSAA"); - msaa_modes++; - } - } - - if (supports_ssaa) - { - for (const auto mode : aa_modes) - { - if (mode != 1) - modes.push_back(std::to_string(mode) + "x SSAA"); - } - } - - return modes; -} -} // namespace VideoUtils diff --git a/Source/Core/UICommon/VideoUtils.h b/Source/Core/UICommon/VideoUtils.h deleted file mode 100644 index 492813adab..0000000000 --- a/Source/Core/UICommon/VideoUtils.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include - -namespace VideoUtils -{ -std::vector GetAvailableAntialiasingModes(int& m_msaa_modes); -} // namespace VideoUtils diff --git a/Source/Core/VideoBackends/D3D/D3DMain.cpp b/Source/Core/VideoBackends/D3D/D3DMain.cpp index 8256674ad5..4f797fcb26 100644 --- a/Source/Core/VideoBackends/D3D/D3DMain.cpp +++ b/Source/Core/VideoBackends/D3D/D3DMain.cpp @@ -63,7 +63,7 @@ std::optional VideoBackend::GetWarningMessage() const return result; } -void VideoBackend::InitBackendInfo() +void VideoBackend::InitBackendInfo(const WindowSystemInfo& wsi) { if (!D3DCommon::LoadLibraries()) return; diff --git a/Source/Core/VideoBackends/D3D/VideoBackend.h b/Source/Core/VideoBackends/D3D/VideoBackend.h index 1349d13b2b..6a94f8c7a3 100644 --- a/Source/Core/VideoBackends/D3D/VideoBackend.h +++ b/Source/Core/VideoBackends/D3D/VideoBackend.h @@ -18,7 +18,7 @@ public: std::string GetDisplayName() const override; std::optional GetWarningMessage() const override; - void InitBackendInfo() override; + void InitBackendInfo(const WindowSystemInfo& wsi) override; static constexpr const char* NAME = "D3D"; diff --git a/Source/Core/VideoBackends/D3D12/VideoBackend.cpp b/Source/Core/VideoBackends/D3D12/VideoBackend.cpp index afc5bb96e8..f82b7d961b 100644 --- a/Source/Core/VideoBackends/D3D12/VideoBackend.cpp +++ b/Source/Core/VideoBackends/D3D12/VideoBackend.cpp @@ -36,7 +36,7 @@ std::string VideoBackend::GetDisplayName() const return "Direct3D 12"; } -void VideoBackend::InitBackendInfo() +void VideoBackend::InitBackendInfo(const WindowSystemInfo& wsi) { if (!D3DCommon::LoadLibraries()) return; diff --git a/Source/Core/VideoBackends/D3D12/VideoBackend.h b/Source/Core/VideoBackends/D3D12/VideoBackend.h index 7d3126b38c..db03b738d0 100644 --- a/Source/Core/VideoBackends/D3D12/VideoBackend.h +++ b/Source/Core/VideoBackends/D3D12/VideoBackend.h @@ -16,7 +16,7 @@ public: std::string GetName() const override; std::string GetDisplayName() const override; - void InitBackendInfo() override; + void InitBackendInfo(const WindowSystemInfo& wsi) override; static constexpr const char* NAME = "D3D12"; diff --git a/Source/Core/VideoBackends/Metal/MTLMain.mm b/Source/Core/VideoBackends/Metal/MTLMain.mm index f799d5eea1..7042e091fd 100644 --- a/Source/Core/VideoBackends/Metal/MTLMain.mm +++ b/Source/Core/VideoBackends/Metal/MTLMain.mm @@ -119,7 +119,7 @@ void Metal::VideoBackend::Shutdown() ObjectCache::Shutdown(); } -void Metal::VideoBackend::InitBackendInfo() +void Metal::VideoBackend::InitBackendInfo(const WindowSystemInfo& wsi) { @autoreleasepool { diff --git a/Source/Core/VideoBackends/Metal/VideoBackend.h b/Source/Core/VideoBackends/Metal/VideoBackend.h index 3a567718e2..a6a24173e5 100644 --- a/Source/Core/VideoBackends/Metal/VideoBackend.h +++ b/Source/Core/VideoBackends/Metal/VideoBackend.h @@ -18,7 +18,7 @@ public: std::string GetDisplayName() const override; std::optional GetWarningMessage() const override; - void InitBackendInfo() override; + void InitBackendInfo(const WindowSystemInfo& wsi) override; void PrepareWindow(WindowSystemInfo& wsi) override; diff --git a/Source/Core/VideoBackends/Null/NullBackend.cpp b/Source/Core/VideoBackends/Null/NullBackend.cpp index 900a911699..28afcce4dc 100644 --- a/Source/Core/VideoBackends/Null/NullBackend.cpp +++ b/Source/Core/VideoBackends/Null/NullBackend.cpp @@ -25,7 +25,7 @@ namespace Null { -void VideoBackend::InitBackendInfo() +void VideoBackend::InitBackendInfo(const WindowSystemInfo& wsi) { g_Config.backend_info.api_type = APIType::Nothing; g_Config.backend_info.MaxTextureSize = 16384; diff --git a/Source/Core/VideoBackends/Null/VideoBackend.h b/Source/Core/VideoBackends/Null/VideoBackend.h index f08098cfd0..4437c0c48d 100644 --- a/Source/Core/VideoBackends/Null/VideoBackend.h +++ b/Source/Core/VideoBackends/Null/VideoBackend.h @@ -15,7 +15,7 @@ public: std::string GetName() const override { return NAME; } std::string GetDisplayName() const override; - void InitBackendInfo() override; + void InitBackendInfo(const WindowSystemInfo& wsi) override; static constexpr const char* NAME = "Null"; }; diff --git a/Source/Core/VideoBackends/OGL/OGLConfig.cpp b/Source/Core/VideoBackends/OGL/OGLConfig.cpp index 95998b836b..2695402b63 100644 --- a/Source/Core/VideoBackends/OGL/OGLConfig.cpp +++ b/Source/Core/VideoBackends/OGL/OGLConfig.cpp @@ -3,6 +3,11 @@ #include "VideoBackends/OGL/OGLConfig.h" +#include +#include +#include + +#include "Common/Assert.h" #include "Common/GL/GLContext.h" #include "Common/GL/GLExtensions/GLExtensions.h" #include "Common/Logging/LogManager.h" @@ -10,14 +15,13 @@ #include "Core/Config/GraphicsSettings.h" +#include "VideoBackends/OGL/OGLTexture.h" + #include "VideoCommon/DriverDetails.h" +#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/VideoConfig.h" -#include -#include -#include - namespace OGL { void InitDriverInfo() @@ -537,9 +541,118 @@ bool PopulateConfig(GLContext* m_main_gl_context) g_Config.backend_info.bSupportsEarlyZ = g_ogl_config.bSupportsImageLoadStore || g_ogl_config.bSupportsConservativeDepth; - glGetIntegerv(GL_MAX_SAMPLES, &g_ogl_config.max_samples); - if (g_ogl_config.max_samples < 1 || !g_ogl_config.bSupportsMSAA) - g_ogl_config.max_samples = 1; + g_Config.backend_info.AAModes.clear(); + if (g_ogl_config.bSupportsMSAA) + { + bool supportsGetInternalFormat = + GLExtensions::Supports("VERSION_4_2") || GLExtensions::Supports("VERSION_GLES_3"); + if (supportsGetInternalFormat) + { + // Note: GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES should technically be used for + // GL_OES_texture_storage_multisample_2d_array, but both are 0x9102 so it does not matter. + + std::vector color_aa_modes; + { + GLenum colorInternalFormat = OGLTexture::GetGLInternalFormatForTextureFormat( + FramebufferManager::GetEFBColorFormat(), true); + GLint num_color_sample_counts = 0; + glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, colorInternalFormat, + GL_NUM_SAMPLE_COUNTS, 1, &num_color_sample_counts); + + ASSERT_MSG(VIDEO, num_color_sample_counts >= 0, + "negative GL_NUM_SAMPLE_COUNTS for colors does not make sense: {}", + num_color_sample_counts); + color_aa_modes.reserve(num_color_sample_counts + 1); + if (num_color_sample_counts > 0) + { + color_aa_modes.resize(num_color_sample_counts); + + static_assert(sizeof(GLint) == sizeof(u32)); + glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, colorInternalFormat, GL_SAMPLES, + num_color_sample_counts, + reinterpret_cast(color_aa_modes.data())); + ASSERT_MSG(VIDEO, std::is_sorted(color_aa_modes.rbegin(), color_aa_modes.rend()), + "GPU driver didn't return sorted color AA modes: [{}]", + fmt::join(color_aa_modes, ", ")); + } + + if (color_aa_modes.empty() || color_aa_modes.back() != 1) + color_aa_modes.push_back(1); + } + + std::vector depth_aa_modes; + { + GLenum depthInternalFormat = OGLTexture::GetGLInternalFormatForTextureFormat( + FramebufferManager::GetEFBColorFormat(), true); + GLint num_depth_sample_counts = 0; + glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, depthInternalFormat, + GL_NUM_SAMPLE_COUNTS, 1, &num_depth_sample_counts); + + ASSERT_MSG(VIDEO, num_depth_sample_counts >= 0, + "negative GL_NUM_SAMPLE_COUNTS for depth does not make sense: {}", + num_depth_sample_counts); + depth_aa_modes.reserve(num_depth_sample_counts + 1); + if (num_depth_sample_counts > 0) + { + depth_aa_modes.resize(num_depth_sample_counts); + + static_assert(sizeof(GLint) == sizeof(u32)); + glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, depthInternalFormat, GL_SAMPLES, + num_depth_sample_counts, + reinterpret_cast(depth_aa_modes.data())); + ASSERT_MSG(VIDEO, std::is_sorted(depth_aa_modes.rbegin(), depth_aa_modes.rend()), + "GPU driver didn't return sorted depth AA modes: [{}]", + fmt::join(depth_aa_modes, ", ")); + } + + if (depth_aa_modes.empty() || depth_aa_modes.back() != 1) + depth_aa_modes.push_back(1); + } + + // The spec says supported sample formats are returned in descending numeric order. + // It also says "Only positive values are returned", but does not specify whether 1 is + // included or not; it seems like NVIDIA and Intel GPUs do not include it. + // We've inserted 1 at the back of both if not present to handle this. + g_Config.backend_info.AAModes.clear(); + g_Config.backend_info.AAModes.reserve(std::min(color_aa_modes.size(), depth_aa_modes.size())); + // We only want AA modes that are supported for both the color and depth textures. Probably + // the support is the same, though. rbegin/rend are used to swap the order ahead of time. + std::set_intersection(color_aa_modes.rbegin(), color_aa_modes.rend(), depth_aa_modes.rbegin(), + depth_aa_modes.rend(), + std::back_inserter(g_Config.backend_info.AAModes)); + } + else + { + // The documentation for glGetInternalformativ says its value is at least the minimum of + // GL_MAX_SAMPLES, GL_MAX_COLOR_TEXTURE_SAMPLES, and GL_MAX_DEPTH_TEXTURE_SAMPLES (and + // GL_MAX_INTEGER_SAMPLES for integer textures, assumed not applicable here). + GLint max_color_samples = 0; + glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &max_color_samples); + GLint max_depth_samples = 0; + glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &max_depth_samples); + // Note: The desktop OpenGL ref pages don't actually say that GL_MAX_SAMPLES is a valid + // parameter for glGetIntegerv (though the ES ones do). However, MAX_SAMPLES is + // referenced in the GL 3.1 spec and by GL_ARB_texture_multisample (which is written against + // the OpenGL 3.1 spec), so presumably it is valid. + GLint max_samples = 0; + glGetIntegerv(GL_MAX_SAMPLES, &max_samples); + u32 supported_max_samples = + static_cast(std::min({max_samples, max_color_samples, max_depth_samples})); + + while (supported_max_samples > 1) + { + g_Config.backend_info.AAModes.push_back(supported_max_samples); + supported_max_samples /= 2; + } + g_Config.backend_info.AAModes.push_back(1); + // The UI wants ascending order + std::reverse(g_Config.backend_info.AAModes.begin(), g_Config.backend_info.AAModes.end()); + } + } + else + { + g_Config.backend_info.AAModes = {1}; + } const bool bSupportsIsHelperInvocation = g_ogl_config.bIsES ? g_ogl_config.eSupportedGLSLVersion >= GlslEs320 : diff --git a/Source/Core/VideoBackends/OGL/OGLConfig.h b/Source/Core/VideoBackends/OGL/OGLConfig.h index 6a50269222..2b78c35c2b 100644 --- a/Source/Core/VideoBackends/OGL/OGLConfig.h +++ b/Source/Core/VideoBackends/OGL/OGLConfig.h @@ -82,8 +82,6 @@ struct VideoConfig const char* gl_vendor; const char* gl_renderer; const char* gl_version; - - s32 max_samples; }; void InitDriverInfo(); diff --git a/Source/Core/VideoBackends/OGL/OGLGfx.cpp b/Source/Core/VideoBackends/OGL/OGLGfx.cpp index e83ff209ea..e545ed7f4b 100644 --- a/Source/Core/VideoBackends/OGL/OGLGfx.cpp +++ b/Source/Core/VideoBackends/OGL/OGLGfx.cpp @@ -146,12 +146,6 @@ OGLGfx::OGLGfx(std::unique_ptr main_gl_context, float backbuffer_scal } } - if (!PopulateConfig(m_main_gl_context.get())) - { - // Not all needed extensions are supported, so we have to stop here. - // Else some of the next calls might crash. - return; - } InitDriverInfo(); // Setup Debug logging diff --git a/Source/Core/VideoBackends/OGL/OGLMain.cpp b/Source/Core/VideoBackends/OGL/OGLMain.cpp index c47b94ceb8..13f47a054f 100644 --- a/Source/Core/VideoBackends/OGL/OGLMain.cpp +++ b/Source/Core/VideoBackends/OGL/OGLMain.cpp @@ -74,8 +74,45 @@ std::string VideoBackend::GetDisplayName() const return _trans("OpenGL"); } -void VideoBackend::InitBackendInfo() +void VideoBackend::InitBackendInfo(const WindowSystemInfo& wsi) { + std::unique_ptr temp_gl_context = + GLContext::Create(wsi, g_Config.stereo_mode == StereoMode::QuadBuffer, true, false, + Config::Get(Config::GFX_PREFER_GLES)); + + if (!temp_gl_context) + return; + + FillBackendInfo(temp_gl_context.get()); +} + +bool VideoBackend::InitializeGLExtensions(GLContext* context) +{ + // Init extension support. + if (!GLExtensions::Init(context)) + { + // OpenGL 2.0 is required for all shader based drawings. There is no way to get this by + // extensions + PanicAlertFmtT("GPU: OGL ERROR: Does your video card support OpenGL 2.0?"); + return false; + } + + if (GLExtensions::Version() < 300) + { + // integer vertex attributes require a gl3 only function + PanicAlertFmtT("GPU: OGL ERROR: Need OpenGL version 3.\n" + "GPU: Does your video card support OpenGL 3?"); + return false; + } + + return true; +} + +bool VideoBackend::FillBackendInfo(GLContext* context) +{ + if (!InitializeGLExtensions(context)) + return false; + g_Config.backend_info.api_type = APIType::OpenGL; g_Config.backend_info.MaxTextureSize = 16384; g_Config.backend_info.bUsesLowerLeftOrigin = true; @@ -105,7 +142,7 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsGPUTextureDecoding = true; g_Config.backend_info.bSupportsBBox = true; - // Overwritten in OGLRender.cpp later + // Overwritten in OGLConfig.cpp later g_Config.backend_info.bSupportsDualSourceBlend = true; g_Config.backend_info.bSupportsPrimitiveRestart = true; g_Config.backend_info.bSupportsPaletteConversion = true; @@ -123,33 +160,6 @@ void VideoBackend::InitBackendInfo() // aamodes - 1 is to stay consistent with D3D (means no AA) g_Config.backend_info.AAModes = {1, 2, 4, 8}; -} - -bool VideoBackend::InitializeGLExtensions(GLContext* context) -{ - // Init extension support. - if (!GLExtensions::Init(context)) - { - // OpenGL 2.0 is required for all shader based drawings. There is no way to get this by - // extensions - PanicAlertFmtT("GPU: OGL ERROR: Does your video card support OpenGL 2.0?"); - return false; - } - - if (GLExtensions::Version() < 300) - { - // integer vertex attributes require a gl3 only function - PanicAlertFmtT("GPU: OGL ERROR: Need OpenGL version 3.\n" - "GPU: Does your video card support OpenGL 3?"); - return false; - } - - return true; -} - -bool VideoBackend::FillBackendInfo() -{ - InitBackendInfo(); // check for the max vertex attributes GLint numvertexattribs = 0; @@ -172,6 +182,13 @@ bool VideoBackend::FillBackendInfo() return false; } + if (!PopulateConfig(context)) + { + // Not all needed extensions are supported, so we have to stop here. + // Else some of the next calls might crash. + return false; + } + // TODO: Move the remaining fields from the Renderer constructor here. return true; } @@ -184,7 +201,7 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) if (!main_gl_context) return false; - if (!InitializeGLExtensions(main_gl_context.get()) || !FillBackendInfo()) + if (!FillBackendInfo(main_gl_context.get())) return false; auto gfx = std::make_unique(std::move(main_gl_context), wsi.render_surface_scale); diff --git a/Source/Core/VideoBackends/OGL/OGLTexture.cpp b/Source/Core/VideoBackends/OGL/OGLTexture.cpp index 0e4e99f59b..f8894a365b 100644 --- a/Source/Core/VideoBackends/OGL/OGLTexture.cpp +++ b/Source/Core/VideoBackends/OGL/OGLTexture.cpp @@ -15,9 +15,7 @@ namespace OGL { -namespace -{ -GLenum GetGLInternalFormatForTextureFormat(AbstractTextureFormat format, bool storage) +GLenum OGLTexture::GetGLInternalFormatForTextureFormat(AbstractTextureFormat format, bool storage) { switch (format) { @@ -55,6 +53,8 @@ GLenum GetGLInternalFormatForTextureFormat(AbstractTextureFormat format, bool st } } +namespace +{ GLenum GetGLFormatForTextureFormat(AbstractTextureFormat format) { switch (format) diff --git a/Source/Core/VideoBackends/OGL/OGLTexture.h b/Source/Core/VideoBackends/OGL/OGLTexture.h index ca08910eae..53d9d7f589 100644 --- a/Source/Core/VideoBackends/OGL/OGLTexture.h +++ b/Source/Core/VideoBackends/OGL/OGLTexture.h @@ -36,6 +36,7 @@ public: { return IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY; } + static GLenum GetGLInternalFormatForTextureFormat(AbstractTextureFormat format, bool storage); GLenum GetGLFormatForImageTexture() const; private: diff --git a/Source/Core/VideoBackends/OGL/VideoBackend.h b/Source/Core/VideoBackends/OGL/VideoBackend.h index 4be861954e..53f7f940d5 100644 --- a/Source/Core/VideoBackends/OGL/VideoBackend.h +++ b/Source/Core/VideoBackends/OGL/VideoBackend.h @@ -19,12 +19,12 @@ public: std::string GetName() const override; std::string GetDisplayName() const override; - void InitBackendInfo() override; + void InitBackendInfo(const WindowSystemInfo& wsi) override; static constexpr const char* NAME = "OGL"; private: bool InitializeGLExtensions(GLContext* context); - bool FillBackendInfo(); + bool FillBackendInfo(GLContext* context); }; } // namespace OGL diff --git a/Source/Core/VideoBackends/Software/SWmain.cpp b/Source/Core/VideoBackends/Software/SWmain.cpp index 8703ea4b4d..ccb040e8ad 100644 --- a/Source/Core/VideoBackends/Software/SWmain.cpp +++ b/Source/Core/VideoBackends/Software/SWmain.cpp @@ -62,7 +62,7 @@ std::optional VideoSoftware::GetWarningMessage() const "really want to enable software rendering? If unsure, select 'No'."); } -void VideoSoftware::InitBackendInfo() +void VideoSoftware::InitBackendInfo(const WindowSystemInfo& wsi) { g_Config.backend_info.api_type = APIType::Nothing; g_Config.backend_info.MaxTextureSize = 16384; diff --git a/Source/Core/VideoBackends/Software/VideoBackend.h b/Source/Core/VideoBackends/Software/VideoBackend.h index 8c3cb081ef..35c3adb1a7 100644 --- a/Source/Core/VideoBackends/Software/VideoBackend.h +++ b/Source/Core/VideoBackends/Software/VideoBackend.h @@ -17,7 +17,7 @@ class VideoSoftware : public VideoBackendBase std::string GetDisplayName() const override; std::optional GetWarningMessage() const override; - void InitBackendInfo() override; + void InitBackendInfo(const WindowSystemInfo& wsi) override; static constexpr const char* NAME = "Software Renderer"; }; diff --git a/Source/Core/VideoBackends/Vulkan/VKMain.cpp b/Source/Core/VideoBackends/Vulkan/VKMain.cpp index 053b592c14..2eb9b34106 100644 --- a/Source/Core/VideoBackends/Vulkan/VKMain.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKMain.cpp @@ -30,7 +30,7 @@ namespace Vulkan { -void VideoBackend::InitBackendInfo() +void VideoBackend::InitBackendInfo(const WindowSystemInfo& wsi) { VulkanContext::PopulateBackendInfo(&g_Config); diff --git a/Source/Core/VideoBackends/Vulkan/VideoBackend.h b/Source/Core/VideoBackends/Vulkan/VideoBackend.h index a16d149307..4e8c3a5471 100644 --- a/Source/Core/VideoBackends/Vulkan/VideoBackend.h +++ b/Source/Core/VideoBackends/Vulkan/VideoBackend.h @@ -16,7 +16,7 @@ public: std::string GetName() const override { return NAME; } std::string GetDisplayName() const override { return _trans("Vulkan"); } - void InitBackendInfo() override; + void InitBackendInfo(const WindowSystemInfo& wsi) override; void PrepareWindow(WindowSystemInfo& wsi) override; static constexpr const char* NAME = "Vulkan"; diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp index 9d6ff70664..6e466c8557 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/VideoBackendBase.cpp @@ -281,7 +281,7 @@ void VideoBackendBase::ActivateBackend(const std::string& name) g_video_backend = iter->get(); } -void VideoBackendBase::PopulateBackendInfo() +void VideoBackendBase::PopulateBackendInfo(const WindowSystemInfo& wsi) { g_Config.Refresh(); // Reset backend_info so if the backend forgets to initialize something it doesn't end up using @@ -289,18 +289,18 @@ void VideoBackendBase::PopulateBackendInfo() g_Config.backend_info = {}; ActivateBackend(Config::Get(Config::MAIN_GFX_BACKEND)); g_Config.backend_info.DisplayName = g_video_backend->GetDisplayName(); - g_video_backend->InitBackendInfo(); + g_video_backend->InitBackendInfo(wsi); // We validate the config after initializing the backend info, as system-specific settings // such as anti-aliasing, or the selected adapter may be invalid, and should be checked. g_Config.VerifyValidity(); } -void VideoBackendBase::PopulateBackendInfoFromUI() +void VideoBackendBase::PopulateBackendInfoFromUI(const WindowSystemInfo& wsi) { // If the core is running, the backend info will have been populated already. // If we did it here, the UI thread can race with the with the GPU thread. if (!Core::IsRunning()) - PopulateBackendInfo(); + PopulateBackendInfo(wsi); } void VideoBackendBase::DoState(PointerWrap& p) diff --git a/Source/Core/VideoCommon/VideoBackendBase.h b/Source/Core/VideoCommon/VideoBackendBase.h index 2ce235f8f8..f5222a1936 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.h +++ b/Source/Core/VideoCommon/VideoBackendBase.h @@ -47,7 +47,7 @@ public: virtual std::string GetName() const = 0; virtual std::string GetDisplayName() const { return GetName(); } - virtual void InitBackendInfo() = 0; + virtual void InitBackendInfo(const WindowSystemInfo& wsi) = 0; virtual std::optional GetWarningMessage() const { return {}; } // Prepares a native window for rendering. This is called on the main thread, or the @@ -69,9 +69,9 @@ public: static void ActivateBackend(const std::string& name); // Fills the backend_info fields with the capabilities of the selected backend/device. - static void PopulateBackendInfo(); + static void PopulateBackendInfo(const WindowSystemInfo& wsi); // Called by the UI thread when the graphics config is opened. - static void PopulateBackendInfoFromUI(); + static void PopulateBackendInfoFromUI(const WindowSystemInfo& wsi); // Wrapper function which pushes the event to the GPU thread. void DoState(PointerWrap& p);