Bug 1312865 - ClearBuffer and similar funcs should mirror Clear's behavior. - r=daoshengmu draft
authorJeff Gilbert <jgilbert@mozilla.com>
Tue, 20 Dec 2016 23:31:22 -0800
changeset 452182 d225c71793c7f34376df952964da474def6da8f2
parent 452181 a789a048c50a5f24bd08a2d96f0e1bd07f71164e
child 540169 0f442c9f891b0ff16e1ac44d66abf43ed151a592
push id39340
push userbmo:jgilbert@mozilla.com
push dateWed, 21 Dec 2016 07:33:16 +0000
reviewersdaoshengmu
bugs1312865
milestone53.0a1
Bug 1312865 - ClearBuffer and similar funcs should mirror Clear's behavior. - r=daoshengmu MozReview-Commit-ID: 4Gm5aNZ1PXX
dom/canvas/WebGL2ContextFramebuffers.cpp
dom/canvas/WebGL2ContextMRTs.cpp
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextDraw.cpp
dom/canvas/WebGLContextFramebufferOperations.cpp
dom/canvas/WebGLFramebuffer.cpp
gfx/gl/GLContext.h
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -51,16 +51,20 @@ WebGL2Context::BlitFramebuffer(GLint src
     if (drawFB &&
         !drawFB->ValidateAndInitAttachments("blitFramebuffer's DRAW_FRAMEBUFFER"))
     {
         return;
     }
 
     ////
 
+    if (!mBoundReadFramebuffer) {
+        ClearBackbufferIfNeeded();
+    }
+
     WebGLFramebuffer::BlitFramebuffer(this,
                                       readFB, srcX0, srcY0, srcX1, srcY1,
                                       drawFB, dstX0, dstY0, dstX1, dstY1,
                                       mask, filter);
 }
 
 void
 WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
@@ -216,16 +220,26 @@ WebGLContext::ValidateInvalidateFramebuf
                     MOZ_CRASH();
                 }
             }
             *out_glNumAttachments = scopedVector->size();
             *out_glAttachments = scopedVector->data();
         }
     }
 
+    ////
+
+    if (!fb) {
+        ClearBackbufferIfNeeded();
+
+        // Don't do more validation after these.
+        Invalidate();
+        mShouldPresent = true;
+    }
+
     return true;
 }
 
 void
 WebGL2Context::InvalidateFramebuffer(GLenum target,
                                      const dom::Sequence<GLenum>& attachments,
                                      ErrorResult& rv)
 {
@@ -256,31 +270,31 @@ WebGL2Context::InvalidateFramebuffer(GLe
 
 void
 WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
                                         GLint x, GLint y, GLsizei width, GLsizei height,
                                         ErrorResult& rv)
 {
     const char funcName[] = "invalidateSubFramebuffer";
 
+    if (!ValidateNonNegative(funcName, "width", width) ||
+        !ValidateNonNegative(funcName, "height", height))
+    {
+        return;
+    }
+
     std::vector<GLenum> scopedVector;
     GLsizei glNumAttachments;
     const GLenum* glAttachments;
     if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
                                        &glNumAttachments, &glAttachments))
     {
         return;
     }
 
-    if (!ValidateNonNegative(funcName, "width", width) ||
-        !ValidateNonNegative(funcName, "height", height))
-    {
-        return;
-    }
-
     ////
 
     // Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
     const bool useFBInvalidation = (mAllowFBInvalidation &&
                                     gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
     if (useFBInvalidation) {
         gl->fInvalidateSubFramebuffer(target, glNumAttachments, glAttachments, x, y,
                                       width, height);
--- a/dom/canvas/WebGL2ContextMRTs.cpp
+++ b/dom/canvas/WebGL2ContextMRTs.cpp
@@ -78,40 +78,46 @@ WebGL2Context::ValidateClearBuffer(const
 void
 WebGL2Context::ClearBufferfv(GLenum buffer, GLint drawBuffer, const Float32Arr& src,
                              GLuint srcElemOffset)
 {
     const char funcName[] = "clearBufferfv";
     if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset))
         return;
 
+    ScopedDrawCallWrapper wrapper(*this);
+
     const auto ptr = src.elemBytes + srcElemOffset;
     gl->fClearBufferfv(buffer, drawBuffer, ptr);
 }
 
 void
 WebGL2Context::ClearBufferiv(GLenum buffer, GLint drawBuffer, const Int32Arr& src,
                              GLuint srcElemOffset)
 {
     const char funcName[] = "clearBufferiv";
     if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset))
         return;
 
