Closed Bug 1978773 Opened 1 year ago Closed 6 months ago

Render gradients from gradient stops directly

Categories

(Core :: Graphics: WebRender, enhancement)

enhancement

Tracking

()

RESOLVED FIXED
150 Branch
Tracking Status
firefox150 --- fixed

People

(Reporter: nical, Assigned: nical)

References

(Blocks 2 open bugs, Regressed 1 open bug)

Details

(Keywords: perf-alert)

Attachments

(25 files, 2 obsolete files)

48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review

WebRender's gradient shaders work with a fixed size table of something that could be thought of as "quantized evenly-spaced gradient stops". It is very fast to evaluate even when the number of stops is high, but it causes many correctness issues that are fundamentally not fixable using this approach.

In some cases it is because the quantization mises high-frequency details, in other cases it is because it shifts the gradient stops slightly, in a way that is very noticeable for axis-aligned hard stops.

Instead we need a way to render the gradient stops directly in the fragment shader without making any quality compromises, potentially at an extra cost. Hopefully we can offset that cost using one or two fast paths for gradients with few stops.
Skia renders gradients this way, and so should we.

This patch replaces the quad radial and conic gradient shaders with a single shader that can do all css gradients.
The new shader also has a fast path for gradients with no more than two gradient stops: in this configuration, all of the data needed by the fragment shader is passed via varying, which yields significant speedups over reading them from the gpu buffer for each fragment.
The slow path performs a linear search in the gradient stop offsets to find the pair affecting the current pixel. This starts fairly cheap for 4 stops or less as the first 4 stops are also provded via varyings in the slow path, and gets more expensive for each new quadruplet of gradient stops. The assumption here that the vast majority of gradients use less than 8 stops.
In the slow path, once the pair of gradient stop offsets has been computed, the color pair is read from the gpu buffer.

The vast majority of gradients do use less than 8 stops except when you consider gradients in the linearRGB (or other non-sRGB) color space. To support those colour spaces we add lots of additional gradient stops.

https://searchfox.org/mozilla-central/source/layout/painting/nsCSSRenderingGradients.h#121
https://searchfox.org/mozilla-central/source/layout/painting/nsCSSRenderingGradients.h#53

Attachment #9502356 - Attachment description: WIP: Bug 1978773 - (WIP) Evaluate radial and conic gradients from gradient stops directly. → Bug 1978773 - Add a shader that evaluates radial and conic gradients from gradient stops directly. r=#gfx-reviewers
Attachment #9503654 - Attachment description: WIP: Bug 1978773 - (WIP) Port the new radial gradient code path to SWGL → Bug 1978773 - Port the new radial gradient code path to SWGL. r=lsalzman
Keywords: leave-open
Pushed by nsilva@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/91303a1fb111 https://hg.mozilla.org/integration/autoland/rev/280cc8e320b3 Add plumbing to enable/disable the new gradient shader. r=gfx-reviewers,gw https://github.com/mozilla-firefox/firefox/commit/80071dedf999 https://hg.mozilla.org/integration/autoland/rev/0b56e4ab162d Use a separate set of gradient prefs for each SWGL and each gradient type. r=lsalzman https://github.com/mozilla-firefox/firefox/commit/252e4a5f11ff https://hg.mozilla.org/integration/autoland/rev/7e907d9e1a0b Add a shader that evaluates radial and conic gradients from gradient stops directly. r=gfx-reviewers,gw https://github.com/mozilla-firefox/firefox/commit/8decf76f7471 https://hg.mozilla.org/integration/autoland/rev/3d1550a5d48b Port the new radial gradient code path to SWGL. r=lsalzman
Pushed by chorotan@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/a481925fd789 https://hg.mozilla.org/integration/autoland/rev/f23322717a45 Revert "Bug 1978773 - Port the new radial gradient code path to SWGL. r=lsalzman" for causing wrench failures
Flags: needinfo?(nical.bugzilla)
See Also: → 1980565
Flags: needinfo?(nical.bugzilla)

This change simplifies the followup patch that will implement a tree traversal of stop offsets.

This patch changes the gradient stop search on the GPU from a linear search to a tree traversal. This drastically reduces the number of gpu buffer reads when there is a lot of gradient stops. An added benefit is that the linear search required non-uniform loop control flow which SWGL currently does not handle (loop that can be exited by some lanes before others). The loop of the tree traversal is uniform which lets SWGL produce correct code.

The tree traversal requires laying out the stops in the gpu buffer in a specific way.

However, the hand-rolled SWGL gradient span shaders benefit enormously from doing an incremental linear search so we keep the linear order of the stops offsets when we know that a span shader will be used.

