1 // Copyright (C) 2015 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
15 #include "host-common/opengl/GpuFrameBridge.h"
16
17 #include <stdio.h> // for printf
18 #include <stdlib.h> // for NULL, free, malloc
19 #include <string.h> // for memcpy
20
21 #include <atomic> // for atomic_bool, memory_o...
22 #include <memory> // for unique_ptr
23
24 #include "aemu/base/synchronization/Lock.h" // for Lock, AutoLock
25 #include "aemu/base/synchronization/MessageChannel.h"
26 #include "host-common/opengles.h" // for android_getFlushReadP...
27
28 #ifdef _WIN32
29 #undef ERROR
30 #endif
31
32 namespace android {
33 namespace opengl {
34
35 using android::base::AutoLock;
36 using android::base::Lock;
37 using android::base::MessageChannel;
38
39 namespace {
40
41 // A small structure to model a single frame of the GPU display,
42 // as passed between the EmuGL and main loop thread.
43 struct Frame {
44 int width;
45 int height;
46 void* pixels;
47 bool isValid;
48
Frameandroid::opengl::__anond2002f030111::Frame49 Frame(int w, int h, const void* pixels)
50 : width(w), height(h), pixels(NULL), isValid(true) {
51 this->pixels = ::malloc(w * 4 * h);
52 }
53
~Frameandroid::opengl::__anond2002f030111::Frame54 ~Frame() { ::free(pixels); }
55 };
56
57 // Real implementation of GpuFrameBridge interface.
58 class Bridge : public GpuFrameBridge {
59 public:
60 // Constructor.
Bridge()61 Bridge()
62 : GpuFrameBridge(),
63 mRecFrame(NULL),
64 mRecTmpFrame(NULL),
65 mRecFrameUpdated(false),
66 mReadPixelsFunc(android_getReadPixelsFunc()),
67 mFlushPixelPipeline(android_getFlushReadPixelPipeline()) {}
68
69 // The gpu bridge receives frames from a buffer that can contain multiple
70 // frames. usually the bridge is one frame behind. This is usually not a
71 // problem when we have a high enough framerate. However it is possible that
72 // the framerate drops really low (even <1). This can result in the bridge
73 // never delivering this "stuck frame".
74 //
75 // As a work around we will flush the reader pipeline if no frames are
76 // delivered within at most 2x kFrameDelayms
77 const long kMinFPS = 24;
78 const long kFrameDelayMs = 1000 / kMinFPS;
79
80 // Destructor
~Bridge()81 virtual ~Bridge() {
82 if (mRecFrame) {
83 delete mRecFrame;
84 }
85 if (mRecTmpFrame) {
86 delete mRecTmpFrame;
87 }
88 }
89
90 // virtual void setLooper(android::base::Looper* aLooper) override {
91 // mTimer = std::unique_ptr<android::base::Looper::Timer>(
92 // aLooper->createTimer(_on_frame_notify, this));
93 // }
94
notify()95 void notify() {
96 AutoLock delay(mDelayLock);
97 switch (mDelayCallback) {
98 case FrameDelay::Reschedule:
99 // mTimer->startRelative(kFrameDelayMs);
100 mDelayCallback = FrameDelay::Scheduled;
101 break;
102 case FrameDelay::Scheduled:
103 // mTimer->stop();
104 mDelayCallback = FrameDelay::Firing;
105 delay.unlock();
106 mFlushPixelPipeline(mDisplayId);
107 break;
108 default:
109 assert(false);
110 }
111 }
112
113 // static void _on_frame_notify(void* opaque,
114 // android::base::Looper::Timer* timer) {
115 // Bridge* worker = static_cast<Bridge*>(opaque);
116 // worker->notify();
117 // }
118
119 // Implementation of the GpuFrameBridge::postRecordFrame() method, must be
120 // called from the EmuGL thread.
postRecordFrame(int width,int height,const void * pixels)121 virtual void postRecordFrame(int width,
122 int height,
123 const void* pixels) override {
124 postFrame(width, height, pixels, true);
125 }
126
postRecordFrameAsync(int width,int height,const void * pixels)127 virtual void postRecordFrameAsync(int width,
128 int height,
129 const void* pixels) override {
130 postFrame(width, height, pixels, false);
131 }
132
getRecordFrame()133 virtual void* getRecordFrame() override {
134 if (mRecFrameUpdated.exchange(false)) {
135 AutoLock lock(mRecLock);
136 memcpy(mRecFrame->pixels, mRecTmpFrame->pixels,
137 mRecFrame->width * mRecFrame->height * 4);
138 mRecFrame->isValid = true;
139 }
140 return mRecFrame && mRecFrame->isValid ? mRecFrame->pixels : nullptr;
141 }
142
getRecordFrameAsync()143 virtual void* getRecordFrameAsync() override {
144 if (mRecFrameUpdated.exchange(false)) {
145 AutoLock lock(mRecLock);
146 mReadPixelsFunc(mRecFrame->pixels,
147 mRecFrame->width * mRecFrame->height * 4,
148 mDisplayId);
149 mRecFrame->isValid = true;
150 }
151 return mRecFrame && mRecFrame->isValid ? mRecFrame->pixels : nullptr;
152 }
153
invalidateRecordingBuffers()154 virtual void invalidateRecordingBuffers() override {
155 {
156 AutoLock lock(mRecLock);
157 // Release the buffers because new recording in the furture may have
158 // different resolution if multi display changes its resolution.
159 if (mRecFrame) {
160 delete mRecFrame;
161 mRecFrame = nullptr;
162 }
163 if (mRecTmpFrame) {
164 delete mRecTmpFrame;
165 mRecTmpFrame = nullptr;
166 }
167 }
168 mRecFrameUpdated.store(false, std::memory_order_release);
169 }
170
setFrameReceiver(FrameAvailableCallback receiver,void * opaque)171 void setFrameReceiver(FrameAvailableCallback receiver,
172 void* opaque) override {
173 mReceiver = receiver;
174 mReceiverOpaque = opaque;
175 }
176
postFrame(int width,int height,const void * pixels,bool copy)177 void postFrame(int width, int height, const void* pixels, bool copy) {
178 {
179 AutoLock lock(mRecLock);
180 if (!mRecFrame) {
181 mRecFrame = new Frame(width, height, pixels);
182 }
183 if (!mRecTmpFrame) {
184 mRecTmpFrame = new Frame(width, height, pixels);
185 }
186 if (copy) {
187 memcpy(mRecTmpFrame->pixels, pixels, width * height * 4);
188 }
189 }
190 mRecFrameUpdated.store(true, std::memory_order_release);
191 if (mReceiver) {
192 mReceiver(mReceiverOpaque);
193 AutoLock delay(mDelayLock);
194 switch (mDelayCallback) {
195 case FrameDelay::NotScheduled:
196 // mTimer->startRelative(kFrameDelayMs);
197 mDelayCallback = FrameDelay::Scheduled;
198 break;
199 case FrameDelay::Firing:
200 mDelayCallback = FrameDelay::NotScheduled;
201 break;
202 default:
203 mDelayCallback = FrameDelay::Reschedule;
204 break;
205 }
206 }
207 }
208
setDisplayId(uint32_t displayId)209 virtual void setDisplayId(uint32_t displayId) override {
210 mDisplayId = displayId;
211 }
212 enum class FrameDelay {
213 NotScheduled = 0, // No delay timer is scheduled
214 Scheduled, // A delay timer has been scheduled and will flush the
215 // pipeline on expiration
216 Reschedule, // Do not flush the pipeline, but reschedule
217 Firing, // A callback has been scheduled, nothing needs to happen
218 };
219
220 private:
221 FrameAvailableCallback mReceiver = nullptr;
222 void* mReceiverOpaque = nullptr;
223 Lock mRecLock;
224 Frame* mRecFrame;
225 Frame* mRecTmpFrame;
226 std::atomic_bool mRecFrameUpdated;
227 ReadPixelsFunc mReadPixelsFunc = 0;
228 uint32_t mDisplayId = 0;
229 FlushReadPixelPipeline mFlushPixelPipeline = 0;
230
231 // std::unique_ptr<android::base::Looper::Timer> mTimer;
232 Lock mDelayLock;
233 FrameDelay mDelayCallback{FrameDelay::NotScheduled};
234 };
235 } // namespace
236 // static
create()237 GpuFrameBridge* GpuFrameBridge::create() {
238 return new Bridge();
239 }
240
241 } // namespace opengl
242 } // namespace android
243