PostProcessing: Load shaders even if disabled

Gets rid of the lag when toggling on and off.
This commit is contained in:
Stenzek
2025-11-11 23:20:27 +10:00
parent a9b9e8952d
commit 3a1e8fe7a1
8 changed files with 75 additions and 81 deletions

View File

@@ -19,6 +19,7 @@
#include "IconsEmoji.h"
#include "IconsFontAwesome6.h"
#include "common/assert.h"
#include "common/bitutils.h"
#include "common/error.h"
#include "common/file_system.h"
#include "common/log.h"
@@ -286,19 +287,6 @@ u32 PostProcessing::Config::GetStageCount(const SettingsInterface& si, const cha
return si.GetUIntValue(section, "StageCount", 0u);
}
u32 PostProcessing::Config::GetEnabledStageCount(const SettingsInterface& si, const char* section)
{
const int stage_count = GetStageCount(si, section);
int enabled_count = 0;
for (int i = 0; i < stage_count; i++)
{
if (IsStageEnabled(si, section, i))
enabled_count++;
}
return enabled_count;
}
std::string PostProcessing::Config::GetStageShaderName(const SettingsInterface& si, const char* section, u32 index)
{
return si.GetStringValue(GetStageConfigSection(section, index), "ShaderName");
@@ -472,23 +460,18 @@ void PostProcessing::Chain::LoadStages(std::unique_lock<std::mutex>& settings_lo
m_wants_unscaled_input = false;
const u32 stage_count = Config::GetStageCount(si, m_section);
const u32 enabled_stage_count = Config::GetEnabledStageCount(si, m_section);
if (stage_count == 0 || enabled_stage_count == 0)
if (stage_count == 0)
return;
Error error;
FullscreenUI::LoadingScreenProgressCallback progress;
progress.SetTitle("Loading Post-Processing Shaders...");
progress.SetProgressRange(enabled_stage_count);
progress.SetProgressRange(stage_count);
u32 enabled_stage_count = 0;
u32 last_enabled_stage = std::numeric_limits<u32>::max();
for (u32 i = 0; i < stage_count; i++)
{
bool stage_enabled = Config::IsStageEnabled(si, m_section, i);
if (!stage_enabled)
{
continue;
}
std::string stage_name = Config::GetStageShaderName(si, m_section, i);
if (stage_name.empty())
{
@@ -511,11 +494,30 @@ void PostProcessing::Chain::LoadStages(std::unique_lock<std::mutex>& settings_lo
settings_lock.lock();
shader->LoadOptions(si, GetStageConfigSection(m_section, i));
const bool stage_enabled = Config::IsStageEnabled(si, m_section, i);
shader->SetEnabled(stage_enabled);
shader->SetFinalStage(false);
enabled_stage_count += BoolToUInt32(stage_enabled);
if (stage_enabled)
last_enabled_stage = i;
m_stages.push_back(std::move(shader));
}
if (enabled_stage_count > 0)
DEV_LOG("Loaded {} post-processing stages.", enabled_stage_count);
{
DEV_LOG("Loaded {} post-processing stages ({} enabled).", stage_count, enabled_stage_count);
if (enabled_stage_count == 0)
{
WARNING_LOG("All post-processing stages are currently disabled.");
m_enabled = false;
}
else
{
m_stages[last_enabled_stage]->SetFinalStage(true);
}
}
// precompile shaders
if (preload_swap_chain_size && g_gpu_device && g_gpu_device->HasMainSwapChain())
@@ -546,8 +548,7 @@ void PostProcessing::Chain::UpdateSettings(std::unique_lock<std::mutex>& setting
m_enabled = Config::IsEnabled(si, m_section);
const u32 stage_count = Config::GetStageCount(si, m_section);
const u32 enabled_stage_count = Config::GetEnabledStageCount(si, m_section);
if (stage_count == 0 || enabled_stage_count == 0)
if (stage_count == 0)
{
m_stages.clear();
return;
@@ -559,12 +560,14 @@ void PostProcessing::Chain::UpdateSettings(std::unique_lock<std::mutex>& setting
FullscreenUI::LoadingScreenProgressCallback progress;
progress.SetTitle("Loading Post-Processing Shaders...");
progress.SetProgressRange(enabled_stage_count);
progress.SetProgressRange(stage_count);
const GPUTexture::Format prev_format = m_target_format;
m_wants_depth_buffer = false;
for (u32 i = 0, j = 0; i < stage_count; i++)
u32 enabled_stage_count = 0;
u32 last_enabled_stage = 0;
for (u32 i = 0; i < stage_count; i++)
{
std::string stage_name = Config::GetStageShaderName(si, m_section, i);
if (stage_name.empty())
@@ -574,18 +577,10 @@ void PostProcessing::Chain::UpdateSettings(std::unique_lock<std::mutex>& setting
return;
}
bool stage_enabled = Config::IsStageEnabled(si, m_section, i);
if (!stage_enabled)
if (!m_stages[i] || stage_name != m_stages[i]->GetName())
{
if (m_stages[j] && stage_name == m_stages[j]->GetName())
m_stages[j].reset();
continue;
}
if (!m_stages[j] || stage_name != m_stages[j]->GetName())
{
if (j < m_stages.size())
m_stages[j].reset();
if (i < m_stages.size())
m_stages[i].reset();
// Force recompile.
m_target_format = GPUTexture::Format::Unknown;
@@ -599,19 +594,23 @@ void PostProcessing::Chain::UpdateSettings(std::unique_lock<std::mutex>& setting
return;
}
if (j < m_stages.size())
m_stages[j] = std::move(shader);
if (i < m_stages.size())
m_stages[i] = std::move(shader);
else
m_stages.push_back(std::move(shader));
settings_lock.lock();
}
m_stages[j]->LoadOptions(si, GetStageConfigSection(m_section, i));
j++;
}
m_stages[i]->LoadOptions(si, GetStageConfigSection(m_section, i));
m_stages.resize(enabled_stage_count);
const bool stage_enabled = Config::IsStageEnabled(si, m_section, i);
m_stages[i]->SetEnabled(stage_enabled);
m_stages[i]->SetFinalStage(false);
enabled_stage_count += BoolToUInt32(stage_enabled);
if (stage_enabled)
last_enabled_stage = i;
}
if (prev_format != GPUTexture::Format::Unknown)
{
@@ -619,10 +618,19 @@ void PostProcessing::Chain::UpdateSettings(std::unique_lock<std::mutex>& setting
m_viewport_height, &progress);
}
if (enabled_stage_count > 0)
if (stage_count > 0)
{
s_start_time = Timer::GetCurrentValue();
DEV_LOG("Loaded {} post-processing stages.", enabled_stage_count);
DEV_LOG("Loaded {} post-processing stages ({} enabled).", stage_count, enabled_stage_count);
if (enabled_stage_count == 0)
{
WARNING_LOG("All post-processing stages are currently disabled.");
m_enabled = false;
}
else
{
m_stages[last_enabled_stage]->SetFinalStage(true);
}
}
// must be down here, because we need to compile first, triggered by CheckTargets()
@@ -797,17 +805,18 @@ GPUDevice::PresentResult PostProcessing::Chain::Apply(GPUTexture* input_color, G
const float time = static_cast<float>(Timer::ConvertValueToSeconds(Timer::GetCurrentValue() - s_start_time));
for (const std::unique_ptr<Shader>& stage : m_stages)
{
const bool is_final = (stage.get() == m_stages.back().get());
if (!stage->IsEnabled())
continue;
if (const GPUDevice::PresentResult pres =
stage->Apply(input_color, input_depth, is_final ? final_target : output, final_rect, orig_width, orig_height,
native_width, native_height, m_target_width, m_target_height, time);
stage->Apply(input_color, input_depth, stage->IsFinalStage() ? final_target : output, final_rect, orig_width,
orig_height, native_width, native_height, m_target_width, m_target_height, time);
pres != GPUDevice::PresentResult::OK)
{
return pres;
}
if (!is_final)
if (!stage->IsFinalStage())
{
output->MakeReadyForSampling();
input_color = output;

View File

@@ -107,7 +107,6 @@ inline constexpr const char* INTERNAL_CHAIN_SECTION = "InternalPostProcessing";
bool IsEnabled(const SettingsInterface& si, const char* section);
bool IsStageEnabled(const SettingsInterface& si, const char* section, u32 index);
u32 GetStageCount(const SettingsInterface& si, const char* section);
u32 GetEnabledStageCount(const SettingsInterface& si, const char* section);
std::string GetStageShaderName(const SettingsInterface& si, const char* section, u32 index);
std::vector<ShaderOption> GetStageOptions(const SettingsInterface& si, const char* section, u32 index);
std::vector<ShaderOption> GetShaderOptions(const std::string& shader_name, Error* error);

View File

@@ -56,16 +56,6 @@ PostProcessing::Shader::Shader(std::string name) : m_name(std::move(name))
PostProcessing::Shader::~Shader() = default;
bool PostProcessing::Shader::WantsDepthBuffer() const
{
return false;
}
bool PostProcessing::Shader::WantsUnscaledInput() const
{
return false;
}
std::vector<PostProcessing::ShaderOption> PostProcessing::Shader::TakeOptions()
{
return std::move(m_options);

View File

@@ -35,8 +35,12 @@ public:
ALWAYS_INLINE std::vector<ShaderOption>& GetOptions() { return m_options; }
ALWAYS_INLINE bool HasOptions() const { return !m_options.empty(); }
virtual bool WantsDepthBuffer() const;
virtual bool WantsUnscaledInput() const;
ALWAYS_INLINE bool IsEnabled() const { return m_enabled; }
ALWAYS_INLINE void SetEnabled(bool enabled) { m_enabled = enabled; }
ALWAYS_INLINE bool IsFinalStage() const { return m_final_stage; }
ALWAYS_INLINE void SetFinalStage(bool final_stage) { m_final_stage = final_stage; }
ALWAYS_INLINE bool WantsDepthBuffer() const { return m_wants_depth_buffer; }
ALWAYS_INLINE bool WantsUnscaledInput() const { return m_wants_unscaled_input; }
std::vector<ShaderOption> TakeOptions();
void LoadOptions(const SettingsInterface& si, const char* section);
@@ -63,6 +67,10 @@ protected:
std::string m_name;
OptionList m_options;
bool m_enabled = false;
bool m_final_stage = false;
bool m_wants_depth_buffer = false;
bool m_wants_unscaled_input = false;
};
} // namespace PostProcessing

View File

@@ -400,11 +400,6 @@ bool PostProcessing::ReShadeFXShader::LoadFromString(std::string name, std::stri
return true;
}
bool PostProcessing::ReShadeFXShader::WantsDepthBuffer() const
{
return m_wants_depth_buffer;
}
bool PostProcessing::ReShadeFXShader::CreateModule(s32 buffer_width, s32 buffer_height, reshadefx::codegen* cg,
GPUShaderLanguage cg_language, std::string code, Error* error)
{

View File

@@ -27,8 +27,6 @@ public:
ReShadeFXShader();
~ReShadeFXShader();
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);
@@ -151,10 +149,9 @@ private:
std::vector<Texture> m_textures;
std::vector<SourceOption> m_source_options;
u32 m_uniforms_size = 0;
bool m_wants_depth_buffer = false;
Timer m_frame_timer;
u32 m_frame_count = 0;
Timer m_frame_timer;
// Specifically using a fixed seed, so that it's consistent from run-to-run.
std::mt19937 m_random{0x1337};

View File

@@ -719,7 +719,10 @@ inline std::string_view PostProcessing::SlangShaderPreprocessor::GetCurrentFilen
return Path::GetFileName(m_path);
}
PostProcessing::SlangShader::SlangShader() = default;
PostProcessing::SlangShader::SlangShader()
{
m_wants_unscaled_input = true;
}
PostProcessing::SlangShader::~SlangShader()
{
@@ -748,11 +751,6 @@ bool PostProcessing::SlangShader::LoadFromString(std::string name, std::string_v
return ParsePresetFile(path, code, error);
}
bool PostProcessing::SlangShader::WantsUnscaledInput() const
{
return true;
}
bool PostProcessing::SlangShader::ParsePresetFile(std::string_view path, std::string_view code, Error* error)
{
SlangPresetParser pp;

View File

@@ -25,9 +25,7 @@ class SlangShader final : public Shader
{
public:
SlangShader();
~SlangShader();
bool WantsUnscaledInput() const override;
~SlangShader() override;
bool LoadFromFile(std::string name, const char* path, Error* error);
bool LoadFromString(std::string name, std::string_view path, std::string_view code, Error* error);