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
Revised backface visibility and 3D plane ordering #3131
Conversation
AAAnd we have a fail in /css/css-transforms/transform3d-backface-visibility-006.html |
https://codepen.io/desandro/pen/LmWoWe Hackerone is fixed. |
Worked quite a bit more on the issue, made it function in accordance to the draft spec. |
Not sure how much the draft spec is web-compatible, probably worth checking with @mattwoodrow. |
The spec has historically been inconsistent with the implementations, which is why Matt and I didn't bother looking at it |
c80dd47
to
b4cb9b4
Compare
☔ The latest upstream changes (presumably #3143) made this pull request unmergeable. Please resolve the merge conflicts. |
I've been looking at backface-visibility-2 myself and with @mstange , and it looks like the failure is caused by Gecko not properly propagating the backface visibility property. Supposedly, error happens here: The front face element is red color and has the backface visibility disabled. It's parented to the "card" div that establishes a preserve-3d context, and that is rotated backwards. Observed behavior: Gecko spawns a (flat) stacking context (SC) around it, which gets backface visibility enabled. Since this SC serves as a preserve-3d hierarchy boundary, and the element still has backface visibility disabled, it turns out to be invisible (regardless of the transforms). Expected behavior: either Gecko specifies the element as is (without wrapping into SC), or the backface-visibility property gets moved up to the SC wrap. @staktrace would you happen to know how (or if?) this should be fixed on Gecko side? Attaching the display lists dump generated by Gecko and passed to WR. Alternatively, I'll keep poking at it. |
@kvark - I'm not totally following your explanation. What I see in the display list dump is this (simplified):
This seems like it matches the HTML exactly, since the backface-visibility:hidden is set on two inner divs and not the card div. Are you saying that we should be propagating the |
... although I may have oversimplified things. There's a lot of reference frames and duplicate stacking contexts as well. |
This stacking context has |
Suggested Gecko patch by @staktrace : diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -8686,16 +8686,24 @@ nsDisplayTransform::ShouldBuildLayerEven
bool
nsDisplayTransform::CreateWebRenderCommands(
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
WebRenderLayerManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder)
{
+ if (mNoExtendContext) {
+ // This is a wrapper nsDisplayTransform that separates descendants from
+ // the 3D context of the ancestors. WR doesn't need a stacking context for
+ // this so we can just generate the WR items for the descendants.
+ return mStoredList.CreateWebRenderCommands(
+ aBuilder, aResources, sc, aManager, aDisplayListBuilder);
+ }
+
// We want to make sure we don't pollute the transform property in the WR
// stacking context by including the position of this frame (relative to the
// parent reference frame). We need to keep those separate; the position of
// this frame goes into the stacking context bounds while the transform goes
// into the transform.
LayoutDevicePoint position;
Matrix4x4 newTransformMatrix = GetTransformForRendering(&position); |
Investigated a bit more, found a problem with WR side code. Fixed, rebased, and pushed here. |
Getting new failure in |
|
Here is what's going on with In the old (Gecko!) code, each of the elements would spawn a separate stacking context, and WR is able to preserve the order of these when plane-splitting. In the new Gecko code, some elements no longer have a separate stacking context, so WR groups them into the same picture, which participates in ordering and plane splitting as a whole... thus, the drawing order gets broken. TL;DR; the proposed Gecko patch unveils a problem in WR 3D ordering that was hidden before. Either the patch needs to be rewritten (i.e. by propagating backface-visibility into the spawned contexts), or WR needs to be fixed w.r.t. ordering in this case. I'd prefer the latter, and I'm looking into it, but it's unfortunate that this very PR is not quite strongly related to this blocking fix. |
@kvark Interesting problem! A couple of comments:
|
The TL;DR is that when a 3d rendering context is established, we add two pictures. The first picture [1] should in theory get any un-transformed content added to it. This picture is parented to the 3d render context container picture [2]. Any preserve-3d items that are encountered are then parented to the 3d container in [2]. The idea is that we end up with a picture for the un-transformed content to be flattened into, which is then sorted with the transformed content. At the time it seemed like this matched the spec, but it's quite likely it has flaws! [1] webrender/webrender/src/display_list_flattener.rs Line 1021 in d558877
[2] webrender/webrender/src/display_list_flattener.rs Line 1104 in d558877
|
@gw3583 thanks for the info! Let's talk this over tonight on IRC. In the meantime, the way our 3D stacking contexts are treated, I think, should be the following:
That scheme would preserve the ordering with regards to the most 3D cases (outside of obscure ones where there is an inversely transformed context inside a transformed one, and the app expects the order to be preserved ... yikes!). |
☔ The latest upstream changes (presumably #3167) made this pull request unmergeable. Please resolve the merge conflicts. |
@kvark I certainly haven't looked into this in detail, so I don't have a full understanding of the problem yet. That said, when I implemented the picture code for this, it seemed like it should match the specification and not require any workarounds like you've mentioned above. I think you already ran into this btw, but the draft spec is quite different from what browsers implement. The spec I used as a reference is https://drafts.csswg.org/css-transforms-2/#transform-functions (linked from the MDN docs at https://developer.mozilla.org/en-US/docs/Web/CSS/transform). I had a quick read again and it seems like we should be matching the specification as far as I can tell (most likely I'm missing something though, since we clearly have an issue here!). The other thing to mention regarding your comment above - I don't think we can change any behavior in Next time we're online, let's discuss this in detail - I also have some other semi-related thoughts on how to optimize plane-splitting in the common case, that may end up factoring into this stuff. |
@kvark OK, this looks good to me! There are a few nits in the review to solve, but that's all that remains. The other question is whether we want to merge this so close to the beta merge date for Gecko. Do we have any thoughts on possible risk / whether we should hold off on merging this until some point later in the week? |
during the primitives preparation.
…reserve-3d). Also use the actual parent for backface-visibility if outside of 3D hierarchy.
Add a new one to mimic transform3d-sorting-004.html
Thanks for the review @gw3583 !
AFAIK, Beta is branching out today, and in order for this code to ship there we'd need another WR update in FF. I'd like this code to stay a bit in Nightly before shipping. Confirmed with @staktrace on IRC that we aren't planning on a WR update before the branch. Any further hotfixes can be cherry-picked, so the PR isn't blocking us to do anything. Let's proceed 🚂 @bors-servo r=gw3583 |
@bors-servo r+ |
@bors-servo are you there? |
@bors-servo: ping |
📌 Commit 6a622a1 has been approved by |
📌 Commit 6a622a1 has been approved by |
😪 I'm awake I'm awake |
Revised backface visibility and 3D plane ordering Fixes #3114 ## Backface visibility logic changes - the property is not propagated hierarchically - the property is inherited only by the pictures directly spawned from a primitive - backface-visibility is determined in the coordinate space of the containing block. For 3D-participating contexts, this is the parent of the 3D sub-tree root. ~~This isn't obvious, and neither it is guaranteed to be correct. It's just a rather simple scheme that makes us behave properly on the issues listed in #3114. Feedback is welcome!~~ Update: this should be correct. [Gecko changes](#3131 (comment)) are also needed though. ~~Try: https://treeherder.mozilla.org/#/jobs?repo=try&revision=f25ab9510acbc46b3a3c4a8a03eb23c7b75fc4ae~~ cc @gankro @mstange (and thanks for fruitful discussion!) ## Plane splitting re-architecture All the interactions with `plane_split` crate have been moved from batching code to `prepare_xxx_for_render`. The code is better structured now, with most of the plane splitting logic in one place inside a (relatively small) `picture` module, organized as helper functions. Batching still does a bit of work to actually make draw instances from the ordered planes, but it's not longer a computational work, it's just shuffling data. ## Plane split logic changes Whenever we iterate the children of a stacking context that participates in plane splitting, and we encounter a child which is another stacking context, we break the immediate children sequence and organize a new picture from them. Any following immediate children will be going to another picture, therefore, and the order or rendering is preserved this way. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/webrender/3131) <!-- Reviewable:end -->
☀️ Test successful - status-appveyor, status-taskcluster |
Fixes #3114
Backface visibility logic changes
This isn't obvious, and neither it is guaranteed to be correct. It's just a rather simple scheme that makes us behave properly on the issues listed in #3114. Feedback is welcome!Update: this should be correct. Gecko changes are also needed though.
Try: https://treeherder.mozilla.org/#/jobs?repo=try&revision=f25ab9510acbc46b3a3c4a8a03eb23c7b75fc4aecc @gankro @mstange (and thanks for fruitful discussion!)
Plane splitting re-architecture
All the interactions with
plane_split
crate have been moved from batching code toprepare_xxx_for_render
. The code is better structured now, with most of the plane splitting logic in one place inside a (relatively small)picture
module, organized as helper functions. Batching still does a bit of work to actually make draw instances from the ordered planes, but it's not longer a computational work, it's just shuffling data.Plane split logic changes
Whenever we iterate the children of a stacking context that participates in plane splitting, and we encounter a child which is another stacking context, we break the immediate children sequence and organize a new picture from them. Any following immediate children will be going to another picture, therefore, and the order or rendering is preserved this way.
This change is