| /* |
| * Copyright 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #include <chrono> |
| #include <condition_variable> |
| #include <mutex> |
| #include <optional> |
| #include <thread> |
| #include <memory> |
| |
| #include <EGL/egl.h> |
| #include <EGL/eglext.h> |
| |
| #include "Thread.h" |
| |
| namespace swappy { |
| |
| class EGL { |
| private: |
| // Allows construction with std::unique_ptr from a static method, but disallows construction |
| // outside of the class since no one else can construct a ConstructorTag |
| struct ConstructorTag { |
| }; |
| |
| public: |
| struct FrameTimestamps { |
| EGLnsecsANDROID requested; |
| EGLnsecsANDROID renderingCompleted; |
| EGLnsecsANDROID compositionLatched; |
| EGLnsecsANDROID presented; |
| }; |
| |
| explicit EGL(std::chrono::nanoseconds refreshPeriod, ConstructorTag) |
| : mRefreshPeriod(refreshPeriod) {} |
| |
| static std::unique_ptr<EGL> create(std::chrono::nanoseconds refreshPeriod); |
| |
| void resetSyncFence(EGLDisplay display); |
| bool lastFrameIsComplete(EGLDisplay display); |
| bool setPresentationTime(EGLDisplay display, |
| EGLSurface surface, |
| std::chrono::steady_clock::time_point time); |
| std::chrono::nanoseconds getFencePendingTime() { return mFenceWaiter.getFencePendingTime(); } |
| |
| // for stats |
| bool statsSupported(); |
| std::pair<bool,EGLuint64KHR> getNextFrameId(EGLDisplay dpy, |
| EGLSurface surface); |
| std::unique_ptr<FrameTimestamps> getFrameTimestamps(EGLDisplay dpy, |
| EGLSurface surface, |
| EGLuint64KHR frameId); |
| |
| private: |
| const std::chrono::nanoseconds mRefreshPeriod; |
| |
| using eglPresentationTimeANDROID_type = EGLBoolean (*)(EGLDisplay, EGLSurface, EGLnsecsANDROID); |
| eglPresentationTimeANDROID_type eglPresentationTimeANDROID = nullptr; |
| using eglCreateSyncKHR_type = EGLSyncKHR (*)(EGLDisplay, EGLenum, const EGLint *); |
| eglCreateSyncKHR_type eglCreateSyncKHR = nullptr; |
| using eglDestroySyncKHR_type = EGLBoolean (*)(EGLDisplay, EGLSyncKHR); |
| eglDestroySyncKHR_type eglDestroySyncKHR = nullptr; |
| using eglGetSyncAttribKHR_type = EGLBoolean (*)(EGLDisplay, EGLSyncKHR, EGLint, EGLint *); |
| eglGetSyncAttribKHR_type eglGetSyncAttribKHR = nullptr; |
| |
| using eglGetError_type = EGLint (*)(void); |
| eglGetError_type eglGetError = nullptr; |
| using eglSurfaceAttrib_type = EGLBoolean (*)(EGLDisplay, EGLSurface, EGLint, EGLint); |
| eglSurfaceAttrib_type eglSurfaceAttrib = nullptr; |
| using eglGetNextFrameIdANDROID_type = EGLBoolean (*)(EGLDisplay, EGLSurface, EGLuint64KHR *); |
| eglGetNextFrameIdANDROID_type eglGetNextFrameIdANDROID = nullptr; |
| using eglGetFrameTimestampsANDROID_type = EGLBoolean (*)(EGLDisplay, EGLSurface, |
| EGLuint64KHR, EGLint, const EGLint *, EGLnsecsANDROID *); |
| eglGetFrameTimestampsANDROID_type eglGetFrameTimestampsANDROID = nullptr; |
| |
| std::mutex mSyncFenceMutex; |
| EGLSyncKHR mSyncFence = EGL_NO_SYNC_KHR; |
| |
| class FenceWaiter { |
| public: |
| FenceWaiter(); |
| ~FenceWaiter(); |
| |
| void onFenceCreation(EGLDisplay display, EGLSyncKHR syncFence); |
| void waitForIdle(); |
| std::chrono::nanoseconds getFencePendingTime(); |
| |
| private: |
| using eglClientWaitSyncKHR_type = EGLBoolean (*)(EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR); |
| eglClientWaitSyncKHR_type eglClientWaitSyncKHR = nullptr; |
| |
| void threadMain(); |
| std::thread mFenceWaiter GUARDED_BY(mFenceWaiterLock); |
| std::mutex mFenceWaiterLock; |
| std::condition_variable_any mFenceWaiterCondition; |
| bool mFenceWaiterRunning GUARDED_BY(mFenceWaiterLock) = true; |
| bool mFenceWaiterPending GUARDED_BY(mFenceWaiterLock) = false; |
| std::atomic<std::chrono::nanoseconds> mFencePendingTime; |
| EGLDisplay mDisplay GUARDED_BY(mFenceWaiterLock); |
| EGLSyncKHR mSyncFence GUARDED_BY(mFenceWaiterLock) = EGL_NO_SYNC_KHR; |
| }; |
| |
| FenceWaiter mFenceWaiter; |
| }; |
| |
| } // namespace swappy |