• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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