Changeset 290003 in webkit


Ignore:
Timestamp:
Feb 17, 2022 12:14:15 AM (5 months ago)
Author:
graouts@webkit.org
Message:

Use the animation frame rate during animation resolution and scheduling
https://bugs.webkit.org/show_bug.cgi?id=234202
rdar://85983678

Reviewed by Simon Fraser.

Source/WebCore:

We've previously added properties to DocumentTimeline to expose the maximum frame rate supported
by the display (bug 234161) and to Animation to let animations specify the frame rate at which
they would like to be updated (bug 234174).

In this patch we add support for accounting for the frame rate set on animations to ensure they
are updated at a cadence close to the one requested, with the following provisions:

  • we do our best to match the frame rate provided by the animation but account for the display's refresh rate to only ever update animations when the display is being refreshed,
  • we update all animations sharing the same frame rate in the same updates,
  • we schedule updates sparingly accounting for the frame rate of animation such that a page only containing animations that are running at, for instance, 15fps only result in calls to DocumentTimelinesController::updateAnimationsAndSendEvents() at 15fps,
  • other factors may impact the animation frame rate, such as low power mode.

There is no test for this code currently. It is not possible to test for the actual
rate at which animations are updated in a testing environment, since there are too
many variables to ensure consistent results. However, future patches will look into
adding internals code such that tests may inspect the update cadence set on the timeline
and frame rates at which animations are optimistically scheduled to update.

The FrameRateAligner class provides a supporting object for DocumentTimelinesController
which contains the data related to the frame rates currently in use by all animations in
the document. This class will be updated in future patches to better handle alignment of
animations added dynamically with previously unused frame rates.

Note that all of those changes to scheduling only affects page rendering updates triggered
by animations. Page rendering updates continue to be scheduled by calls to requestAnimationFrame()
independently from the frame rate specified on animations.

  • Headers.cmake:
  • Sources.txt:
  • WebCore.xcodeproj/project.pbxproj:
  • animation/DocumentTimeline.cpp:

(WebCore::DocumentTimeline::animationInterval const):
(WebCore::DocumentTimeline::scheduleNextTick):

  • animation/DocumentTimelinesController.cpp:

(WebCore::DocumentTimelinesController::DocumentTimelinesController):
(WebCore::DocumentTimelinesController::updateAnimationsAndSendEvents):
(WebCore::DocumentTimelinesController::timeUntilNextTickForAnimationsWithFrameRate const):

  • animation/DocumentTimelinesController.h:

(WebCore::DocumentTimelinesController::maximumAnimationFrameRate const):

  • animation/FrameRateAligner.cpp: Added.

(WebCore::idealTimeForNextUpdate):
(WebCore::FrameRateAligner::beginUpdate):
(WebCore::FrameRateAligner::updateFrameRate):
(WebCore::FrameRateAligner::timeUntilNextUpdateForFrameRate const):
(WebCore::FrameRateAligner::maximumFrameRate const):

  • animation/FrameRateAligner.h: Copied from Source/WebCore/animation/DocumentTimelinesController.h.
  • animation/WebAnimation.cpp:

(WebCore::WebAnimation::setEffectiveFrameRate):

  • page/Page.cpp:

(WebCore::Page::timelineControllerMaximumAnimationFrameRateDidChange):
(WebCore::Page::preferredRenderingUpdateFramesPerSecond const):

  • page/Page.h:

LayoutTests:

Update this test to not rely on hard values but rather check that throttling
has the expected effect of doubling the interval between frames.

  • fast/animation/css-animation-throttling-lowPowerMode-expected.txt:
  • fast/animation/css-animation-throttling-lowPowerMode.html:
