1faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis/* 2faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * Copyright (C) 2012 The Android Open Source Project 3faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * 4faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * Licensed under the Apache License, Version 2.0 (the "License"); 5faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * you may not use this file except in compliance with the License. 6faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * You may obtain a copy of the License at 7faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * 8faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * http://www.apache.org/licenses/LICENSE-2.0 9faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * 10faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * Unless required by applicable law or agreed to in writing, software 11faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * distributed under the License is distributed on an "AS IS" BASIS, 12faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * See the License for the specific language governing permissions and 14faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis * limitations under the License. 15faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis */ 16faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 17faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis#ifndef ANDROID_DISPSYNC_H 18faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis#define ANDROID_DISPSYNC_H 19faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 20faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis#include <stddef.h> 21faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 22faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis#include <utils/Mutex.h> 23faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis#include <utils/RefBase.h> 2478ce418ea76033a19663dcc0905e0390d21e5bafLloyd Pique#include <utils/Timers.h> 25faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 26fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Anderson#include <ui/FenceTime.h> 27fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Anderson 28fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Anderson#include <memory> 29fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Anderson 30faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennisnamespace android { 31faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 32faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennisclass String8; 33fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Andersonclass FenceTime; 34faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennisclass DispSyncThread; 35faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 36faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// DispSync maintains a model of the periodic hardware-based vsync events of a 37faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// display and uses that model to execute period callbacks at specific phase 38faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// offsets from the hardware vsync events. The model is constructed by 39faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// feeding consecutive hardware event timestamps to the DispSync object via 40faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// the addResyncSample method. 41faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// 42faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// The model is validated using timestamps from Fence objects that are passed 43faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// to the DispSync object via the addPresentFence method. These fence 44faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// timestamps should correspond to a hardware vsync event, but they need not 45faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// be consecutive hardware vsync times. If this method determines that the 46faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// current model accurately represents the hardware event times it will return 47faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// false to indicate that a resynchronization (via addResyncSample) is not 48faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis// needed. 49faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennisclass DispSync { 50faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennispublic: 51e83f93151800f4f7999f7e0c3b727de9267a5f5fLloyd Pique class Callback { 52faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis public: 5378ce418ea76033a19663dcc0905e0390d21e5bafLloyd Pique virtual ~Callback(){}; 54faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis virtual void onDispSyncEvent(nsecs_t when) = 0; 55faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis }; 56faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 57342b760763300593cd20b01dac8cef61e7b25b86Chih-Hung Hsieh explicit DispSync(const char* name); 58faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis ~DispSync(); 59faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 60f41745301d5ecfa680dcef3a1948a8a321f80509Saurabh Shah void init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset); 61f41745301d5ecfa680dcef3a1948a8a321f80509Saurabh Shah 62645b1f7ffb41d21a60765d1ec54ba82f14a36a59Andy McFadden // reset clears the resync samples and error value. 63faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis void reset(); 64faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 65faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // addPresentFence adds a fence for use in validating the current vsync 66faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // event model. The fence need not be signaled at the time 67faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // addPresentFence is called. When the fence does signal, its timestamp 68faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // should correspond to a hardware vsync event. Unlike the 69faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // addResyncSample method, the timestamps of consecutive fences need not 70faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // correspond to consecutive hardware vsync events. 71faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // 72faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // This method should be called with the retire fence from each HWComposer 73faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // set call that affects the display. 74fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Anderson bool addPresentFence(const std::shared_ptr<FenceTime>& fenceTime); 75faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 76faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // The beginResync, addResyncSample, and endResync methods are used to re- 77faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // synchronize the DispSync's model to the hardware vsync events. The re- 78faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // synchronization process involves first calling beginResync, then 79faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // calling addResyncSample with a sequence of consecutive hardware vsync 80faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // event timestamps, and finally calling endResync when addResyncSample 81faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // indicates that no more samples are needed by returning false. 82faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // 83faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // This resynchronization process should be performed whenever the display 84faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // is turned on (i.e. once immediately after it's turned on) and whenever 85faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // addPresentFence returns true indicating that the model has drifted away 86faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // from the hardware vsync events. 87faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis void beginResync(); 88faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis bool addResyncSample(nsecs_t timestamp); 89faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis void endResync(); 90faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 9141d67d7ab4da1c393497a620a116a854b3c618e7Andy McFadden // The setPeriod method sets the vsync event model's period to a specific 92faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // value. This should be used to prime the model when a display is first 93faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // turned on. It should NOT be used after that. 94faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis void setPeriod(nsecs_t period); 95faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 9667d8bd66aaf04805cb8f2616ba964141b865e3b9Lajos Molnar // The getPeriod method returns the current vsync period. 9767d8bd66aaf04805cb8f2616ba964141b865e3b9Lajos Molnar nsecs_t getPeriod(); 9867d8bd66aaf04805cb8f2616ba964141b865e3b9Lajos Molnar 99645b1f7ffb41d21a60765d1ec54ba82f14a36a59Andy McFadden // setRefreshSkipCount specifies an additional number of refresh 100645b1f7ffb41d21a60765d1ec54ba82f14a36a59Andy McFadden // cycles to skip. For example, on a 60Hz display, a skip count of 1 101645b1f7ffb41d21a60765d1ec54ba82f14a36a59Andy McFadden // will result in events happening at 30Hz. Default is zero. The idea 102645b1f7ffb41d21a60765d1ec54ba82f14a36a59Andy McFadden // is to sacrifice smoothness for battery life. 103645b1f7ffb41d21a60765d1ec54ba82f14a36a59Andy McFadden void setRefreshSkipCount(int count); 104f52b3c88f18c0546526996c839fbce74172e11c7Ruchi Kandoi 105faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // addEventListener registers a callback to be called repeatedly at the 106faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // given phase offset from the hardware vsync events. The callback is 107faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // called from a separate thread and it should return reasonably quickly 108faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // (i.e. within a few hundred microseconds). 109e83f93151800f4f7999f7e0c3b727de9267a5f5fLloyd Pique status_t addEventListener(const char* name, nsecs_t phase, Callback* callback); 110faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 111faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // removeEventListener removes an already-registered event callback. Once 112faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // this method returns that callback will no longer be called by the 113faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // DispSync object. 114e83f93151800f4f7999f7e0c3b727de9267a5f5fLloyd Pique status_t removeEventListener(Callback* callback); 115faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 1162713c30843816d3511b39b85a2c268a2b7682047Dan Stoza // changePhaseOffset changes the phase offset of an already-registered event callback. The 1172713c30843816d3511b39b85a2c268a2b7682047Dan Stoza // method will make sure that there is no skipping or double-firing on the listener per frame, 1182713c30843816d3511b39b85a2c268a2b7682047Dan Stoza // even when changing the offsets multiple times. 1192713c30843816d3511b39b85a2c268a2b7682047Dan Stoza status_t changePhaseOffset(Callback* callback, nsecs_t phase); 1202713c30843816d3511b39b85a2c268a2b7682047Dan Stoza 12141d67d7ab4da1c393497a620a116a854b3c618e7Andy McFadden // computeNextRefresh computes when the next refresh is expected to begin. 12241d67d7ab4da1c393497a620a116a854b3c618e7Andy McFadden // The periodOffset value can be used to move forward or backward; an 12341d67d7ab4da1c393497a620a116a854b3c618e7Andy McFadden // offset of zero is the next refresh, -1 is the previous refresh, 1 is 12441d67d7ab4da1c393497a620a116a854b3c618e7Andy McFadden // the refresh after next. etc. 12541d67d7ab4da1c393497a620a116a854b3c618e7Andy McFadden nsecs_t computeNextRefresh(int periodOffset) const; 12641d67d7ab4da1c393497a620a116a854b3c618e7Andy McFadden 127c751e92c56de5f335a36e68607c7a6c627dcd0dcAndy McFadden // dump appends human-readable debug info to the result string. 128c751e92c56de5f335a36e68607c7a6c627dcd0dcAndy McFadden void dump(String8& result) const; 129c751e92c56de5f335a36e68607c7a6c627dcd0dcAndy McFadden 130faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennisprivate: 131faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis void updateModelLocked(); 132faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis void updateErrorLocked(); 133faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis void resetErrorLocked(); 134faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 135faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis enum { MAX_RESYNC_SAMPLES = 32 }; 1364a4e4a239f034cb8af2df9a438b26c3bc088889cTim Murray enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 6 }; 137faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis enum { NUM_PRESENT_SAMPLES = 8 }; 138ef78916d86fa60e08a6358af4b0b1f6bd0134164Dan Stoza enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 }; 139fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Anderson enum { ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT = 64 }; 140faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 1414a4e4a239f034cb8af2df9a438b26c3bc088889cTim Murray const char* const mName; 1424a4e4a239f034cb8af2df9a438b26c3bc088889cTim Murray 143faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // mPeriod is the computed period of the modeled vsync events in 144faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // nanoseconds. 145faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis nsecs_t mPeriod; 146faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 147faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // mPhase is the phase offset of the modeled vsync events. It is the 148faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // number of nanoseconds from time 0 to the first vsync event. 149faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis nsecs_t mPhase; 150faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 151676b1f6ed0d637b7eb1858361e0d09068f26e9faHaixia Shi // mReferenceTime is the reference time of the modeled vsync events. 152676b1f6ed0d637b7eb1858361e0d09068f26e9faHaixia Shi // It is the nanosecond timestamp of the first vsync event after a resync. 153676b1f6ed0d637b7eb1858361e0d09068f26e9faHaixia Shi nsecs_t mReferenceTime; 154676b1f6ed0d637b7eb1858361e0d09068f26e9faHaixia Shi 155faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // mError is the computed model error. It is based on the difference 156faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // between the estimated vsync event times and those observed in the 157fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Anderson // mPresentFences array. 158faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis nsecs_t mError; 159faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 160fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Anderson // mZeroErrSamplesCount keeps track of how many times in a row there were 161fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Anderson // zero timestamps available in the mPresentFences array. 162fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Anderson // Used to sanity check that we are able to calculate the model error. 163fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Anderson size_t mZeroErrSamplesCount; 164fbc80aef0ba1b11982cf4ca88d218b65b6eca0f3Brian Anderson 165676b1f6ed0d637b7eb1858361e0d09068f26e9faHaixia Shi // Whether we have updated the vsync event model since the last resync. 166676b1f6ed0d637b7eb1858361e0d09068f26e9faHaixia Shi bool mModelUpdated; 167676b1f6ed0d637b7eb1858361e0d09068f26e9faHaixia Shi 168faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // These member variables are the state used during the resynchronization 169faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // process to store information about the hardware vsync event times used 170faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // to compute the model. 171faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES]; 172faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis size_t mFirstResyncSample; 173faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis size_t mNumResyncSamples; 174faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis int mNumResyncSamplesSincePresent; 175faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 176faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // These member variables store information about the present fences used 177faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // to validate the currently computed model. 17878ce418ea76033a19663dcc0905e0390d21e5bafLloyd Pique std::shared_ptr<FenceTime> mPresentFences[NUM_PRESENT_SAMPLES]{FenceTime::NO_FENCE}; 179faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis size_t mPresentSampleOffset; 180faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 181645b1f7ffb41d21a60765d1ec54ba82f14a36a59Andy McFadden int mRefreshSkipCount; 182645b1f7ffb41d21a60765d1ec54ba82f14a36a59Andy McFadden 183faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // mThread is the thread from which all the callbacks are called. 184faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis sp<DispSyncThread> mThread; 185faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 186faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis // mMutex is used to protect access to all member variables. 187faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis mutable Mutex mMutex; 188c45a7d9dfdefa07512c5acc07bcbee5362b34e3dFabien Sanglard 189c45a7d9dfdefa07512c5acc07bcbee5362b34e3dFabien Sanglard // This is the offset from the present fence timestamps to the corresponding 190c45a7d9dfdefa07512c5acc07bcbee5362b34e3dFabien Sanglard // vsync event. 191c45a7d9dfdefa07512c5acc07bcbee5362b34e3dFabien Sanglard int64_t mPresentTimeOffset; 192cbf153bedf2eafc1443bbc97c4e74f97e7973eddFabien Sanglard 193cbf153bedf2eafc1443bbc97c4e74f97e7973eddFabien Sanglard // Ignore present (retire) fences if the device doesn't have support for the 194cbf153bedf2eafc1443bbc97c4e74f97e7973eddFabien Sanglard // sync framework 195cbf153bedf2eafc1443bbc97c4e74f97e7973eddFabien Sanglard bool mIgnorePresentFences; 196e83f93151800f4f7999f7e0c3b727de9267a5f5fLloyd Pique 197e83f93151800f4f7999f7e0c3b727de9267a5f5fLloyd Pique std::unique_ptr<Callback> mZeroPhaseTracer; 198faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis}; 199faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 20078ce418ea76033a19663dcc0905e0390d21e5bafLloyd Pique} // namespace android 201faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis 202faf77cce9d9ec0238d6999b3bd0d40c71ff403c5Jamie Gennis#endif // ANDROID_DISPSYNC_H 203