From d0ed4622772661131bd9c018b5747ed4bcd8da5a Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Wed, 21 May 2014 19:03:09 -0700 Subject: [PATCH] Bug 1004309 - Add func to assert shadowed state is correct. - r=kamidphish * * * Bug 980178 - Dither default is true. - r=kamidphish --- content/canvas/src/WebGLContext.cpp | 87 +--------- content/canvas/src/WebGLContext.h | 22 ++- content/canvas/src/WebGLContextUtils.cpp | 179 ++++++++++++++++++-- content/canvas/src/WebGLContextValidate.cpp | 30 +++- content/canvas/src/WebGLProgram.h | 10 +- gfx/gl/GLContext.cpp | 4 +- 6 files changed, 225 insertions(+), 107 deletions(-) diff --git a/content/canvas/src/WebGLContext.cpp b/content/canvas/src/WebGLContext.cpp index 6459410cd30..b8a0bfabd49 100644 --- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -588,14 +588,12 @@ WebGLContext::SetDimensions(int32_t width, int32_t height) // we'll end up displaying random memory gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); - gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f); - gl->fClearDepth(1.0f); - gl->fClearStencil(0); - - mBackbufferNeedsClear = true; + AssertCachedBindings(); + AssertCachedState(); // Clear immediately, because we need to present the cleared initial // buffer. + mBackbufferNeedsClear = true; ClearBackbufferIfNeeded(); mShouldPresent = true; @@ -607,6 +605,9 @@ WebGLContext::SetDimensions(int32_t width, int32_t height) MOZ_ASSERT(gl->Caps().antialias == caps.antialias || !gl->Caps().antialias); MOZ_ASSERT(gl->Caps().preserve == caps.preserve); + AssertCachedBindings(); + AssertCachedState(); + reporter.SetSuccessful(); return NS_OK; } @@ -973,19 +974,6 @@ WebGLContext::ClearScreen() ForceClearFramebufferWithDefaultValues(clearMask, colorAttachmentsMask); } -#ifdef DEBUG -// For NaNs, etc. -static bool IsShadowCorrect(float shadow, float actual) { - if (IsNaN(shadow)) { - // GL is allowed to do anything it wants for NaNs, so if we're shadowing - // a NaN, then whatever `actual` is might be correct. - return true; - } - - return shadow == actual; -} -#endif - void WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool colorAttachmentsMask[kMaxColorAttachments]) { @@ -1000,67 +988,8 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool // Fun GL fact: No need to worry about the viewport here, glViewport is just // setting up a coordinates transformation, it doesn't affect glClear at all. - -#ifdef DEBUG - // Scope to hide our variables. - { - // Sanity-check that all our state is set properly. Otherwise, when we - // reset out state to what we *think* it is, we'll get it wrong. - - // Dither shouldn't matter when we're clearing to {0,0,0,0}. - MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled); - - if (initializeColorBuffer) { - realGLboolean colorWriteMask[4] = {2, 2, 2, 2}; - GLfloat colorClearValue[4] = {-1.0f, -1.0f, -1.0f, -1.0f}; - - gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask); - gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue); - - MOZ_ASSERT(colorWriteMask[0] == mColorWriteMask[0] && - colorWriteMask[1] == mColorWriteMask[1] && - colorWriteMask[2] == mColorWriteMask[2] && - colorWriteMask[3] == mColorWriteMask[3]); - MOZ_ASSERT(IsShadowCorrect(mColorClearValue[0], colorClearValue[0]) && - IsShadowCorrect(mColorClearValue[1], colorClearValue[1]) && - IsShadowCorrect(mColorClearValue[2], colorClearValue[2]) && - IsShadowCorrect(mColorClearValue[3], colorClearValue[3])); - } - - if (initializeDepthBuffer) { - realGLboolean depthWriteMask = 2; - GLfloat depthClearValue = -1.0f; - - - gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask); - gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue); - - MOZ_ASSERT(depthWriteMask == mDepthWriteMask); - MOZ_ASSERT(IsShadowCorrect(mDepthClearValue, depthClearValue)); - } - - if (initializeStencilBuffer) { - GLuint stencilWriteMaskFront = 0xdeadbad1; - GLuint stencilWriteMaskBack = 0xdeadbad1; - GLuint stencilClearValue = 0xdeadbad1; - - gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &stencilWriteMaskFront); - gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &stencilWriteMaskBack); - gl->GetUIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE, &stencilClearValue); - - GLuint stencilBits = 0; - gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits); - GLuint stencilMask = (GLuint(1) << stencilBits) - 1; - - MOZ_ASSERT( ( stencilWriteMaskFront & stencilMask) == - (mStencilWriteMaskFront & stencilMask) ); - MOZ_ASSERT( ( stencilWriteMaskBack & stencilMask) == - (mStencilWriteMaskBack & stencilMask) ); - MOZ_ASSERT( ( stencilClearValue & stencilMask) == - (mStencilClearValue & stencilMask) ); - } - } -#endif + AssertCachedState(); // Can't check cached bindings, as we could + // have a different FB bound temporarily. // Prepare GL state for clearing. gl->fDisable(LOCAL_GL_SCISSOR_TEST); diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 11172ea49b4..e3c127bc7ee 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -10,6 +10,7 @@ #include "GLDefs.h" #include "WebGLActiveInfo.h" #include "WebGLObjectModel.h" +#include "WebGLRenderbuffer.h" #include #include "nsTArray.h" @@ -88,6 +89,8 @@ class SourceSurface; WebGLTexelFormat GetWebGLTexelFormat(GLenum format, GLenum type); +void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow); + struct WebGLContextOptions { // these are defaults WebGLContextOptions(); @@ -114,6 +117,19 @@ struct WebGLContextOptions { bool preserveDrawingBuffer; }; +#ifdef DEBUG +static bool +IsTextureBinding(GLenum binding) +{ + switch (binding) { + case LOCAL_GL_TEXTURE_BINDING_2D: + case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP: + return true; + } + return false; +} +#endif + class WebGLContext : public nsIDOMWebGLRenderingContext, public nsICanvasRenderingContextInternal, @@ -204,7 +220,8 @@ public: void DummyFramebufferOperation(const char *info); - WebGLTexture *activeBoundTextureForTarget(GLenum target) const { + WebGLTexture* activeBoundTextureForTarget(GLenum target) const { + MOZ_ASSERT(!IsTextureBinding(target)); return target == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture] : mBoundCubeMapTextures[mActiveTexture]; } @@ -249,6 +266,9 @@ public: void SetupContextLossTimer(); void TerminateContextLossTimer(); + void AssertCachedBindings(); + void AssertCachedState(); + // WebIDL WebGLRenderingContext API dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; } GLsizei DrawingBufferWidth() const { return IsContextLost() ? 0 : mWidth; } diff --git a/content/canvas/src/WebGLContextUtils.cpp b/content/canvas/src/WebGLContextUtils.cpp index ddb443f1da4..3db33fd407e 100644 --- a/content/canvas/src/WebGLContextUtils.cpp +++ b/content/canvas/src/WebGLContextUtils.cpp @@ -3,25 +3,26 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "WebGLContext.h" + #include -#include "WebGLContext.h" #include "GLContext.h" - -#include "prprf.h" - #include "jsapi.h" -#include "nsIScriptSecurityManager.h" -#include "nsServiceManagerUtils.h" -#include "nsIVariant.h" -#include "nsCxPusher.h" - -#include "nsIDOMEvent.h" -#include "nsIDOMDataContainerEvent.h" - #include "mozilla/Preferences.h" - -using namespace mozilla; +#include "nsCxPusher.h" +#include "nsIDOMDataContainerEvent.h" +#include "nsIDOMEvent.h" +#include "nsIScriptSecurityManager.h" +#include "nsIVariant.h" +#include "nsServiceManagerUtils.h" +#include "prprf.h" +#include "WebGLBuffer.h" +#include "WebGLExtensions.h" +#include "WebGLFramebuffer.h" +#include "WebGLProgram.h" +#include "WebGLTexture.h" +#include "WebGLVertexArray.h" namespace mozilla { @@ -193,8 +194,6 @@ DriverTypeFromType(GLContext* gl, GLenum webGLType) return webGLType; } -} // namespace mozilla - void WebGLContext::GenerateWarning(const char *fmt, ...) { @@ -398,3 +397,151 @@ WebGLContext::GetAndFlushUnderlyingGLErrors() return error; } + +#ifdef DEBUG +// For NaNs, etc. +static bool +IsCacheCorrect(float cached, float actual) +{ + if (IsNaN(cached)) { + // GL is allowed to do anything it wants for NaNs, so if we're shadowing + // a NaN, then whatever `actual` is might be correct. + return true; + } + + return cached == actual; +} + +void +AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow) +{ + GLuint val = 0; + gl->GetUIntegerv(pname, &val); + if (val != shadow) { + printf_stderr("Failed 0x%04x shadow: Cached 0x%x/%u, should be 0x%x/%u.\n", + pname, shadow, shadow, val, val); + MOZ_ASSERT(false, "Bad cached value."); + } +} +#else +void +AssertUintParamCorrect(gl::GLContext*, GLenum, GLuint) +{ +} +#endif + +void +WebGLContext::AssertCachedBindings() +{ +#ifdef DEBUG + MakeContextCurrent(); + + GetAndFlushUnderlyingGLErrors(); + + if (IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) { + GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0; + AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound); + } + + // Bound object state + GLuint bound = mBoundFramebuffer ? mBoundFramebuffer->GLName() : 0; + AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound); + + bound = mCurrentProgram ? mCurrentProgram->GLName() : 0; + AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound); + + // Textures + GLenum activeTexture = mActiveTexture + LOCAL_GL_TEXTURE0; + AssertUintParamCorrect(gl, LOCAL_GL_ACTIVE_TEXTURE, activeTexture); + + WebGLTexture* curTex = activeBoundTextureForTarget(LOCAL_GL_TEXTURE_2D); + bound = curTex ? curTex->GLName() : 0; + AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_2D, bound); + + curTex = activeBoundTextureForTarget(LOCAL_GL_TEXTURE_CUBE_MAP); + bound = curTex ? curTex->GLName() : 0; + AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, bound); + + // Buffers + bound = mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0; + AssertUintParamCorrect(gl, LOCAL_GL_ARRAY_BUFFER_BINDING, bound); + + MOZ_ASSERT(mBoundVertexArray); + WebGLBuffer* curBuff = mBoundVertexArray->mBoundElementArrayBuffer; + bound = curBuff ? curBuff->GLName() : 0; + AssertUintParamCorrect(gl, LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING, bound); + + MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors()); +#endif +} + +void +WebGLContext::AssertCachedState() +{ +#ifdef DEBUG + MakeContextCurrent(); + + GetAndFlushUnderlyingGLErrors(); + + // extensions + if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) { + AssertUintParamCorrect(gl, LOCAL_GL_MAX_COLOR_ATTACHMENTS, mGLMaxColorAttachments); + AssertUintParamCorrect(gl, LOCAL_GL_MAX_DRAW_BUFFERS, mGLMaxDrawBuffers); + } + + // Draw state + MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled); + MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DITHER) == mDitherEnabled); + MOZ_ASSERT_IF(IsWebGL2(), + gl->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD) == mRasterizerDiscardEnabled); + + + realGLboolean colorWriteMask[4] = {0, 0, 0, 0}; + gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask); + MOZ_ASSERT(colorWriteMask[0] == mColorWriteMask[0] && + colorWriteMask[1] == mColorWriteMask[1] && + colorWriteMask[2] == mColorWriteMask[2] && + colorWriteMask[3] == mColorWriteMask[3]); + + GLfloat colorClearValue[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue); + MOZ_ASSERT(IsCacheCorrect(mColorClearValue[0], colorClearValue[0]) && + IsCacheCorrect(mColorClearValue[1], colorClearValue[1]) && + IsCacheCorrect(mColorClearValue[2], colorClearValue[2]) && + IsCacheCorrect(mColorClearValue[3], colorClearValue[3])); + + realGLboolean depthWriteMask = 0; + gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask); + MOZ_ASSERT(depthWriteMask == mDepthWriteMask); + + GLfloat depthClearValue = 0.0f; + gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue); + MOZ_ASSERT(IsCacheCorrect(mDepthClearValue, depthClearValue)); + + AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE, mStencilClearValue); + + AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, mStencilRefFront); + AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, mStencilRefBack); + + AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, mStencilValueMaskFront); + AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack); + + AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK, mStencilWriteMaskFront); + AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, mStencilWriteMaskBack); + + // Viewport + GLint int4[4] = {0, 0, 0, 0}; + gl->fGetIntegerv(LOCAL_GL_VIEWPORT, int4); + MOZ_ASSERT(int4[0] == mViewportX && + int4[1] == mViewportY && + int4[2] == mViewportWidth && + int4[3] == mViewportHeight); + + AssertUintParamCorrect(gl, LOCAL_GL_PACK_ALIGNMENT, mPixelStorePackAlignment); + AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ALIGNMENT, mPixelStoreUnpackAlignment); + + MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors()); +#endif +} + +} // namespace mozilla diff --git a/content/canvas/src/WebGLContextValidate.cpp b/content/canvas/src/WebGLContextValidate.cpp index 5917181d760..309195ab904 100644 --- a/content/canvas/src/WebGLContextValidate.cpp +++ b/content/canvas/src/WebGLContextValidate.cpp @@ -1642,10 +1642,32 @@ WebGLContext::InitAndValidateGL() mStencilClearValue = 0; mStencilRefFront = 0; mStencilRefBack = 0; - mStencilValueMaskFront = 0xffffffff; - mStencilValueMaskBack = 0xffffffff; - mStencilWriteMaskFront = 0xffffffff; - mStencilWriteMaskBack = 0xffffffff; + + /* + // Technically, we should be setting mStencil[...] values to + // `allOnes`, but either ANGLE breaks or the SGX540s on Try break. + GLuint stencilBits = 0; + gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits); + GLuint allOnes = ~(UINT32_MAX << stencilBits); + mStencilValueMaskFront = allOnes; + mStencilValueMaskBack = allOnes; + mStencilWriteMaskFront = allOnes; + mStencilWriteMaskBack = allOnes; + */ + + gl->GetUIntegerv(LOCAL_GL_STENCIL_VALUE_MASK, &mStencilValueMaskFront); + gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_VALUE_MASK, &mStencilValueMaskBack); + gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &mStencilWriteMaskFront); + gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &mStencilWriteMaskBack); + + AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, mStencilValueMaskFront); + AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack); + AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK, mStencilWriteMaskFront); + AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, mStencilWriteMaskBack); + + mDitherEnabled = true; + mRasterizerDiscardEnabled = false; + mScissorTestEnabled = false; // Bindings, etc. mActiveTexture = 0; diff --git a/content/canvas/src/WebGLProgram.h b/content/canvas/src/WebGLProgram.h index 11079fc7d04..ca4670e358d 100644 --- a/content/canvas/src/WebGLProgram.h +++ b/content/canvas/src/WebGLProgram.h @@ -8,12 +8,14 @@ #include "WebGLObjectModel.h" -#include "nsWrapperCache.h" - -#include "mozilla/LinkedList.h" -#include "mozilla/CheckedInt.h" #include +#include "mozilla/CheckedInt.h" +#include "mozilla/LinkedList.h" +#include "nsWrapperCache.h" +#include "WebGLShader.h" +#include "WebGLUniformInfo.h" + namespace mozilla { class WebGLShader; diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 77181b161b5..13bf707f546 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -1183,11 +1183,9 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) 0, nullptr, true); } - } - if (mInitialized) reporter.SetSuccessful(); - else { + } else { // if initialization fails, ensure all symbols are zero, to avoid hard-to-understand bugs mSymbols.Zero(); NS_WARNING("InitWithPrefix failed!");