1 /* 2 * Copyright 2018 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 <chrono> 20 #include <condition_variable> 21 #include <mutex> 22 #include <thread> 23 #include <memory> 24 #include <atomic> 25 26 #include <EGL/egl.h> 27 #include <EGL/eglext.h> 28 29 #include "Thread.h" 30 31 namespace swappy { 32 33 class EGL { 34 private: 35 // Allows construction with std::unique_ptr from a static method, but disallows construction 36 // outside of the class since no one else can construct a ConstructorTag 37 struct ConstructorTag { 38 }; 39 40 public: 41 struct FrameTimestamps { 42 EGLnsecsANDROID requested; 43 EGLnsecsANDROID renderingCompleted; 44 EGLnsecsANDROID compositionLatched; 45 EGLnsecsANDROID presented; 46 }; 47 EGL(std::chrono::nanoseconds refreshPeriod,ConstructorTag)48 explicit EGL(std::chrono::nanoseconds refreshPeriod, ConstructorTag) 49 : mRefreshPeriod(refreshPeriod) {} 50 51 static std::unique_ptr<EGL> create(std::chrono::nanoseconds refreshPeriod); 52 53 void resetSyncFence(EGLDisplay display); 54 bool lastFrameIsComplete(EGLDisplay display); 55 bool setPresentationTime(EGLDisplay display, 56 EGLSurface surface, 57 std::chrono::steady_clock::time_point time); getFencePendingTime()58 std::chrono::nanoseconds getFencePendingTime() { return mFenceWaiter.getFencePendingTime(); } 59 60 // for stats 61 bool statsSupported(); 62 std::pair<bool,EGLuint64KHR> getNextFrameId(EGLDisplay dpy, 63 EGLSurface surface); 64 std::unique_ptr<FrameTimestamps> getFrameTimestamps(EGLDisplay dpy, 65 EGLSurface surface, 66 EGLuint64KHR frameId); 67 68 private: 69 const std::chrono::nanoseconds mRefreshPeriod; 70 71 using eglPresentationTimeANDROID_type = EGLBoolean (*)(EGLDisplay, EGLSurface, EGLnsecsANDROID); 72 eglPresentationTimeANDROID_type eglPresentationTimeANDROID = nullptr; 73 using eglCreateSyncKHR_type = EGLSyncKHR (*)(EGLDisplay, EGLenum, const EGLint *); 74 eglCreateSyncKHR_type eglCreateSyncKHR = nullptr; 75 using eglDestroySyncKHR_type = EGLBoolean (*)(EGLDisplay, EGLSyncKHR); 76 eglDestroySyncKHR_type eglDestroySyncKHR = nullptr; 77 using eglGetSyncAttribKHR_type = EGLBoolean (*)(EGLDisplay, EGLSyncKHR, EGLint, EGLint *); 78 eglGetSyncAttribKHR_type eglGetSyncAttribKHR = nullptr; 79 80 using eglGetError_type = EGLint (*)(void); 81 eglGetError_type eglGetError = nullptr; 82 using eglSurfaceAttrib_type = EGLBoolean (*)(EGLDisplay, EGLSurface, EGLint, EGLint); 83 eglSurfaceAttrib_type eglSurfaceAttrib = nullptr; 84 using eglGetNextFrameIdANDROID_type = EGLBoolean (*)(EGLDisplay, EGLSurface, EGLuint64KHR *); 85 eglGetNextFrameIdANDROID_type eglGetNextFrameIdANDROID = nullptr; 86 using eglGetFrameTimestampsANDROID_type = EGLBoolean (*)(EGLDisplay, EGLSurface, 87 EGLuint64KHR, EGLint, const EGLint *, EGLnsecsANDROID *); 88 eglGetFrameTimestampsANDROID_type eglGetFrameTimestampsANDROID = nullptr; 89 90 std::mutex mSyncFenceMutex; 91 EGLSyncKHR mSyncFence = EGL_NO_SYNC_KHR; 92 93 class FenceWaiter { 94 public: 95 FenceWaiter(); 96 ~FenceWaiter(); 97 98 void onFenceCreation(EGLDisplay display, EGLSyncKHR syncFence); 99 void waitForIdle(); 100 std::chrono::nanoseconds getFencePendingTime(); 101 102 private: 103 using eglClientWaitSyncKHR_type = EGLBoolean (*)(EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR); 104 eglClientWaitSyncKHR_type eglClientWaitSyncKHR = nullptr; 105 106 void threadMain(); 107 std::thread mFenceWaiter GUARDED_BY(mFenceWaiterLock); 108 std::mutex mFenceWaiterLock; 109 std::condition_variable_any mFenceWaiterCondition; 110 bool mFenceWaiterRunning GUARDED_BY(mFenceWaiterLock) = true; 111 bool mFenceWaiterPending GUARDED_BY(mFenceWaiterLock) = false; 112 std::atomic<std::chrono::nanoseconds> mFencePendingTime; 113 EGLDisplay mDisplay GUARDED_BY(mFenceWaiterLock); 114 EGLSyncKHR mSyncFence GUARDED_BY(mFenceWaiterLock) = EGL_NO_SYNC_KHR; 115 }; 116 117 FenceWaiter mFenceWaiter; 118 }; 119 120 } // namespace swappy 121