PostProcessing: Add depth buffer input
This commit is contained in:
parent
a54fed4204
commit
dbe6263270
|
@ -1890,7 +1890,7 @@ bool GPU::RenderDisplay(GPUTexture* target, const Common::Rectangle<s32>& 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<s32> real_draw_rect =
|
||||
g_gpu_device->UsesLowerLeftOrigin() ? GPUDevice::FlipToLowerLeft(draw_rect, target_height) : draw_rect;
|
||||
if (really_postfx)
|
||||
|
|
|
@ -48,14 +48,19 @@ static void DestroyTextures();
|
|||
|
||||
static std::vector<std::unique_ptr<PostProcessing::Shader>> 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<GPUTexture> s_input_texture;
|
||||
|
||||
static std::unique_ptr<GPUTexture> s_input_depth_texture;
|
||||
|
||||
static std::unique_ptr<GPUTexture> s_output_texture;
|
||||
|
||||
static std::unordered_map<u64, std::unique_ptr<GPUSampler>> 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>& 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>& 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<u32>(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<u32>(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<u32>(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<u32>(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<Shader>& stage : s_stages)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// 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);
|
||||
|
|
|
@ -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<ShaderOption> TakeOptions();
|
||||
void LoadOptions(const SettingsInterface& si, const char* section);
|
||||
|
|
|
@ -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<float>(buffer_width)));
|
||||
pp.add_macro_definition("BUFFER_RCP_HEIGHT", std::to_string(1.0f / static_cast<float>(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<float>(PostProcessing::GetTimer().GetTimeMilliseconds());
|
||||
|
|
|
@ -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<SourceOption> 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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue