PostProcessing: Add native width/height inputs

Available in GLSL as GetNativeSize(), GetUpscaleMultiplier(), and in
reshade as native_width/native_height/upscale_multiplier.

GetPaddedOriginalSize() is now deprecated, as it does not make since
since the postfx shader runs with a window-sized off-screen target as an
input, not the internal render texture.
This commit is contained in:
Stenzek 2024-06-11 14:04:43 +10:00
parent bac2ac0151
commit 354b250642
No known key found for this signature in database
8 changed files with 107 additions and 67 deletions

View file

@ -2066,9 +2066,17 @@ bool GPU::RenderDisplay(GPUTexture* target, const Common::Rectangle<s32>& draw_r
if (really_postfx) if (really_postfx)
{ {
// "original size" in postfx includes padding.
const float upscale_x =
static_cast<float>(m_display_texture_view_width) / static_cast<float>(m_display_active_width);
const float upscale_y =
static_cast<float>(m_display_texture_view_height) / static_cast<float>(m_display_active_height);
const s32 orig_width = static_cast<s32>(std::ceil(m_display_width * upscale_x));
const s32 orig_height = static_cast<s32>(std::ceil(m_display_height * upscale_y));
return PostProcessing::Apply(target, real_draw_rect.left, real_draw_rect.top, real_draw_rect.GetWidth(), return PostProcessing::Apply(target, real_draw_rect.left, real_draw_rect.top, real_draw_rect.GetWidth(),
real_draw_rect.GetHeight(), m_display_texture_view_width, real_draw_rect.GetHeight(), orig_width, orig_height, m_display_width,
m_display_texture_view_height); m_display_height);
} }
else else
{ {

View file

@ -728,7 +728,7 @@ void PostProcessing::DestroyTextures()
} }
bool PostProcessing::Apply(GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height, bool PostProcessing::Apply(GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height,
s32 orig_width, s32 orig_height) s32 orig_width, s32 orig_height, s32 native_width, s32 native_height)
{ {
GL_SCOPE("PostProcessing Apply"); GL_SCOPE("PostProcessing Apply");
@ -741,7 +741,7 @@ bool PostProcessing::Apply(GPUTexture* final_target, s32 final_left, s32 final_t
const bool is_final = (stage.get() == s_stages.back().get()); const bool is_final = (stage.get() == s_stages.back().get());
if (!stage->Apply(input, is_final ? final_target : output, final_left, final_top, final_width, final_height, if (!stage->Apply(input, is_final ? final_target : output, final_left, final_top, final_width, final_height,
orig_width, orig_height, s_target_width, s_target_height)) orig_width, orig_height, native_width, native_height, s_target_width, s_target_height))
{ {
return false; return false;
} }

View file

@ -125,10 +125,11 @@ void Shutdown();
GPUTexture* GetInputTexture(); GPUTexture* GetInputTexture();
const Common::Timer& GetTimer(); 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, 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, bool Apply(GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height, s32 orig_width,
s32 orig_height); s32 orig_height, s32 native_width, s32 native_height);
GPUSampler* GetSampler(const GPUSampler::Config& config); GPUSampler* GetSampler(const GPUSampler::Config& config);
GPUTexture* GetDummyTexture(); GPUTexture* GetDummyTexture();

View file

@ -49,7 +49,8 @@ public:
virtual bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, ProgressCallback* progress) = 0; virtual bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, ProgressCallback* progress) = 0;
virtual bool Apply(GPUTexture* input, GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width, virtual bool Apply(GPUTexture* input, GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width,
s32 final_height, s32 orig_width, s32 orig_height, u32 target_width, u32 target_height) = 0; s32 final_height, s32 orig_width, s32 orig_height, s32 native_width, s32 native_height,
u32 target_width, u32 target_height) = 0;
protected: protected:
static void ParseKeyValue(std::string_view line, std::string_view* key, std::string_view* value); static void ParseKeyValue(std::string_view line, std::string_view* key, std::string_view* value);

View file

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 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) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "postprocessing_shader_fx.h" #include "postprocessing_shader_fx.h"
@ -863,6 +864,29 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
SourceOptionType::InternalHeight; SourceOptionType::InternalHeight;
return true; return true;
} }
else if (source == "nativewidth")
{
*si = (ui.type.base == reshadefx::type::t_float) ? SourceOptionType::NativeWidthF : SourceOptionType::NativeWidth;
return true;
}
else if (source == "nativeheight")
{
*si =
(ui.type.base == reshadefx::type::t_float) ? SourceOptionType::NativeHeightF : SourceOptionType::NativeHeight;
return true;
}
else if (source == "upscale_multiplier")
{
if (!ui.type.is_floating_point() || ui.type.components() != 1)
{
Error::SetString(error, fmt::format("Unexpected type '{}' for upscale_multiplier source in uniform '{}'",
ui.type.description(), ui.name));
return false;
}
*si = SourceOptionType::UpscaleMultiplier;
return true;
}
else else
{ {
Error::SetString(error, fmt::format("Unknown source '{}' in uniform '{}'", source, ui.name)); Error::SetString(error, fmt::format("Unknown source '{}' in uniform '{}'", source, ui.name));
@ -1318,7 +1342,7 @@ bool PostProcessing::ReShadeFXShader::ResizeOutput(GPUTexture::Format format, u3
bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input, GPUTexture* final_target, s32 final_left, s32 final_top, bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input, GPUTexture* final_target, s32 final_left, s32 final_top,
s32 final_width, s32 final_height, s32 orig_width, s32 orig_height, s32 final_width, s32 final_height, s32 orig_width, s32 orig_height,
u32 target_width, u32 target_height) s32 native_width, s32 native_height, u32 target_width, u32 target_height)
{ {
GL_PUSH_FMT("PostProcessingShaderFX {}", m_name); GL_PUSH_FMT("PostProcessingShaderFX {}", m_name);
@ -1452,8 +1476,8 @@ bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input, GPUTexture* final
case SourceOptionType::InternalWidth: case SourceOptionType::InternalWidth:
case SourceOptionType::InternalHeight: case SourceOptionType::InternalHeight:
{ {
const s32 value = const s32 value = (so.source == SourceOptionType::InternalWidth) ? static_cast<s32>(orig_width) :
(so.source == SourceOptionType::BufferWidth) ? static_cast<s32>(orig_width) : static_cast<s32>(orig_height); static_cast<s32>(orig_height);
std::memcpy(dst, &value, sizeof(value)); std::memcpy(dst, &value, sizeof(value));
} }
break; break;
@ -1461,8 +1485,33 @@ bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input, GPUTexture* final
case SourceOptionType::InternalWidthF: case SourceOptionType::InternalWidthF:
case SourceOptionType::InternalHeightF: case SourceOptionType::InternalHeightF:
{ {
const float value = (so.source == SourceOptionType::BufferWidthF) ? static_cast<float>(orig_width) : const float value = (so.source == SourceOptionType::InternalWidthF) ? static_cast<float>(orig_width) :
static_cast<float>(orig_height); static_cast<float>(orig_height);
std::memcpy(dst, &value, sizeof(value));
}
break;
case SourceOptionType::NativeWidth:
case SourceOptionType::NativeHeight:
{
const s32 value = (so.source == SourceOptionType::NativeWidth) ? static_cast<s32>(native_width) :
static_cast<s32>(native_height);
std::memcpy(dst, &value, sizeof(value));
}
break;
case SourceOptionType::NativeWidthF:
case SourceOptionType::NativeHeightF:
{
const float value = (so.source == SourceOptionType::NativeWidthF) ? static_cast<float>(native_width) :
static_cast<float>(native_height);
std::memcpy(dst, &value, sizeof(value));
}
break;
case SourceOptionType::UpscaleMultiplier:
{
const float value = static_cast<float>(orig_width) / static_cast<float>(native_width);
std::memcpy(dst, &value, sizeof(value)); std::memcpy(dst, &value, sizeof(value));
} }
break; break;

View file

@ -31,7 +31,8 @@ public:
bool ResizeOutput(GPUTexture::Format format, u32 width, u32 height) override; bool ResizeOutput(GPUTexture::Format format, u32 width, u32 height) override;
bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, ProgressCallback* progress) override; bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, ProgressCallback* progress) override;
bool Apply(GPUTexture* input, GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width, bool Apply(GPUTexture* input, GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width,
s32 final_height, s32 orig_width, s32 orig_height, u32 target_width, u32 target_height) override; s32 final_height, s32 orig_width, s32 orig_height, s32 native_width, s32 native_height, u32 target_width,
u32 target_height) override;
private: private:
using TextureID = s32; using TextureID = s32;
@ -60,6 +61,11 @@ private:
InternalHeight, InternalHeight,
InternalWidthF, InternalWidthF,
InternalHeightF, InternalHeightF,
NativeWidth,
NativeHeight,
NativeWidthF,
NativeHeightF,
UpscaleMultiplier,
MaxCount MaxCount
}; };

