• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "EmulatedEglFenceSync.h"
17 
18 #include <unordered_set>
19 
20 #include "OpenGLESDispatch/DispatchTables.h"
21 #include "OpenGLESDispatch/EGLDispatch.h"
22 #include "RenderThreadInfoGl.h"
23 #include "StalePtrRegistry.h"
24 #include "aemu/base/containers/Lookup.h"
25 #include "aemu/base/containers/StaticMap.h"
26 #include "aemu/base/files/StreamSerializing.h"
27 #include "aemu/base/synchronization/Lock.h"
28 
29 namespace gfxstream {
30 namespace gl {
31 namespace {
32 
33 using android::base::AutoLock;
34 using android::base::Lock;
35 using android::base::StaticMap;
36 
37 // Timeline class is meant to delete native fences after the
38 // sync device has incremented the timeline.  We assume a
39 // maximum number of outstanding timelines in the guest (16) in
40 // order to derive when a native fence is definitely safe to
41 // delete. After at least that many timeline increments have
42 // happened, we sweep away the remaining native fences.
43 // The function that performs the deleting,
44 // incrementTimelineAndDeleteOldFences(), happens on the SyncThread.
45 
46 class Timeline {
47   public:
48     Timeline() = default;
49 
50     static constexpr int kMaxGuestTimelines = 16;
addFence(EmulatedEglFenceSync * fence)51     void addFence(EmulatedEglFenceSync* fence) {
52         mFences.set(fence, mTime.load() + kMaxGuestTimelines);
53     }
54 
incrementTimelineAndDeleteOldFences()55     void incrementTimelineAndDeleteOldFences() {
56         ++mTime;
57         sweep();
58     }
59 
sweep()60     void sweep() {
61         mFences.eraseIf([time = mTime.load()](EmulatedEglFenceSync* fence, int fenceTime) {
62             EmulatedEglFenceSync* actual = EmulatedEglFenceSync::getFromHandle((uint64_t)(uintptr_t)fence);
63             if (!actual) return true;
64 
65             bool shouldErase = fenceTime <= time;
66             if (shouldErase) {
67                 if (!actual->decRef() &&
68                     actual->shouldDestroyWhenSignaled()) {
69                     actual->decRef();
70                 }
71             }
72             return shouldErase;
73         });
74     }
75 
76   private:
77     std::atomic<int> mTime {0};
78     StaticMap<EmulatedEglFenceSync*, int> mFences;
79 };
80 
sTimeline()81 static Timeline* sTimeline() {
82     static Timeline* t = new Timeline;
83     return t;
84 }
85 
86 }  // namespace
87 
88 // static
incrementTimelineAndDeleteOldFences()89 void EmulatedEglFenceSync::incrementTimelineAndDeleteOldFences() {
90     sTimeline()->incrementTimelineAndDeleteOldFences();
91 }
92 
93 // static
create(EGLDisplay display,bool hasNativeFence,bool destroyWhenSignaled)94 std::unique_ptr<EmulatedEglFenceSync> EmulatedEglFenceSync::create(
95         EGLDisplay display,
96         bool hasNativeFence,
97         bool destroyWhenSignaled) {
98     auto sync = s_egl.eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
99     if (sync == EGL_NO_SYNC_KHR) {
100         ERR("Failed to create EGL fence sync: %d", s_egl.eglGetError());
101         return nullptr;
102     }
103 
104     // This MUST be present, or we get a deadlock effect.
105     s_gles2.glFlush();
106 
107     return std::unique_ptr<EmulatedEglFenceSync>(
108         new EmulatedEglFenceSync(display,
109                                  sync,
110                                  hasNativeFence,
111                                  destroyWhenSignaled));
112 }
113 
EmulatedEglFenceSync(EGLDisplay display,EGLSyncKHR sync,bool hasNativeFence,bool destroyWhenSignaled)114 EmulatedEglFenceSync::EmulatedEglFenceSync(EGLDisplay display,
115                                            EGLSyncKHR sync,
116                                            bool hasNativeFence,
117                                            bool destroyWhenSignaled)
118     : mDestroyWhenSignaled(destroyWhenSignaled),
119       mDisplay(display),
120       mSync(sync) {
121 
122     addToRegistry();
123 
124     assert(mCount == 1);
125     if (hasNativeFence) {
126         incRef();
127         sTimeline()->addFence(this);
128     }
129 
130     // Assumes that there is a valid + current OpenGL context
131     assert(RenderThreadInfoGl::get());
132 }
133 
~EmulatedEglFenceSync()134 EmulatedEglFenceSync::~EmulatedEglFenceSync() {
135     removeFromRegistry();
136 }
137 
wait(uint64_t timeout)138 EGLint EmulatedEglFenceSync::wait(uint64_t timeout) {
139     incRef();
140     EGLint wait_res =
141         s_egl.eglClientWaitSyncKHR(mDisplay, mSync,
142                                    EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
143                                    timeout);
144     decRef();
145     return wait_res;
146 }
147 
waitAsync()148 void EmulatedEglFenceSync::waitAsync() {
149     s_egl.eglWaitSyncKHR(mDisplay, mSync, 0);
150 }
151 
isSignaled()152 bool EmulatedEglFenceSync::isSignaled() {
153     EGLint val;
154     if (EGL_TRUE ==
155             s_egl.eglGetSyncAttribKHR(
156                 mDisplay, mSync, EGL_SYNC_STATUS_KHR, &val))
157         return val == EGL_SIGNALED_KHR;
158 
159     return true; // if invalid, treat as signaled
160 }
161 
destroy()162 void EmulatedEglFenceSync::destroy() {
163     s_egl.eglDestroySyncKHR(mDisplay, mSync);
164 }
165 
166 // Snapshots for EmulatedEglFenceSync//////////////////////////////////////////////////////
167 // It's possible, though it does not happen often, that a fence
168 // can be created but not yet waited on by the guest, which
169 // needs careful handling:
170 //
171 // 1. Avoid manipulating garbage memory on snapshot restore;
172 // rcCreateSyncKHR *creates new fence in valid memory*
173 // --snapshot--
174 // rcClientWaitSyncKHR *refers to uninitialized memory*
175 // rcDestroySyncKHR *refers to uninitialized memory*
176 // 2. Make rcCreateSyncKHR/rcDestroySyncKHR implementations return
177 // the "signaled" status if referring to previous snapshot fences. It's
178 // assumed that the GPU is long done with them.
179 // 3. Avoid name collisions where a new EmulatedEglFenceSync object is created
180 // that has the same uint64_t casting as a EmulatedEglFenceSync object from a previous
181 // snapshot.
182 
183 // Maintain a StalePtrRegistry<EmulatedEglFenceSync>:
sFenceRegistry()184 static StalePtrRegistry<EmulatedEglFenceSync>* sFenceRegistry() {
185     static StalePtrRegistry<EmulatedEglFenceSync>* s = new StalePtrRegistry<EmulatedEglFenceSync>;
186     return s;
187 }
188 
189 // static
addToRegistry()190 void EmulatedEglFenceSync::addToRegistry() {
191     sFenceRegistry()->addPtr(this);
192 }
193 
194 // static
removeFromRegistry()195 void EmulatedEglFenceSync::removeFromRegistry() {
196     sFenceRegistry()->removePtr(this);
197 }
198 
199 // static
onSave(android::base::Stream * stream)200 void EmulatedEglFenceSync::onSave(android::base::Stream* stream) {
201     sFenceRegistry()->makeCurrentPtrsStale();
202     sFenceRegistry()->onSave(stream);
203 }
204 
205 // static
onLoad(android::base::Stream * stream)206 void EmulatedEglFenceSync::onLoad(android::base::Stream* stream) {
207     sFenceRegistry()->onLoad(stream);
208 }
209 
210 // static
getFromHandle(uint64_t handle)211 EmulatedEglFenceSync* EmulatedEglFenceSync::getFromHandle(uint64_t handle) {
212     return sFenceRegistry()->getPtr(handle);
213 }
214 
215 }  // namespace gl
216 }  // namespace gfxstream
217