From 50bdcb8d9ce0cf7531c428c8bc565e7cead01b33 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 30 Jan 2019 00:47:01 +1000 Subject: [PATCH] TextureCache: Bind textures/samplers after loading all textures Since loading textures can result in rendering, e.g. partial copies, we don't want to disturb partially-bound GX state. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 72 +++++++++++++++++- Source/Core/VideoCommon/VertexManagerBase.cpp | 74 +------------------ 2 files changed, 71 insertions(+), 75 deletions(-) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index a42438e0b1..d0355b724b 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -33,6 +33,7 @@ #include "VideoCommon/Debugger.h" #include "VideoCommon/FramebufferManagerBase.h" #include "VideoCommon/HiresTextures.h" +#include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/RenderBase.h" #include "VideoCommon/SamplerCommon.h" #include "VideoCommon/Statistics.h" @@ -482,12 +483,79 @@ static u32 CalculateLevelSize(u32 level_0_size, u32 level) return std::max(level_0_size >> level, 1u); } +static void SetSamplerState(u32 index, float custom_tex_scale, bool custom_tex, + bool has_arbitrary_mips) +{ + const FourTexUnits& tex = bpmem.tex[index / 4]; + const TexMode0& tm0 = tex.texMode0[index % 4]; + + SamplerState state = {}; + state.Generate(bpmem, index); + + // Force texture filtering config option. + if (g_ActiveConfig.bForceFiltering) + { + state.min_filter = SamplerState::Filter::Linear; + state.mag_filter = SamplerState::Filter::Linear; + state.mipmap_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? + SamplerState::Filter::Linear : + SamplerState::Filter::Point; + } + + // Custom textures may have a greater number of mips + if (custom_tex) + state.max_lod = 255; + + // Anisotropic filtering option. + if (g_ActiveConfig.iMaxAnisotropy != 0 && !SamplerCommon::IsBpTexMode0PointFiltering(tm0)) + { + // https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt + // For predictable results on all hardware/drivers, only use one of: + // GL_LINEAR + GL_LINEAR (No Mipmaps [Bilinear]) + // GL_LINEAR + GL_LINEAR_MIPMAP_LINEAR (w/ Mipmaps [Trilinear]) + // Letting the game set other combinations will have varying arbitrary results; + // possibly being interpreted as equal to bilinear/trilinear, implicitly + // disabling anisotropy, or changing the anisotropic algorithm employed. + state.min_filter = SamplerState::Filter::Linear; + state.mag_filter = SamplerState::Filter::Linear; + if (SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0)) + state.mipmap_filter = SamplerState::Filter::Linear; + state.anisotropic_filtering = 1; + } + else + { + state.anisotropic_filtering = 0; + } + + if (has_arbitrary_mips && SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0)) + { + // Apply a secondary bias calculated from the IR scale to pull inwards mipmaps + // that have arbitrary contents, eg. are used for fog effects where the + // distance they kick in at is important to preserve at any resolution. + // Correct this with the upscaling factor of custom textures. + s64 lod_offset = std::log2(g_renderer->GetEFBScale() / custom_tex_scale) * 256.f; + state.lod_bias = MathUtil::Clamp(state.lod_bias + lod_offset, -32768, 32767); + + // Anisotropic also pushes mips farther away so it cannot be used either + state.anisotropic_filtering = 0; + } + + g_renderer->SetSamplerState(index, state); +} + void TextureCacheBase::BindTextures() { for (u32 i = 0; i < bound_textures.size(); i++) { - if (IsValidBindPoint(i) && bound_textures[i]) - g_renderer->SetTexture(i, bound_textures[i]->texture.get()); + const TCacheEntry* tentry = bound_textures[i]; + if (IsValidBindPoint(i) && tentry) + { + g_renderer->SetTexture(i, tentry->texture.get()); + PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height); + + const float custom_tex_scale = tentry->GetWidth() / float(tentry->native_width); + SetSamplerState(i, custom_tex_scale, tentry->is_custom_tex, tentry->has_arbitrary_mips); + } } } diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index 0e178e4d9b..e50cc1ceed 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -232,66 +232,6 @@ void VertexManagerBase::UploadUtilityVertices(const void* vertices, u32 vertex_s CommitBuffer(num_vertices, vertex_stride, num_indices, out_base_vertex, out_base_index); } -static void SetSamplerState(u32 index, float custom_tex_scale, bool custom_tex, - bool has_arbitrary_mips) -{ - const FourTexUnits& tex = bpmem.tex[index / 4]; - const TexMode0& tm0 = tex.texMode0[index % 4]; - - SamplerState state = {}; - state.Generate(bpmem, index); - - // Force texture filtering config option. - if (g_ActiveConfig.bForceFiltering) - { - state.min_filter = SamplerState::Filter::Linear; - state.mag_filter = SamplerState::Filter::Linear; - state.mipmap_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? - SamplerState::Filter::Linear : - SamplerState::Filter::Point; - } - - // Custom textures may have a greater number of mips - if (custom_tex) - state.max_lod = 255; - - // Anisotropic filtering option. - if (g_ActiveConfig.iMaxAnisotropy != 0 && !SamplerCommon::IsBpTexMode0PointFiltering(tm0)) - { - // https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt - // For predictable results on all hardware/drivers, only use one of: - // GL_LINEAR + GL_LINEAR (No Mipmaps [Bilinear]) - // GL_LINEAR + GL_LINEAR_MIPMAP_LINEAR (w/ Mipmaps [Trilinear]) - // Letting the game set other combinations will have varying arbitrary results; - // possibly being interpreted as equal to bilinear/trilinear, implicitly - // disabling anisotropy, or changing the anisotropic algorithm employed. - state.min_filter = SamplerState::Filter::Linear; - state.mag_filter = SamplerState::Filter::Linear; - if (SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0)) - state.mipmap_filter = SamplerState::Filter::Linear; - state.anisotropic_filtering = 1; - } - else - { - state.anisotropic_filtering = 0; - } - - if (has_arbitrary_mips && SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0)) - { - // Apply a secondary bias calculated from the IR scale to pull inwards mipmaps - // that have arbitrary contents, eg. are used for fog effects where the - // distance they kick in at is important to preserve at any resolution. - // Correct this with the upscaling factor of custom textures. - s64 lod_offset = std::log2(g_renderer->GetEFBScale() / custom_tex_scale) * 256.f; - state.lod_bias = MathUtil::Clamp(state.lod_bias + lod_offset, -32768, 32767); - - // Anisotropic also pushes mips farther away so it cannot be used either - state.anisotropic_filtering = 0; - } - - g_renderer->SetSamplerState(index, state); -} - void VertexManagerBase::Flush() { if (m_is_flushed) @@ -355,20 +295,8 @@ void VertexManagerBase::Flush() usedtextures[bpmem.tevindref.getTexMap(bpmem.tevind[i].bt)] = true; for (unsigned int i : usedtextures) - { - const auto* tentry = g_texture_cache->Load(i); + g_texture_cache->Load(i); - if (tentry) - { - float custom_tex_scale = tentry->GetWidth() / float(tentry->native_width); - SetSamplerState(i, custom_tex_scale, tentry->is_custom_tex, tentry->has_arbitrary_mips); - PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height); - } - else - { - ERROR_LOG(VIDEO, "error loading texture"); - } - } g_texture_cache->BindTextures(); }