Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GS/HW: Allow use of trilinear with shader sampling #11448

Merged
merged 3 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions bin/resources/shaders/dx11/tfx.fx
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ cbuffer cb1
uint4 FbMask;
float4 HalfTexel;
float4 MinMax;
float4 LODParams;
float4 STRange;
int4 ChannelShuffle;
float2 TC_OffsetHack;
Expand Down Expand Up @@ -207,10 +208,10 @@ float4 sample_c(float2 uv, float uv_w)
return Texture.Sample(TextureSampler, uv);
#elif PS_MANUAL_LOD == 1
// FIXME add LOD: K - ( LOG2(Q) * (1 << L))
float K = MinMax.x;
float L = MinMax.y;
float bias = MinMax.z;
float max_lod = MinMax.w;
float K = LODParams.x;
float L = LODParams.y;
float bias = LODParams.z;
float max_lod = LODParams.w;

float gs_lod = K - log2(abs(uv_w)) * L;
// FIXME max useful ?
Expand Down
9 changes: 5 additions & 4 deletions bin/resources/shaders/opengl/tfx_fs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ layout(std140, binding = 0) uniform cb21
vec4 HalfTexel;

vec4 MinMax;
vec4 LODParams;
vec4 STRange;

ivec4 ChannelShuffle;
Expand Down Expand Up @@ -159,10 +160,10 @@ vec4 sample_c(vec2 uv)
return texture(TextureSampler, uv);
#elif PS_MANUAL_LOD == 1
// FIXME add LOD: K - ( LOG2(Q) * (1 << L))
float K = MinMax.x;
float L = MinMax.y;
float bias = MinMax.z;
float max_lod = MinMax.w;
float K = LODParams.x;
float L = LODParams.y;
float bias = LODParams.z;
float max_lod = LODParams.w;

float gs_lod = K - log2(abs(PSin.t_float.w)) * L;
// FIXME max useful ?
Expand Down
9 changes: 5 additions & 4 deletions bin/resources/shaders/vulkan/tfx.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ layout(std140, set = 0, binding = 1) uniform cb1
uvec4 FbMask;
vec4 HalfTexel;
vec4 MinMax;
vec4 LODParams;
vec4 STRange;
ivec4 ChannelShuffle;
vec2 TC_OffsetHack;
Expand Down Expand Up @@ -399,10 +400,10 @@ vec4 sample_c(vec2 uv)
return texture(Texture, uv);
#elif PS_MANUAL_LOD == 1
// FIXME add LOD: K - ( LOG2(Q) * (1 << L))
float K = MinMax.x;
float L = MinMax.y;
float bias = MinMax.z;
float max_lod = MinMax.w;
float K = LODParams.x;
float L = LODParams.y;
float bias = LODParams.z;
float max_lod = LODParams.w;

float gs_lod = K - log2(abs(vsIn.t.w)) * L;
// FIXME max useful ?
Expand Down
1 change: 1 addition & 0 deletions pcsx2/GS/Renderers/Common/GSDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,7 @@ struct alignas(16) GSHWDrawConfig

GSVector4 HalfTexel;
GSVector4 MinMax;
GSVector4 LODParams;
GSVector4 STRange;
GSVector4i ChannelShuffle;
GSVector2 TCOffsetHack;
Expand Down
43 changes: 23 additions & 20 deletions pcsx2/GS/Renderers/HW/GSRendererHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4739,7 +4739,6 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DAT
__ri static constexpr bool IsRedundantClamp(u8 clamp, u32 clamp_min, u32 clamp_max, u32 tsize)
{
// Don't shader sample when the clamp/repeat is configured to the texture size.
// That way trilinear etc still works.
const u32 textent = (1u << tsize) - 1u;
if (clamp == CLAMP_REGION_CLAMP)
return (clamp_min == 0 && clamp_max >= textent);
Expand Down Expand Up @@ -4790,9 +4789,9 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
// we keep the shader clamp. See #5851 on github, and the note in Draw().
[[maybe_unused]] static constexpr const char* clamp_modes[] = {"REPEAT", "CLAMP", "REGION_CLAMP", "REGION_REPEAT"};
const bool redundant_wms = IsRedundantClamp(m_cached_ctx.CLAMP.WMS, m_cached_ctx.CLAMP.MINU,
m_cached_ctx.CLAMP.MAXU, tex->m_TEX0.TW);
m_cached_ctx.CLAMP.MAXU, m_cached_ctx.TEX0.TW);
const bool redundant_wmt = IsRedundantClamp(m_cached_ctx.CLAMP.WMT, m_cached_ctx.CLAMP.MINV,
m_cached_ctx.CLAMP.MAXV, tex->m_TEX0.TH);
m_cached_ctx.CLAMP.MAXV, m_cached_ctx.TEX0.TH);
const u8 wms = EffectiveClamp(m_cached_ctx.CLAMP.WMS, !tex->m_target && (source_region.HasX() || redundant_wms));
const u8 wmt = EffectiveClamp(m_cached_ctx.CLAMP.WMT, !tex->m_target && (source_region.HasY() || redundant_wmt));
const bool complex_wms_wmt = !!((wms | wmt) & 2) || target_region;
Expand All @@ -4805,6 +4804,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
const bool need_mipmap = IsMipMapDraw();
const bool shader_emulated_sampler = tex->m_palette || (tex->m_target && !m_conf.ps.shuffle && cpsm.fmt != 0) ||
complex_wms_wmt || psm.depth || target_region;
const bool can_trilinear = !tex->m_palette && !tex->m_target && !m_conf.ps.shuffle;
const bool trilinear_manual = need_mipmap && GSConfig.HWMipmap;

bool bilinear = m_vt.IsLinear();
Expand All @@ -4817,16 +4817,19 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
// Force bilinear otherwise we can end up with min/mag nearest and mip linear.
// We don't need to check for HWMipmapLevel::Off here, because forced trilinear implies forced mipmaps.
bilinear = true;
trilinear = static_cast<u8>(GS_MIN_FILTER::Linear_Mipmap_Linear);
trilinear_auto = !tex->m_target && (!need_mipmap || !GSConfig.HWMipmap);
if (can_trilinear)
{
trilinear = static_cast<u8>(GS_MIN_FILTER::Linear_Mipmap_Linear);
trilinear_auto = !tex->m_target && (!need_mipmap || !GSConfig.HWMipmap);
}
}
break;

case TriFiltering::PS2:
case TriFiltering::Automatic:
{
// Can only use PS2 trilinear when mipmapping is enabled.
if (need_mipmap && GSConfig.HWMipmap)
if (need_mipmap && GSConfig.HWMipmap && can_trilinear)
{
trilinear = m_context->TEX1.MMIN;
trilinear_auto = !tex->m_target && !GSConfig.HWMipmap;
Expand Down Expand Up @@ -5033,17 +5036,19 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
m_conf.cb_ps.MinMax.w = (wmt == CLAMP_REGION_CLAMP && !m_conf.ps.depth_fmt) ? region_clamp.w : region_repeat.w;
}
}
else if (trilinear_manual)

if (trilinear_manual)
{
// Reuse uv_min_max for mipmap parameter to avoid an extension of the UBO
m_conf.cb_ps.MinMax.x = static_cast<float>(m_context->TEX1.K) / 16.0f;
m_conf.cb_ps.MinMax.y = static_cast<float>(1 << m_context->TEX1.L);
m_conf.cb_ps.MinMax.z = static_cast<float>(m_lod.x); // Offset because first layer is m_lod, dunno if we can do better
m_conf.cb_ps.MinMax.w = static_cast<float>(m_lod.y);
m_conf.cb_ps.LODParams.x = static_cast<float>(m_context->TEX1.K) / 16.0f;
m_conf.cb_ps.LODParams.y = static_cast<float>(1 << m_context->TEX1.L);
m_conf.cb_ps.LODParams.z = static_cast<float>(m_lod.x); // Offset because first layer is m_lod, dunno if we can do better
m_conf.cb_ps.LODParams.w = static_cast<float>(m_lod.y);
m_conf.ps.manual_lod = 1;
}
else if (trilinear_auto)
{
tex->m_texture->GenerateMipmapsIfNeeded();
m_conf.ps.automatic_lod = 1;
}