View file

@ -71,7 +71,8 @@ u32 PostProcessing::GLSLShader::GetUniformsSize() const
void PostProcessing::GLSLShader::FillUniformBuffer(void* buffer, u32 texture_width, s32 texture_height, void PostProcessing::GLSLShader::FillUniformBuffer(void* buffer, u32 texture_width, s32 texture_height,
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
s32 texture_view_height, u32 window_width, u32 window_height, s32 texture_view_height, u32 window_width, u32 window_height,
s32 original_width, s32 original_height, float time) const s32 original_width, s32 original_height, s32 native_width,
s32 native_height, float time) const
{ {
CommonUniforms* common = static_cast<CommonUniforms*>(buffer); CommonUniforms* common = static_cast<CommonUniforms*>(buffer);
@ -91,17 +92,11 @@ void PostProcessing::GLSLShader::FillUniformBuffer(void* buffer, u32 texture_wid
common->window_resolution[1] = static_cast<float>(window_height); common->window_resolution[1] = static_cast<float>(window_height);
common->rcp_window_resolution[0] = 1.0f / static_cast<float>(window_width); common->rcp_window_resolution[0] = 1.0f / static_cast<float>(window_width);
common->rcp_window_resolution[1] = 1.0f / static_cast<float>(window_height); common->rcp_window_resolution[1] = 1.0f / static_cast<float>(window_height);
// pad the "original size" relative to the positioning on the screen
const float view_scale_x = static_cast<float>(original_width) / static_cast<float>(texture_view_width);
const float view_scale_y = static_cast<float>(original_height) / static_cast<float>(texture_view_height);
const s32 view_pad_x = texture_view_x + (texture_width - texture_view_width - texture_view_x);
const s32 view_pad_y = texture_view_y + (texture_height - texture_view_height - texture_view_y);
common->original_size[0] = static_cast<float>(original_width); common->original_size[0] = static_cast<float>(original_width);
common->original_size[1] = static_cast<float>(original_height); common->original_size[1] = static_cast<float>(original_height);
common->padded_original_size[0] = common->original_size[0] + static_cast<float>(view_pad_x) * view_scale_x; common->native_size[0] = static_cast<float>(native_width);
common->padded_original_size[1] = common->original_size[1] + static_cast<float>(view_pad_y) * view_scale_y; common->native_size[1] = static_cast<float>(native_height);
common->upscale_multiplier = static_cast<float>(original_width) / static_cast<float>(native_width);
common->time = time; common->time = time;
u8* option_values = reinterpret_cast<u8*>(common + 1); u8* option_values = reinterpret_cast<u8*>(common + 1);
@ -160,7 +155,7 @@ bool PostProcessing::GLSLShader::CompilePipeline(GPUTexture::Format format, u32
bool PostProcessing::GLSLShader::Apply(GPUTexture* input, GPUTexture* final_target, s32 final_left, s32 final_top, bool PostProcessing::GLSLShader::Apply(GPUTexture* input, GPUTexture* final_target, s32 final_left, s32 final_top,
s32 final_width, s32 final_height, s32 orig_width, s32 orig_height, s32 final_width, s32 final_height, s32 orig_width, s32 orig_height,
u32 target_width, u32 target_height) s32 native_width, s32 native_height, u32 target_width, u32 target_height)
{ {
GL_SCOPE_FMT("GLSL Shader {}", m_name); GL_SCOPE_FMT("GLSL Shader {}", m_name);
@ -183,7 +178,7 @@ bool PostProcessing::GLSLShader::Apply(GPUTexture* input, GPUTexture* final_targ
const u32 uniforms_size = GetUniformsSize(); const u32 uniforms_size = GetUniformsSize();
void* uniforms = g_gpu_device->MapUniformBuffer(uniforms_size); void* uniforms = g_gpu_device->MapUniformBuffer(uniforms_size);
FillUniformBuffer(uniforms, input->GetWidth(), input->GetHeight(), final_left, final_top, final_width, final_height, FillUniformBuffer(uniforms, input->GetWidth(), input->GetHeight(), final_left, final_top, final_width, final_height,
target_width, target_height, orig_width, orig_height, target_width, target_height, orig_width, orig_height, native_width, native_height,
static_cast<float>(PostProcessing::GetTimer().GetTimeSeconds())); static_cast<float>(PostProcessing::GetTimer().GetTimeSeconds()));
g_gpu_device->UnmapUniformBuffer(uniforms_size); g_gpu_device->UnmapUniformBuffer(uniforms_size);
g_gpu_device->Draw(3, 0); g_gpu_device->Draw(3, 0);
@ -407,42 +402,20 @@ static float4 o_col0;
float4 Sample() { return texture(samp0, v_tex0); } float4 Sample() { return texture(samp0, v_tex0); }
float4 SampleLocation(float2 location) { return texture(samp0, location); } float4 SampleLocation(float2 location) { return texture(samp0, location); }
#define SampleOffset(offset) textureOffset(samp0, v_tex0, offset) #define SampleOffset(offset) textureOffset(samp0, v_tex0, offset)
float2 GetFragCoord() float2 GetFragCoord() { return gl_FragCoord.xy; }
{ float2 GetWindowResolution() { return window_resolution; }
return gl_FragCoord.xy; float2 GetResolution() { return resolution; }
} float2 GetInvResolution() { return rcp_resolution; }
float2 GetWindowResolution() float2 GetCoordinates() { return v_tex0; }
{ float2 GetOriginalSize() { return original_size; }
return window_resolution; float2 GetNativeSize() { return native_size; }
} float GetUpscaleMultiplier() { return upscale_multiplier; }
float2 GetResolution() float GetTime() { return time; }
{ void SetOutput(float4 color) { o_col0 = color; }
return resolution;
} // Deprecated, only present for backwards compatibility.
float2 GetInvResolution() float2 GetPaddedOriginalSize() { return original_size; }
{
return rcp_resolution;
}
float2 GetCoordinates()
{
return v_tex0;
}
float2 GetOriginalSize()
{
return original_size;
}
float2 GetPaddedOriginalSize()
{
return padded_original_size;
}
float GetTime()
{
return time;
}
void SetOutput(float4 color)
{
o_col0 = color;
}
#define GetOption(x) (x) #define GetOption(x) (x)
#define OptionEnabled(x) ((x) != 0) #define OptionEnabled(x) ((x) != 0)
)"; )";
@ -480,9 +453,9 @@ void PostProcessingGLSLShaderGen::WriteUniformBuffer(std::stringstream& ss, cons
ss << " float2 window_resolution;\n"; ss << " float2 window_resolution;\n";
ss << " float2 rcp_window_resolution;\n"; ss << " float2 rcp_window_resolution;\n";
ss << " float2 original_size;\n"; ss << " float2 original_size;\n";
ss << " float2 padded_original_size;\n"; ss << " float2 native_size;\n";
ss << " float time;\n"; ss << " float time;\n";
ss << " float ubo_pad" << (pad_counter++) << ";\n"; ss << " float upscale_multiplier;\n";
ss << "\n"; ss << "\n";
static constexpr std::array<const char*, PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS + 1> vector_size_suffix = static constexpr std::array<const char*, PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS + 1> vector_size_suffix =

View file

@ -24,7 +24,8 @@ public:
bool ResizeOutput(GPUTexture::Format format, u32 width, u32 height) override; bool ResizeOutput(GPUTexture::Format format, u32 width, u32 height) override;
bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, ProgressCallback* progress) override; bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, ProgressCallback* progress) override;
bool Apply(GPUTexture* input, GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width, bool Apply(GPUTexture* input, GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width,
s32 final_height, s32 orig_width, s32 orig_height, u32 target_width, u32 target_height) override; s32 final_height, s32 orig_width, s32 orig_height, s32 native_width, s32 native_height, u32 target_width,
u32 target_height) override;
private: private:
struct CommonUniforms struct CommonUniforms
@ -36,9 +37,9 @@ private:
float window_resolution[2]; float window_resolution[2];
float rcp_window_resolution[2]; float rcp_window_resolution[2];
float original_size[2]; float original_size[2];
float padded_original_size[2]; float native_size[2];
float upscale_multiplier;
float time; float time;
float padding;
}; };
void LoadOptions(); void LoadOptions();
@ -46,7 +47,8 @@ private:
u32 GetUniformsSize() const; u32 GetUniformsSize() const;
void FillUniformBuffer(void* buffer, u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y, void FillUniformBuffer(void* buffer, u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y,
s32 texture_view_width, s32 texture_view_height, u32 window_width, u32 window_height, s32 texture_view_width, s32 texture_view_height, u32 window_width, u32 window_height,
s32 original_width, s32 original_height, float time) const; s32 original_width, s32 original_height, s32 native_width, s32 native_height,
float time) const;
std::string m_code; std::string m_code;