-
Notifications
You must be signed in to change notification settings - Fork 669
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Only complain on stencil writemask/value_mask/ref front/back mismatch… #2583
Conversation
|
Do we want to require the reference values to be the same? The reference values are all masked by their respectively-masked masks, so refs at least always behave as if they are masked to the available bits. |
debug("...with 8 stencil bits in the draw framebuffer"); | ||
testForStencilBits(gl.INVALID_OPERATION); | ||
|
||
gl.deleteRenderbuffer(fb); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Should be deleteFramebuffer
since fb
is a framebuffer, not a renderbuffer.
|
||
wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilFuncSeparate(gl.FRONT, gl.ALWAYS, 1, 1023)"); | ||
wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilFuncSeparate(gl.BACK, gl.ALWAYS, 257, 1023)"); | ||
wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawArrays(gl.POINTS, 0, 0)"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jdashg , I tried running your new test with the ANGLE running in webglCompatibility mode and received several failures.
This fourth call to drawArrays
fails with INVALID_OPERATION in the following ANGLE code in ValidateDrawBase
// Note: these separate values are not supported in WebGL, due to D3D's limitations. See
// Section 6.10 of the WebGL 1.0 spec.
Framebuffer *framebuffer = state.getDrawFramebuffer();
if (context->getLimitations().noSeparateStencilRefsAndMasks || extensions.webglCompatibility)
{
const FramebufferAttachment *dsAttachment =
framebuffer->getStencilOrDepthStencilAttachment();
GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0;
GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
const DepthStencilState &depthStencilState = state.getDepthStencilState();
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)
{
if (!extensions.webglCompatibility)
{
ERR() << "This ANGLE implementation does not support separate front/back stencil "
"writemasks, reference values, or stencil mask values.";
}
ANGLE_VALIDATION_ERR(context, InvalidOperation(), StencilReferenceMaskOrMismatch);
return false;
}
}
Though differentWritemasks
and differentMasks
are false, differentRefs
is true. The stencil ref is 1 and the stencil back ref is 257. Looks like the minimum required bits only applies to the masks, not the reference value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like a bug in ANGLE that the minimumRequiredStencilMask isn't applied to the reference values. @RafaelCintron, do you agree? Is applying this mask compatible with Direct3D's semantics?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kenrussell , D3D11 does not support creating textures with more than 8bits of stencil data. Hence, the read and write masks are only limited to 8 bits. See the DEPTH_STENCIL_DESC documentation. The reference value is an unsigned integer. See the OMSetDepthStencilState for documentation.
In StateManager11::syncDepthStencilState
, ANGLE clamps the reference value before calling D3D11 with a comment stating this is because of the GL spec.
I suppose It would be nice to inform the web developer (via an error) when bits of their reference value are not taking effect but I do not feel strongly about that.
wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawArrays(gl.POINTS, 0, 0)"); | ||
|
||
wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.stencilFuncSeparate(gl.BACK, gl.ALWAYS, 258, 1023)"); | ||
wtu.shouldGenerateGLError(gl, errIfMismatch, "gl.drawArrays(gl.POINTS, 0, 0)"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This call to drawArrays
fails for the same reason as above.
Adding @Kangz @null77 and @vonture. @jdashg , for reference, ANGLE has two tests for this functionality. One is RequiresSameStencilMaskAndRef added by @Kangz as part of the WebGL compatibility test. The other is DifferentStencilMasksTests added by Jinyoung Hur. |
Looking at those tests it seems to me that if we change WebGL's validation semantics so that the stencil reference value is masked by minimumRequiredStencilMask, too, then things should still work fine on Direct3D. I think we should make that change to the validation, and test it. |
@jdashg , since D3D11 only supports setting one reference value for depth stencil state, we need to enforce the reference values for read and write be equal. |
@RafaelCintron Is it ok if they are equal only /after/ masking? That's what I've proposed here. |
Should we just deprecate stencilFuncSeparate and stencilMaskSeparate? stencilOpSeparate seems to be the only aspect that D3D11 supports. |
It's easier/clearer if we just forbid separate values outright, instead of being tricky and only forbidding them when active. |
@jdashg @RafaelCintron a couple of questions:
Some references: [2] ANGLE's RenderStateCache::getDepthStencilState , which populates the D3D11_DEPTH_STENCIL_DESC structure: [3] Documentation for D3D11_DEPTH_STENCIL_DESC: |
Yes, I mean the reference values for front and back must be equal. As I said in my reply, I don't feel strongly about masking the reference value by the minimumRequiredStencilMask. We would need to make this change in ANGLE. |
Attempting to adjust WebGL's stencil rules.
After attempting to make this change in ANGLE, I discovered that masking the stencil reference value by the number of stencil bits is fundamentally incompatible with the OpenGL ES spec. OpenGL ES already specifies that the stencil reference value is clamped to the range [0, 2^s-1], where s is the number of bits in the current framebuffer's stencil buffer. The rule that the WebGL spec will need to implement is that the draw call is rejected if the stencil front and back reference values are different, after clamping to the range [0, 2^s-1]. Can we agree on these new semantics? It is going to be impossible to update ANGLE otherwise. I attempted to update the test in: and implement the new checks in ANGLE here: In Chromium, this required this patch to be applied: It doesn't work yet. Errors aren't being generated where they should be, and some assertion is being hit when the -1 reference value is sent. I don't know how to see the stack traces for those assertion failures on Windows. I think we need to get this test passing 100% somewhere before we merge this pull request, so we know whether the new semantics are workable. |
Can we just require that they're all the same? That's way simpler, and ANGLE wouldn't have to do any crazy stuff. Since it's required in D3D11, apps that were targeting d3d11 natively would have to deal with not having this. It is definitely simpler if we just standardize on embracing d3d11's restrictions directly. |
WebGL's current rules are that everything must match. An external developer found while running the drawElements tests on top of ANGLE that this was too restrictive, and @null77 and @vonture reviewed https://chromium-review.googlesource.com/302703 to make these checks more compatible with the dEQP. I think I can debug the clamping of the reference values. If we get that working in ANGLE then @jdashg are you OK with changing the WebGL spec validation to include that? It would be best to not revert https://chromium-review.googlesource.com/302703 . Because of masking and clamping, the Direct3D restrictions are actually that these writemasks and reference values only have to be equal up to the number of bits in the stencil buffer. |
I would actually prefer to retain the explicit d3d11 restriction, if deqp is the only place we've run into problems with it. I think that would be simpler, and shouldn't change how actual content is written, since it's not useful to rely on masks/values outside the number of stencil bits. I don't think we should put in extra work just so we happen to pass deqp. I'm actually surprised that restricting things to the number of stencil bits is enough to pass deqp, since restricting to the number of stencil bits doesn't bring back differing front/back masks and references. |
Attempting to adjust WebGL's stencil rules.
Associated ANGLE changes are in this patch: |
Updated. I'll check this against my local patches tomorrow. |
Looks great! Great work @jdashg and @kainino0x! |
debug("With depthbuffer=" + haveDepthBuffer + | ||
", stencilbuffer=" + haveStencilBuffer + | ||
", stencilTest=" + enableStencilTest + | ||
", expecting error=" + errIfMismatch + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Consider using glEnumToString(errIfMismatch)
to make the output read a bit easier. wtu.shouldGenerateGLError
already uses this helper function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I forgot about that helper.
var vertexObject = gl.createBuffer(); | ||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject); | ||
gl.enableVertexAttribArray(0); | ||
gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Since the draw primitive is not relevant for the test, consider using wtu.setupQuad
and wtu.drawQuad
to save lines of code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I copied this from webgl-specific without thinking about whether it was all necessary.
(EDIT: I think I can actually remove all of this, because no actual quads are drawn.)
testStencilMaskCase([0, 256], gl.NO_ERROR); | ||
testStencilMaskCase([1, 256], errIfMismatch); | ||
testStencilMaskCase([1, 257], gl.NO_ERROR); | ||
testStencilMaskCase([1, 258], errIfMismatch); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the max stencil value is 255 and we're ANDing that with the front and back masks, I don't understand how any of these could pass without error. The front and back masks have to match.
I must be missing something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As written, the front and back mask settings don't have to match - just the mask bits that actually take effect. On an 8 bit stencil buffer, only the least significant 8 bits take effect. So the check:
(0 & 255) == (256 & 255)
passes (NO_ERROR).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, right. I misread the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll submit a follow-on PR [to @jdashg's branch again] to take care of these issues, since I introduced them.
debug("With depthbuffer=" + haveDepthBuffer + | ||
", stencilbuffer=" + haveStencilBuffer + | ||
", stencilTest=" + enableStencilTest + | ||
", expecting error=" + errIfMismatch + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I forgot about that helper.
var vertexObject = gl.createBuffer(); | ||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject); | ||
gl.enableVertexAttribArray(0); | ||
gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I copied this from webgl-specific without thinking about whether it was all necessary.
(EDIT: I think I can actually remove all of this, because no actual quads are drawn.)
testStencilMaskCase([0, 256], gl.NO_ERROR); | ||
testStencilMaskCase([1, 256], errIfMismatch); | ||
testStencilMaskCase([1, 257], gl.NO_ERROR); | ||
testStencilMaskCase([1, 258], errIfMismatch); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As written, the front and back mask settings don't have to match - just the mask bits that actually take effect. On an 8 bit stencil buffer, only the least significant 8 bits take effect. So the check:
(0 & 255) == (256 & 255)
passes (NO_ERROR).
Here: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My remaining issues should be straightforward to resolve so I am approving to unblock Kai and Jeff.
Just waiting on CI. |
Great. Let's make sure to squash and merge this one and compose a good commit message, to keep the commit history clearer. |
… for the `s` stencil bits of the draw framebuffer. - WRITEMASK and VALUE_MASK mask, whereas REF clamps - Add and use drawNothing call
Confirmed fixed by my pending Gecko patches too, fwiw. |
Based on kbr's patch: https://chromium-review.googlesource.com/c/angle/angle/+/890605 Implements new rules in this revised WebGL conformance test: KhronosGroup/WebGL#2583 BUG=chromium:806557 Change-Id: I84701dd7156f0bc4a45ba68e63cb962d2d54c2e5 Reviewed-on: https://chromium-review.googlesource.com/952567 Commit-Queue: Kai Ninomiya <kainino@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
… for the
s
stencil bits of the draw framebuffer.No one seems to implement this yet. Is this what we want?