mirror of
https://github.com/stenzek/duckstation.git
synced 2026-02-14 18:34:32 +00:00
PostProcessing: Load shaders even if disabled
Gets rid of the lag when toggling on and off.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user