PostProcessing: Expose aspect-correct pixel sizes

That consider the display aspect ratio/padding when sampling pixels in
the input (window size).
This commit is contained in:
Stenzek 2024-06-11 23:15:24 +10:00
parent c2eed018c1
commit facce0d8cb
No known key found for this signature in database
4 changed files with 289 additions and 56 deletions

View File

@ -754,6 +754,7 @@ bool PostProcessing::ReShadeFXShader::CreateOptions(const reshadefx::module& mod
bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_info& ui, SourceOptionType* si, bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_info& ui, SourceOptionType* si,
Error* error) Error* error)
{ {
// TODO: Rewrite these to a lookup table instead, this if chain is terrible.
const std::string_view source = GetStringAnnotationValue(ui.annotations, "source", {}); const std::string_view source = GetStringAnnotationValue(ui.annotations, "source", {});
if (!source.empty()) if (!source.empty())
{ {
@ -879,14 +880,134 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 1) if (!ui.type.is_floating_point() || ui.type.components() != 1)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for upscale_multiplier source in uniform '{}'", Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(),
ui.type.description(), ui.name)); source, ui.name));
return false; return false;
} }
*si = SourceOptionType::UpscaleMultiplier; *si = SourceOptionType::UpscaleMultiplier;
return true; return true;
} }
else if (source == "viewportx")
{
if (!ui.type.is_floating_point() || ui.type.components() != 1)
{
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(),
source, ui.name));
return false;
}
*si = SourceOptionType::ViewportX;
return true;
}
else if (source == "viewporty")
{
if (!ui.type.is_floating_point() || ui.type.components() != 1)
{
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(),
source, ui.name));
return false;
}
*si = SourceOptionType::ViewportY;
return true;
}
else if (source == "viewportwidth")
{
if (!ui.type.is_floating_point() || ui.type.components() != 1)
{
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(),
source, ui.name));
return false;
}
*si = SourceOptionType::ViewportWidth;
return true;
}
else if (source == "viewportheight")
{
if (!ui.type.is_floating_point() || ui.type.components() != 1)
{
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(),
source, ui.name));
return false;
}
*si = SourceOptionType::ViewportHeight;
return true;
}
else if (source == "viewportsize")
{
if (!ui.type.is_floating_point() || ui.type.components() != 2)
{
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(),
source, ui.name));
return false;
}
*si = SourceOptionType::ViewportSize;
return true;
}
else if (source == "internal_pixel_size")
{
if (!ui.type.is_floating_point() || ui.type.components() != 2)
{
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(),
source, ui.name));
return false;
}
*si = SourceOptionType::InternalPixelSize;
return true;
}
else if (source == "normalized_internal_pixel_size")
{
if (!ui.type.is_floating_point() || ui.type.components() != 2)
{
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(),
source, ui.name));
return false;
}
*si = SourceOptionType::InternalNormPixelSize;
return true;
}
else if (source == "native_pixel_size")
{
if (!ui.type.is_floating_point() || ui.type.components() != 2)
{
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(),
source, ui.name));
return false;
}
*si = SourceOptionType::NativePixelSize;
return true;
}
else if (source == "normalized_native_pixel_size")
{
if (!ui.type.is_floating_point() || ui.type.components() != 2)
{
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(),
source, ui.name));
return false;
}
*si = SourceOptionType::NativeNormPixelSize;
return true;
}
else if (source == "buffer_to_viewport_ratio")
{
if (!ui.type.is_floating_point() || ui.type.components() != 2)
{
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(),
source, ui.name));
return false;
}
*si = SourceOptionType::BufferToViewportRatio;
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));
@ -1516,6 +1637,83 @@ bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input, GPUTexture* final
} }
break; break;
case SourceOptionType::ViewportX:
{
const float value = static_cast<float>(final_left);
std::memcpy(dst, &value, sizeof(value));
}
break;
case SourceOptionType::ViewportY:
{
const float value = static_cast<float>(final_top);
std::memcpy(dst, &value, sizeof(value));
}
break;
case SourceOptionType::ViewportWidth:
{
const float value = static_cast<float>(final_width);
std::memcpy(dst, &value, sizeof(value));
}
break;
case SourceOptionType::ViewportHeight:
{
const float value = static_cast<float>(final_height);
std::memcpy(dst, &value, sizeof(value));
}
break;
case SourceOptionType::ViewportSize:
{
const float value[2] = {static_cast<float>(final_width), static_cast<float>(final_height)};
std::memcpy(dst, &value, sizeof(value));
}
break;
case SourceOptionType::InternalPixelSize:
{
const float value[2] = {static_cast<float>(final_width) / static_cast<float>(orig_width),
static_cast<float>(final_height) / static_cast<float>(orig_height)};
std::memcpy(dst, value, sizeof(value));
}
break;
case SourceOptionType::InternalNormPixelSize:
{
const float value[2] = {
(static_cast<float>(final_width) / static_cast<float>(orig_width)) / static_cast<float>(target_height),
(static_cast<float>(final_height) / static_cast<float>(orig_height)) / static_cast<float>(target_height)};
std::memcpy(dst, value, sizeof(value));
}
break;
case SourceOptionType::NativePixelSize:
{
const float value[2] = {static_cast<float>(final_width) / static_cast<float>(native_width),
static_cast<float>(final_height) / static_cast<float>(native_height)};
std::memcpy(dst, value, sizeof(value));
}
break;
case SourceOptionType::NativeNormPixelSize:
{
const float value[2] = {
(static_cast<float>(final_width) / static_cast<float>(native_width)) / static_cast<float>(target_height),
(static_cast<float>(final_height) / static_cast<float>(native_height)) / static_cast<float>(target_height)};
std::memcpy(dst, value, sizeof(value));
}
break;
case SourceOptionType::BufferToViewportRatio:
{
const float value[2] = {static_cast<float>(target_width) / static_cast<float>(final_width),
static_cast<float>(target_height) / static_cast<float>(final_height)};
std::memcpy(dst, value, sizeof(value));
}
break;
default: default:
UnreachableCode(); UnreachableCode();
break; break;