+    ScopedDrawCallWrapper wrapper(*this);
+
     const auto ptr = src.elemBytes + srcElemOffset;
     gl->fClearBufferiv(buffer, drawBuffer, ptr);
 }
 
 void
 WebGL2Context::ClearBufferuiv(GLenum buffer, GLint drawBuffer, const Uint32Arr& src,
-                             GLuint srcElemOffset)
+                              GLuint srcElemOffset)
 {
     const char funcName[] = "clearBufferuiv";
     if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset))
         return;
 
+    ScopedDrawCallWrapper wrapper(*this);
+
     const auto ptr = src.elemBytes + srcElemOffset;
     gl->fClearBufferuiv(buffer, drawBuffer, ptr);
 }
 
 ////
 
 void
 WebGL2Context::ClearBufferfi(GLenum buffer, GLint drawBuffer, GLfloat depth,
@@ -119,12 +125,14 @@ WebGL2Context::ClearBufferfi(GLenum buff
 {
     const char funcName[] = "clearBufferfi";
     if (!ValidateClearBuffer(funcName, LOCAL_GL_DEPTH, drawBuffer, 1, 0))
         return;
 
     if (buffer != LOCAL_GL_DEPTH_STENCIL)
         return ErrorInvalidEnumInfo(funcName, buffer);
 
+    ScopedDrawCallWrapper wrapper(*this);
+
     gl->fClearBufferfi(buffer, drawBuffer, depth, stencil);
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -2033,55 +2033,64 @@ WebGLContext::ValidateCurFBForRead(const
     }
 
     return mBoundReadFramebuffer->ValidateForRead(funcName, out_format, out_width,
                                                   out_height);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
+WebGLContext::ScopedDrawCallWrapper::ScopedDrawCallWrapper(WebGLContext& webgl)
     : mWebGL(webgl)
     , mFakeNoAlpha(ShouldFakeNoAlpha(webgl))
     , mFakeNoDepth(ShouldFakeNoDepth(webgl))
     , mFakeNoStencil(ShouldFakeNoStencil(webgl))
 {
+    if (!mWebGL.mBoundDrawFramebuffer) {
+        mWebGL.ClearBackbufferIfNeeded();
+    }
+
     if (mFakeNoAlpha) {
         mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
                               mWebGL.mColorWriteMask[1],
                               mWebGL.mColorWriteMask[2],
                               false);
     }
     if (mFakeNoDepth) {
         mWebGL.gl->fDisable(LOCAL_GL_DEPTH_TEST);
     }
     if (mFakeNoStencil) {
         mWebGL.gl->fDisable(LOCAL_GL_STENCIL_TEST);
     }
 }
 
-WebGLContext::ScopedMaskWorkaround::~ScopedMaskWorkaround()
+WebGLContext::ScopedDrawCallWrapper::~ScopedDrawCallWrapper()
 {
     if (mFakeNoAlpha) {
         mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
                               mWebGL.mColorWriteMask[1],
                               mWebGL.mColorWriteMask[2],
                               mWebGL.mColorWriteMask[3]);
     }
     if (mFakeNoDepth) {
         mWebGL.gl->fEnable(LOCAL_GL_DEPTH_TEST);
     }
     if (mFakeNoStencil) {
         MOZ_ASSERT(mWebGL.mStencilTestEnabled);
         mWebGL.gl->fEnable(LOCAL_GL_STENCIL_TEST);
     }
+
+    if (!mWebGL.mBoundDrawFramebuffer) {
+        mWebGL.Invalidate();
+        mWebGL.mShouldPresent = true;
+    }
 }
 
 /*static*/ bool
-WebGLContext::ScopedMaskWorkaround::HasDepthButNoStencil(const WebGLFramebuffer* fb)
+WebGLContext::ScopedDrawCallWrapper::HasDepthButNoStencil(const WebGLFramebuffer* fb)
 {
     const auto& depth = fb->DepthAttachment();
     const auto& stencil = fb->StencilAttachment();
     return depth.IsDefined() && !stencil.IsDefined();
 }
 
 ////////////////////////////////////////
 
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1895,17 +1895,17 @@ protected:
     bool mNeedsFakeNoDepth;
     bool mNeedsFakeNoStencil;
     bool mNeedsEmulatedLoneDepthStencil;
 
     const bool mAllowFBInvalidation;
 
     bool Has64BitTimestamps() const;
 
-    struct ScopedMaskWorkaround {
+    struct ScopedDrawCallWrapper final {
         WebGLContext& mWebGL;
         const bool mFakeNoAlpha;
         const bool mFakeNoDepth;
         const bool mFakeNoStencil;
 
         static bool ShouldFakeNoAlpha(WebGLContext& webgl) {
             // We should only be doing this if we're about to draw to the backbuffer, but
             // the backbuffer needs to have this fake-no-alpha workaround.
@@ -1944,19 +1944,19 @@ protected:
                 HasDepthButNoStencil(webgl.mBoundDrawFramebuffer))
             {
                 return true;
             }
 
             return false;
         }
 
-        explicit ScopedMaskWorkaround(WebGLContext& webgl);
+        explicit ScopedDrawCallWrapper(WebGLContext& webgl);
 
-        ~ScopedMaskWorkaround();
+        ~ScopedDrawCallWrapper();
     };
 
     void LoseOldestWebGLContextIfLimitExceeded();
     void UpdateLastUseIndex();
 
     template <typename WebGLObjectType>
     JS::Value WebGLObjectAsJSValue(JSContext* cx, const WebGLObjectType*,
                                    ErrorResult& rv) const;
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -509,17 +509,17 @@ WebGLContext::DrawArrays(GLenum mode, GL
         return;
 
     const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
                                                    instanceCount, &error);
     if (error)
         return;
 
     {
-        ScopedMaskWorkaround autoMask(*this);
+        ScopedDrawCallWrapper wrapper(*this);
         gl->fDrawArrays(mode, first, vertCount);
     }
 
     Draw_cleanup(funcName);
     scopedTF.Advance();
 }
 
 void
