From 1298246ed7f38bea17f93e6ec438ba2e0e7f23f4 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Mon, 2 Nov 2020 21:45:46 +1000 Subject: [PATCH] WIP --- src/core/host_display.h | 1 + src/core/host_interface.cpp | 1 + src/core/settings.cpp | 6 + src/core/settings.h | 1 + src/frontend-common/common_host_interface.cpp | 31 ++++- src/frontend-common/d3d11_host_display.cpp | 111 ++++++++++++++---- src/frontend-common/d3d11_host_display.h | 5 + src/frontend-common/opengl_host_display.cpp | 10 ++ src/frontend-common/opengl_host_display.h | 1 + src/frontend-common/postprocessing_chain.cpp | 19 +++ src/frontend-common/postprocessing_chain.h | 1 + src/frontend-common/vulkan_host_display.cpp | 10 ++ src/frontend-common/vulkan_host_display.h | 1 + 13 files changed, 172 insertions(+), 26 deletions(-) diff --git a/src/core/host_display.h b/src/core/host_display.h index f4cda7756..231e18548 100644 --- a/src/core/host_display.h +++ b/src/core/host_display.h @@ -72,6 +72,7 @@ public: virtual bool CreateResources() = 0; virtual void DestroyResources() = 0; + virtual bool SetScalingShader(const std::string_view& config) = 0; virtual bool SetPostProcessingChain(const std::string_view& config) = 0; /// Call when the window size changes externally to recreate any resources. diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index c08936ce5..7245b15bc 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -461,6 +461,7 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si) si.SetBoolValue("Display", "ShowResolution", false); si.SetBoolValue("Display", "Fullscreen", false); si.SetBoolValue("Display", "VSync", true); + si.SetStringValue("Display", "ScaleShader", ""); si.SetStringValue("Display", "PostProcessChain", ""); si.SetBoolValue("CDROM", "ReadThread", true); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 626b2a078..d7c83bcf2 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -175,6 +175,7 @@ void Settings::Load(SettingsInterface& si) display_show_speed = si.GetBoolValue("Display", "ShowSpeed", false); display_show_resolution = si.GetBoolValue("Display", "ShowResolution", false); video_sync_enabled = si.GetBoolValue("Display", "VSync", true); + display_scale_shader = si.GetStringValue("Display", "ScaleShader", ""); display_post_process_chain = si.GetStringValue("Display", "PostProcessChain", ""); cdrom_read_thread = si.GetBoolValue("CDROM", "ReadThread", true); @@ -298,6 +299,11 @@ void Settings::Save(SettingsInterface& si) const si.SetBoolValue("Display", "ShowSpeed", display_show_speed); si.SetBoolValue("Display", "ShowResolution", display_show_speed); si.SetBoolValue("Display", "VSync", video_sync_enabled); + if (display_scale_shader.empty()) + si.DeleteValue("Display", "ScaleShader"); + else + si.SetStringValue("Display", "ScaleShader", display_scale_shader.c_str()); + if (display_post_process_chain.empty()) si.DeleteValue("Display", "PostProcessChain"); else diff --git a/src/core/settings.h b/src/core/settings.h index 3ad76714e..256d6dd8c 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -91,6 +91,7 @@ struct Settings GPURenderer gpu_renderer = GPURenderer::Software; std::string gpu_adapter; + std::string display_scale_shader; std::string display_post_process_chain; u32 gpu_resolution_scale = 1; u32 gpu_multisamples = 1; diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp index 1a0c0e87c..859dea5e3 100644 --- a/src/frontend-common/common_host_interface.cpp +++ b/src/frontend-common/common_host_interface.cpp @@ -177,6 +177,7 @@ void CommonHostInterface::DestroySystem() SetTimerResolutionIncreased(false); m_save_state_selector_ui->Close(); m_display->SetPostProcessingChain({}); + m_display->SetScalingShader({}); HostInterface::DestroySystem(); } @@ -715,6 +716,9 @@ void CommonHostInterface::OnSystemCreated() { HostInterface::OnSystemCreated(); + if (!g_settings.display_scale_shader.empty() && !m_display->SetScalingShader(g_settings.display_scale_shader)) + AddOSDMessage(TranslateStdString("OSDMessage", "Failed to load scaling shader."), 20.0f); + if (g_settings.display_post_processing && !m_display->SetPostProcessingChain(g_settings.display_post_process_chain)) AddOSDMessage(TranslateStdString("OSDMessage", "Failed to load post processing shader chain."), 20.0f); } @@ -2082,6 +2086,12 @@ void CommonHostInterface::CheckForSettingsChanges(const Settings& old_settings) UpdateSpeedLimiterState(); } + if (g_settings.display_scale_shader != old_settings.display_scale_shader) + { + if (!m_display->SetScalingShader(g_settings.display_post_process_chain)) + AddOSDMessage(TranslateStdString("OSDMessage", "Failed to load scaling shader."), 20.0f); + } + if (g_settings.display_post_processing != old_settings.display_post_processing || g_settings.display_post_process_chain != old_settings.display_post_process_chain) { @@ -2469,13 +2479,24 @@ void CommonHostInterface::TogglePostProcessing() void CommonHostInterface::ReloadPostProcessingShaders() { - if (!m_display || !g_settings.display_post_processing) + if (!m_display) return; - if (!m_display->SetPostProcessingChain(g_settings.display_post_process_chain)) - AddOSDMessage(TranslateStdString("OSDMessage", "Failed to load post-processing shader chain."), 20.0f); - else - AddOSDMessage(TranslateStdString("OSDMessage", "Post-processing shaders reloaded."), 10.0f); + if (!g_settings.display_scale_shader.empty()) + { + if (!m_display->SetScalingShader(g_settings.display_scale_shader)) + AddOSDMessage(TranslateStdString("OSDMessage", "Failed to load scaling shader."), 20.0f); + else + AddOSDMessage(TranslateStdString("OSDMessage", "Scaling shader reloaded."), 10.0f); + } + + if (g_settings.display_post_processing) + { + if (!m_display->SetPostProcessingChain(g_settings.display_post_process_chain)) + AddOSDMessage(TranslateStdString("OSDMessage", "Failed to load post-processing shader chain."), 20.0f); + else + AddOSDMessage(TranslateStdString("OSDMessage", "Post-processing shaders reloaded."), 10.0f); + } } bool CommonHostInterface::ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, diff --git a/src/frontend-common/d3d11_host_display.cpp b/src/frontend-common/d3d11_host_display.cpp index ef15a9c16..3915e7146 100644 --- a/src/frontend-common/d3d11_host_display.cpp +++ b/src/frontend-common/d3d11_host_display.cpp @@ -724,19 +724,38 @@ void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, v s32 texture_view_height, bool linear_filter) { m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0); - m_context->PSSetShader(m_display_pixel_shader.Get(), nullptr, 0); m_context->PSSetShaderResources(0, 1, reinterpret_cast(&texture_handle)); - m_context->PSSetSamplers(0, 1, linear_filter ? m_linear_sampler.GetAddressOf() : m_point_sampler.GetAddressOf()); + m_context->PSSetSamplers(0, 1, + (linear_filter && !m_scale_stage.has_value()) ? m_linear_sampler.GetAddressOf() : + m_point_sampler.GetAddressOf()); + + if (!m_scale_stage) + { + const float uniforms[4] = {static_cast(texture_view_x) / static_cast(texture_width), + static_cast(texture_view_y) / static_cast(texture_height), + (static_cast(texture_view_width) - 0.5f) / static_cast(texture_width), + (static_cast(texture_view_height) - 0.5f) / static_cast(texture_height)}; + const auto map = + m_display_uniform_buffer.Map(m_context.Get(), m_display_uniform_buffer.GetSize(), sizeof(uniforms)); + std::memcpy(map.pointer, uniforms, sizeof(uniforms)); + m_display_uniform_buffer.Unmap(m_context.Get(), sizeof(uniforms)); + m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0); + m_context->VSSetConstantBuffers(0, 1, m_display_uniform_buffer.GetD3DBufferArray()); + m_context->PSSetShader(m_display_pixel_shader.Get(), nullptr, 0); + } + else + { + const auto map = + m_display_uniform_buffer.Map(m_context.Get(), m_display_uniform_buffer.GetSize(), m_scale_stage->uniforms_size); + m_scale_shader->FillUniformBuffer(map.pointer, texture_width, texture_height, texture_view_x, texture_view_y, + texture_view_width, texture_view_height, width, height, 0.0f); + m_display_uniform_buffer.Unmap(m_context.Get(), m_scale_stage->uniforms_size); + m_context->VSSetShader(m_scale_stage->vertex_shader.Get(), nullptr, 0); + m_context->VSSetConstantBuffers(0, 1, m_display_uniform_buffer.GetD3DBufferArray()); + m_context->PSSetShader(m_scale_stage->pixel_shader.Get(), nullptr, 0); + m_context->PSSetConstantBuffers(0, 1, m_display_uniform_buffer.GetD3DBufferArray()); + } - const float uniforms[4] = {static_cast(texture_view_x) / static_cast(texture_width), - static_cast(texture_view_y) / static_cast(texture_height), - (static_cast(texture_view_width) - 0.5f) / static_cast(texture_width), - (static_cast(texture_view_height) - 0.5f) / static_cast(texture_height)}; - const auto map = m_display_uniform_buffer.Map(m_context.Get(), m_display_uniform_buffer.GetSize(), sizeof(uniforms)); - std::memcpy(map.pointer, uniforms, sizeof(uniforms)); - m_display_uniform_buffer.Unmap(m_context.Get(), sizeof(uniforms)); - m_context->VSSetConstantBuffers(0, 1, m_display_uniform_buffer.GetD3DBufferArray()); const CD3D11_VIEWPORT vp(static_cast(left), static_cast(top), static_cast(width), static_cast(height)); @@ -862,6 +881,43 @@ D3D11HostDisplay::AdapterInfo D3D11HostDisplay::GetAdapterInfo(IDXGIFactory* dxg return adapter_info; } +bool D3D11HostDisplay::SetScalingShader(const std::string_view& config) +{ + if (config.empty()) + { + m_scale_shader.reset(); + m_scale_stage.reset(); + return true; + } + + m_scale_shader = PostProcessingShader(); + if (!PostProcessingChain::CreateSingleShader(&m_scale_shader.value(), config)) + { + m_scale_shader.reset(); + return false; + } + + m_scale_stage = PostProcessingStage(); + if (!CompilePostProcessingStage(m_scale_shader.value(), &m_scale_stage.value())) + { + Log_ErrorPrintf("Failed to compile resize shader"); + m_scale_stage.reset(); + m_scale_shader.reset(); + return false; + } + + if (m_display_uniform_buffer.GetSize() < m_scale_stage->uniforms_size && + !m_display_uniform_buffer.Create(m_device.Get(), D3D11_BIND_CONSTANT_BUFFER, m_scale_stage->uniforms_size)) + { + Log_ErrorPrintf("Failed to allocate %u byte constant buffer for scaling", m_scale_stage->uniforms_size); + m_scale_stage.reset(); + m_scale_shader.reset(); + return false; + } + + return true; +} + bool D3D11HostDisplay::SetPostProcessingChain(const std::string_view& config) { if (config.empty()) @@ -882,17 +938,10 @@ bool D3D11HostDisplay::SetPostProcessingChain(const std::string_view& config) for (u32 i = 0; i < m_post_processing_chain.GetStageCount(); i++) { - const PostProcessingShader& shader = m_post_processing_chain.GetShaderStage(i); - const std::string vs = shadergen.GeneratePostProcessingVertexShader(shader); - const std::string ps = shadergen.GeneratePostProcessingFragmentShader(shader); - PostProcessingStage stage; - stage.uniforms_size = shader.GetUniformsSize(); - stage.vertex_shader = - D3D11::ShaderCompiler::CompileAndCreateVertexShader(m_device.Get(), vs, g_settings.gpu_use_debug_device); - stage.pixel_shader = - D3D11::ShaderCompiler::CompileAndCreatePixelShader(m_device.Get(), ps, g_settings.gpu_use_debug_device); - if (!stage.vertex_shader || !stage.pixel_shader) + + const PostProcessingShader& shader = m_post_processing_chain.GetShaderStage(i); + if (!CompilePostProcessingStage(shader, &stage)) { Log_ErrorPrintf("Failed to compile one or more post-processing shaders, disabling."); m_post_processing_stages.clear(); @@ -944,6 +993,21 @@ bool D3D11HostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 ta return true; } +bool D3D11HostDisplay::CompilePostProcessingStage(const PostProcessingShader& shader, PostProcessingStage* stage) +{ + FrontendCommon::PostProcessingShaderGen shadergen(HostDisplay::RenderAPI::D3D11, true); + + const std::string vs = shadergen.GeneratePostProcessingVertexShader(shader); + const std::string ps = shadergen.GeneratePostProcessingFragmentShader(shader); + + stage->uniforms_size = shader.GetUniformsSize(); + stage->vertex_shader = + D3D11::ShaderCompiler::CompileAndCreateVertexShader(m_device.Get(), vs, g_settings.gpu_use_debug_device); + stage->pixel_shader = + D3D11::ShaderCompiler::CompileAndCreatePixelShader(m_device.Get(), ps, g_settings.gpu_use_debug_device); + return stage->vertex_shader && stage->pixel_shader; +} + void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height, void* texture_handle, u32 texture_width, s32 texture_height, s32 texture_view_x, @@ -1013,6 +1077,11 @@ void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_ta #else // LIBRETRO +bool D3D11HostDisplay::SetScalingShader(const std::string_view& config) +{ + return false; +} + bool D3D11HostDisplay::SetPostProcessingChain(const std::string_view& config) { return false; diff --git a/src/frontend-common/d3d11_host_display.h b/src/frontend-common/d3d11_host_display.h index adbf29a3d..86406e135 100644 --- a/src/frontend-common/d3d11_host_display.h +++ b/src/frontend-common/d3d11_host_display.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ public: virtual bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) override; virtual void DestroyRenderSurface() override; + virtual bool SetScalingShader(const std::string_view& config) override; virtual bool SetPostProcessingChain(const std::string_view& config) override; std::unique_ptr CreateTexture(u32 width, u32 height, const void* initial_data, @@ -108,6 +110,7 @@ protected: }; bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height); + bool CompilePostProcessingStage(const PostProcessingShader& shader, PostProcessingStage* stage); void ApplyPostProcessingChain(ID3D11RenderTargetView* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height, void* texture_handle, u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, @@ -142,6 +145,8 @@ protected: bool m_using_allow_tearing = false; bool m_vsync = true; + std::optional m_scale_shader; + std::optional m_scale_stage; PostProcessingChain m_post_processing_chain; D3D11::Texture m_post_processing_input_texture; std::vector m_post_processing_stages; diff --git a/src/frontend-common/opengl_host_display.cpp b/src/frontend-common/opengl_host_display.cpp index 983f16025..7bc7cf633 100644 --- a/src/frontend-common/opengl_host_display.cpp +++ b/src/frontend-common/opengl_host_display.cpp @@ -572,6 +572,11 @@ void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s3 #ifndef LIBRETRO +bool OpenGLHostDisplay::SetScalingShader(const std::string_view& config) +{ + return false; +} + bool OpenGLHostDisplay::SetPostProcessingChain(const std::string_view& config) { if (config.empty()) @@ -742,6 +747,11 @@ void OpenGLHostDisplay::ApplyPostProcessingChain(GLuint final_target, s32 final_ #else +bool OpenGLHostDisplay::SetScalingShader(const std::string_view& config) +{ + return false; +} + bool OpenGLHostDisplay::SetPostProcessingChain(const std::string_view& config) { return false; diff --git a/src/frontend-common/opengl_host_display.h b/src/frontend-common/opengl_host_display.h index 98de0b33d..4b68f87bc 100644 --- a/src/frontend-common/opengl_host_display.h +++ b/src/frontend-common/opengl_host_display.h @@ -49,6 +49,7 @@ public: virtual bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) override; virtual void DestroyRenderSurface() override; + virtual bool SetScalingShader(const std::string_view& config) override; virtual bool SetPostProcessingChain(const std::string_view& config) override; std::unique_ptr CreateTexture(u32 width, u32 height, const void* initial_data, diff --git a/src/frontend-common/postprocessing_chain.cpp b/src/frontend-common/postprocessing_chain.cpp index 5b72a09fe..e6d9741b9 100644 --- a/src/frontend-common/postprocessing_chain.cpp +++ b/src/frontend-common/postprocessing_chain.cpp @@ -128,6 +128,25 @@ bool PostProcessingChain::CreateFromString(const std::string_view& chain_config) return true; } +bool PostProcessingChain::CreateSingleShader(PostProcessingShader* shader, const std::string_view& shader_config) +{ + size_t first_shader_sep = shader_config.find(';'); + if (first_shader_sep == std::string::npos) + first_shader_sep = shader_config.size(); + + const std::string_view shader_name = shader_config.substr(0, first_shader_sep); + if (shader_name.empty()) + return false; + + if (!TryLoadingShader(shader, shader_name)) + return false; + + if (first_shader_sep < shader_config.size()) + shader->SetConfigString(shader_config.substr(first_shader_sep + 1)); + + return true; +} + std::vector PostProcessingChain::GetAvailableShaderNames() { std::vector names; diff --git a/src/frontend-common/postprocessing_chain.h b/src/frontend-common/postprocessing_chain.h index 6f4f9b93c..c02e1801f 100644 --- a/src/frontend-common/postprocessing_chain.h +++ b/src/frontend-common/postprocessing_chain.h @@ -28,6 +28,7 @@ public: bool CreateFromString(const std::string_view& chain_config); static std::vector GetAvailableShaderNames(); + static bool CreateSingleShader(PostProcessingShader* shader, const std::string_view& shader_config); private: std::vector m_shaders; diff --git a/src/frontend-common/vulkan_host_display.cpp b/src/frontend-common/vulkan_host_display.cpp index ba7484f3e..2d4b2ea1e 100644 --- a/src/frontend-common/vulkan_host_display.cpp +++ b/src/frontend-common/vulkan_host_display.cpp @@ -750,6 +750,11 @@ VulkanHostDisplay::PostProcessingStage::~PostProcessingStage() g_vulkan_context->DeferPipelineDestruction(pipeline); } +bool VulkanHostDisplay::SetScalingShader(const std::string_view& config) +{ + return false; +} + bool VulkanHostDisplay::SetPostProcessingChain(const std::string_view& config) { g_vulkan_context->ExecuteCommandBuffer(true); @@ -991,6 +996,11 @@ void VulkanHostDisplay::ApplyPostProcessingChain(s32 final_left, s32 final_top, #else // LIBRETRO +bool VulkanHostDisplay::SetScalingShader(const std::string_view& config) +{ + return false; +} + bool VulkanHostDisplay::SetPostProcessingChain(const std::string_view& config) { return false; diff --git a/src/frontend-common/vulkan_host_display.h b/src/frontend-common/vulkan_host_display.h index 991d311dc..ad1575159 100644 --- a/src/frontend-common/vulkan_host_display.h +++ b/src/frontend-common/vulkan_host_display.h @@ -46,6 +46,7 @@ public: virtual bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) override; virtual void DestroyRenderSurface() override; + virtual bool SetScalingShader(const std::string_view& config) override; virtual bool SetPostProcessingChain(const std::string_view& config) override; std::unique_ptr CreateTexture(u32 width, u32 height, const void* initial_data,