Frontends: Pick best render API based on renderer

Stops unnecessary display recreation in big picture UI.
This commit is contained in:
Connor McLaughlin 2022-08-26 21:59:45 +10:00
parent 215cfd3daf
commit 1aa7facda8
24 changed files with 94 additions and 67 deletions

View file

@ -366,7 +366,7 @@ protected:
u32 m_multisamples = 1;
u32 m_max_resolution_scale = 1;
u32 m_max_multisamples = 1;
HostDisplay::RenderAPI m_render_api = HostDisplay::RenderAPI::None;
RenderAPI m_render_api = RenderAPI::None;
bool m_true_color = true;
union

View file

@ -35,7 +35,7 @@ GPURenderer GPU_HW_D3D11::GetRendererType() const
bool GPU_HW_D3D11::Initialize()
{
if (!Host::AcquireHostDisplay(HostDisplay::RenderAPI::D3D11))
if (!Host::AcquireHostDisplay(RenderAPI::D3D11))
{
Log_ErrorPrintf("Host render API is incompatible");
return false;

View file

@ -34,7 +34,7 @@ GPURenderer GPU_HW_D3D12::GetRendererType() const
bool GPU_HW_D3D12::Initialize()
{
if (!Host::AcquireHostDisplay(HostDisplay::RenderAPI::D3D12))
if (!Host::AcquireHostDisplay(RenderAPI::D3D12))
{
Log_ErrorPrintf("Host render API is incompatible");
return false;

View file

@ -43,16 +43,16 @@ GPURenderer GPU_HW_OpenGL::GetRendererType() const
bool GPU_HW_OpenGL::Initialize()
{
if (!Host::AcquireHostDisplay(HostDisplay::RenderAPI::OpenGL))
if (!Host::AcquireHostDisplay(RenderAPI::OpenGL))
{
Log_ErrorPrintf("Host render API type is incompatible");
return false;
}
const bool opengl_is_available =
((g_host_display->GetRenderAPI() == HostDisplay::RenderAPI::OpenGL &&
((g_host_display->GetRenderAPI() == RenderAPI::OpenGL &&
(GLAD_GL_VERSION_3_0 || GLAD_GL_ARB_uniform_buffer_object)) ||
(g_host_display->GetRenderAPI() == HostDisplay::RenderAPI::OpenGLES && GLAD_GL_ES_VERSION_3_0));
(g_host_display->GetRenderAPI() == RenderAPI::OpenGLES && GLAD_GL_ES_VERSION_3_0));
if (!opengl_is_available)
{
Host::AddOSDMessage(Host::TranslateStdString("OSDMessage",

View file

@ -53,7 +53,7 @@ private:
u32 num_uniform_buffer_updates;
};
ALWAYS_INLINE bool IsGLES() const { return (m_render_api == HostDisplay::RenderAPI::OpenGLES); }
ALWAYS_INLINE bool IsGLES() const { return (m_render_api == RenderAPI::OpenGLES); }
std::tuple<s32, s32> ConvertToFramebufferCoordinates(s32 x, s32 y);

View file

@ -2,7 +2,7 @@
#include "common/assert.h"
#include <cstdio>
GPU_HW_ShaderGen::GPU_HW_ShaderGen(HostDisplay::RenderAPI render_api, u32 resolution_scale, u32 multisamples,
GPU_HW_ShaderGen::GPU_HW_ShaderGen(RenderAPI render_api, u32 resolution_scale, u32 multisamples,
bool per_sample_shading, bool true_color, bool scaled_dithering,
GPUTextureFilter texture_filtering, bool uv_limits, bool pgxp_depth,
bool supports_dual_source_blend)

View file

@ -5,7 +5,7 @@
class GPU_HW_ShaderGen : public ShaderGen
{
public:
GPU_HW_ShaderGen(HostDisplay::RenderAPI render_api, u32 resolution_scale, u32 multisamples, bool per_sample_shading,
GPU_HW_ShaderGen(RenderAPI render_api, u32 resolution_scale, u32 multisamples, bool per_sample_shading,
bool true_color, bool scaled_dithering, GPUTextureFilter texture_filtering, bool uv_limits,
bool pgxp_depth, bool supports_dual_source_blend);
~GPU_HW_ShaderGen();

View file

@ -33,7 +33,7 @@ GPURenderer GPU_HW_Vulkan::GetRendererType() const
bool GPU_HW_Vulkan::Initialize()
{
if (!Host::AcquireHostDisplay(HostDisplay::RenderAPI::Vulkan))
if (!Host::AcquireHostDisplay(RenderAPI::Vulkan))
{
Log_ErrorPrintf("Host render API is incompatible");
return false;

View file

@ -21,7 +21,7 @@ HostDisplayTexture::~HostDisplayTexture() = default;
HostDisplay::~HostDisplay() = default;
HostDisplay::RenderAPI HostDisplay::GetPreferredAPI()
RenderAPI HostDisplay::GetPreferredAPI()
{
#ifdef _WIN32
return RenderAPI::D3D11;

View file

@ -8,6 +8,16 @@
#include <tuple>
#include <vector>
enum class RenderAPI : u32
{
None,
D3D11,
D3D12,
Vulkan,
OpenGL,
OpenGLES
};
enum class HostDisplayPixelFormat : u32
{
Unknown,
@ -37,16 +47,6 @@ public:
class HostDisplay
{
public:
enum class RenderAPI
{
None,
D3D11,
D3D12,
Vulkan,
OpenGL,
OpenGLES
};
enum class Alignment
{
LeftOrTop,
@ -304,10 +304,10 @@ protected:
extern std::unique_ptr<HostDisplay> g_host_display;
namespace Host {
std::unique_ptr<HostDisplay> CreateDisplayForAPI(HostDisplay::RenderAPI api);
std::unique_ptr<HostDisplay> CreateDisplayForAPI(RenderAPI api);
/// Creates the host display. This may create a new window. The API used depends on the current configuration.
bool AcquireHostDisplay(HostDisplay::RenderAPI api);
bool AcquireHostDisplay(RenderAPI api);
/// Destroys the host display. This may close the display window.
void ReleaseHostDisplay();

View file

@ -850,6 +850,30 @@ const char* Settings::GetRendererDisplayName(GPURenderer renderer)
return s_gpu_renderer_display_names[static_cast<int>(renderer)];
}
RenderAPI Settings::GetRenderAPIForRenderer(GPURenderer renderer)
{
switch (renderer)
{
#ifdef _WIN32
case GPURenderer::HardwareD3D11:
return RenderAPI::D3D11;
case GPURenderer::HardwareD3D12:
return RenderAPI::D3D12;
#endif
#ifdef WITH_VULKAN
case GPURenderer::HardwareVulkan:
return RenderAPI::Vulkan;
#endif
#ifdef WITH_OPENGL
case GPURenderer::HardwareOpenGL:
return RenderAPI::OpenGL;
#endif
case GPURenderer::Software:
default:
return HostDisplay::GetPreferredAPI();
}
}
static constexpr auto s_texture_filter_names =
make_array("Nearest", "Bilinear", "BilinearBinAlpha", "JINC2", "JINC2BinAlpha", "xBR", "xBRBinAlpha");
static constexpr auto s_texture_filter_display_names =

View file

@ -9,6 +9,8 @@
#include <string>
#include <vector>
enum class RenderAPI : u32;
struct SettingInfo
{
enum class Type
@ -332,6 +334,7 @@ struct Settings
static std::optional<GPURenderer> ParseRendererName(const char* str);
static const char* GetRendererName(GPURenderer renderer);
static const char* GetRendererDisplayName(GPURenderer renderer);
static RenderAPI GetRenderAPIForRenderer(GPURenderer renderer);
static std::optional<GPUTextureFilter> ParseTextureFilterName(const char* str);
static const char* GetTextureFilterName(GPUTextureFilter filter);

View file

@ -10,22 +10,22 @@
Log_SetChannel(ShaderGen);
ShaderGen::ShaderGen(HostDisplay::RenderAPI render_api, bool supports_dual_source_blend)
ShaderGen::ShaderGen(RenderAPI render_api, bool supports_dual_source_blend)
: m_render_api(render_api),
m_glsl(render_api != HostDisplay::RenderAPI::D3D11 && render_api != HostDisplay::RenderAPI::D3D12),
m_glsl(render_api != RenderAPI::D3D11 && render_api != RenderAPI::D3D12),
m_supports_dual_source_blend(supports_dual_source_blend), m_use_glsl_interface_blocks(false)
{
#if defined(WITH_OPENGL) || defined(WITH_VULKAN)
if (m_glsl)
{
#ifdef WITH_OPENGL
if (m_render_api == HostDisplay::RenderAPI::OpenGL || m_render_api == HostDisplay::RenderAPI::OpenGLES)
if (m_render_api == RenderAPI::OpenGL || m_render_api == RenderAPI::OpenGLES)
SetGLSLVersionString();
m_use_glsl_interface_blocks = (IsVulkan() || GLAD_GL_ES_VERSION_3_2 || GLAD_GL_VERSION_3_2);
m_use_glsl_binding_layout = (IsVulkan() || UseGLSLBindingLayout());
if (m_render_api == HostDisplay::RenderAPI::OpenGL)
if (m_render_api == RenderAPI::OpenGL)
{
// SSAA with interface blocks is broken on AMD's OpenGL driver.
const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
@ -62,7 +62,7 @@ void ShaderGen::DefineMacro(std::stringstream& ss, const char* name, bool enable
void ShaderGen::SetGLSLVersionString()
{
const char* glsl_version = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
const bool glsl_es = (m_render_api == HostDisplay::RenderAPI::OpenGLES);
const bool glsl_es = (m_render_api == RenderAPI::OpenGLES);
Assert(glsl_version != nullptr);
// Skip any strings in front of the version code.
@ -105,14 +105,14 @@ void ShaderGen::SetGLSLVersionString()
void ShaderGen::WriteHeader(std::stringstream& ss)
{
if (m_render_api == HostDisplay::RenderAPI::OpenGL || m_render_api == HostDisplay::RenderAPI::OpenGLES)
if (m_render_api == RenderAPI::OpenGL || m_render_api == RenderAPI::OpenGLES)
ss << m_glsl_version_string << "\n\n";
else if (m_render_api == HostDisplay::RenderAPI::Vulkan)
else if (m_render_api == RenderAPI::Vulkan)
ss << "#version 450 core\n\n";
#ifdef WITH_OPENGL
// Extension enabling for OpenGL.
if (m_render_api == HostDisplay::RenderAPI::OpenGLES)
if (m_render_api == RenderAPI::OpenGLES)
{
// Enable EXT_blend_func_extended for dual-source blend on OpenGL ES.
if (GLAD_GL_EXT_blend_func_extended)
@ -131,7 +131,7 @@ void ShaderGen::WriteHeader(std::stringstream& ss)
ss << "#define DRIVER_POWERVR 1\n";
}
}
else if (m_render_api == HostDisplay::RenderAPI::OpenGL)
else if (m_render_api == RenderAPI::OpenGL)
{
// Need extensions for binding layout if GL<4.3.
if (m_use_glsl_binding_layout && !GLAD_GL_VERSION_4_3)
@ -150,14 +150,14 @@ void ShaderGen::WriteHeader(std::stringstream& ss)
}
#endif
DefineMacro(ss, "API_OPENGL", m_render_api == HostDisplay::RenderAPI::OpenGL);
DefineMacro(ss, "API_OPENGL_ES", m_render_api == HostDisplay::RenderAPI::OpenGLES);
DefineMacro(ss, "API_D3D11", m_render_api == HostDisplay::RenderAPI::D3D11);
DefineMacro(ss, "API_D3D12", m_render_api == HostDisplay::RenderAPI::D3D12);
DefineMacro(ss, "API_VULKAN", m_render_api == HostDisplay::RenderAPI::Vulkan);
DefineMacro(ss, "API_OPENGL", m_render_api == RenderAPI::OpenGL);
DefineMacro(ss, "API_OPENGL_ES", m_render_api == RenderAPI::OpenGLES);
DefineMacro(ss, "API_D3D11", m_render_api == RenderAPI::D3D11);
DefineMacro(ss, "API_D3D12", m_render_api == RenderAPI::D3D12);
DefineMacro(ss, "API_VULKAN", m_render_api == RenderAPI::Vulkan);
#ifdef WITH_OPENGL
if (m_render_api == HostDisplay::RenderAPI::OpenGLES)
if (m_render_api == RenderAPI::OpenGLES)
{
ss << "precision highp float;\n";
ss << "precision highp int;\n";

View file

@ -7,7 +7,7 @@
class ShaderGen
{
public:
ShaderGen(HostDisplay::RenderAPI render_api, bool supports_dual_source_blend);
ShaderGen(RenderAPI render_api, bool supports_dual_source_blend);
~ShaderGen();
static bool UseGLSLBindingLayout();
@ -19,7 +19,7 @@ public:
std::string GenerateSampleFragmentShader();
protected:
ALWAYS_INLINE bool IsVulkan() const { return (m_render_api == HostDisplay::RenderAPI::Vulkan); }
ALWAYS_INLINE bool IsVulkan() const { return (m_render_api == RenderAPI::Vulkan); }
const char* GetInterpolationQualifier(bool interface_block, bool centroid_interpolation, bool sample_interpolation,
bool is_out) const;
@ -45,7 +45,7 @@ protected:
bool declare_fragcoord = false, u32 num_color_outputs = 1, bool depth_output = false,
bool msaa = false, bool ssaa = false, bool declare_sample_id = false);
HostDisplay::RenderAPI m_render_api;
RenderAPI m_render_api;
bool m_glsl;
bool m_supports_dual_source_blend;
bool m_use_glsl_interface_blocks;

View file

@ -77,7 +77,7 @@ static std::unique_ptr<NoGUIPlatform> CreatePlatform();
static std::string GetWindowTitle(const std::string& game_title);
static void UpdateWindowTitle(const std::string& game_title);
static void GameListRefreshThreadEntryPoint(bool invalidate_cache);
static bool AcquireHostDisplay(HostDisplay::RenderAPI api);
static bool AcquireHostDisplay(RenderAPI api);
static void ReleaseHostDisplay();
} // namespace NoGUIHost
@ -658,7 +658,7 @@ void NoGUIHost::CPUThreadEntryPoint()
CommonHost::Initialize();
// start the GS thread up and get it going
if (AcquireHostDisplay(HostDisplay::GetPreferredAPI()))
if (AcquireHostDisplay(Settings::GetRenderAPIForRenderer(g_settings.gpu_renderer)))
{
// kick a game list refresh if we're not in batch mode
if (!InBatchMode())
@ -699,7 +699,7 @@ void NoGUIHost::CPUThreadMainLoop()
}
}
bool NoGUIHost::AcquireHostDisplay(HostDisplay::RenderAPI api)
bool NoGUIHost::AcquireHostDisplay(RenderAPI api)
{
Assert(!g_host_display);
@ -759,7 +759,7 @@ bool NoGUIHost::AcquireHostDisplay(HostDisplay::RenderAPI api)
return true;
}
bool Host::AcquireHostDisplay(HostDisplay::RenderAPI api)
bool Host::AcquireHostDisplay(RenderAPI api)
{
if (g_host_display && g_host_display->GetRenderAPI() == api)
{

View file

@ -443,7 +443,7 @@ void EmuThread::startFullscreenUI()
if (s_start_fullscreen_ui_fullscreen)
m_is_fullscreen = true;
if (!acquireHostDisplay(HostDisplay::GetPreferredAPI()))
if (!acquireHostDisplay(Settings::GetRenderAPIForRenderer(g_settings.gpu_renderer)))
{
m_run_fullscreen_ui = false;
return;
@ -707,7 +707,7 @@ void EmuThread::requestDisplaySize(float scale)
System::RequestDisplaySize(scale);
}
bool EmuThread::acquireHostDisplay(HostDisplay::RenderAPI api)
bool EmuThread::acquireHostDisplay(RenderAPI api)
{
if (g_host_display)
{
@ -1632,7 +1632,7 @@ void Host::CommitBaseSettingChanges()
QtHost::QueueSettingsSave();
}
bool Host::AcquireHostDisplay(HostDisplay::RenderAPI api)
bool Host::AcquireHostDisplay(RenderAPI api)
{
return g_emu_thread->acquireHostDisplay(api);
}

View file

@ -91,7 +91,7 @@ public:
ALWAYS_INLINE bool isSurfaceless() const { return m_is_surfaceless; }
ALWAYS_INLINE bool isRunningFullscreenUI() const { return m_run_fullscreen_ui; }
bool acquireHostDisplay(HostDisplay::RenderAPI api);
bool acquireHostDisplay(RenderAPI api);
void connectDisplaySignals(DisplayWidget* widget);
void releaseHostDisplay();
void renderDisplay(bool skip_present);

View file

@ -130,26 +130,26 @@ void CommonHost::PumpMessagesOnCPUThread()
#endif
}
std::unique_ptr<HostDisplay> Host::CreateDisplayForAPI(HostDisplay::RenderAPI api)
std::unique_ptr<HostDisplay> Host::CreateDisplayForAPI(RenderAPI api)
{
switch (api)
{
#ifdef WITH_VULKAN
case HostDisplay::RenderAPI::Vulkan:
case RenderAPI::Vulkan:
return std::make_unique<FrontendCommon::VulkanHostDisplay>();
#endif
#ifdef WITH_OPENGL
case HostDisplay::RenderAPI::OpenGL:
case HostDisplay::RenderAPI::OpenGLES:
case RenderAPI::OpenGL:
case RenderAPI::OpenGLES:
return std::make_unique<FrontendCommon::OpenGLHostDisplay>();
#endif
#ifdef _WIN32
case HostDisplay::RenderAPI::D3D12:
case RenderAPI::D3D12:
return std::make_unique<FrontendCommon::D3D12HostDisplay>();
case HostDisplay::RenderAPI::D3D11:
case RenderAPI::D3D11:
return std::make_unique<FrontendCommon::D3D11HostDisplay>();
#endif

View file

@ -59,9 +59,9 @@ D3D11HostDisplay::~D3D11HostDisplay()
AssertMsg(!m_swap_chain, "Swap chain should have been destroyed by now");
}
HostDisplay::RenderAPI D3D11HostDisplay::GetRenderAPI() const
RenderAPI D3D11HostDisplay::GetRenderAPI() const
{
return HostDisplay::RenderAPI::D3D11;
return RenderAPI::D3D11;
}
void* D3D11HostDisplay::GetRenderDevice() const
@ -1026,7 +1026,7 @@ bool D3D11HostDisplay::SetPostProcessingChain(const std::string_view& config)
shader_cache.Open(EmuFolders::Cache, m_device->GetFeatureLevel(), SHADER_CACHE_VERSION,
g_settings.gpu_use_debug_device);
FrontendCommon::PostProcessingShaderGen shadergen(HostDisplay::RenderAPI::D3D11, true);
FrontendCommon::PostProcessingShaderGen shadergen(RenderAPI::D3D11, true);
u32 max_ubo_size = 0;
for (u32 i = 0; i < m_post_processing_chain.GetStageCount(); i++)

View file

@ -60,9 +60,9 @@ D3D12HostDisplay::~D3D12HostDisplay()
AssertMsg(!m_swap_chain, "Swap chain should have been destroyed by now");
}
HostDisplay::RenderAPI D3D12HostDisplay::GetRenderAPI() const
RenderAPI D3D12HostDisplay::GetRenderAPI() const
{
return HostDisplay::RenderAPI::D3D12;
return RenderAPI::D3D12;
}
void* D3D12HostDisplay::GetRenderDevice() const

View file

@ -44,7 +44,7 @@ OpenGLHostDisplay::~OpenGLHostDisplay()
AssertMsg(!m_gl_context, "Context should have been destroyed by now");
}
HostDisplay::RenderAPI OpenGLHostDisplay::GetRenderAPI() const
RenderAPI OpenGLHostDisplay::GetRenderAPI() const
{
return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL;
}
@ -947,7 +947,7 @@ bool OpenGLHostDisplay::SetPostProcessingChain(const std::string_view& config)
m_post_processing_stages.clear();
FrontendCommon::PostProcessingShaderGen shadergen(HostDisplay::RenderAPI::OpenGL, false);
FrontendCommon::PostProcessingShaderGen shadergen(RenderAPI::OpenGL, false);
for (u32 i = 0; i < m_post_processing_chain.GetStageCount(); i++)
{

View file

@ -2,7 +2,7 @@
namespace FrontendCommon {
PostProcessingShaderGen::PostProcessingShaderGen(HostDisplay::RenderAPI render_api, bool supports_dual_source_blend)
PostProcessingShaderGen::PostProcessingShaderGen(RenderAPI render_api, bool supports_dual_source_blend)
: ShaderGen(render_api, supports_dual_source_blend)
{
}

View file

@ -8,7 +8,7 @@ namespace FrontendCommon {
class PostProcessingShaderGen : public ShaderGen
{
public:
PostProcessingShaderGen(HostDisplay::RenderAPI render_api, bool supports_dual_source_blend);
PostProcessingShaderGen(RenderAPI render_api, bool supports_dual_source_blend);
~PostProcessingShaderGen();
std::string GeneratePostProcessingVertexShader(const PostProcessingShader& shader);

View file

@ -55,9 +55,9 @@ VulkanHostDisplay::~VulkanHostDisplay()
AssertMsg(!m_swap_chain, "Swap chain should have been destroyed by now");
}
HostDisplay::RenderAPI VulkanHostDisplay::GetRenderAPI() const
RenderAPI VulkanHostDisplay::GetRenderAPI() const
{
return HostDisplay::RenderAPI::Vulkan;
return RenderAPI::Vulkan;
}
void* VulkanHostDisplay::GetRenderDevice() const
@ -950,7 +950,7 @@ bool VulkanHostDisplay::SetPostProcessingChain(const std::string_view& config)
m_post_processing_stages.clear();
FrontendCommon::PostProcessingShaderGen shadergen(HostDisplay::RenderAPI::Vulkan, false);
FrontendCommon::PostProcessingShaderGen shadergen(RenderAPI::Vulkan, false);
bool only_use_push_constants = true;
for (u32 i = 0; i < m_post_processing_chain.GetStageCount(); i++)