1/* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#ifndef DisplayRefreshMonitor_h 27#define DisplayRefreshMonitor_h 28 29#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) 30 31#include "PlatformScreen.h" 32#include <wtf/HashMap.h> 33#include <wtf/HashSet.h> 34#include <wtf/RefCounted.h> 35#include <wtf/RefPtr.h> 36#include <wtf/Threading.h> 37#if PLATFORM(BLACKBERRY) 38#include <BlackBerryPlatformAnimationFrameRateController.h> 39#endif 40 41#if PLATFORM(MAC) 42typedef struct __CVDisplayLink *CVDisplayLinkRef; 43#endif 44 45namespace WebCore { 46 47class DisplayAnimationClient; 48class DisplayRefreshMonitor; 49class DisplayRefreshMonitorManager; 50 51// 52// Abstract virtual client which receives refresh fired messages on the main thread 53// 54class DisplayRefreshMonitorClient { 55 friend class DisplayRefreshMonitor; 56 friend class DisplayRefreshMonitorManager; 57 58public: 59 DisplayRefreshMonitorClient(); 60 virtual ~DisplayRefreshMonitorClient(); 61 62 virtual void displayRefreshFired(double timestamp) = 0; 63 64private: 65 void fireDisplayRefreshIfNeeded(double timestamp); 66 67 void setDisplayID(PlatformDisplayID displayID) 68 { 69 m_displayID = displayID; 70 m_displayIDIsSet = true; 71 } 72 73 bool m_scheduled; 74 bool m_displayIDIsSet; 75 PlatformDisplayID m_displayID; 76}; 77 78// 79// Monitor for display refresh messages for a given screen 80// 81 82class DisplayRefreshMonitor : public RefCounted<DisplayRefreshMonitor> { 83public: 84 static PassRefPtr<DisplayRefreshMonitor> create(PlatformDisplayID displayID) 85 { 86 return adoptRef(new DisplayRefreshMonitor(displayID)); 87 } 88 89 ~DisplayRefreshMonitor(); 90 91 // Return true if callback request was scheduled, false if it couldn't be 92 // (e.g., hardware refresh is not available) 93 bool requestRefreshCallback(); 94 void windowScreenDidChange(PlatformDisplayID); 95 96 bool hasClients() const { return m_clients.size(); } 97 void addClient(DisplayRefreshMonitorClient*); 98 bool removeClient(DisplayRefreshMonitorClient*); 99 100 PlatformDisplayID displayID() const { return m_displayID; } 101 102 bool shouldBeTerminated() const 103 { 104 const int maxInactiveFireCount = 10; 105 return !m_scheduled && m_unscheduledFireCount > maxInactiveFireCount; 106 } 107 108private: 109 explicit DisplayRefreshMonitor(PlatformDisplayID); 110 111 void displayDidRefresh(); 112 static void handleDisplayRefreshedNotificationOnMainThread(void* data); 113 114 double m_monotonicAnimationStartTime; 115 bool m_active; 116 bool m_scheduled; 117 bool m_previousFrameDone; 118 int m_unscheduledFireCount; // Number of times the display link has fired with no clients. 119 PlatformDisplayID m_displayID; 120 Mutex m_mutex; 121 122 HashSet<DisplayRefreshMonitorClient*> m_clients; 123 HashSet<DisplayRefreshMonitorClient*>* m_clientsToBeNotified; 124 125#if PLATFORM(BLACKBERRY) 126public: 127 void displayLinkFired(); 128private: 129 DisplayAnimationClient *m_animationClient; 130 void startAnimationClient(); 131 void stopAnimationClient(); 132#endif 133 134#if PLATFORM(MAC) 135public: 136 void displayLinkFired(double nowSeconds, double outputTimeSeconds); 137private: 138 CVDisplayLinkRef m_displayLink; 139#endif 140}; 141 142// 143// Singleton manager for all the DisplayRefreshMonitors. This is the interface to the 144// outside world. It distributes requests to the appropriate monitor. When the display 145// refresh event fires, the passed DisplayRefreshMonitorClient is called directly on 146// the main thread. 147// 148class DisplayRefreshMonitorManager { 149public: 150 static DisplayRefreshMonitorManager* sharedManager(); 151 152 void registerClient(DisplayRefreshMonitorClient*); 153 void unregisterClient(DisplayRefreshMonitorClient*); 154 155 bool scheduleAnimation(DisplayRefreshMonitorClient*); 156 void windowScreenDidChange(PlatformDisplayID, DisplayRefreshMonitorClient*); 157 158private: 159 friend class DisplayRefreshMonitor; 160 void displayDidRefresh(DisplayRefreshMonitor*); 161 162 DisplayRefreshMonitorManager() { } 163 DisplayRefreshMonitor* ensureMonitorForClient(DisplayRefreshMonitorClient*); 164 165 // We know nothing about the values of PlatformDisplayIDs, so use UnsignedWithZeroKeyHashTraits. 166 // FIXME: Since we know nothing about these values, this is not sufficient. 167 // Even with UnsignedWithZeroKeyHashTraits, there are still two special values used for empty and deleted hash table slots. 168 typedef HashMap<uint64_t, RefPtr<DisplayRefreshMonitor>, WTF::IntHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>> DisplayRefreshMonitorMap; 169 DisplayRefreshMonitorMap m_monitors; 170}; 171 172} 173 174#endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) 175 176#endif 177