better handle anisotropic filtering with various drivers

Some drivers claim to support anisotropic filtering but don't allow
setting it via glSamplerParameter. Until now we were disabling 
anisotropic filtering entirely on these drivers at compile time.

With this change, we should detect at runtime which drivers have this
issue and use a workaround -- instead of disabling anisotropic 
filtering entirely.
This commit is contained in:
Mathias Agopian
2021-04-08 17:27:39 -07:00
committed by Mathias Agopian
parent afdc3d068c
commit ba7ebf5ea6
6 changed files with 47 additions and 15 deletions

View File

@@ -70,7 +70,6 @@ OpenGLContext::OpenGLContext() noexcept {
bugs.dont_use_timer_query = true;
}
if (strstr(renderer, "Mali-G")) {
bugs.disable_texture_filter_anisotropic = true;
// note: We have verified that timer queries work well at least on some Mali-G.
}
} else if (strstr(renderer, "Intel")) {
@@ -83,9 +82,9 @@ OpenGLContext::OpenGLContext() noexcept {
bugs.disable_invalidate_framebuffer = true;
}
#if defined(__EMSCRIPTEN__)
// Chrome does not support feedback loops in WebGL 2.0. See also:
// https://bugs.chromium.org/p/chromium/issues/detail?id=1066201
#if defined(__EMSCRIPTEN__)
bugs.disable_feedback_loops = true;
#endif
@@ -147,8 +146,22 @@ OpenGLContext::OpenGLContext() noexcept {
#endif
#ifdef GL_EXT_texture_filter_anisotropic
if (ext.EXT_texture_filter_anisotropic && !bugs.disable_texture_filter_anisotropic) {
if (ext.EXT_texture_filter_anisotropic) {
// make sure we don't have any error flag
while (glGetError() != GL_NO_ERROR) { }
// query max anisotropy
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gets.maxAnisotropy);
// check that we can actually set the anysotropy on the sampler
GLuint s;
glGenSamplers(1, &s);
glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, gets.maxAnisotropy);
if (glGetError() != GL_NO_ERROR) {
// some drivers only allow to set the anisotropy on the texture itself
bugs.texture_filter_anisotropic_broken_on_sampler = true;
}
glDeleteSamplers(1, &s);
}
#endif

View File

@@ -169,7 +169,7 @@ public:
// Some drivers declare GL_EXT_texture_filter_anisotropic but don't support
// calling glSamplerParameter() with GL_TEXTURE_MAX_ANISOTROPY_EXT
bool disable_texture_filter_anisotropic = false;
bool texture_filter_anisotropic_broken_on_sampler = false;
// Some drivers have issues when reading from a mip while writing to a different mip.
// In the OpenGL ES 3.0 specification this is covered in section 4.4.3,

View File

@@ -211,6 +211,10 @@ ShaderModel OpenGLDriver::getShaderModel() const noexcept {
// Change and track GL state
// ------------------------------------------------------------------------------------------------
void OpenGLDriver::bindSampler(GLuint unit, backend::SamplerParams params) noexcept {
mContext.bindSampler(unit, getSampler(params));
}
void OpenGLDriver::bindTexture(GLuint unit, GLTexture const* t) noexcept {
assert_invariant(t != nullptr);
mContext.bindTexture(unit, t->gl.target, t->gl.id, t->gl.targetIndex);
@@ -2813,12 +2817,13 @@ GLuint OpenGLDriver::getSamplerSlow(SamplerParams params) const noexcept {
glSamplerParameteri(s, GL_TEXTURE_COMPARE_MODE, getTextureCompareMode(params.compareMode));
glSamplerParameteri(s, GL_TEXTURE_COMPARE_FUNC, getTextureCompareFunc(params.compareFunc));
// TODO: Why does this fail with WebGL 2.0? The run-time check should suffice.
#if defined(GL_EXT_texture_filter_anisotropic) && !defined(__EMSCRIPTEN__)
#if defined(GL_EXT_texture_filter_anisotropic)
auto& gl = mContext;
if (gl.ext.EXT_texture_filter_anisotropic && !gl.bugs.disable_texture_filter_anisotropic) {
if (gl.ext.EXT_texture_filter_anisotropic &&
!gl.bugs.texture_filter_anisotropic_broken_on_sampler) {
GLfloat anisotropy = float(1u << params.anisotropyLog2);
glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, std::min(gl.gets.maxAnisotropy, anisotropy));
glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT,
std::min(gl.gets.maxAnisotropy, anisotropy));
}
#endif
CHECK_GL_ERROR(utils::slog.e)

View File

@@ -357,6 +357,7 @@ private:
/* State tracking GL wrappers... */
void bindTexture(GLuint unit, GLTexture const* t) noexcept;
void bindSampler(GLuint unit, backend::SamplerParams params) noexcept;
inline void useProgram(OpenGLProgram* p) noexcept;
enum class ResolveAction { LOAD, STORE };

View File

@@ -195,11 +195,14 @@ OpenGLProgram::~OpenGLProgram() noexcept {
}
}
void OpenGLProgram::updateSamplers(OpenGLDriver* gl) noexcept {
void OpenGLProgram::updateSamplers(OpenGLDriver* gld) noexcept {
using GLTexture = OpenGLDriver::GLTexture;
// cache a few member variable locally, outside of the loop
auto const& UTILS_RESTRICT samplerBindings = gl->getSamplerBindings();
OpenGLContext& glc = gld->getContext();
const bool anisotropyWorkaround = glc.ext.EXT_texture_filter_anisotropic &&
glc.bugs.texture_filter_anisotropic_broken_on_sampler;
auto const& UTILS_RESTRICT samplerBindings = gld->getSamplerBindings();
auto const& UTILS_RESTRICT indicesRun = mIndicesRuns;
auto const& UTILS_RESTRICT blockInfos = mBlockInfos;
@@ -222,17 +225,27 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* gl) noexcept {
continue;
}
const GLTexture* const UTILS_RESTRICT t = gl->handle_cast<const GLTexture*>(th);
const GLTexture* const UTILS_RESTRICT t = gld->handle_cast<const GLTexture*>(th);
if (UTILS_UNLIKELY(t->gl.fence)) {
glWaitSync(t->gl.fence, 0, GL_TIMEOUT_IGNORED);
glDeleteSync(t->gl.fence);
t->gl.fence = nullptr;
}
gl->bindTexture(tmu, t);
gld->bindTexture(tmu, t);
gld->bindSampler(tmu, samplers[index].s);
GLuint sampler = gl->getSampler(samplers[index].s);
gl->getContext().bindSampler(tmu, sampler);
#if defined(GL_EXT_texture_filter_anisotropic)
if (UTILS_UNLIKELY(anisotropyWorkaround)) {
// Driver claims to support anisotropic filtering, but it fails when set on
// the sampler, we have to set it on the texture instead.
// The texture is already bound here.
SamplerParams params = samplers[index].s;
GLfloat anisotropy = float(1u << params.anisotropyLog2);
glTexParameterf(t->gl.target, GL_TEXTURE_MAX_ANISOTROPY_EXT,
std::min(glc.gets.maxAnisotropy, anisotropy));
}
#endif
}
}
CHECK_GL_ERROR(utils::slog.e)

View File

@@ -95,7 +95,7 @@ private:
// runs of indices into SamplerGroup -- run start index and size given by BlockInfo
std::array<uint8_t, TEXTURE_UNIT_COUNT> mIndicesRuns; // 16 bytes
void updateSamplers(OpenGLDriver* gl) noexcept;
void updateSamplers(OpenGLDriver* gld) noexcept;
};