Bug 1444563 - Update stencil front/back mismatch validation. - r=kvark
authorJeff Gilbert <jgilbert@mozilla.com>
Fri, 09 Mar 2018 16:48:51 -0800
changeset 464719 32da6aeeb1e8173b0412863e627460a740e56da9
parent 464718 74f745d7c4e0a7b0c84be6ede6a20311304042c5
child 464720 7c25484d9888d1be690ce53bd4a5ecd1c3af724b
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskvark
bugs1444563
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1444563 - Update stencil front/back mismatch validation. - r=kvark Also update corresponding test to have a stencil buffer and enable STENCIL_TEST. MozReview-Commit-ID: GyCpJ0a1F9H
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextDraw.cpp
dom/canvas/WebGLContextValidate.cpp
dom/canvas/test/webgl-conf/checkout/conformance/misc/webgl-specific.html
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1632,17 +1632,17 @@ protected:
     bool ValidateFaceEnum(GLenum face, const char* info);
     bool ValidateTexInputData(GLenum type, js::Scalar::Type jsArrayType,
                               WebGLTexImageFunc func, WebGLTexDimensions dims);
     bool ValidateDrawModeEnum(GLenum mode, const char* info);
     bool ValidateAttribIndex(GLuint index, const char* info);
     bool ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type,
                                WebGLboolean normalized, GLsizei stride,
                                WebGLintptr byteOffset, const char* info);
-    bool ValidateStencilParamsForDrawCall();
+    bool ValidateStencilParamsForDrawCall(const char* funcName) const;
 
     bool ValidateCopyTexImage(TexInternalFormat srcFormat, TexInternalFormat dstformat,
                               WebGLTexImageFunc func, WebGLTexDimensions dims);
 
     bool ValidateTexImage(TexImageTarget texImageTarget,
                           GLint level, GLenum internalFormat,
                           GLint xoffset, GLint yoffset, GLint zoffset,
                           GLint width, GLint height, GLint depth,
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -214,16 +214,59 @@ WebGLContext::BindFakeBlack(uint32_t tex
     gl->fActiveTexture(LOCAL_GL_TEXTURE0 + texUnit);
     gl->fBindTexture(target.get(), fakeBlackTex->mGLName);
     gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
     return true;
 }
 
 ////////////////////////////////////////
 
+bool
+WebGLContext::ValidateStencilParamsForDrawCall(const char* const funcName) const
+{
+    const auto stencilBits = [&]() -> uint8_t {
+        if (!mStencilTestEnabled)
+            return 0;
+
+        if (!mBoundDrawFramebuffer)
+            return mOptions.stencil ? 8 : 0;
+
+        if (mBoundDrawFramebuffer->StencilAttachment().IsDefined())
+            return 8;
+
+        if (mBoundDrawFramebuffer->DepthStencilAttachment().IsDefined())
+            return 8;
+
+        return 0;
+    }();
+    const uint32_t stencilMax = (1 << stencilBits) - 1;
+
+    const auto fnMask = [&](const uint32_t x) { return x & stencilMax; };
+    const auto fnClamp = [&](const int32_t x) {
+        return std::max(0, std::min(x, (int32_t)stencilMax));
+    };
+
+    bool ok = true;
+    ok &= (fnMask(mStencilWriteMaskFront) == fnMask(mStencilWriteMaskBack));
+    ok &= (fnMask(mStencilValueMaskFront) == fnMask(mStencilValueMaskBack));
+    ok &= (fnClamp(mStencilRefFront) == fnClamp(mStencilRefBack));
+
+    if (!ok) {
+        ErrorInvalidOperation("%s: Stencil front/back state must effectively match."
+                              " (before front/back comparison, WRITEMASK and VALUE_MASK"
+                              " are masked with (2^s)-1, and REF is clamped to"
+                              " [0, (2^s)-1], where `s` is the number of enabled stencil"
+                              " bits in the draw framebuffer)",
+                              funcName);
+    }
+    return ok;
+}
+
+////////////////////////////////////////
+
 template<typename T>
 static bool
 DoSetsIntersect(const std::set<T>& a, const std::set<T>& b)
 {
     std::vector<T> intersection;
     std::set_intersection(a.begin(), a.end(), b.begin(), b.end(),
                           std::back_inserter(intersection));
     return bool(intersection.size());
@@ -248,17 +291,17 @@ public:
             return;
         }
 
         if (!mWebGL->ValidateDrawModeEnum(mode, funcName)) {
             *out_error = true;
             return;
         }
 
-        if (!mWebGL->ValidateStencilParamsForDrawCall()) {
+        if (!mWebGL->ValidateStencilParamsForDrawCall(funcName)) {
             *out_error = true;
             return;
         }
 
         if (!mWebGL->mActiveProgramLinkInfo) {
             mWebGL->ErrorInvalidOperation("%s: The current program is not linked.", funcName);
             *out_error = true;
             return;
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -361,40 +361,16 @@ WebGLContext::ValidateAttribIndex(GLuint
                               " MAX_VERTEX_ATTRIBS.", info);
         }
     }
 
     return valid;
 }
 
 bool
