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