VideoBackends: Move SamplerState to common

This commit is contained in:
Stenzek
2017-09-09 18:30:15 +10:00
parent 340aabbb06
commit 24ddea04ce
21 changed files with 352 additions and 401 deletions

View File

@ -1119,7 +1119,8 @@ bool ProgramShaderCache::ShaderCompileWorkItem::Compile()
gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, m_uid.guid.GetUidData());
CompileShader(m_program, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer());
DrawPrerenderArray(m_program, m_uid.guid.GetUidData()->primitive_type);
DrawPrerenderArray(m_program,
static_cast<PrimitiveType>(m_uid.guid.GetUidData()->primitive_type));
return true;
}
@ -1157,7 +1158,8 @@ bool ProgramShaderCache::UberShaderCompileWorkItem::Compile()
gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, m_uid.guid.GetUidData());
CompileShader(m_program, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer());
DrawPrerenderArray(m_program, m_uid.guid.GetUidData()->primitive_type);
DrawPrerenderArray(m_program,
static_cast<PrimitiveType>(m_uid.guid.GetUidData()->primitive_type));
return true;
}

View File

@ -1503,9 +1503,13 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
g_Config.iSaveTargetId = 0;
int old_anisotropy = g_ActiveConfig.iMaxAnisotropy;
UpdateActiveConfig();
g_texture_cache->OnConfigChanged(g_ActiveConfig);
if (old_anisotropy != g_ActiveConfig.iMaxAnisotropy)
g_sampler_cache->Clear();
// Invalidate shader cache when the host config changes.
if (CheckForHostConfigChanges())
ProgramShaderCache::Reload();
@ -1834,13 +1838,9 @@ void Renderer::SetDepthState(const DepthState& state)
}
}
void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex)
void Renderer::SetSamplerState(u32 index, const SamplerState& state)
{
auto const& tex = bpmem.tex[texindex];
auto const& tm0 = tex.texMode0[stage];
auto const& tm1 = tex.texMode1[stage];
g_sampler_cache->SetSamplerState((texindex * 4) + stage, tm0, tm1, custom_tex);
g_sampler_cache->SetSamplerState(index, state);
}
void Renderer::SetInterlacingMode()

View File

@ -81,7 +81,7 @@ public:
void SetScissorRect(const EFBRectangle& rc) override;
void SetRasterizationState(const RasterizationState& state) override;
void SetDepthState(const DepthState& state) override;
void SetSamplerState(int stage, int texindex, bool custom_tex) override;
void SetSamplerState(u32 index, const SamplerState& state) override;
void SetInterlacingMode() override;
void SetViewport() override;

View File