-WebGLContext::ValidateStencilParamsForDrawCall()
-{
-    const char msg[] = "%s set different front and back stencil %s. Drawing in"
-                       " this configuration is not allowed.";
-
-    if (mStencilRefFront != mStencilRefBack) {
-        ErrorInvalidOperation(msg, "stencilFuncSeparate", "reference values");
-        return false;
-    }
-
-    if (mStencilValueMaskFront != mStencilValueMaskBack) {
-        ErrorInvalidOperation(msg, "stencilFuncSeparate", "value masks");
-        return false;
-    }
-
-    if (mStencilWriteMaskFront != mStencilWriteMaskBack) {
-        ErrorInvalidOperation(msg, "stencilMaskSeparate", "write masks");
-        return false;
-    }
-
-    return true;
-}
-
-bool
 WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
 {
     MOZ_RELEASE_ASSERT(gl, "GFX: GL not initialized");
 
     // Unconditionally create a new format usage authority. This is
     // important when restoring contexts and extensions need to add
     // formats back into the authority.
     mFormatUsage = CreateFormatUsage(gl);
--- a/dom/canvas/test/webgl-conf/checkout/conformance/misc/webgl-specific.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/misc/webgl-specific.html
@@ -38,17 +38,17 @@
 <div id="description"></div>
 <div id="console"></div>
 
 <script>
 "use strict";
 var wtu = WebGLTestUtils;
 description("Tests the few differences between WebGL and GLES2");
 
-var gl = wtu.create3DContext();
+var gl = wtu.create3DContext(undefined, {stencil:true});
 var program = wtu.loadStandardProgram(gl);
 gl.useProgram(program);
 var vertexObject = gl.createBuffer();
 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
 gl.enableVertexAttribArray(0);
 gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0);
 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup should succeed");
 
@@ -73,16 +73,17 @@ wtu.shouldGenerateGLError(gl, gl.INVALID
 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.blendFuncSeparate(gl.ONE_MINUS_CONSTANT_ALPHA, gl.ONE_MINUS_CONSTANT_COLOR, gl.ONE, gl.ZERO)");
 
 debug("");
 debug("Verify that in depthRange zNear <= zFar");
 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.depthRange(20, 10)");
 
 debug("");
 debug("Verify that front/back settings should be the same for stenclMask and stencilFunc");
+gl.enable(gl.STENCIL_TEST);
 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilMask(255)");
 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawArrays(gl.TRIANGLES, 0, 0)");
 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilMaskSeparate(gl.FRONT, 1)");
 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawArrays(gl.TRIANGLES, 0, 0)");
 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilMaskSeparate(gl.BACK, 1)");
 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawArrays(gl.TRIANGLES, 0, 0)");
 
 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilFunc(gl.ALWAYS, 0, 255)");