View File

@ -66,6 +66,16 @@ private:
NativeWidthF, NativeWidthF,
NativeHeightF, NativeHeightF,
UpscaleMultiplier, UpscaleMultiplier,
ViewportX,
ViewportY,
ViewportWidth,
ViewportHeight,
ViewportSize,
InternalPixelSize,
InternalNormPixelSize,
NativePixelSize,
NativeNormPixelSize,
BufferToViewportRatio,
MaxCount MaxCount
}; };

View File

@ -68,34 +68,43 @@ u32 PostProcessing::GLSLShader::GetUniformsSize() const
return sizeof(CommonUniforms) + (sizeof(ShaderOption::ValueVector) * static_cast<u32>(m_options.size())); return sizeof(CommonUniforms) + (sizeof(ShaderOption::ValueVector) * static_cast<u32>(m_options.size()));
} }
void PostProcessing::GLSLShader::FillUniformBuffer(void* buffer, u32 texture_width, s32 texture_height, void PostProcessing::GLSLShader::FillUniformBuffer(void* buffer, s32 viewport_x, s32 viewport_y, s32 viewport_width,
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 viewport_height, u32 window_width, u32 window_height,
s32 texture_view_height, u32 window_width, u32 window_height,
s32 original_width, s32 original_height, s32 native_width, s32 original_width, s32 original_height, s32 native_width,
s32 native_height, float time) const s32 native_height, float time) const
{ {
CommonUniforms* common = static_cast<CommonUniforms*>(buffer); CommonUniforms* common = static_cast<CommonUniforms*>(buffer);
const float rcp_texture_width = 1.0f / static_cast<float>(texture_width); const float internal_pixel_width = static_cast<float>(viewport_width) / static_cast<float>(original_width);
const float rcp_texture_height = 1.0f / static_cast<float>(texture_height); const float internal_pixel_height = static_cast<float>(viewport_height) / static_cast<float>(original_height);
common->src_rect[0] = static_cast<float>(texture_view_x) * rcp_texture_width; const float native_pixel_width = (static_cast<float>(viewport_width) / static_cast<float>(native_width));
common->src_rect[1] = static_cast<float>(texture_view_y) * rcp_texture_height; const float native_pixel_height = (static_cast<float>(viewport_height) / static_cast<float>(native_height));
common->src_rect[2] = (static_cast<float>(texture_view_x + texture_view_width - 1)) * rcp_texture_width; common->src_rect[0] = static_cast<float>(viewport_x) / static_cast<float>(window_width);
common->src_rect[3] = (static_cast<float>(texture_view_y + texture_view_height - 1)) * rcp_texture_height; common->src_rect[1] = static_cast<float>(viewport_y) / static_cast<float>(window_height);
common->src_size[0] = (static_cast<float>(texture_view_width)) * rcp_texture_width; common->src_rect[2] = (static_cast<float>(viewport_x + viewport_width - 1)) / static_cast<float>(window_width);
common->src_size[1] = (static_cast<float>(texture_view_height)) * rcp_texture_height; common->src_rect[3] = (static_cast<float>(viewport_y + viewport_height - 1)) / static_cast<float>(window_height);
common->resolution[0] = static_cast<float>(texture_width); common->src_size[0] = static_cast<float>(viewport_width) / static_cast<float>(window_width);
common->resolution[1] = static_cast<float>(texture_height); common->src_size[1] = static_cast<float>(viewport_height) / static_cast<float>(window_height);
common->rcp_resolution[0] = rcp_texture_width; common->window_size[0] = static_cast<float>(window_width);
common->rcp_resolution[1] = rcp_texture_height; common->window_size[1] = static_cast<float>(window_height);
common->window_resolution[0] = static_cast<float>(window_width); common->rcp_window_size[0] = 1.0f / static_cast<float>(window_width);
common->window_resolution[1] = static_cast<float>(window_height); common->rcp_window_size[1] = 1.0f / static_cast<float>(window_height);
common->rcp_window_resolution[0] = 1.0f / static_cast<float>(window_width); common->viewport_size[0] = static_cast<float>(viewport_width);
common->rcp_window_resolution[1] = 1.0f / static_cast<float>(window_height); common->viewport_size[1] = static_cast<float>(viewport_height);
common->original_size[0] = static_cast<float>(original_width); common->window_to_viewport_ratio[0] = static_cast<float>(window_width) / static_cast<float>(viewport_width);
common->original_size[1] = static_cast<float>(original_height); common->window_to_viewport_ratio[1] = static_cast<float>(window_height) / static_cast<float>(viewport_height);
common->internal_size[0] = static_cast<float>(original_width);
common->internal_size[1] = static_cast<float>(original_height);
common->internal_pixel_size[0] = internal_pixel_width;
common->internal_pixel_size[1] = internal_pixel_height;
common->norm_internal_pixel_size[0] = internal_pixel_width / static_cast<float>(window_width);
common->norm_internal_pixel_size[1] = internal_pixel_height / static_cast<float>(window_height);
common->native_size[0] = static_cast<float>(native_width); common->native_size[0] = static_cast<float>(native_width);
common->native_size[1] = static_cast<float>(native_height); common->native_size[1] = static_cast<float>(native_height);
common->native_pixel_size[0] = native_pixel_width;
common->native_pixel_size[1] = native_pixel_height;
common->norm_native_pixel_size[0] = native_pixel_width / static_cast<float>(window_width);
common->norm_native_pixel_size[1] = native_pixel_height / static_cast<float>(window_height);
common->upscale_multiplier = static_cast<float>(original_width) / static_cast<float>(native_width); common->upscale_multiplier = static_cast<float>(original_width) / static_cast<float>(native_width);
common->time = time; common->time = time;
@ -177,8 +186,8 @@ 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, final_left, final_top, final_width, final_height, target_width, target_height, orig_width,
target_width, target_height, orig_width, orig_height, native_width, native_height, 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);
@ -341,7 +350,7 @@ std::string PostProcessingGLSLShaderGen::GeneratePostProcessingVertexShader(cons
#if API_OPENGL || API_OPENGL_ES || API_VULKAN #if API_OPENGL || API_OPENGL_ES || API_VULKAN
v_pos.y = -v_pos.y; v_pos.y = -v_pos.y;
#endif #endif
v_tex0 = src_rect.xy + (src_size * v_tex0); v_tex0 = u_src_rect.xy + (u_src_size * v_tex0);
} }
)"; )";
@ -403,18 +412,27 @@ 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() { return gl_FragCoord.xy; } float2 GetFragCoord() { return gl_FragCoord.xy; }
float2 GetWindowResolution() { return window_resolution; }
float2 GetResolution() { return resolution; }
float2 GetInvResolution() { return rcp_resolution; }
float2 GetCoordinates() { return v_tex0; } float2 GetCoordinates() { return v_tex0; }
float2 GetOriginalSize() { return original_size; } float2 GetWindowSize() { return u_window_size; }
float2 GetNativeSize() { return native_size; } float2 GetInvWindowSize() { return u_rcp_window_size; }
float GetUpscaleMultiplier() { return upscale_multiplier; } float2 GetViewportSize() { return u_viewport_size; }
float GetTime() { return time; } float2 GetWindowToViewportRatio() { return u_window_to_viewport_ratio; }
float2 GetInternalSize() { return u_internal_size; }
float2 GetInternalPixelSize() { return u_internal_pixel_size; }
float2 GetInvInternalPixelSize() { return u_norm_internal_pixel_size; }
float2 GetNativeSize() { return u_native_size; }
float2 GetNativePixelSize() { return u_native_pixel_size; }
float2 GetInvNativePixelSize() { return u_norm_native_pixel_size; }
float GetUpscaleMultiplier() { return u_upscale_multiplier; }
float GetTime() { return u_time; }
void SetOutput(float4 color) { o_col0 = color; } void SetOutput(float4 color) { o_col0 = color; }
// Deprecated, only present for backwards compatibility. // Deprecated, only present for backwards compatibility.
float2 GetPaddedOriginalSize() { return original_size; } float2 GetResolution() { return u_window_size; }
float2 GetInvResolution() { return u_rcp_window_size; }
float2 GetOriginalSize() { return u_internal_size; }
float2 GetPaddedOriginalSize() { return u_internal_size * u_window_to_viewport_ratio; }
float2 GetWindowResolution() { return u_window_size; }
#define GetOption(x) (x) #define GetOption(x) (x)
#define OptionEnabled(x) ((x) != 0) #define OptionEnabled(x) ((x) != 0)
@ -446,16 +464,20 @@ void PostProcessingGLSLShaderGen::WriteUniformBuffer(std::stringstream& ss, cons
WriteUniformBufferDeclaration(ss, use_push_constants); WriteUniformBufferDeclaration(ss, use_push_constants);
ss << "{\n"; ss << "{\n";
ss << " float4 src_rect;\n"; ss << " float4 u_src_rect;\n";
ss << " float2 src_size;\n"; ss << " float2 u_src_size;\n";
ss << " float2 resolution;\n"; ss << " float2 u_window_size;\n";
ss << " float2 rcp_resolution;\n"; ss << " float2 u_rcp_window_size;\n";
ss << " float2 window_resolution;\n"; ss << " float2 u_viewport_size;\n";
ss << " float2 rcp_window_resolution;\n"; ss << " float2 u_window_to_viewport_ratio;\n";
ss << " float2 original_size;\n"; ss << " float2 u_internal_size;\n";
ss << " float2 native_size;\n"; ss << " float2 u_internal_pixel_size;\n";
ss << " float time;\n"; ss << " float2 u_norm_internal_pixel_size;\n";
ss << " float upscale_multiplier;\n"; ss << " float2 u_native_size;\n";
ss << " float2 u_native_pixel_size;\n";
ss << " float2 u_norm_native_pixel_size;\n";
ss << " float u_upscale_multiplier;\n";
ss << " float u_time;\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 =
@ -467,14 +489,14 @@ void PostProcessingGLSLShaderGen::WriteUniformBuffer(std::stringstream& ss, cons
case PostProcessing::ShaderOption::Type::Bool: case PostProcessing::ShaderOption::Type::Bool:
ss << " int " << option.name << ";\n"; ss << " int " << option.name << ";\n";
for (u32 i = option.vector_size; i < PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS; i++) for (u32 i = option.vector_size; i < PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS; i++)
ss << " int ubo_pad" << (pad_counter++) << ";\n"; ss << " int u_ubo_pad" << (pad_counter++) << ";\n";
break; break;
case PostProcessing::ShaderOption::Type::Int: case PostProcessing::ShaderOption::Type::Int:
{ {
ss << " int" << vector_size_suffix[option.vector_size] << " " << option.name << ";\n"; ss << " int" << vector_size_suffix[option.vector_size] << " " << option.name << ";\n";
for (u32 i = option.vector_size; i < PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS; i++) for (u32 i = option.vector_size; i < PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS; i++)
ss << " int ubo_pad" << (pad_counter++) << ";\n"; ss << " int u_ubo_pad" << (pad_counter++) << ";\n";
} }
break; break;
@ -483,7 +505,7 @@ void PostProcessingGLSLShaderGen::WriteUniformBuffer(std::stringstream& ss, cons
{ {
ss << " float" << vector_size_suffix[option.vector_size] << " " << option.name << ";\n"; ss << " float" << vector_size_suffix[option.vector_size] << " " << option.name << ";\n";
for (u32 i = option.vector_size; i < PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS; i++) for (u32 i = option.vector_size; i < PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS; i++)
ss << " float ubo_pad" << (pad_counter++) << ";\n"; ss << " float u_ubo_pad" << (pad_counter++) << ";\n";
} }
break; break;
} }

View File

@ -32,12 +32,16 @@ private:
{ {
float src_rect[4]; float src_rect[4];
float src_size[2]; float src_size[2];
float resolution[2]; float window_size[2];
float rcp_resolution[2]; float rcp_window_size[2];
float window_resolution[2]; float viewport_size[2];
float rcp_window_resolution[2]; float window_to_viewport_ratio[2];
float original_size[2]; float internal_size[2];
float internal_pixel_size[2];
float norm_internal_pixel_size[2];
float native_size[2]; float native_size[2];
float native_pixel_size[2];
float norm_native_pixel_size[2];
float upscale_multiplier; float upscale_multiplier;
float time; float time;
}; };
@ -45,10 +49,9 @@ private:
void LoadOptions(); void LoadOptions();
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, s32 viewport_x, s32 viewport_y, s32 viewport_width, s32 viewport_height,
s32 texture_view_width, s32 texture_view_height, u32 window_width, u32 window_height, u32 window_width, u32 window_height, s32 original_width, s32 original_height, s32 native_width,
s32 original_width, s32 original_height, s32 native_width, s32 native_height, s32 native_height, float time) const;
float time) const;
std::string m_code; std::string m_code;