• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "Vsync.h"
15 
16 #include "base/ConditionVariable.h"
17 #include "base/Lock.h"
18 #include "base/System.h"
19 #include "base/FunctorThread.h"
20 
21 #include <atomic>
22 #include <memory>
23 
24 using android::base::AutoLock;
25 using android::base::ConditionVariable;
26 using android::base::FunctorThread;
27 using android::base::Lock;
28 
29 namespace aemu {
30 
31 class Vsync::Impl {
32 public:
Impl(Callback callback,int refreshRate=60)33     Impl(Callback callback, int refreshRate = 60)
34         : mCallback(std::move(callback)),
35           mRefreshRate(refreshRate),
36           mRefreshIntervalUs(1000000ULL / mRefreshRate),
37           mThread([this] {
38 
39               mNowUs = android::base::getHighResTimeUs();
40               mNextVsyncDeadlineUs = mNowUs + mRefreshIntervalUs;
41 
42               while (true) {
43                   if (mShouldStop.load(std::memory_order_relaxed))
44                       return 0;
45 
46                   mNowUs = android::base::getHighResTimeUs();
47 
48                   if (mNextVsyncDeadlineUs > mNowUs) {
49                     android::base::sleepUs(mNextVsyncDeadlineUs - mNowUs);
50                   }
51 
52                   mNowUs = android::base::getHighResTimeUs();
53                   mNextVsyncDeadlineUs = mNowUs + mRefreshIntervalUs;
54 
55                   AutoLock lock(mLock);
56                   mSync = 1;
57                   mCv.signal();
58                   mCallback();
59               }
60               return 0;
61           }) {
62     }
63 
start()64     void start() {
65         mShouldStop.store(false, std::memory_order_relaxed);
66         mThread.start();
67     }
68 
join()69     void join() {
70         mShouldStop.store(true, std::memory_order_relaxed);
71         mThread.wait();
72     }
73 
~Impl()74     ~Impl() { join(); }
75 
waitUntilNextVsync()76     void waitUntilNextVsync() {
77         AutoLock lock(mLock);
78         mSync = 0;
79         while (!mSync) {
80             mCv.wait(&mLock);
81         }
82     }
83 
84 private:
85     std::atomic<bool> mShouldStop { false };
86     int mSync = 0;
87     Lock mLock;
88     ConditionVariable mCv;
89 
90     Callback mCallback;
91     int mRefreshRate = 60;
92     uint64_t mRefreshIntervalUs;
93     uint64_t mNowUs = 0;
94     uint64_t mNextVsyncDeadlineUs = 0;
95     FunctorThread mThread;
96 };
97 
Vsync(int refreshRate,Vsync::Callback callback)98 Vsync::Vsync(int refreshRate, Vsync::Callback callback)
99     : mImpl(new Vsync::Impl(std::move(callback), refreshRate)) {}
100 
101 Vsync::~Vsync() = default;
102 
start()103 void Vsync::start() { mImpl->start(); }
join()104 void Vsync::join() { mImpl->join(); }
105 
waitUntilNextVsync()106 void Vsync::waitUntilNextVsync() {
107     mImpl->waitUntilNextVsync();
108 }
109 
110 } // namespace aemu
111