• 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 
17 #include "FenceSync.h"
18 
19 #include "DispatchTables.h"
20 #include "FrameBuffer.h"
21 #include "OpenGLESDispatch/EGLDispatch.h"
22 #include "RenderThreadInfo.h"
23 #include "StalePtrRegistry.h"
24 
25 #include "base/Lookup.h"
26 #include "base/StaticMap.h"
27 #include "base/StreamSerializing.h"
28 #include "base/Lock.h"
29 
30 #include <unordered_set>
31 
32 using android::base::AutoLock;
33 using android::base::Lock;
34 using android::base::StaticMap;
35 
36 // Timeline class is meant to delete native fences after the
37 // sync device has incremented the timeline.  We assume a
38 // maximum number of outstanding timelines in the guest (16) in
39 // order to derive when a native fence is definitely safe to
40 // delete. After at least that many timeline increments have
41 // happened, we sweep away the remaining native fences.
42 // The function that performs the deleting,
43 // incrementTimelineAndDeleteOldFences(), happens on the SyncThread.
44 
45 class Timeline {
46 public:
47     Timeline() = default;
48 
49     static constexpr int kMaxGuestTimelines = 16;
addFence(FenceSync * fence)50     void addFence(FenceSync* fence) {
51         mFences.set(fence, mTime.load() + kMaxGuestTimelines);
52     }
53 
incrementTimelineAndDeleteOldFences()54     void incrementTimelineAndDeleteOldFences() {
55         ++mTime;
56         sweep();
57     }
58 
sweep()59     void sweep() {
60         mFences.eraseIf([time = mTime.load()](FenceSync* fence, int fenceTime) {
61             FenceSync* actual = FenceSync::getFromHandle((uint64_t)(uintptr_t)fence);
62             if (!actual) return true;
63 
64             bool shouldErase = fenceTime <= time;
65             if (shouldErase) {
66                 if (!actual->decRef() &&
67                     actual->shouldDestroyWhenSignaled()) {
68                     actual->decRef();
69                 }
70             }
71             return shouldErase;
72         });
73     }
74 
75 private:
76     std::atomic<int> mTime {0};
77     StaticMap<FenceSync*, int> mFences;
78 };
79 
sTimeline()80 static Timeline* sTimeline() {
81     static Timeline* t = new Timeline;
82     return t;
83 }
84 
85 // static
incrementTimelineAndDeleteOldFences()86 void FenceSync::incrementTimelineAndDeleteOldFences() {
87     sTimeline()->incrementTimelineAndDeleteOldFences();
88 }
89 
FenceSync(bool hasNativeFence,bool destroyWhenSignaled)90 FenceSync::FenceSync(bool hasNativeFence,
91                      bool destroyWhenSignaled) :
92     mDestroyWhenSignaled(destroyWhenSignaled) {
93 
94     addToRegistry();
95 
96     assert(mCount == 1);
97     if (hasNativeFence) {
98         incRef();
99         sTimeline()->addFence(this);
100     }
101 
102     // assumes that there is a valid + current OpenGL context
103     assert(RenderThreadInfo::get());
104 
105     mDisplay = FrameBuffer::getFB()->getDisplay();
106     mSync = s_egl.eglCreateSyncKHR(mDisplay,
107                                    EGL_SYNC_FENCE_KHR,
108                                    NULL);
109 }
110 
~FenceSync()111 FenceSync::~FenceSync() {
112     removeFromRegistry();
113 }
114 
wait(uint64_t timeout)115 EGLint FenceSync::wait(uint64_t timeout) {
116     incRef();
117     EGLint wait_res =
118         s_egl.eglClientWaitSyncKHR(mDisplay, mSync,
119                                    EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
120                                    timeout);
121     decRef();
122     return wait_res;
123 }
124 
waitAsync()125 void FenceSync::waitAsync() {
126     s_egl.eglWaitSyncKHR(mDisplay, mSync, 0);
127 }
128 
isSignaled()129 bool FenceSync::isSignaled() {
130     EGLint val;
131     if (EGL_TRUE ==
132             s_egl.eglGetSyncAttribKHR(
133                 mDisplay, mSync, EGL_SYNC_STATUS_KHR, &val))
134         return val == EGL_SIGNALED_KHR;
135 
136     return true; // if invalid, treat as signaled
137 }
138 
destroy()139 void FenceSync::destroy() {
140     s_egl.eglDestroySyncKHR(mDisplay, mSync);
141 }
142 
143 // Snapshots for FenceSync//////////////////////////////////////////////////////
144 // It's possible, though it does not happen often, that a fence
145 // can be created but not yet waited on by the guest, which
146 // needs careful handling:
147 //
148 // 1. Avoid manipulating garbage memory on snapshot restore;
149 // rcCreateSyncKHR *creates new fence in valid memory*
150 // --snapshot--
151 // rcClientWaitSyncKHR *refers to uninitialized memory*
152 // rcDestroySyncKHR *refers to uninitialized memory*
153 // 2. Make rcCreateSyncKHR/rcDestroySyncKHR implementations return
154 // the "signaled" status if referring to previous snapshot fences. It's
155 // assumed that the GPU is long done with them.
156 // 3. Avoid name collisions where a new FenceSync object is created
157 // that has the same uint64_t casting as a FenceSync object from a previous
158 // snapshot.
159 
160 // Maintain a StalePtrRegistry<FenceSync>:
sFenceRegistry()161 static StalePtrRegistry<FenceSync>* sFenceRegistry() {
162     static StalePtrRegistry<FenceSync>* s = new StalePtrRegistry<FenceSync>;
163     return s;
164 }
165 
166 // static
addToRegistry()167 void FenceSync::addToRegistry() {
168     sFenceRegistry()->addPtr(this);
169 }
170 
171 // static
removeFromRegistry()172 void FenceSync::removeFromRegistry() {
173     sFenceRegistry()->removePtr(this);
174 }
175 
176 // static
onSave(android::base::Stream * stream)177 void FenceSync::onSave(android::base::Stream* stream) {
178     sFenceRegistry()->makeCurrentPtrsStale();
179     sFenceRegistry()->onSave(stream);
180 }
181 
182 // static
onLoad(android::base::Stream * stream)183 void FenceSync::onLoad(android::base::Stream* stream) {
184     sFenceRegistry()->onLoad(stream);
185 }
186 
187 // static
getFromHandle(uint64_t handle)188 FenceSync* FenceSync::getFromHandle(uint64_t handle) {
189     return sFenceRegistry()->getPtr(handle);
190 }
191