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