Closed Bug 1599251 Opened 5 years ago Closed 4 years ago

Make NativeLayerCA double-buffered instead of triple-buffered and add a poll-wait-loop with a timeout

Categories

(Core :: Graphics, task)

All
macOS
task
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla73
Tracking Status
firefox73 --- fixed

People

(Reporter: mstange, Assigned: mstange)

Details

Attachments

(2 files, 1 obsolete file)

At the moment, every NativeLayerCA holds on to three surfaces by default: One in-progress surface, one surface in mFrontSurface, and one surface in mSurfaces. (It also holds on to an arbitrarily high number of surfaces that are still in use by the window server.)

This takes up more memory than we would like it to.

Here's an alternative model:

  • Instead of an mSurfaces queue, just have one mBackbufferSurface field.
  • When calling NextSurface:
    • If IOSurfaceIsInUse(mBackbufferSurface) then poll + sleep(0.1ms) spin until it's no longer in use, with a timeout of 500ms.
    • If timed out, allocate a new surface.
    • Otherwise, use mBackbufferSurface.

This should only take 2x window size instead of 3x to 4x window size memory.

Two buffers doesn't seem to be enough. I have run into cases where the WindowServer keeps the old IOSurface in use for a long time (> half a second) even when the layer's contents have already been replaced with a new IOSurface. I think this may be happening in cases where the layer is not visible on the screen.
Moreover, in the cases where the window server does let go of the old IOSurface, 60 fps compositing is possible but can come with additional frame delay. I've seen cases where the old IOSurface is in use until about halfway through the "vsync budget", so we spend the first 5ms of each composite waiting. It's possible that this drastically reduces our "margin of error" of composite timing if we want to have low frame delay.

I'll use this bug to implement a more conservative approach that still uses 3 buffers when compositing is busy but falls back to 2 buffers when the layer is only updating rarely.

When updating the layer at 60fps, the surface that we would be leaving behind
here would usually still be in use at the time this method was called.
But when some time has passed since the last update, usually all surfaces in
mSurfaces are no longer "in use" so we can "compress" the swap chain to be
double-buffered.

Depends on D54859

This effectively limits the swap chain to three buffers.
I haven't seen this sleep call show up in profiles except on very rare occasions.
In the cases where it does show up, it usually only takes up a single 1ms sample
within a many-second range.

Depends on D54860

The second patch causes long pauses after GPU switching. I'll need to experiment with this some more.

Attachment #9111819 - Attachment is obsolete: true
Pushed by mstange@themasta.com:
https://hg.mozilla.org/integration/autoland/rev/f5127ba5a484
Don't leave unused surfaces in the swap chain. r=jrmuizel
https://hg.mozilla.org/integration/autoland/rev/6d3376e13bcf
Don't keep surfaces which never become unused in NativeLayer::mSurfaces. r=jrmuizel
Status: ASSIGNED → RESOLVED
Closed: 4 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla73
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: