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