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