Location:
trunk
Files:
1 added
13 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r289999 r290003  
     12022-02-16  Antoine Quint  <graouts@webkit.org>
     2
     3        Use the animation frame rate during animation resolution and scheduling
     4        https://bugs.webkit.org/show_bug.cgi?id=234202
     5        rdar://85983678
     6
     7        Reviewed by Simon Fraser.
     8
     9        Update this test to not rely on hard values but rather check that throttling
     10        has the expected effect of doubling the interval between frames.
     11
     12        * fast/animation/css-animation-throttling-lowPowerMode-expected.txt:
     13        * fast/animation/css-animation-throttling-lowPowerMode.html:
     14
    1152022-02-16  Tim Horton  <timothy_horton@apple.com>
    216
  • trunk/LayoutTests/fast/animation/css-animation-throttling-lowPowerMode-expected.txt

    r213473 r290003  
    44
    55
    6 PASS internals.animationsInterval is 0.015
    76internals.setLowPowerModeEnabled(true)
    8 PASS internals.animationsInterval is 0.030
     7PASS internals.animationsInterval is throttled
    98internals.setLowPowerModeEnabled(false)
    10 PASS internals.animationsInterval is 0.015
     9PASS internals.animationsInterval is unthrottled
    1110PASS successfullyParsed is true
    1211
  • trunk/LayoutTests/fast/animation/css-animation-throttling-lowPowerMode.html

    r256512 r290003  
    3030    element.onanimationstart = null;
    3131
    32     shouldBe("internals.animationsInterval", "0.015");
     32    window.unthrottled = internals.animationsInterval;
     33    window.throttled = unthrottled * 2;
     34
    3335    evalAndLog("internals.setLowPowerModeEnabled(true)");
    34     shouldBe("internals.animationsInterval", "0.030");
     36    shouldBe("internals.animationsInterval", "throttled");
    3537    evalAndLog("internals.setLowPowerModeEnabled(false)");
    36     shouldBe("internals.animationsInterval", "0.015");
     38    shouldBe("internals.animationsInterval", "unthrottled");
    3739    finishJSTest();
    3840};
  • trunk/Source/WebCore/ChangeLog

    r290002 r290003  
     12022-02-16  Antoine Quint  <graouts@webkit.org>
     2
     3        Use the animation frame rate during animation resolution and scheduling
     4        https://bugs.webkit.org/show_bug.cgi?id=234202
     5        rdar://85983678
     6
     7        Reviewed by Simon Fraser.
     8
     9        We've previously added properties to DocumentTimeline to expose the maximum frame rate supported
     10        by the display (bug 234161) and to Animation to let animations specify the frame rate at which
     11        they would like to be updated (bug 234174).
     12
     13        In this patch we add support for accounting for the frame rate set on animations to ensure they
     14        are updated at a cadence close to the one requested, with the following provisions:
     15
     16        - we do our best to match the frame rate provided by the animation but account for the
     17          display's refresh rate to only ever update animations when the display is being refreshed,
     18        - we update all animations sharing the same frame rate in the same updates,
     19        - we schedule updates sparingly accounting for the frame rate of animation such that
     20          a page only containing animations that are running at, for instance, 15fps only result
     21          in calls to DocumentTimelinesController::updateAnimationsAndSendEvents() at 15fps,
     22        - other factors may impact the animation frame rate, such as low power mode.
     23
     24        There is no test for this code currently. It is not possible to test for the actual
     25        rate at which animations are updated in a testing environment, since there are too
     26        many variables to ensure consistent results. However, future patches will look into
     27        adding internals code such that tests may inspect the update cadence set on the timeline
     28        and frame rates at which animations are optimistically scheduled to update.
     29
     30        The FrameRateAligner class provides a supporting object for DocumentTimelinesController
     31        which contains the data related to the frame rates currently in use by all animations in
     32        the document. This class will be updated in future patches to better handle alignment of
     33        animations added dynamically with previously unused frame rates.
     34
     35        Note that all of those changes to scheduling only affects page rendering updates triggered
     36        by animations. Page rendering updates continue to be scheduled by calls to requestAnimationFrame()
     37        independently from the frame rate specified on animations.
     38
     39        * Headers.cmake:
     40        * Sources.txt:
     41        * WebCore.xcodeproj/project.pbxproj:
     42        * animation/DocumentTimeline.cpp:
     43        (WebCore::DocumentTimeline::animationInterval const):
     44        (WebCore::DocumentTimeline::scheduleNextTick):
     45        * animation/DocumentTimelinesController.cpp:
     46        (WebCore::DocumentTimelinesController::DocumentTimelinesController):
     47        (WebCore::DocumentTimelinesController::updateAnimationsAndSendEvents):
     48        (WebCore::DocumentTimelinesController::timeUntilNextTickForAnimationsWithFrameRate const):
     49        * animation/DocumentTimelinesController.h:
     50        (WebCore::DocumentTimelinesController::maximumAnimationFrameRate const):
     51        * animation/FrameRateAligner.cpp: Added.
     52        (WebCore::idealTimeForNextUpdate):
     53        (WebCore::FrameRateAligner::beginUpdate):
     54        (WebCore::FrameRateAligner::updateFrameRate):
     55        (WebCore::FrameRateAligner::timeUntilNextUpdateForFrameRate const):
     56        (WebCore::FrameRateAligner::maximumFrameRate const):
     57        * animation/FrameRateAligner.h: Copied from Source/WebCore/animation/DocumentTimelinesController.h.
     58        * animation/WebAnimation.cpp:
     59        (WebCore::WebAnimation::setEffectiveFrameRate):
     60        * page/Page.cpp:
     61        (WebCore::Page::timelineControllerMaximumAnimationFrameRateDidChange):
     62        (WebCore::Page::preferredRenderingUpdateFramesPerSecond const):
     63        * page/Page.h:
     64
    1652022-02-17  Commit Queue  <commit-queue@webkit.org>
    266
  • trunk/Source/WebCore/Headers.cmake

    r289994 r290003  
    405405    animation/EffectTiming.h
    406406    animation/FillMode.h
     407    animation/FrameRateAligner.h
    407408    animation/GetAnimationsOptions.h
    408409    animation/IterationCompositeOperation.h
  • trunk/Source/WebCore/Sources.txt

    r289991 r290003  
    483483animation/DocumentTimelinesController.cpp
    484484animation/ElementAnimationRareData.cpp
     485animation/FrameRateAligner.cpp
    485486animation/KeyframeEffect.cpp
    486487animation/KeyframeEffectStack.cpp
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r289994 r290003  
    23272327                71EFCEDC202B38A900D7C411 /* AnimationEffect.h in Headers */ = {isa = PBXBuildFile; fileRef = 71EFCED7202B388D00D7C411 /* AnimationEffect.h */; settings = {ATTRIBUTES = (Private, ); }; };
    23282328                71F05F802512442E0071E693 /* CSSPropertyAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 71F05F7E2512440C0071E693 /* CSSPropertyAnimation.h */; settings = {ATTRIBUTES = (Private, ); }; };
     2329                71FCB17027BAB3FE00E0631C /* FrameRateAligner.h in Headers */ = {isa = PBXBuildFile; fileRef = 71FCB16D27BAB3DF00E0631C /* FrameRateAligner.h */; settings = {ATTRIBUTES = (Private, ); }; };
    23292330                72144333223EC8B000F12FF7 /* SVGProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = 55EE5363223B2A2400FBA944 /* SVGProperty.h */; settings = {ATTRIBUTES = (Private, ); }; };
    23302331                72144334223EC91600F12FF7 /* SVGPropertyOwner.h in Headers */ = {isa = PBXBuildFile; fileRef = 55EE5360223B2A2100FBA944 /* SVGPropertyOwner.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    1130811309                71F6EE41255EDF9C00FC4C5B /* GridTrackSize.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GridTrackSize.cpp; sourceTree = "<group>"; };
    1130911310                71F936F71DD4F99B00922CC7 /* tracks-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "tracks-support.js"; sourceTree = "<group>"; };
     11311                71FCB16D27BAB3DF00E0631C /* FrameRateAligner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrameRateAligner.h; sourceTree = "<group>"; };
     11312                71FCB16F27BAB3E000E0631C /* FrameRateAligner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameRateAligner.cpp; sourceTree = "<group>"; };
    1131011313                71FF851822A3F81F005D5959 /* NavigatorMaxTouchPoints.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = NavigatorMaxTouchPoints.idl; sourceTree = "<group>"; };
    1131111314                7211B5D6276536820076FEF8 /* FilterResults.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FilterResults.h; sourceTree = "<group>"; };
     
    2459824601                                712BE4811FE865D4002031CC /* FillMode.h */,
    2459924602                                712BE4821FE865D5002031CC /* FillMode.idl */,
     24603                                71FCB16F27BAB3E000E0631C /* FrameRateAligner.cpp */,
     24604                                71FCB16D27BAB3DF00E0631C /* FrameRateAligner.h */,
    2460024605                                713F1D5923DF1D7D003F5EFA /* GetAnimationsOptions.h */,
    2460124606                                713F1D5723DF1D7D003F5EFA /* GetAnimationsOptions.idl */,
     
    3467034675                                658436860AE01B7400E53753 /* FrameLoadRequest.h in Headers */,
    3467134676                                628D214E12131EF40055DCFC /* FrameNetworkingContext.h in Headers */,
     34677                                71FCB17027BAB3FE00E0631C /* FrameRateAligner.h in Headers */,
    3467234678                                4190F3A524A0B4EE00531C57 /* FrameRateMonitor.h in Headers */,
    3467334679                                93309E0E099E64920056E581 /* FrameSelection.h in Headers */,
  • trunk/Source/WebCore/animation/DocumentTimeline.cpp

    r289806 r290003  
    102102    if (!m_document || !m_document->page())
    103103        return Seconds::infinity();
     104
    104105    return m_document->page()->preferredRenderingUpdateInterval();
    105106}
     
    332333    Seconds scheduleDelay = Seconds::infinity();
    333334
     335    const auto nextTickTimeEpsilon = 1_ms;
     336
     337    auto timeUntilNextTickForAnimationsWithFrameRate = [&](std::optional<FramesPerSecond> frameRate) -> std::optional<Seconds> {
     338        if (frameRate) {
     339            if (auto* controller = this->controller())
     340                return controller->timeUntilNextTickForAnimationsWithFrameRate(*frameRate);
     341        }
     342        return std::nullopt;
     343    };
     344
    334345    for (const auto& animation : m_animations) {
    335346        if (!animation->isRelevant())
    336347            continue;
     348
     349        // Get the time until the next tick for this animation. This does not
     350        // account for the animation frame rate, only accounting for the timing
     351        // model and the playback rate.
    337352        auto animationTimeToNextRequiredTick = animation->timeToNextTick();
     353
     354        if (auto animationFrameRate = animation->frameRate()) {
     355            // Now let's get the time until any animation with this animation's frame rate would tick.
     356            // If that time is longer than what we previously computed without accounting for the frame
     357            // rate, we use this time instead since our animation wouldn't tick anyway since the
     358            // DocumentTimelinesController would ignore it. Doing this ensures that we don't schedule
     359            // updates that wouldn't actually yield any work and guarantees that in a page with only
     360            // animations as the source for scheduling updates, updates are only scheduled at the minimal
     361            // frame rate.
     362            auto timeToNextPossibleTickAccountingForFrameRate = timeUntilNextTickForAnimationsWithFrameRate(animationFrameRate);
     363            if (timeToNextPossibleTickAccountingForFrameRate && animationTimeToNextRequiredTick < *timeToNextPossibleTickAccountingForFrameRate)
     364                animationTimeToNextRequiredTick = *timeToNextPossibleTickAccountingForFrameRate - nextTickTimeEpsilon;
     365        }
     366
    338367        if (animationTimeToNextRequiredTick < animationInterval()) {
    339368            scheduleAnimationResolution();
  • trunk/Source/WebCore/animation/DocumentTimelinesController.cpp

    r282860 r290003  
    4545DocumentTimelinesController::DocumentTimelinesController(Document& document)
    4646    : m_document(document)
     47    , m_frameRateAligner()
    4748{
    4849    if (auto* page = document.page()) {
     
    7980void DocumentTimelinesController::updateAnimationsAndSendEvents(ReducedResolutionSeconds timestamp)
    8081{
     82    auto previousMaximumAnimationFrameRate = maximumAnimationFrameRate();
     83    // This will hold the frame rate at which we would schedule updates not
     84    // accounting for the frame rate of animations.
     85    std::optional<FramesPerSecond> defaultTimelineFrameRate;
     86    // This will hold the frame rate used for this timeline until now.
     87    std::optional<FramesPerSecond> previousTimelineFrameRate;
     88    if (auto* page = m_document.page()) {
     89        defaultTimelineFrameRate = page->preferredRenderingUpdateFramesPerSecond({ Page::PreferredRenderingUpdateOption::IncludeThrottlingReasons });
     90        previousTimelineFrameRate = page->preferredRenderingUpdateFramesPerSecond({
     91            Page::PreferredRenderingUpdateOption::IncludeThrottlingReasons,
     92            Page::PreferredRenderingUpdateOption::IncludeAnimationsFrameRate
     93        });
     94    }
     95
    8196    LOG_WITH_STREAM(Animations, stream << "DocumentTimelinesController::updateAnimationsAndSendEvents for time " << timestamp);
    8297
     
    93108    if (!m_isSuspended)
    94109        cacheCurrentTime(timestamp);
     110
     111    m_frameRateAligner.beginUpdate(timestamp, previousTimelineFrameRate);
    95112
    96113    // 1. Update the current time of all timelines associated with document passing now as the timestamp.
     
    111128            }
    112129
     130            // Even though this animation is relevant, its frame rate may be such that it should
     131            // be disregarded during this update. If it does not specify an explicit frame rate,
     132            // this means this animation uses the default frame rate at which we typically schedule
     133            // updates not accounting for the frame rate of animations.
     134            auto animationFrameRate = animation->frameRate();
     135            if (!animationFrameRate)
     136                animationFrameRate = defaultTimelineFrameRate;
     137
     138            if (animationFrameRate) {
     139                ASSERT(*animationFrameRate > 0);
     140                if (m_frameRateAligner.updateFrameRate(*animationFrameRate) == FrameRateAligner::ShouldUpdate::No)
     141                    continue;
     142            }
     143
    113144            // This will notify the animation that timing has changed and will call automatically
    114145            // schedule invalidation if required for this animation.
     
    123154                    completedTransitions.append(transition);
    124155            }
     156        }
     157    }
     158
     159    // If the maximum frame rate we've encountered is the same as the default frame rate,
     160    // let's reset it to not have an explicit value which will indicate that there is no
     161    // need to override the default animation frame rate to service animations.
     162    auto maximumAnimationFrameRate = m_frameRateAligner.maximumFrameRate();
     163    if (maximumAnimationFrameRate == defaultTimelineFrameRate)
     164        maximumAnimationFrameRate = std::nullopt;
     165
     166    // Ensure the timeline updates at the maximum frame rate we've encountered for our animations.
     167    if (previousMaximumAnimationFrameRate != maximumAnimationFrameRate) {
     168        if (auto* page = m_document.page()) {
     169            if (previousTimelineFrameRate != maximumAnimationFrameRate)
     170                page->timelineControllerMaximumAnimationFrameRateDidChange(*this);
    125171        }
    126172    }
     
    176222}
    177223
     224std::optional<Seconds> DocumentTimelinesController::timeUntilNextTickForAnimationsWithFrameRate(FramesPerSecond frameRate) const
     225{
     226    if (!m_cachedCurrentTime)
     227        return std::nullopt;
     228    return m_frameRateAligner.timeUntilNextUpdateForFrameRate(frameRate, *m_cachedCurrentTime);
     229};
     230
    178231void DocumentTimelinesController::suspendAnimations()
    179232{
  • trunk/Source/WebCore/animation/DocumentTimelinesController.h

    r278580 r290003  
    2626#pragma once
    2727
     28#include "FrameRateAligner.h"
    2829#include "ReducedResolutionSeconds.h"
    2930#include "Timer.h"
     
    5253
    5354    std::optional<Seconds> currentTime();
     55    std::optional<FramesPerSecond> maximumAnimationFrameRate() const { return m_frameRateAligner.maximumFrameRate(); }
     56    std::optional<Seconds> timeUntilNextTickForAnimationsWithFrameRate(FramesPerSecond) const;
    5457
    5558    WEBCORE_EXPORT void suspendAnimations();
     
    6770    void maybeClearCachedCurrentTime();
    6871
     72    HashMap<FramesPerSecond, ReducedResolutionSeconds> m_animationFrameRateToLastTickTimeMap;
    6973    WeakHashSet<DocumentTimeline> m_timelines;
    7074    TaskCancellationGroup m_currentTimeClearingTaskCancellationGroup;
    7175    Document& m_document;
     76    FrameRateAligner m_frameRateAligner;
    7277    Markable<Seconds, Seconds::MarkableTraits> m_cachedCurrentTime;
    7378    bool m_isSuspended { false };
  • trunk/Source/WebCore/animation/FrameRateAligner.h

    r290002 r290003  
    11/*
    2  * Copyright (C) 2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2022 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2626#pragma once
    2727
     28#include "AnimationFrameRate.h"
    2829#include "ReducedResolutionSeconds.h"
    29 #include "Timer.h"
    30 #include <wtf/CancellableTask.h>
    31 #include <wtf/Markable.h>
    3230#include <wtf/Seconds.h>
    33 #include <wtf/WeakHashSet.h>
    3431
    3532namespace WebCore {
    3633
    37 class CSSTransition;
    38 class Document;
    39 class DocumentTimeline;
    40 class WebAnimation;
    41 
    42 class DocumentTimelinesController {
     34class FrameRateAligner {
    4335    WTF_MAKE_FAST_ALLOCATED;
    4436public:
    45     explicit DocumentTimelinesController(Document&);
    46     ~DocumentTimelinesController();
     37    explicit FrameRateAligner();
     38    ~FrameRateAligner();
    4739
    48     void addTimeline(DocumentTimeline&);
    49     void removeTimeline(DocumentTimeline&);
    50     void detachFromDocument();
    51     void updateAnimationsAndSendEvents(ReducedResolutionSeconds);
     40    void beginUpdate(ReducedResolutionSeconds, std::optional<FramesPerSecond>);
    5241
    53     std::optional<Seconds> currentTime();
     42    enum class ShouldUpdate { Yes, No };
     43    ShouldUpdate updateFrameRate(FramesPerSecond);
    5444
    55     WEBCORE_EXPORT void suspendAnimations();
    56     WEBCORE_EXPORT void resumeAnimations();
    57     WEBCORE_EXPORT bool animationsAreSuspended() const;
     45    std::optional<Seconds> timeUntilNextUpdateForFrameRate(FramesPerSecond, ReducedResolutionSeconds) const;
     46    std::optional<FramesPerSecond> maximumFrameRate() const;
    5847
    5948private:
    60     struct AnimationsToProcess {
    61         Vector<RefPtr<WebAnimation>> animationsToRemove;
    62         Vector<RefPtr<CSSTransition>> completedTransitions;
     49    struct FrameRateData {
     50        ReducedResolutionSeconds firstUpdateTime;
     51        ReducedResolutionSeconds lastUpdateTime;
    6352    };
    6453
    65     ReducedResolutionSeconds liveCurrentTime() const;
    66     void cacheCurrentTime(ReducedResolutionSeconds);
    67     void maybeClearCachedCurrentTime();
    68 
    69     WeakHashSet<DocumentTimeline> m_timelines;
    70     TaskCancellationGroup m_currentTimeClearingTaskCancellationGroup;
    71     Document& m_document;
    72     Markable<Seconds, Seconds::MarkableTraits> m_cachedCurrentTime;
    73     bool m_isSuspended { false };
    74     bool m_waitingOnVMIdle { false };
     54    HashMap<FramesPerSecond, FrameRateData> m_frameRates;
     55    ReducedResolutionSeconds m_timestamp;
    7556};
    7657
  • trunk/Source/WebCore/animation/WebAnimation.cpp

    r289455 r290003  
    631631
    632632    m_effectiveFrameRate = adjustedEffectiveFrameRate;
     633
     634    // FIXME: When the effective frame rate of an animation changes, this could have implications
     635    // on the time until the next animation update is scheduled. We should notify the timeline such
     636    // that it may schedule an update if our update cadence is now longer (or shorter).
    633637}
    634638
  • trunk/Source/WebCore/page/Page.cpp

    r289994 r290003  
    19131913}
    19141914
    1915 std::optional<FramesPerSecond> Page::preferredRenderingUpdateFramesPerSecond() const
    1916 {
    1917     return preferredFramesPerSecond(m_throttlingReasons, m_displayNominalFramesPerSecond, settings().preferPageRenderingUpdatesNear60FPSEnabled());
     1915void Page::timelineControllerMaximumAnimationFrameRateDidChange(DocumentTimelinesController&)
     1916{
     1917    renderingUpdateScheduler().adjustRenderingUpdateFrequency();
     1918}
     1919
     1920std::optional<FramesPerSecond> Page::preferredRenderingUpdateFramesPerSecond(OptionSet<PreferredRenderingUpdateOption> flags) const
     1921{
     1922    // Unless the call site specifies an explicit set of options, this method will account for both
     1923    // throttling reasons and the frame rate of animations to determine its return value. The only
     1924    // place where we specify an explicit set of options is DocumentTimelinesController::updateAnimationsAndSendEvents()
     1925    // where we need to identify what the update frame rate would be _not_ accounting for animations.
     1926
     1927    auto throttlingReasons = m_throttlingReasons;
     1928    if (!flags.contains(PreferredRenderingUpdateOption::IncludeThrottlingReasons))
     1929        throttlingReasons = { };
     1930
     1931    auto frameRate = preferredFramesPerSecond(throttlingReasons, m_displayNominalFramesPerSecond, settings().preferPageRenderingUpdatesNear60FPSEnabled());
     1932    if (!flags.contains(PreferredRenderingUpdateOption::IncludeAnimationsFrameRate))
     1933        return frameRate;
     1934
     1935    // If we're throttled, we do not account for the frame rate set on animations and simply use the throttled frame rate.
     1936    auto unthrottledDefaultFrameRate = preferredRenderingUpdateFramesPerSecond({ });
     1937    auto isThrottled = frameRate && unthrottledDefaultFrameRate && *frameRate < *unthrottledDefaultFrameRate;
     1938    if (isThrottled)
     1939        return frameRate;
     1940
     1941    forEachDocument([&] (Document& document) {
     1942        if (auto* timelinesController = document.timelinesController()) {
     1943            if (auto timelinePreferredFrameRate = timelinesController->maximumAnimationFrameRate()) {
     1944                if (!frameRate || *frameRate < *timelinePreferredFrameRate)
     1945                    frameRate = *timelinePreferredFrameRate;
     1946            }
     1947        }
     1948    });
     1949
     1950    return frameRate;
    19181951}
    19191952
  • trunk/Source/WebCore/page/Page.h

    r289994 r290003  
    5555#include <wtf/HashSet.h>
    5656#include <wtf/Noncopyable.h>
     57#include <wtf/OptionSet.h>
    5758#include <wtf/Ref.h>
    5859#include <wtf/UniqueRef.h>
     
    461462    // preferredRenderingUpdateInterval provides the frequency.
    462463    // FIXME: Have a single function that returns a std::variant<>.
    463     std::optional<FramesPerSecond> preferredRenderingUpdateFramesPerSecond() const;
     464    enum class PreferredRenderingUpdateOption : uint8_t {
     465        IncludeThrottlingReasons    = 1 << 0,
     466        IncludeAnimationsFrameRate  = 1 << 1
     467    };
     468    static constexpr OptionSet<PreferredRenderingUpdateOption> allPreferredRenderingUpdateOptions = { PreferredRenderingUpdateOption::IncludeThrottlingReasons, PreferredRenderingUpdateOption::IncludeAnimationsFrameRate };
     469    std::optional<FramesPerSecond> preferredRenderingUpdateFramesPerSecond(OptionSet<PreferredRenderingUpdateOption> = allPreferredRenderingUpdateOptions) const;
    464470    Seconds preferredRenderingUpdateInterval() const;
    465471
     
    945951    bool isAwaitingLayerTreeTransactionFlush() const { return m_isAwaitingLayerTreeTransactionFlush; }
    946952#endif
     953
     954    void timelineControllerMaximumAnimationFrameRateDidChange(DocumentTimelinesController&);
    947955
    948956private:
Note: See TracChangeset for help on using the changeset viewer.