/* * Copyright (C) 2018 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once namespace WebCore { // This class is used to detect when we are painting frequently so that - even in a painting model // without display lists - we can build and cache portions of display lists and reuse them only when // animating. Once we transition fully to display lists, we can probably just pull from the previous // paint's display list if it is still around and get rid of this code. class PaintFrequencyTracker { WTF_MAKE_FAST_ALLOCATED; public: PaintFrequencyTracker() = default; void begin(MonotonicTime timestamp) { static unsigned paintFrequencyPaintCountThreshold = 30; static Seconds paintFrequencyTimePerFrameThreshold = 32_ms; static Seconds paintFrequencySecondsIdleThreshold = 5_s; // Start by assuming the paint frequency is low m_paintFrequency = PaintFrequency::Low; if (!m_firstPaintTime) { // Handle the first time this method is called. m_firstPaintTime = timestamp; } else if (timestamp - m_lastPaintTime > paintFrequencySecondsIdleThreshold) { // It has been 5 seconds since last time we draw this renderer. Reset the state // of this object as if, we've just started tracking the paint frequency. m_firstPaintTime = timestamp; m_totalPaints = 0; } else if (m_totalPaints >= paintFrequencyPaintCountThreshold && ((m_lastPaintTime - m_firstPaintTime) / m_totalPaints) <= paintFrequencyTimePerFrameThreshold) { // Change the paint frequency to be high only if: // - This renderer has been painted at least 30 times. // - The frame rate to paint this renderer has been at least 31.25 FPS. m_paintFrequency = PaintFrequency::High; } m_lastPaintTime = timestamp; ++m_totalPaints; } void end() { ASSERT(m_firstPaintTime); ASSERT(m_firstPaintTime <= m_lastPaintTime); } bool paintingFrequently() const { return m_paintFrequency == PaintFrequency::High; } private: MonotonicTime m_firstPaintTime; MonotonicTime m_lastPaintTime; unsigned m_totalPaints { 0 }; enum class PaintFrequency : bool { Low, High }; PaintFrequency m_paintFrequency { PaintFrequency::Low }; }; class SinglePaintFrequencyTracking { WTF_MAKE_FAST_ALLOCATED; public: SinglePaintFrequencyTracking(PaintFrequencyTracker& paintFrequencyTracker, MonotonicTime timestamp) : m_paintFrequencyTracker(paintFrequencyTracker) { m_paintFrequencyTracker.begin(timestamp ? timestamp : MonotonicTime::now()); } ~SinglePaintFrequencyTracking() { m_paintFrequencyTracker.end(); } private: PaintFrequencyTracker& m_paintFrequencyTracker; }; }