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