@ -15,141 +15,106 @@ namespace OGL
{
std::unique_ptr<SamplerCache> g_sampler_cache;
SamplerCache::SamplerCache() : m_last_max_anisotropy()
SamplerCache::SamplerCache()
{
glGenSamplers(2, m_sampler_id);
glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGenSamplers(1, &m_point_sampler);
glGenSamplers(1, &m_linear_sampler);
glSamplerParameteri(m_point_sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(m_point_sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glSamplerParameteri(m_point_sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(m_point_sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glSamplerParameteri(m_linear_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(m_linear_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(m_linear_sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(m_linear_sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
SamplerCache::~SamplerCache()
{
Clear();
glDeleteSamplers(2, m_sampler_id);
glDeleteSamplers(1, &m_point_sampler);
glDeleteSamplers(1, &m_linear_sampler);
}
void SamplerCache::BindNearestSampler(int stage)
{
glBindSampler(stage, m_sampler_id[0]);
glBindSampler(stage, m_point_sampler);
}
void SamplerCache::BindLinearSampler(int stage)
{
glBindSampler(stage, m_sampler_id[1]);
glBindSampler(stage, m_linear_sampler);
}
void SamplerCache::SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1,
bool custom_tex)
void SamplerCache::SetSamplerState(u32 stage, const SamplerState& state)
{
// TODO: can this go somewhere else?
if (m_last_max_anisotropy != g_ActiveConfig.iMaxAnisotropy)
if (m_active_samplers[stage].first == state && m_active_samplers[stage].second != 0)
return;
auto it = m_cache.find(state);
if (it == m_cache.end())
{
m_last_max_anisotropy = g_ActiveConfig.iMaxAnisotropy;
Clear();
GLuint sampler;
glGenSamplers(1, &sampler);
SetParameters(sampler, state);
it = m_cache.emplace(state, sampler).first;
}
Params params(tm0, tm1);
// take equivalent forced linear when bForceFiltering
if (g_ActiveConfig.bForceFiltering)
{
params.tm0.min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4;
params.tm0.mag_filter = 1;
}
// custom textures may have higher resolution, so disable the max_lod
if (custom_tex)
{
params.tm1.max_lod = 255;
}
// TODO: Should keep a circular buffer for each stage of recently used samplers.
auto& active_sampler = m_active_samplers[stage];
if (active_sampler.first != params || !active_sampler.second.sampler_id)
{
// Active sampler does not match parameters (or is invalid), bind the proper one.
active_sampler.first = params;
active_sampler.second = GetEntry(params);
glBindSampler(stage, active_sampler.second.sampler_id);
}
m_active_samplers[stage].first = state;
m_active_samplers[stage].second = it->second;
glBindSampler(stage, it->second);
}
SamplerCache::Value& SamplerCache::GetEntry(const Params& params)
void SamplerCache::InvalidateBinding(u32 stage)
{
auto& val = m_cache[params];
if (!val.sampler_id)
{
// Sampler not found in cache, create it.
glGenSamplers(1, &val.sampler_id);
SetParameters(val.sampler_id, params);
// TODO: Maybe kill old samplers if the cache gets huge. It doesn't seem to get huge though.
// ERROR_LOG(VIDEO, "Sampler cache size is now %ld.", m_cache.size());
}
return val;
m_active_samplers[stage].second = 0;
}
void SamplerCache::SetParameters(GLuint sampler_id, const Params& params)
void SamplerCache::SetParameters(GLuint sampler_id, const SamplerState& params)
{
static const GLint min_filters[8] = {
GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST,
GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR,
};
static const GLint wrap_settings[4] = {
GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRRORED_REPEAT, GL_REPEAT,
};
auto& tm0 = params.tm0;
auto& tm1 = params.tm1;
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, wrap_settings[tm0.wrap_s]);
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, wrap_settings[tm0.wrap_t]);
glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, tm1.min_lod / 16.f);
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, tm1.max_lod / 16.f);
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, (s32)tm0.lod_bias / 32.f);
GLint min_filter = min_filters[tm0.min_filter];
GLint mag_filter = tm0.mag_filter ? GL_LINEAR : GL_NEAREST;
if (g_ActiveConfig.iMaxAnisotropy > 0 && g_ogl_config.bSupportsAniso &&
!SamplerCommon::IsBpTexMode0PointFiltering(tm0))
GLenum min_filter;
GLenum mag_filter = (params.mag_filter == SamplerState::Filter::Point) ? GL_NEAREST : GL_LINEAR;
if (params.mipmap_filter == SamplerState::Filter::Linear)
{
// 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.
min_filter =
SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
mag_filter = GL_LINEAR;
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT,
(float)(1 << g_ActiveConfig.iMaxAnisotropy));
min_filter = (params.min_filter == SamplerState::Filter::Point) ? GL_NEAREST_MIPMAP_LINEAR :
GL_LINEAR_MIPMAP_LINEAR;
}
else
{
min_filter = (params.min_filter == SamplerState::Filter::Point) ? GL_NEAREST_MIPMAP_NEAREST :
GL_LINEAR_MIPMAP_NEAREST;
}
glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, min_filter);
glSamplerParameteri(sampler_id, GL_TEXTURE_MAG_FILTER, mag_filter);
static constexpr std::array<GLenum, 3> address_modes = {
{GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRRORED_REPEAT}};
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S,
address_modes[static_cast<u32>(params.wrap_u.Value())]);
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T,
address_modes[static_cast<u32>(params.wrap_v.Value())]);
glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, params.min_lod / 16.f);
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, params.max_lod / 16.f);
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, params.lod_bias / 32.f);
if (params.anisotropic_filtering && g_ogl_config.bSupportsAniso)
{
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT,
static_cast<float>(1 << g_ActiveConfig.iMaxAnisotropy));
}
}
void SamplerCache::Clear()
{
for (auto& p : m_cache)
{
glDeleteSamplers(1, &p.second.sampler_id);
}
glDeleteSamplers(1, &p.second);
for (auto& p : m_active_samplers)
p.second = 0;
m_cache.clear();
}
}

View File

@ -4,6 +4,7 @@
#pragma once
#include <array>
#include <map>
#include <memory>
@ -24,49 +25,21 @@ public:
SamplerCache(SamplerCache&&) = delete;
SamplerCache& operator=(SamplerCache&&) = delete;
void SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1, bool custom_tex);
void SetSamplerState(u32 stage, const SamplerState& state);
void InvalidateBinding(u32 stage);
void Clear();
void BindNearestSampler(int stage);
void BindLinearSampler(int stage);
private:
struct Params
{
union
{
struct
{
TexMode0 tm0;
TexMode1 tm1;
};
static void SetParameters(GLuint sampler_id, const SamplerState& params);
u64 hex;
};
std::map<SamplerState, GLuint> m_cache;
std::array<std::pair<SamplerState, GLuint>, 8> m_active_samplers{};
Params() : hex() {}
Params(const TexMode0& _tm0, const TexMode1& _tm1) : tm0(_tm0), tm1(_tm1)
{
static_assert(sizeof(Params) == 8, "Assuming I can treat this as a 64bit int.");
}
bool operator<(const Params& other) const { return hex < other.hex; }
bool operator!=(const Params& other) const { return hex != other.hex; }
};
struct Value
{
Value() : sampler_id() {}
GLuint sampler_id;
};
void SetParameters(GLuint sampler_id, const Params& params);
Value& GetEntry(const Params& params);
std::map<Params, Value> m_cache;
std::pair<Params, Value> m_active_samplers[8];
int m_last_max_anisotropy;
u32 m_sampler_id[2];
GLuint m_point_sampler;
GLuint m_linear_sampler;
};
extern std::unique_ptr<SamplerCache> g_sampler_cache;