• 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 #pragma once
18 
19 #include <atomic>
20 #include <memory>
21 
22 #include <EGL/egl.h>
23 #include <EGL/eglext.h>
24 
25 #include "aemu/base/Compiler.h"
26 #include "aemu/base/files/Stream.h"
27 #include "aemu/base/synchronization/Lock.h"
28 
29 namespace gfxstream {
30 namespace gl {
31 
32 // The EmulatedEglFenceSync class wraps actual EGLSyncKHR objects
33 // and issues calls to eglCreateSyncKHR, eglClientWaitSyncKHR,
34 // and eglDestroySyncKHR.
35 //
36 // The purpose of this class:
37 // - We need to track EGL sync objects created by the guest and
38 //   realized in the host OpenGL driver. They are passed between
39 //   guest and host all the time.
40 // - In particular, we also need to destroy EGL sync objects at
41 //   the proper time. There are at least 3 issues (referenced below
42 //   in spec comments):
43 //   1 According to spec, we would need to allow concurrent
44 //     eglClientWaitSyncKHR and eglDestroySyncKHR to all finish
45 //     properly.
46 //   2 If the EGL sync object is of EGL_SYNC_NATIVE_FENCE_ANDROID
47 //     nature, we cannot mirror the guest's call to eglDestroySyncKHR
48 //     by calling the same function on the host, because Goldfish
49 //     sync device can only know when native fence FD's are signaled
50 //     when a host-side EGL sync object is signaled. Thus, we would
51 //     need to delete such sync objects after both the guest and
52 //     the Goldfish sync device are done with them.
53 //   3 We sometimes create sync objects that are only seen by
54 //     the Goldfish OpenGL driver in the guest, such as for
55 //     implementing eglSwapBuffers() in a way that avoids
56 //     out of order frames. It is cumbersome to eglDestroySyncKHR
57 //     those on the guest, as that would require starting up another guest
58 //     thread and OpenGL context (complete with host connection)
59 //     to destroy it.
60 class EmulatedEglFenceSync {
61   public:
62     // The constructor wraps eglCreateSyncKHR on the host OpenGL driver.
63     // |hasNativeFence| specifies whether this sync object
64     // is of EGL_SYNC_NATIVE_FENCE_ANDROID nature (2), and
65     // |destroyWhenSignaled| specifies whether or not to destroy
66     // the sync object when the native fence FD becomes signaled (3).
67     static std::unique_ptr<EmulatedEglFenceSync> create(
68         EGLSyncKHR sync,
69         bool hasNativeFence,
70         bool destroyWhenSignaled);
71 
72     ~EmulatedEglFenceSync();
73 
74     // wait() wraps eglClientWaitSyncKHR. During such a wait, we need
75     // to increment the reference count while the wait is active,
76     // in case there is a concurrent call to eglDestroySyncKHR (1).
77     EGLint wait(uint64_t timeout);
78 
79     // waitAsync wraps eglWaitSyncKHR.
80     void waitAsync();
81 
82     // isSignaled wraps eglGetSyncAttribKHR.
83     bool isSignaled();
84 
shouldDestroyWhenSignaled()85     bool shouldDestroyWhenSignaled() const {
86         return mDestroyWhenSignaled;
87     }
88 
89     // When a native fence gets signaled, this function is called to update the
90     // timeline counter in the EmulatedEglFenceSync internal timeline and delete old
91     // fences.
92     static void incrementTimelineAndDeleteOldFences();
93 
94     // incRef() / decRef() increment/decrement refence counts in order
95     // to deal with sync object destruction. This is a simple reference
96     // counting implementation that is almost literally the kref() in
97     // the Linux kernel.
98     //
99     // We do not use shared_ptr or anything like that here because
100     // we need to explicitly manipulate the reference count in order to
101     // satisfy (1,2,3) above.
incRef()102     void incRef() { assert(mCount > 0); ++mCount; }
decRef()103     bool decRef() {
104         assert(mCount > 0);
105         if (mCount == 1 || --mCount == 0) {
106             // destroy() here would delay calls to eglDestroySyncKHR
107             // in the host driver until all waits have completed,
108             // which is a bit different from simply allowing concurrent calls.
109             // But, from the guest's perspective, the contract of allowing
110             // everything to finish is still fulfilled, and there is
111             // no reason to think (theoretically or practically) that
112             // is undesirable to destroy the underlying EGL sync object
113             // a tiny bit later. We could have put in extra logic to allow
114             // concurrent destruction, but this would have made the code
115             // undesirably less simple.
116             destroy();
117             // This delete-then-return seems OK.
118             delete this;
119             return true;
120         }
121         return false;
122     }
123 
setIsCompositionFence(bool isComposition)124     void setIsCompositionFence(bool isComposition) {
125         mIsCompositionFence = isComposition;
126     }
127 
isCompositionFence()128     bool isCompositionFence() const {
129         return mIsCompositionFence;
130     }
131 
132     // Tracks current active set of fences. Useful for snapshotting.
133     void addToRegistry();
134     void removeFromRegistry();
135 
136     static EmulatedEglFenceSync* getFromHandle(uint64_t handle);
137 
138     // Functions for snapshotting all fence state at once
139     static void onSave(android::base::Stream* stream);
140     static void onLoad(android::base::Stream* stream);
141 
142   private:
143     EmulatedEglFenceSync(EGLDisplay display,
144                          EGLSyncKHR sync,
145                          bool hasNativeFence,
146                          bool destroyWhenSignaled);
147 
148     bool mDestroyWhenSignaled;
149     std::atomic<int> mCount {1};
150 
151     // EGL state needed for calling OpenGL sync operations.
152     EGLDisplay mDisplay;
153     EGLSyncKHR mSync;
154 
155     // Whether this fence was against composition, in which case
156     // we should make this wait till next vsync.
157     bool mIsCompositionFence = false;
158 
159     // destroy() wraps eglDestroySyncKHR. This is private, because we need
160     // careful control of when eglDestroySyncKHR is actually called.
161     void destroy();
162 
163     DISALLOW_COPY_AND_ASSIGN(EmulatedEglFenceSync);
164 };
165 
166 }  // namespace gl
167 }  // namespace gfxstream
168