Attachment #9513937 - Attachment is obsolete: true
Pushed by nsilva@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/2d20381b352a https://hg.mozilla.org/integration/autoland/rev/0fd08b4b810a Move the dithering code into its own file and integrate it in the precise gradient shader. r=gfx-reviewers,lsalzman https://github.com/mozilla-firefox/firefox/commit/1992b30278a9 https://hg.mozilla.org/integration/autoland/rev/a545ddf93ac7 Integrate the linear gradient quad path. r=gfx-reviewers,gw
  • There were a few leftover comments referring to the merge step which is not needed in this version of the shader.
  • Removed a few unused variables also orphaned by the absence of the merge step.
  • Renamed radius into startRadius

This is already covered by wrench tests and makes them pass with the new (currently preffed off) code path.

The code was incorrectly assuming that one could simply update dotPos and dotPosDelta for partial chunks by dividing by the chunk size and multiplying by the number of pixels in the partial chunk. That's true for dotPosDelta but not for dotPos where there is a compounding effect with each iteration feeding back into the next in a way that makes things non-linear. There has to be a more elegant solution but after many failed attempts I ended up expressing it in terms of a single-pixel step applied multiple times depending on the number of pixels in the partial chunk. It should be pretty fast still and this way the math looks similar to the whole-chunk steps.

In addition, the patch rounds endT up so that we go all the way to the next pixel that is in a different stop pair rather than stopping one pixel before. This removes a lot of unnecessary partial chunks. Before that, we would round endT down which meant that in the next sub-span we would still be in the same gradient stop pair and advance by a pixel before stepping into the next stop pair.

A followup patch will enable this for SWGL.

A followup patch will enable this for SWGL.

A followup patch will enable this for SWGL.

Pushed by nsilva@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/068d1ccc4d12 https://hg.mozilla.org/integration/autoland/rev/e468d20a5154 Adjust outdated comments and rename radius into startRadius. r=lsalzman https://github.com/mozilla-firefox/firefox/commit/53edbab52298 https://hg.mozilla.org/integration/autoland/rev/e022f593f310 Fix start_radius taking the wrong input in the swgl span shader. r=gfx-reviewers,lsalzman https://github.com/mozilla-firefox/firefox/commit/ebe39ce25dd1 https://hg.mozilla.org/integration/autoland/rev/39f3130c67c7 Fix partial chunk steps in the new radial gradient swgl span shader. r=lsalzman

The existing function is overly conservative for precise gradients because the latter require less storage per gradient stop.

Pushed by abutkovits@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/53c6a9618a3b https://hg.mozilla.org/integration/autoland/rev/17fb42d96b61 Revert "Bug 1978773 - Fix validatation of precise gradient addresses. r=lsalzman" for causing wrench failures complaining about atomic.h.
Flags: needinfo?(nical.bugzilla)

Precise gradients have a SWGL-specific optimization to speed up the gradient stop lookup. This was implemented in a way that requires SWGL to use the span shader only, since the fallback code uses a different stop representation (the one that works better on GPU but doesn't allow incrementally searching for stops). Unfortunately I discovered late that span shaders are only run on full sized chunks. The Remaining pixels are always going through the (incompatible) fallback. This was caught by tests on the linear gradients but by the time I got to that, radial and conic gradients had already landed.

Until I have a fix for the partial chunk situation, precise gradients will have to be disabled on SWGL.

This patch replaces the linear search in the new SWGL gradient paths with the same tree traversal as the GPU version.
The linear version had the advantage of being incremental, so within a span, searches were very fast after the first one. Unfortunately it required the SWGL and GPU paths to use different representations for gradient stop offsets which led to issues when accidentally falling back to the translated glsl code in SWGL.
This version is not incremental so we do the full search each time the span crosses a new gradient stop. This should only matter when the number of gradient stops is high. The tree structure very aggressively converges, though. For example it takes 3 iterations to find a pair in a 124 stops gradient.

Comment on attachment 9529020 [details]
Bug 1978773 - Temporarily disable precise gradients in SWGL. r=#gfx-reviewers

Beta/Release Uplift Approval Request

  • User impact if declined/Reason for urgency: Incorrect rendering of radial gradients when using software WebRender
  • Is this code covered by automated tests?: No
  • Has the fix been verified in Nightly?: Yes
  • Needs manual test from QE?: No
  • If yes, steps to reproduce:
  • List of other uplifts needed: None
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): It's a backout of a recent pref flip. It reverts to well known code paths.
  • String changes made/needed:
  • Is Android affected?: Yes
Attachment #9529020 - Flags: approval-mozilla-beta?

:nical, it's tricky to follow the bug meta data since it's in a leave open state.
Can you confirm only that one pref flip is needed for Fx146?
There is only one beta build left for Fx146 and we go to RC next week

