diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index c08a116d1..cd48ec9a6 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -1890,7 +1890,7 @@ bool GPU::RenderDisplay(GPUTexture* target, const Common::Rectangle& draw_r const bool really_postfx = (postfx && HasDisplayTexture() && PostProcessing::IsActive() && !g_gpu_device->GetWindowInfo().IsSurfaceless() && hdformat != GPUTexture::Format::Unknown && target_width > 0 && target_height > 0 && - PostProcessing::CheckTargets(hdformat, target_width, target_height)); + PostProcessing::CheckTargets(hdformat, GPUTexture::Format::Unknown, target_width, target_height)); const Common::Rectangle real_draw_rect = g_gpu_device->UsesLowerLeftOrigin() ? GPUDevice::FlipToLowerLeft(draw_rect, target_height) : draw_rect; if (really_postfx) diff --git a/src/util/postprocessing.cpp b/src/util/postprocessing.cpp index e01d02e96..23a4c3694 100644 --- a/src/util/postprocessing.cpp +++ b/src/util/postprocessing.cpp @@ -48,14 +48,19 @@ static void DestroyTextures(); static std::vector> s_stages; static bool s_enabled = false; +static bool s_wants_depth_buffer = false; +static bool s_needs_depth_buffer = false; static GPUTexture::Format s_target_format = GPUTexture::Format::Unknown; +static GPUTexture::Format s_depth_format = GPUTexture::Format::Unknown; static u32 s_target_width = 0; static u32 s_target_height = 0; static Common::Timer s_timer; static std::unique_ptr s_input_texture; +static std::unique_ptr s_input_depth_texture; + static std::unique_ptr s_output_texture; static std::unordered_map> s_samplers; @@ -460,6 +465,7 @@ void PostProcessing::LoadStages() SettingsInterface& si = GetLoadSettingsInterface(); s_enabled = si.GetBoolValue("PostProcessing", "Enabled", false); + s_wants_depth_buffer = false; const u32 stage_count = Config::GetStageCount(si); if (stage_count == 0) @@ -491,23 +497,28 @@ void PostProcessing::LoadStages() lock.lock(); shader->LoadOptions(si, GetStageConfigSection(i)); + s_wants_depth_buffer |= shader->WantsDepthBuffer(); s_stages.push_back(std::move(shader)); progress.IncrementProgressValue(); } - if (stage_count > 0) - { - s_timer.Reset(); - Log_DevPrintf("Loaded %u post-processing stages.", stage_count); - } - // precompile shaders if (g_gpu_device && g_gpu_device->GetWindowFormat() != GPUTexture::Format::Unknown) { - CheckTargets(g_gpu_device->GetWindowFormat(), g_gpu_device->GetWindowWidth(), g_gpu_device->GetWindowHeight(), - &progress); + CheckTargets(g_gpu_device->GetWindowFormat(), GPUTexture::Format::R16, g_gpu_device->GetWindowWidth(), + g_gpu_device->GetWindowHeight(), &progress); } + + if (stage_count > 0) + Log_DevFmt("Loaded {} post-processing stages.", stage_count); + + // must be down here, because we need to compile first, triggered by CheckTargets() + for (std::unique_ptr& shader : s_stages) + s_wants_depth_buffer |= shader->WantsDepthBuffer(); + s_needs_depth_buffer = s_enabled && s_wants_depth_buffer; + if (s_wants_depth_buffer) + Log_DevPrint("Depth buffer is needed."); } void PostProcessing::UpdateSettings() @@ -532,6 +543,7 @@ void PostProcessing::UpdateSettings() progress.SetProgressRange(stage_count); const GPUTexture::Format prev_format = s_target_format; + s_wants_depth_buffer = false; for (u32 i = 0; i < stage_count; i++) { @@ -569,16 +581,21 @@ void PostProcessing::UpdateSettings() } s_stages[i]->LoadOptions(si, GetStageConfigSection(i)); + s_wants_depth_buffer |= s_stages[i]->WantsDepthBuffer(); } if (prev_format != GPUTexture::Format::Unknown) - CheckTargets(prev_format, s_target_width, s_target_height, &progress); + CheckTargets(prev_format, s_depth_format, s_target_width, s_target_height, &progress); if (stage_count > 0) - { - s_timer.Reset(); - Log_DevPrintf("Loaded %u post-processing stages.", stage_count); - } + Log_DevFmt("Loaded {} post-processing stages.", stage_count); + + // must be down here, because we need to compile first, triggered by CheckTargets() + for (std::unique_ptr& shader : s_stages) + s_wants_depth_buffer |= shader->WantsDepthBuffer(); + s_needs_depth_buffer = s_enabled && s_wants_depth_buffer; + if (s_wants_depth_buffer) + Log_DevPrint("Depth buffer is needed."); } void PostProcessing::Toggle() @@ -597,10 +614,16 @@ void PostProcessing::Toggle() TRANSLATE_STR("OSDMessage", "Post-processing is now disabled."), Host::OSD_QUICK_DURATION); s_enabled = new_enabled; + s_needs_depth_buffer = new_enabled && s_wants_depth_buffer; if (s_enabled) s_timer.Reset(); } +bool PostProcessing::NeedsDepthBuffer() +{ + return s_needs_depth_buffer; +} + bool PostProcessing::ReloadShaders() { if (s_stages.empty()) @@ -625,6 +648,7 @@ void PostProcessing::Shutdown() g_gpu_device->RecycleTexture(std::move(s_dummy_texture)); s_samplers.clear(); s_enabled = false; + s_needs_depth_buffer = false; decltype(s_stages)().swap(s_stages); DestroyTextures(); } @@ -634,6 +658,11 @@ GPUTexture* PostProcessing::GetInputTexture() return s_input_texture.get(); } +GPUTexture* PostProcessing::GetInputDepthTexture() +{ + return s_input_depth_texture.get(); +} + const Common::Timer& PostProcessing::GetTimer() { return s_timer; @@ -667,51 +696,75 @@ GPUTexture* PostProcessing::GetDummyTexture() return s_dummy_texture.get(); } -bool PostProcessing::CheckTargets(GPUTexture::Format target_format, u32 target_width, u32 target_height, - ProgressCallback* progress) +bool PostProcessing::CheckTargets(GPUTexture::Format target_format, GPUTexture::Format depth_format, u32 target_width, + u32 target_height, ProgressCallback* progress) { - if (s_target_format == target_format && s_target_width == target_width && s_target_height == target_height) + const bool size_changed = (s_target_width != target_width || s_target_height != target_height); + if (s_target_format == target_format && s_depth_format == depth_format && !size_changed) return true; - // In case any allocs fail. - DestroyTextures(); - - if (!(s_input_texture = g_gpu_device->FetchTexture(target_width, target_height, 1, 1, 1, - GPUTexture::Type::RenderTarget, target_format)) || - !(s_output_texture = g_gpu_device->FetchTexture(target_width, target_height, 1, 1, 1, - GPUTexture::Type::RenderTarget, target_format))) + if (s_target_format != target_format || size_changed) { - DestroyTextures(); - return false; - } + g_gpu_device->RecycleTexture(std::move(s_output_texture)); + g_gpu_device->RecycleTexture(std::move(s_input_texture)); - if (!progress) - progress = ProgressCallback::NullProgressCallback; - - progress->SetProgressRange(static_cast(s_stages.size())); - progress->SetProgressValue(0); - - for (size_t i = 0; i < s_stages.size(); i++) - { - Shader* const shader = s_stages[i].get(); - - progress->SetFormattedStatusText("Compiling %s...", shader->GetName().c_str()); - - if (!shader->CompilePipeline(target_format, target_width, target_height, progress) || - !shader->ResizeOutput(target_format, target_width, target_height)) + if (!(s_input_texture = g_gpu_device->FetchTexture(target_width, target_height, 1, 1, 1, + GPUTexture::Type::RenderTarget, target_format)) || + !(s_output_texture = g_gpu_device->FetchTexture(target_width, target_height, 1, 1, 1, + GPUTexture::Type::RenderTarget, target_format))) { - Log_ErrorPrintf("Failed to compile one or more post-processing shaders, disabling."); - Host::AddIconOSDMessage( - "PostProcessLoadFail", ICON_FA_EXCLAMATION_TRIANGLE, - fmt::format("Failed to compile post-processing shader '{}'. Disabling post-processing.", shader->GetName())); - s_enabled = false; + DestroyTextures(); return false; } + } - progress->SetProgressValue(static_cast(i + 1)); + if (s_depth_format != depth_format || size_changed) + { + g_gpu_device->RecycleTexture(std::move(s_input_depth_texture)); + + if (depth_format != GPUTexture::Format::Unknown && + (!(s_input_depth_texture = g_gpu_device->CreateTexture( + target_width, target_height, 1, 1, 1, + GPUTexture::IsDepthFormat(depth_format) ? GPUTexture::Type::DepthStencil : GPUTexture::Type::RenderTarget, + depth_format)))) + { + DestroyTextures(); + return false; + } + } + + if (s_target_format != target_format || size_changed) + { + if (!progress) + progress = ProgressCallback::NullProgressCallback; + + progress->SetProgressRange(static_cast(s_stages.size())); + progress->SetProgressValue(0); + + for (size_t i = 0; i < s_stages.size(); i++) + { + Shader* const shader = s_stages[i].get(); + + progress->SetFormattedStatusText("Compiling %s...", shader->GetName().c_str()); + + if (!shader->CompilePipeline(target_format, target_width, target_height, progress) || + !shader->ResizeOutput(target_format, target_width, target_height)) + { + Log_ErrorPrintf("Failed to compile one or more post-processing shaders, disabling."); + Host::AddIconOSDMessage( + "PostProcessLoadFail", ICON_FA_EXCLAMATION_TRIANGLE, + fmt::format("Failed to compile post-processing shader '{}'. Disabling post-processing.", shader->GetName())); + s_enabled = false; + DestroyTextures(); + return false; + } + + progress->SetProgressValue(static_cast(i + 1)); + } } s_target_format = target_format; + s_depth_format = depth_format; s_target_width = target_width; s_target_height = target_height; return true; @@ -720,21 +773,27 @@ bool PostProcessing::CheckTargets(GPUTexture::Format target_format, u32 target_w void PostProcessing::DestroyTextures() { s_target_format = GPUTexture::Format::Unknown; + s_depth_format = GPUTexture::Format::Unknown; s_target_width = 0; s_target_height = 0; g_gpu_device->RecycleTexture(std::move(s_output_texture)); + g_gpu_device->RecycleTexture(std::move(s_input_depth_texture)); g_gpu_device->RecycleTexture(std::move(s_input_texture)); } bool PostProcessing::Apply(GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height, s32 orig_width, s32 orig_height) { + Assert(s_input_texture && s_output_texture); + GL_SCOPE("PostProcessing Apply"); GPUTexture* input = s_input_texture.get(); GPUTexture* output = s_output_texture.get(); input->MakeReadyForSampling(); + if (s_input_depth_texture) + s_input_depth_texture->MakeReadyForSampling(); for (const std::unique_ptr& stage : s_stages) { diff --git a/src/util/postprocessing.h b/src/util/postprocessing.h index fe1642e7d..1df272dae 100644 --- a/src/util/postprocessing.h +++ b/src/util/postprocessing.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once @@ -117,15 +117,20 @@ void UpdateSettings(); /// Temporarily toggles post-processing on/off. void Toggle(); +/// Returns true if depth buffers are needed for the current configuration. +bool NeedsDepthBuffer(); + /// Reloads post processing shaders with the current configuration. bool ReloadShaders(); void Shutdown(); GPUTexture* GetInputTexture(); +GPUTexture* GetInputDepthTexture(); const Common::Timer& GetTimer(); -bool CheckTargets(GPUTexture::Format target_format, u32 target_width, u32 target_height, ProgressCallback* progress = nullptr); +bool CheckTargets(GPUTexture::Format target_format, GPUTexture::Format depth_format, u32 target_width, + u32 target_height, ProgressCallback* progress = nullptr); bool Apply(GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height, s32 orig_width, s32 orig_height); diff --git a/src/util/postprocessing_shader.h b/src/util/postprocessing_shader.h index e53530d0e..b04f74b65 100644 --- a/src/util/postprocessing_shader.h +++ b/src/util/postprocessing_shader.h @@ -37,6 +37,7 @@ public: ALWAYS_INLINE bool HasOptions() const { return !m_options.empty(); } virtual bool IsValid() const = 0; + virtual bool WantsDepthBuffer() const = 0; std::vector TakeOptions(); void LoadOptions(const SettingsInterface& si, const char* section); diff --git a/src/util/postprocessing_shader_fx.cpp b/src/util/postprocessing_shader_fx.cpp index 4d43521a5..5bbba3a69 100644 --- a/src/util/postprocessing_shader_fx.cpp +++ b/src/util/postprocessing_shader_fx.cpp @@ -367,6 +367,11 @@ bool PostProcessing::ReShadeFXShader::IsValid() const return m_valid; } +bool PostProcessing::ReShadeFXShader::WantsDepthBuffer() const +{ + return m_wants_depth_buffer; +} + bool PostProcessing::ReShadeFXShader::CreateModule(s32 buffer_width, s32 buffer_height, reshadefx::module* mod, std::string code, Error* error) { @@ -395,6 +400,11 @@ bool PostProcessing::ReShadeFXShader::CreateModule(s32 buffer_width, s32 buffer_ pp.add_macro_definition("BUFFER_RCP_WIDTH", std::to_string(1.0f / static_cast(buffer_width))); pp.add_macro_definition("BUFFER_RCP_HEIGHT", std::to_string(1.0f / static_cast(buffer_height))); pp.add_macro_definition("BUFFER_COLOR_BIT_DEPTH", "32"); + //pp.add_macro_definition("RESHADE_DEPTH_MULTIPLIER", "7.0"); + pp.add_macro_definition("RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWN", "0"); + pp.add_macro_definition("RESHADE_DEPTH_INPUT_IS_LOGARITHMIC", "0"); + pp.add_macro_definition("RESHADE_DEPTH_LINEARIZATION_FAR_PLANE", "1000.0"); + pp.add_macro_definition("RESHADE_DEPTH_INPUT_IS_REVERSED", "0"); switch (GetRenderAPI()) { @@ -434,7 +444,7 @@ bool PostProcessing::ReShadeFXShader::CreateModule(s32 buffer_width, s32 buffer_ cg->write_result(*mod); - // FileSystem::WriteBinaryFile("D:\\out.txt", mod->code.data(), mod->code.size()); + FileSystem::WriteBinaryFile("D:\\out.txt", mod->code.data(), mod->code.size()); return true; } @@ -835,11 +845,16 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i *si = (ui.type.base == reshadefx::type::t_float) ? SourceOptionType::RandomF : SourceOptionType::Random; return true; } - else if (source == "overlay_active" || source == "has_depth") + else if (source == "overlay_active") { *si = SourceOptionType::Zero; return true; } + else if (source == "has_depth") + { + *si = SourceOptionType::One; + return true; + } else if (source == "bufferwidth") { *si = (ui.type.base == reshadefx::type::t_float) ? SourceOptionType::BufferWidthF : SourceOptionType::BufferWidth; @@ -1028,8 +1043,8 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer } else if (ti.semantic == "DEPTH") { - Log_WarningFmt("Shader '{}' uses input depth as '{}' which is not supported.", m_name, si.texture_name); sampler.texture_id = INPUT_DEPTH_TEXTURE; + m_wants_depth_buffer = true; break; } else if (!ti.semantic.empty()) @@ -1106,7 +1121,7 @@ GPUTexture* PostProcessing::ReShadeFXShader::GetTextureByID(TextureID id, GPUTex } else if (id == INPUT_DEPTH_TEXTURE) { - return PostProcessing::GetDummyTexture(); + return PostProcessing::GetInputDepthTexture(); } else if (id == OUTPUT_COLOR_TEXTURE) { @@ -1134,6 +1149,7 @@ bool PostProcessing::ReShadeFXShader::CompilePipeline(GPUTexture::Format format, m_valid = false; m_textures.clear(); m_passes.clear(); + m_wants_depth_buffer = false; std::string fxcode; if (!PreprocessorReadFileCallback(m_filename, fxcode)) @@ -1344,6 +1360,13 @@ bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input, GPUTexture* final } break; + case SourceOptionType::One: + { + const float value = 1.0f; + std::memcpy(dst, &value, sizeof(value)); + } + break; + case SourceOptionType::Timer: { const float value = static_cast(PostProcessing::GetTimer().GetTimeMilliseconds()); diff --git a/src/util/postprocessing_shader_fx.h b/src/util/postprocessing_shader_fx.h index d6fa941f3..cd929d47d 100644 --- a/src/util/postprocessing_shader_fx.h +++ b/src/util/postprocessing_shader_fx.h @@ -24,6 +24,7 @@ public: ~ReShadeFXShader(); bool IsValid() const override; + bool WantsDepthBuffer() const override; bool LoadFromFile(std::string name, std::string filename, bool only_config, Error* error); bool LoadFromString(std::string name, std::string filename, std::string code, bool only_config, Error* error); @@ -44,6 +45,7 @@ private: { None, Zero, + One, Timer, FrameTime, FrameCount, @@ -118,6 +120,7 @@ private: std::vector m_source_options; u32 m_uniforms_size = 0; bool m_valid = false; + bool m_wants_depth_buffer = false; Common::Timer m_frame_timer; u32 m_frame_count = 0; diff --git a/src/util/postprocessing_shader_glsl.cpp b/src/util/postprocessing_shader_glsl.cpp index 0fa20fcb8..deeeecf52 100644 --- a/src/util/postprocessing_shader_glsl.cpp +++ b/src/util/postprocessing_shader_glsl.cpp @@ -62,6 +62,11 @@ bool PostProcessing::GLSLShader::IsValid() const return !m_name.empty() && !m_code.empty(); } +bool PostProcessing::GLSLShader::WantsDepthBuffer() const +{ + return false; +} + u32 PostProcessing::GLSLShader::GetUniformsSize() const { // lazy packing. todo improve. diff --git a/src/util/postprocessing_shader_glsl.h b/src/util/postprocessing_shader_glsl.h index ec6d99ce3..95c1da409 100644 --- a/src/util/postprocessing_shader_glsl.h +++ b/src/util/postprocessing_shader_glsl.h @@ -17,6 +17,7 @@ public: ALWAYS_INLINE const std::string& GetCode() const { return m_code; } bool IsValid() const override; + bool WantsDepthBuffer() const override; bool LoadFromFile(std::string name, const char* filename, Error* error); bool LoadFromString(std::string name, std::string code, Error* error);