diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index d6c4d910b20c..a8b5364f4bbe 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -635,6 +635,7 @@ void WebGLContext::FinishInit() { // Initial setup. gl->mImplicitMakeCurrent = true; + gl->mElideDuplicateBindFramebuffers = true; const auto& size = mDefaultFB->mSize; diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 032124d91ea9..9b3adfde127c 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -2158,39 +2158,72 @@ void GLContext::fCopyTexImage2D(GLenum target, GLint level, AfterGLReadCall(); } -void GLContext::fGetIntegerv(GLenum pname, GLint* params) const { +void GLContext::fGetIntegerv(const GLenum pname, GLint* const params) const { + const auto AssertBinding = [&](const char* const name, const GLenum binding, + const GLuint expected) { + if (MOZ_LIKELY(!mDebugFlags)) return; + GLuint actual = 0; + raw_fGetIntegerv(binding, (GLint*)&actual); + if (actual != expected) { + gfxCriticalError() << "Misprediction: " << name << " expected " + << expected << ", was " << actual; + } + }; + switch (pname) { case LOCAL_GL_MAX_TEXTURE_SIZE: MOZ_ASSERT(mMaxTextureSize > 0); *params = mMaxTextureSize; - break; + return; case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE: MOZ_ASSERT(mMaxCubeMapTextureSize > 0); *params = mMaxCubeMapTextureSize; - break; + return; case LOCAL_GL_MAX_RENDERBUFFER_SIZE: MOZ_ASSERT(mMaxRenderbufferSize > 0); *params = mMaxRenderbufferSize; - break; + return; case LOCAL_GL_VIEWPORT: for (size_t i = 0; i < 4; i++) { params[i] = mViewportRect[i]; } - break; + return; case LOCAL_GL_SCISSOR_BOX: for (size_t i = 0; i < 4; i++) { params[i] = mScissorRect[i]; } + return; + + case LOCAL_GL_DRAW_FRAMEBUFFER_BINDING: + if (mElideDuplicateBindFramebuffers) { + static_assert(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING == + LOCAL_GL_FRAMEBUFFER_BINDING); + AssertBinding("GL_DRAW_FRAMEBUFFER_BINDING", + LOCAL_GL_DRAW_FRAMEBUFFER_BINDING, mCachedDrawFb); + *params = static_cast(mCachedDrawFb); + return; + } + break; + + case LOCAL_GL_READ_FRAMEBUFFER_BINDING: + if (mElideDuplicateBindFramebuffers) { + if (IsSupported(GLFeature::framebuffer_blit)) { + AssertBinding("GL_READ_FRAMEBUFFER_BINDING", + LOCAL_GL_READ_FRAMEBUFFER_BINDING, mCachedReadFb); + } + *params = static_cast(mCachedReadFb); + return; + } break; default: - raw_fGetIntegerv(pname, params); break; } + raw_fGetIntegerv(pname, params); } void GLContext::fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index 1ab94c28b90d..bc199853b680 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -27,6 +27,7 @@ # define MOZ_GL_DEBUG 1 #endif +#include "mozilla/IntegerRange.h" #include "mozilla/RefPtr.h" #include "mozilla/UniquePtr.h" #include "mozilla/ThreadLocal.h" @@ -2019,10 +2020,49 @@ class GLContext : public GenericAtomicRefCounted, public SupportsWeakPtr { AFTER_GL_CALL; } - void fBindFramebuffer(GLenum target, GLuint framebuffer) { + private: + mutable GLuint mCachedDrawFb = 0; + mutable GLuint mCachedReadFb = 0; + + public: + bool mElideDuplicateBindFramebuffers = false; + + void fBindFramebuffer(const GLenum target, const GLuint fb) const { + if (mElideDuplicateBindFramebuffers) { + MOZ_ASSERT(mCachedDrawFb == + GetIntAs(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING)); + MOZ_ASSERT(mCachedReadFb == + GetIntAs(LOCAL_GL_READ_FRAMEBUFFER_BINDING)); + + switch (target) { + case LOCAL_GL_FRAMEBUFFER: + if (mCachedDrawFb == fb && mCachedReadFb == fb) return; + break; + case LOCAL_GL_DRAW_FRAMEBUFFER: + if (mCachedDrawFb == fb) return; + break; + case LOCAL_GL_READ_FRAMEBUFFER: + if (mCachedReadFb == fb) return; + break; + } + } + BEFORE_GL_CALL; - mSymbols.fBindFramebuffer(target, framebuffer); + mSymbols.fBindFramebuffer(target, fb); AFTER_GL_CALL; + + switch (target) { + case LOCAL_GL_FRAMEBUFFER: + mCachedDrawFb = fb; + mCachedReadFb = fb; + break; + case LOCAL_GL_DRAW_FRAMEBUFFER: + mCachedDrawFb = fb; + break; + case LOCAL_GL_READ_FRAMEBUFFER: + mCachedReadFb = fb; + break; + } } void fBindRenderbuffer(GLenum target, GLuint renderbuffer) { @@ -2286,6 +2326,16 @@ class GLContext : public GenericAtomicRefCounted, public SupportsWeakPtr { BEFORE_GL_CALL; mSymbols.fDeleteFramebuffers(n, names); AFTER_GL_CALL; + + for (const auto i : IntegerRange(n)) { + const auto fb = names[i]; + if (mCachedDrawFb == fb) { + mCachedDrawFb = 0; + } + if (mCachedReadFb == fb) { + mCachedReadFb = 0; + } + } } void raw_fDeleteRenderbuffers(GLsizei n, const GLuint* names) {