WebGL compatibility: add stencil mask and ref restriction
BUG=angleproject:1523
BUG=chromium:668223
Change-Id: I0726769c938fdfd50af0fad1cef1746d4af2a589
Reviewed-on: https://chromium-review.googlesource.com/422084
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index cd248fb..3bb107a 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -531,8 +531,7 @@
GLuint Context::createShader(GLenum type)
{
- return mResourceManager->createShader(mImplementation.get(),
- mImplementation->getNativeLimitations(), type);
+ return mResourceManager->createShader(mImplementation.get(), mLimitations, type);
}
GLuint Context::createTexture()
diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp
index ee72b36..72886d6 100644
--- a/src/libANGLE/Framebuffer.cpp
+++ b/src/libANGLE/Framebuffer.cpp
@@ -132,6 +132,15 @@
return nullptr;
}
+const FramebufferAttachment *FramebufferState::getStencilOrDepthStencilAttachment() const
+{
+ if (mStencilAttachment.isAttached())
+ {
+ return &mStencilAttachment;
+ }
+ return getDepthStencilAttachment();
+}
+
const FramebufferAttachment *FramebufferState::getColorAttachment(size_t colorAttachment) const
{
ASSERT(colorAttachment < mColorAttachments.size());
@@ -360,6 +369,11 @@
return mState.getDepthOrStencilAttachment();
}
+const FramebufferAttachment *Framebuffer::getStencilOrDepthStencilAttachment() const
+{
+ return mState.getStencilOrDepthStencilAttachment();
+}
+
const FramebufferAttachment *Framebuffer::getReadColorbuffer() const
{
return mState.getReadAttachment();
diff --git a/src/libANGLE/Framebuffer.h b/src/libANGLE/Framebuffer.h
index db0d621..bdc7a30 100644
--- a/src/libANGLE/Framebuffer.h
+++ b/src/libANGLE/Framebuffer.h
@@ -62,6 +62,7 @@
const FramebufferAttachment *getReadAttachment() const;
const FramebufferAttachment *getFirstColorAttachment() const;
const FramebufferAttachment *getDepthOrStencilAttachment() const;
+ const FramebufferAttachment *getStencilOrDepthStencilAttachment() const;
const FramebufferAttachment *getColorAttachment(size_t colorAttachment) const;
const FramebufferAttachment *getDepthAttachment() const;
const FramebufferAttachment *getStencilAttachment() const;
@@ -121,6 +122,7 @@
const FramebufferAttachment *getStencilbuffer() const;
const FramebufferAttachment *getDepthStencilBuffer() const;
const FramebufferAttachment *getDepthOrStencilbuffer() const;
+ const FramebufferAttachment *getStencilOrDepthStencilAttachment() const;
const FramebufferAttachment *getReadColorbuffer() const;
GLenum getReadColorbufferType() const;
const FramebufferAttachment *getFirstColorbuffer() const;
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 9483931..afd7a5a 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -3114,17 +3114,23 @@
}
Framebuffer *framebuffer = state.getDrawFramebuffer();
- if (context->getLimitations().noSeparateStencilRefsAndMasks)
+ if (context->getLimitations().noSeparateStencilRefsAndMasks ||
+ context->getExtensions().webglCompatibility)
{
- const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
- GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
+ const FramebufferAttachment *dsAttachment =
+ framebuffer->getStencilOrDepthStencilAttachment();
+ GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0;
GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
const DepthStencilState &depthStencilState = state.getDepthStencilState();
- if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
- (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
- state.getStencilRef() != state.getStencilBackRef() ||
- (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
- (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
+
+ bool differentRefs = state.getStencilRef() != state.getStencilBackRef();
+ bool differentWritemasks =
+ (depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
+ (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask);
+ bool differentMasks = (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
+ (depthStencilState.stencilBackMask & minimumRequiredStencilMask);
+
+ if (differentRefs || differentWritemasks || differentMasks)
{
// Note: these separate values are not supported in WebGL, due to D3D's limitations. See
// Section 6.10 of the WebGL 1.0 spec
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
index 8464111..86f4954 100644
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
@@ -212,6 +212,66 @@
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
+// Tests the WebGL requirement of having the same stencil mask, writemask and ref for fron and back
+TEST_P(WebGLCompatibilityTest, RequiresSameStencilMaskAndRef)
+{
+ // Run the test in an FBO to make sure we have some stencil bits.
+ GLRenderbuffer renderbuffer;
+ glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
+
+ GLFramebuffer framebuffer;
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ renderbuffer.get());
+
+ ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
+ "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
+ glUseProgram(program.get());
+ ASSERT_GL_NO_ERROR();
+
+ // Having ref and mask the same for front and back is valid.
+ glStencilMask(255);
+ glStencilFunc(GL_ALWAYS, 0, 255);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ ASSERT_GL_NO_ERROR();
+
+ // Having a different front - back write mask generates an error.
+ glStencilMaskSeparate(GL_FRONT, 1);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+
+ // Setting both write masks separately to the same value is valid.
+ glStencilMaskSeparate(GL_BACK, 1);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ ASSERT_GL_NO_ERROR();
+
+ // Having a different stencil front - back mask generates an error
+ glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0, 1);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+
+ // Setting both masks separately to the same value is valid.
+ glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 1);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ ASSERT_GL_NO_ERROR();
+
+ // Having a different stencil front - back reference generates an error
+ glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 255, 1);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+
+ // Setting both references separately to the same value is valid.
+ glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 255, 1);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ ASSERT_GL_NO_ERROR();
+
+ // Using different stencil funcs, everything being equal is valid.
+ glStencilFuncSeparate(GL_BACK, GL_NEVER, 255, 1);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ ASSERT_GL_NO_ERROR();
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,