// TC Offset Hack
Expand All @@ -5059,7 +5064,11 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
{
m_conf.sampler.biln = 0;
m_conf.sampler.aniso = 0;
m_conf.sampler.triln = 0;

// Remove linear from trilinear, since we're doing the bilinear in the shader, and we only want this for mip selection.
m_conf.sampler.triln = (trilinear >= static_cast<u8>(GS_MIN_FILTER::Linear_Mipmap_Nearest)) ?
(trilinear - static_cast<u8>(GS_MIN_FILTER::Nearest_Mipmap_Nearest)) :
0;
}
else
{
Expand All @@ -5069,14 +5078,8 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
const bool anisotropic = m_vt.m_primclass == GS_TRIANGLE_CLASS && !trilinear_manual;
m_conf.sampler.aniso = anisotropic;
m_conf.sampler.triln = trilinear;
if (trilinear_manual)
{
m_conf.ps.manual_lod = 1;
}
else if (trilinear_auto || anisotropic)
{
if (anisotropic && !trilinear_manual)
m_conf.ps.automatic_lod = 1;
}
}

// clamp to base level if we're not providing or generating mipmaps
Expand Down
5 changes: 3 additions & 2 deletions pcsx2/GS/Renderers/HW/GSTextureCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5366,8 +5366,7 @@ GSTextureCache::HashCacheEntry* GSTextureCache::LookupHashCache(const GIFRegTEX0
if (lod)
{
const int basemip = lod->x;
const int nmips = lod->y - lod->x + 1;
for (int mip = 1; mip < nmips; mip++)
for (int mip = 1; mip < tlevels; mip++)
{
const GIFRegTEX0 MIP_TEX0{g_gs_renderer->GetTex0Layer(basemip + mip)};
std::pair<u8, u8> mip_alpha_minmax;
Expand All @@ -5379,6 +5378,8 @@ GSTextureCache::HashCacheEntry* GSTextureCache::LookupHashCache(const GIFRegTEX0
alpha_minmax.second = std::max(alpha_minmax.second, mip_alpha_minmax.second);
}
}

tex->ClearMipmapGenerationFlag();
}

// remove the palette hash when using paltex/indexed
Expand Down
1 change: 1 addition & 0 deletions pcsx2/GS/Renderers/Metal/GSMTLSharedHeader.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ struct GSMTLMainPSUniform
vector_float4 uv_min_max;
vector_uint4 uv_msk_fix;
};
vector_float4 lod_params;
vector_float4 st_range;
struct
{
Expand Down
8 changes: 4 additions & 4 deletions pcsx2/GS/Renderers/Metal/tfx.metal
Original file line number Diff line number Diff line change
Expand Up @@ -356,10 +356,10 @@ struct PSMain
}
else if (PS_MANUAL_LOD)
{
float K = cb.uv_min_max.x;
float L = cb.uv_min_max.y;
float bias = cb.uv_min_max.z;
float max_lod = cb.uv_min_max.w;
float K = cb.lod_params.x;
float L = cb.lod_params.y;
float bias = cb.lod_params.z;
float max_lod = cb.lod_params.w;

float gs_lod = K - log2(abs(in.t.w)) * L;
// FIXME max useful ?
Expand Down
2 changes: 1 addition & 1 deletion pcsx2/ShaderCacheVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

/// Version number for GS and other shaders. Increment whenever any of the contents of the
/// shaders change, to invalidate the cache.
static constexpr u32 SHADER_CACHE_VERSION = 50;
static constexpr u32 SHADER_CACHE_VERSION = 51;