@@ -548,17 +548,17 @@ WebGLContext::DrawArraysInstanced(GLenum
         return;
 
     const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
                                                    instanceCount, &error);
     if (error)
         return;
 
     {
-        ScopedMaskWorkaround autoMask(*this);
+        ScopedDrawCallWrapper wrapper(*this);
         gl->fDrawArraysInstanced(mode, first, vertCount, instanceCount);
     }
 
     Draw_cleanup(funcName);
     scopedTF.Advance();
 }
 
 ////////////////////////////////////////
@@ -714,17 +714,17 @@ WebGLContext::DrawElements(GLenum mode, 
         return;
 
     const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
                                         &error);
     if (error)
         return;
 
     {
-        ScopedMaskWorkaround autoMask(*this);
+        ScopedDrawCallWrapper wrapper(*this);
         gl->fDrawElements(mode, vertCount, type,
                           reinterpret_cast<GLvoid*>(byteOffset));
     }
 
     Draw_cleanup(funcName);
 }
 
 void
@@ -749,36 +749,30 @@ WebGLContext::DrawElementsInstanced(GLen
         return;
 
     const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
                                         &error);
     if (error)
         return;
 
     {
-        ScopedMaskWorkaround autoMask(*this);
+        ScopedDrawCallWrapper wrapper(*this);
         gl->fDrawElementsInstanced(mode, vertCount, type,
                                    reinterpret_cast<GLvoid*>(byteOffset),
                                    instanceCount);
     }
 
     Draw_cleanup(funcName);
 }
 
 ////////////////////////////////////////
 
 void
 WebGLContext::Draw_cleanup(const char* funcName)
 {
-    if (!mBoundDrawFramebuffer) {
-        Invalidate();
-        mShouldPresent = true;
-        MOZ_ASSERT(!mBackbufferNeedsClear);
-    }
-
     if (gl->WorkAroundDriverBugs()) {
         if (gl->Renderer() == gl::GLRenderer::Tegra) {
             mDrawCallsSinceLastFlush++;
 
             if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
                 gl->fFlush();
                 mDrawCallsSinceLastFlush = 0;
             }
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp
+++ b/dom/canvas/WebGLContextFramebufferOperations.cpp
@@ -27,34 +27,24 @@ WebGLContext::Clear(GLbitfield mask)
         return ErrorInvalidValue("%s: invalid mask bits", funcName);
 
     if (mask == 0) {
         GenerateWarning("Calling gl.clear(0) has no effect.");
     } else if (mRasterizerDiscardEnabled) {
         GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects.");
     }
 
-    if (mBoundDrawFramebuffer) {
-        if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
-            return;
-
-        gl->fClear(mask);
+    if (mBoundDrawFramebuffer &&
+        !mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
+    {
         return;
-    } else {
-        ClearBackbufferIfNeeded();
     }
 
-    // Ok, we're clearing the default framebuffer/screen.
-    {
-        ScopedMaskWorkaround autoMask(*this);
-        gl->fClear(mask);
-    }
-
-    Invalidate();
-    mShouldPresent = true;
+    ScopedDrawCallWrapper wrapper(*this);
+    gl->fClear(mask);
 }
 
 static GLfloat
 GLClampFloat(GLfloat val)
 {
     if (val < 0.0)
         return 0.0;
 
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -1814,16 +1814,17 @@ WebGLFramebuffer::BlitFramebuffer(WebGLC
     } else if (!srcFB && !dstFB) {
         webgl->ErrorInvalidOperation("%s: Feedback with default framebuffer.", funcName);
         return;
     }
 
     ////
 
     gl->MakeCurrent();
+    WebGLContext::ScopedDrawCallWrapper wrapper(*webgl);
     gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
                          dstX0, dstY0, dstX1, dstY1,
                          mask, filter);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Goop.
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -978,37 +978,45 @@ private:
 public:
     void fClear(GLbitfield mask) {
         BeforeGLDrawCall();
         raw_fClear(mask);
         AfterGLDrawCall();
     }
 
     void fClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
+        BeforeGLDrawCall();
         BEFORE_GL_CALL;
         mSymbols.fClearBufferfi(buffer, drawbuffer, depth, stencil);
         AFTER_GL_CALL;
+        AfterGLDrawCall();
     }
 
     void fClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {
+        BeforeGLDrawCall();
         BEFORE_GL_CALL;
         mSymbols.fClearBufferfv(buffer, drawbuffer, value);
         AFTER_GL_CALL;
+        AfterGLDrawCall();
     }
 
     void fClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {
+        BeforeGLDrawCall();
         BEFORE_GL_CALL;
         mSymbols.fClearBufferiv(buffer, drawbuffer, value);
         AFTER_GL_CALL;
+        AfterGLDrawCall();
     }
 
     void fClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {
+        BeforeGLDrawCall();
         BEFORE_GL_CALL;
         mSymbols.fClearBufferuiv(buffer, drawbuffer, value);
         AFTER_GL_CALL;
+        AfterGLDrawCall();
     }
 
     void fClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
         BEFORE_GL_CALL;
         mSymbols.fClearColor(r, g, b, a);
         AFTER_GL_CALL;
     }