mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-07 12:05:52 +00:00
GPU/HW: Add Scale2x/Scale3x texture filters
This commit is contained in:
parent
6e02133452
commit
7971bb949b
@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||||
//
|
//
|
||||||
// NOTE: Some parts of this file have more permissive licenses. They are marked appropriately.
|
// NOTE: Some parts of this file have more permissive licenses. They are marked appropriately.
|
||||||
@ -831,6 +831,98 @@ void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limi
|
|||||||
texcol = unpackUnorm4x8(res);
|
texcol = unpackUnorm4x8(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef src
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
else if (texture_filter == GPUTextureFilter::Scale2x)
|
||||||
|
{
|
||||||
|
// Based on https://www.scale2x.it/algorithm
|
||||||
|
ss << R"(
|
||||||
|
#define src(xoffs, yoffs) packUnorm4x8(SampleFromVRAM(texpage, clamp(bcoords + float2((xoffs), (yoffs)), uv_limits.xy, uv_limits.zw)))
|
||||||
|
|
||||||
|
void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limits, out float4 texcol, out float ialpha)
|
||||||
|
{
|
||||||
|
float2 bcoords = floor(coords);
|
||||||
|
|
||||||
|
uint E = src(+0, +0);
|
||||||
|
uint B = src(+0, - 1);
|
||||||
|
uint D = src(-1, +0);
|
||||||
|
uint F = src(+1, +0);
|
||||||
|
uint H = src(+0, +1);
|
||||||
|
|
||||||
|
uint J = (D == B && B != F && D != H) ? D : E;
|
||||||
|
uint K = (B == F && D != F && H != F) ? F : E;
|
||||||
|
uint L = (H == D && F != D && B != D) ? D : E;
|
||||||
|
uint M = (H == F && D != H && B != F) ? F : E;
|
||||||
|
|
||||||
|
// select quadrant based on fractional part of texture coordinates
|
||||||
|
float2 fpart = frac(coords);
|
||||||
|
uint res = (fpart.x < 0.5f) ? ((fpart.y < 0.5f) ? J : L) : ((fpart.y < 0.5f) ? K : M);
|
||||||
|
|
||||||
|
ialpha = float(res != 0u);
|
||||||
|
texcol = unpackUnorm4x8(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef src
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
else if (texture_filter == GPUTextureFilter::Scale3x)
|
||||||
|
{
|
||||||
|
// Based on https://www.scale2x.it/algorithm
|
||||||
|
ss << R"(
|
||||||
|
#define src(xoffs, yoffs) packUnorm4x8(SampleFromVRAM(texpage, clamp(bcoords + float2((xoffs), (yoffs)), uv_limits.xy, uv_limits.zw)))
|
||||||
|
|
||||||
|
void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limits, out float4 texcol, out float ialpha)
|
||||||
|
{
|
||||||
|
float2 bcoords = floor(coords);
|
||||||
|
|
||||||
|
uint E = src(+0, +0);
|
||||||
|
uint B = src(+0, -1);
|
||||||
|
uint D = src(-1, +0);
|
||||||
|
uint F = src(+1, +0);
|
||||||
|
uint H = src(+0, +1);
|
||||||
|
|
||||||
|
uint res = E;
|
||||||
|
if (B != H && D != F) {
|
||||||
|
uint A = src(-1, -1);
|
||||||
|
uint C = src(+1, -1);
|
||||||
|
uint G = src(-1, +1);
|
||||||
|
uint I = src(+1, +1);
|
||||||
|
|
||||||
|
uint E0 = (D == B) ? D : E;
|
||||||
|
uint E1 = (D == B && E != C) || (B == F && E != A) ? B : E;
|
||||||
|
uint E2 = (B == F) ? F : E;
|
||||||
|
uint E3 = (D == B && E != G) || (D == H && E != A) ? D : E;
|
||||||
|
uint E4 = E;
|
||||||
|
uint E5 = (B == F && E != I) || (H == F && E != C) ? F : E;
|
||||||
|
uint E6 = (D == H) ? D : E;
|
||||||
|
uint E7 = (D == H && E != I) || (H == F && E != G) ? H : E;
|
||||||
|
uint E8 = (H == F) ? F : E;
|
||||||
|
|
||||||
|
// select quadrant based on fractional part of texture coordinates
|
||||||
|
float2 fpart = frac(coords);
|
||||||
|
uint R0, R1, R2;
|
||||||
|
if (fpart.y < 0.34f) {
|
||||||
|
R0 = E0;
|
||||||
|
R1 = E1;
|
||||||
|
R2 = E2;
|
||||||
|
} else if (fpart.y < 0.67f) {
|
||||||
|
R0 = E3;
|
||||||
|
R1 = E4;
|
||||||
|
R2 = E5;
|
||||||
|
} else {
|
||||||
|
R0 = E6;
|
||||||
|
R1 = E7;
|
||||||
|
R2 = E8;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = (fpart.x < 0.34f) ? R0 : ((fpart.x < 0.67f) ? R1 : R2);
|
||||||
|
}
|
||||||
|
|
||||||
|
ialpha = float(res != 0u);
|
||||||
|
texcol = unpackUnorm4x8(res);
|
||||||
|
}
|
||||||
|
|
||||||
#undef src
|
#undef src
|
||||||
)";
|
)";
|
||||||
}
|
}
|
||||||
|
@ -1531,7 +1531,8 @@ GPURenderer Settings::GetAutomaticRenderer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
static constexpr const std::array s_texture_filter_names = {
|
static constexpr const std::array s_texture_filter_names = {
|
||||||
"Nearest", "Bilinear", "BilinearBinAlpha", "JINC2", "JINC2BinAlpha", "xBR", "xBRBinAlpha", "MMPX",
|
"Nearest", "Bilinear", "BilinearBinAlpha", "JINC2", "JINC2BinAlpha",
|
||||||
|
"xBR", "xBRBinAlpha", "Scale2x", "Scale3x", "MMPX",
|
||||||
};
|
};
|
||||||
static constexpr const std::array s_texture_filter_display_names = {
|
static constexpr const std::array s_texture_filter_display_names = {
|
||||||
TRANSLATE_DISAMBIG_NOOP("Settings", "Nearest-Neighbor", "GPUTextureFilter"),
|
TRANSLATE_DISAMBIG_NOOP("Settings", "Nearest-Neighbor", "GPUTextureFilter"),
|
||||||
@ -1541,8 +1542,12 @@ static constexpr const std::array s_texture_filter_display_names = {
|
|||||||
TRANSLATE_DISAMBIG_NOOP("Settings", "JINC2 (Slow, No Edge Blending)", "GPUTextureFilter"),
|
TRANSLATE_DISAMBIG_NOOP("Settings", "JINC2 (Slow, No Edge Blending)", "GPUTextureFilter"),
|
||||||
TRANSLATE_DISAMBIG_NOOP("Settings", "xBR (Very Slow)", "GPUTextureFilter"),
|
TRANSLATE_DISAMBIG_NOOP("Settings", "xBR (Very Slow)", "GPUTextureFilter"),
|
||||||
TRANSLATE_DISAMBIG_NOOP("Settings", "xBR (Very Slow, No Edge Blending)", "GPUTextureFilter"),
|
TRANSLATE_DISAMBIG_NOOP("Settings", "xBR (Very Slow, No Edge Blending)", "GPUTextureFilter"),
|
||||||
|
TRANSLATE_DISAMBIG_NOOP("Settings", "Scale2x (EPX)", "GPUTextureFilter"),
|
||||||
|
TRANSLATE_DISAMBIG_NOOP("Settings", "Scale3x (Slow)", "GPUTextureFilter"),
|
||||||
TRANSLATE_DISAMBIG_NOOP("Settings", "MMPX (Slow)", "GPUTextureFilter"),
|
TRANSLATE_DISAMBIG_NOOP("Settings", "MMPX (Slow)", "GPUTextureFilter"),
|
||||||
};
|
};
|
||||||
|
static_assert(s_texture_filter_names.size() == static_cast<size_t>(GPUTextureFilter::Count));
|
||||||
|
static_assert(s_texture_filter_display_names.size() == static_cast<size_t>(GPUTextureFilter::Count));
|
||||||
|
|
||||||
std::optional<GPUTextureFilter> Settings::ParseTextureFilterName(const char* str)
|
std::optional<GPUTextureFilter> Settings::ParseTextureFilterName(const char* str)
|
||||||
{
|
{
|
||||||
|
@ -97,6 +97,8 @@ enum class GPUTextureFilter : u8
|
|||||||
JINC2BinAlpha,
|
JINC2BinAlpha,
|
||||||
xBR,
|
xBR,
|
||||||
xBRBinAlpha,
|
xBRBinAlpha,
|
||||||
|
Scale2x,
|
||||||
|
Scale3x,
|
||||||
MMPX,
|
MMPX,
|
||||||
Count
|
Count
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user