Flags: needinfo?(nical.bugzilla)

(In reply to Donal Meehan [:dmeehan] from comment #53)

:nical, it's tricky to follow the bug meta data since it's in a leave open state.
Can you confirm only that one pref flip is needed for Fx146?
There is only one beta build left for Fx146 and we go to RC next week

Both gfx.webrender.precise-radial-gradients-swgl and gfx.webrender.precise-conic-gradients-swgl should be set to false in beta.

Flags: needinfo?(nical.bugzilla)

Comment on attachment 9529020 [details]
Bug 1978773 - Temporarily disable precise gradients in SWGL. r=#gfx-reviewers

Approved for 146.0b9

Attachment #9529020 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
Regressions: 2003996

They can be reenabled now that they are cached.

Pushed by chorotan@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/f4a44a4ad046 https://hg.mozilla.org/integration/autoland/rev/666db2373586 Revert "Bug 1978773 - Enable precise linear gradients when using SWGL. r=gfx-reviewers,lsalzman" for causing reftest failures on aja-linear-5a.html

Backed out for causing reftest failures on aja-linear-5a.html

Backout link

Push with failures

Failure log

Flags: needinfo?(nical.bugzilla)
Pushed by csabou@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/d9e44cf64349 https://hg.mozilla.org/integration/autoland/rev/b8a3a89d0434 Revert "Bug 1978773 - Enable precise linear gradients when using SWGL. r=gfx-reviewers,lsalzman" for causing unexpected passes on aja-linear-5a.html

Backed out for causing unexpected passes on aja-linear-5a.html

Push with failures

Failure log

Backout link

Flags: needinfo?(nical.bugzilla)

(In reply to Pulsebot from comment #58)

Pushed by nsilva@mozilla.com:
https://github.com/mozilla-firefox/firefox/commit/585dadcba78a
https://hg.mozilla.org/integration/autoland/rev/fef66115a015
Reenable precise gradients with SWGL. r=gfx-reviewers,jnicol

Perfherder has detected a talos performance change from push fef66115a015e98adc6b55259774524a8eb07eed.

No action is required from the author; this comment is provided for informational purposes only.

Improvements:

Ratio Test Platform Options Absolute values (old vs new)
8% rasterflood_gradient linux1804-64-shippable-qr e10s fission stylo webrender-sw 1,068.00 -> 1,156.92

Need Help or Information?

If you have any questions, please reach out to afinder@mozilla.com. Alternatively, you can find help on Slack by joining #perf-help, and on Matrix you can find help by joining #perftest.

Details of the alert can be found in the alert summary, including links to graphs and comparisons for each of the affected tests.

Keywords: perf-alert
Depends on: 2006848

This reflects a change that happened in an previous patch in this series.

Comment on attachment 9543535 [details]
Bug 1978773 - Rename ClipSpace::Raster into ClipSpace::Device. r=gw

Revision D282387 was moved to bug 1998432. Setting attachment 9543535 [details] to obsolete.

Attachment #9543535 - Attachment is obsolete: true
Pushed by abutkovits@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/fd3163957fb5 https://hg.mozilla.org/integration/autoland/rev/844fb16c6ad5 Revert "Bug 1978773 - Cache quad linear gradients in some cases. r=gfx-reviewers,gw" for causing failures at border-gradient-nine-patch.yaml.
Attachment #9533488 - Attachment description: Bug 1978773 - Cache quad linear gradients in some cases. r=#gfx-reviewers → Bug 1978773 - Cache quad linear gradients in some cases. r=gw
Pushed by smolnar@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/40a78dfc3a1f https://hg.mozilla.org/integration/autoland/rev/b434689e8b86 Revert "Bug 1978773 - Cache quad linear gradients in some cases. r=gfx-reviewers,gw" for causing build bustages
Flags: needinfo?(nical.bugzilla)
Depends on: 2017919
Created web-platform-tests PR https://github.com/web-platform-tests/wpt/pull/57996 for changes under testing/web-platform/tests
Upstream PR merged by moz-wptsync-bot
Regressions: 2019872

This is leave-open but it looks like all of the patches have landed. Maybe this should be closed as FIXED? (unless backing out turns out to be the fix for regression bug 2019872)

Flags: needinfo?(nical.bugzilla)

Indeed. Let's close (and potentially reopen later if I can't figure out the bug 2019872 soon enough).

Status: ASSIGNED → RESOLVED
Closed: 6 months ago
Flags: needinfo?(nical.bugzilla)
Keywords: leave-open
Resolution: --- → FIXED
Target Milestone: --- → 150 Branch
Regressions: 2020981
Regressions: 2025272
QA Whiteboard: [qa-triage-done-c151/b150]
Regressions: 2043502
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: