Loading libs/renderengine/gl/GLESRenderEngine.cpp +78 −2 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ #include <GLES2/gl2ext.h> #include <android-base/stringprintf.h> #include <cutils/compiler.h> #include <cutils/properties.h> #include <renderengine/Mesh.h> #include <renderengine/Texture.h> #include <renderengine/private/Description.h> Loading Loading @@ -416,6 +417,13 @@ GLESRenderEngine::GLESRenderEngine(uint32_t featureFlags, EGLDisplay display, EG mBt2020ToSrgb = mXyzToSrgb * mBt2020ToXyz; mBt2020ToDisplayP3 = mXyzToDisplayP3 * mBt2020ToXyz; } char value[PROPERTY_VALUE_MAX]; property_get("debug.egl.traceGpuCompletion", value, "0"); if (atoi(value)) { mTraceGpuCompletion = true; mFlushTracer = std::make_unique<FlushTracer>(this); } } GLESRenderEngine::~GLESRenderEngine() { Loading Loading @@ -461,6 +469,12 @@ base::unique_fd GLESRenderEngine::flush() { ALOGW("failed to dup EGL native fence sync: %#x", eglGetError()); } // Only trace if we have a valid fence, as current usage falls back to // calling finish() if the fence fd is invalid. if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer) && fenceFd.get() >= 0) { mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr)); } return fenceFd; } Loading @@ -476,8 +490,15 @@ bool GLESRenderEngine::finish() { return false; } EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/); if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer)) { mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr)); } return waitSync(sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR); } bool GLESRenderEngine::waitSync(EGLSyncKHR sync, EGLint flags) { EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, flags, 2000000000 /*2 sec*/); EGLint error = eglGetError(); eglDestroySyncKHR(mEGLDisplay, sync); if (result != EGL_CONDITION_SATISFIED_KHR) { Loading Loading @@ -1224,6 +1245,61 @@ bool GLESRenderEngine::needsXYZTransformMatrix() const { return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer; } // FlushTracer implementation GLESRenderEngine::FlushTracer::FlushTracer(GLESRenderEngine* engine) : mEngine(engine) { mThread = std::thread(&GLESRenderEngine::FlushTracer::loop, this); } GLESRenderEngine::FlushTracer::~FlushTracer() { { std::lock_guard<std::mutex> lock(mMutex); mRunning = false; } mCondition.notify_all(); if (mThread.joinable()) { mThread.join(); } } void GLESRenderEngine::FlushTracer::queueSync(EGLSyncKHR sync) { std::lock_guard<std::mutex> lock(mMutex); char name[64]; const uint64_t frameNum = mFramesQueued++; snprintf(name, sizeof(name), "Queueing sync for frame: %lu", static_cast<unsigned long>(frameNum)); ATRACE_NAME(name); mQueue.push({sync, frameNum}); ATRACE_INT("GPU Frames Outstanding", mQueue.size()); mCondition.notify_one(); } void GLESRenderEngine::FlushTracer::loop() { while (mRunning) { QueueEntry entry; { std::lock_guard<std::mutex> lock(mMutex); mCondition.wait(mMutex, [&]() REQUIRES(mMutex) { return !mQueue.empty() && !mRunning; }); if (!mRunning) { // if mRunning is false, then FlushTracer is being destroyed, so // bail out now. break; } entry = mQueue.front(); mQueue.pop(); } { char name[64]; snprintf(name, sizeof(name), "waiting for frame %lu", static_cast<unsigned long>(entry.mFrameNum)); ATRACE_NAME(name); mEngine->waitSync(entry.mSync, 0); } } } } // namespace gl } // namespace renderengine } // namespace android libs/renderengine/gl/GLESRenderEngine.h +32 −0 Original line number Diff line number Diff line Loading @@ -17,8 +17,13 @@ #ifndef SF_GLESRENDERENGINE_H_ #define SF_GLESRENDERENGINE_H_ #include <android-base/thread_annotations.h> #include <stdint.h> #include <sys/types.h> #include <condition_variable> #include <mutex> #include <queue> #include <thread> #include <EGL/egl.h> #include <EGL/eglext.h> Loading Loading @@ -119,6 +124,7 @@ private: Protection protection); static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config, int hwcFormat, Protection protection); bool waitSync(EGLSyncKHR sync, EGLint flags); // A data space is considered HDR data space if it has BT2020 color space // with PQ or HLG transfer function. Loading Loading @@ -159,6 +165,8 @@ private: mat4 mBt2020ToDisplayP3; bool mInProtectedContext = false; // If set to true, then enables tracing flush() and finish() to systrace. bool mTraceGpuCompletion = false; int32_t mFboHeight = 0; // Current dataspace of layer being rendered Loading @@ -170,6 +178,30 @@ private: // Whether device supports color management, currently color management // supports sRGB, DisplayP3 color spaces. const bool mUseColorManagement = false; class FlushTracer { public: FlushTracer(GLESRenderEngine* engine); ~FlushTracer(); void queueSync(EGLSyncKHR sync) EXCLUDES(mMutex); struct QueueEntry { EGLSyncKHR mSync = nullptr; uint64_t mFrameNum = 0; }; private: void loop(); GLESRenderEngine* const mEngine; std::thread mThread; std::condition_variable_any mCondition; std::mutex mMutex; std::queue<QueueEntry> mQueue GUARDED_BY(mMutex); uint64_t mFramesQueued GUARDED_BY(mMutex) = 0; bool mRunning = true; }; friend class FlushTracer; std::unique_ptr<FlushTracer> mFlushTracer; }; } // namespace gl Loading Loading
libs/renderengine/gl/GLESRenderEngine.cpp +78 −2 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ #include <GLES2/gl2ext.h> #include <android-base/stringprintf.h> #include <cutils/compiler.h> #include <cutils/properties.h> #include <renderengine/Mesh.h> #include <renderengine/Texture.h> #include <renderengine/private/Description.h> Loading Loading @@ -416,6 +417,13 @@ GLESRenderEngine::GLESRenderEngine(uint32_t featureFlags, EGLDisplay display, EG mBt2020ToSrgb = mXyzToSrgb * mBt2020ToXyz; mBt2020ToDisplayP3 = mXyzToDisplayP3 * mBt2020ToXyz; } char value[PROPERTY_VALUE_MAX]; property_get("debug.egl.traceGpuCompletion", value, "0"); if (atoi(value)) { mTraceGpuCompletion = true; mFlushTracer = std::make_unique<FlushTracer>(this); } } GLESRenderEngine::~GLESRenderEngine() { Loading Loading @@ -461,6 +469,12 @@ base::unique_fd GLESRenderEngine::flush() { ALOGW("failed to dup EGL native fence sync: %#x", eglGetError()); } // Only trace if we have a valid fence, as current usage falls back to // calling finish() if the fence fd is invalid. if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer) && fenceFd.get() >= 0) { mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr)); } return fenceFd; } Loading @@ -476,8 +490,15 @@ bool GLESRenderEngine::finish() { return false; } EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/); if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer)) { mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr)); } return waitSync(sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR); } bool GLESRenderEngine::waitSync(EGLSyncKHR sync, EGLint flags) { EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, flags, 2000000000 /*2 sec*/); EGLint error = eglGetError(); eglDestroySyncKHR(mEGLDisplay, sync); if (result != EGL_CONDITION_SATISFIED_KHR) { Loading Loading @@ -1224,6 +1245,61 @@ bool GLESRenderEngine::needsXYZTransformMatrix() const { return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer; } // FlushTracer implementation GLESRenderEngine::FlushTracer::FlushTracer(GLESRenderEngine* engine) : mEngine(engine) { mThread = std::thread(&GLESRenderEngine::FlushTracer::loop, this); } GLESRenderEngine::FlushTracer::~FlushTracer() { { std::lock_guard<std::mutex> lock(mMutex); mRunning = false; } mCondition.notify_all(); if (mThread.joinable()) { mThread.join(); } } void GLESRenderEngine::FlushTracer::queueSync(EGLSyncKHR sync) { std::lock_guard<std::mutex> lock(mMutex); char name[64]; const uint64_t frameNum = mFramesQueued++; snprintf(name, sizeof(name), "Queueing sync for frame: %lu", static_cast<unsigned long>(frameNum)); ATRACE_NAME(name); mQueue.push({sync, frameNum}); ATRACE_INT("GPU Frames Outstanding", mQueue.size()); mCondition.notify_one(); } void GLESRenderEngine::FlushTracer::loop() { while (mRunning) { QueueEntry entry; { std::lock_guard<std::mutex> lock(mMutex); mCondition.wait(mMutex, [&]() REQUIRES(mMutex) { return !mQueue.empty() && !mRunning; }); if (!mRunning) { // if mRunning is false, then FlushTracer is being destroyed, so // bail out now. break; } entry = mQueue.front(); mQueue.pop(); } { char name[64]; snprintf(name, sizeof(name), "waiting for frame %lu", static_cast<unsigned long>(entry.mFrameNum)); ATRACE_NAME(name); mEngine->waitSync(entry.mSync, 0); } } } } // namespace gl } // namespace renderengine } // namespace android
libs/renderengine/gl/GLESRenderEngine.h +32 −0 Original line number Diff line number Diff line Loading @@ -17,8 +17,13 @@ #ifndef SF_GLESRENDERENGINE_H_ #define SF_GLESRENDERENGINE_H_ #include <android-base/thread_annotations.h> #include <stdint.h> #include <sys/types.h> #include <condition_variable> #include <mutex> #include <queue> #include <thread> #include <EGL/egl.h> #include <EGL/eglext.h> Loading Loading @@ -119,6 +124,7 @@ private: Protection protection); static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config, int hwcFormat, Protection protection); bool waitSync(EGLSyncKHR sync, EGLint flags); // A data space is considered HDR data space if it has BT2020 color space // with PQ or HLG transfer function. Loading Loading @@ -159,6 +165,8 @@ private: mat4 mBt2020ToDisplayP3; bool mInProtectedContext = false; // If set to true, then enables tracing flush() and finish() to systrace. bool mTraceGpuCompletion = false; int32_t mFboHeight = 0; // Current dataspace of layer being rendered Loading @@ -170,6 +178,30 @@ private: // Whether device supports color management, currently color management // supports sRGB, DisplayP3 color spaces. const bool mUseColorManagement = false; class FlushTracer { public: FlushTracer(GLESRenderEngine* engine); ~FlushTracer(); void queueSync(EGLSyncKHR sync) EXCLUDES(mMutex); struct QueueEntry { EGLSyncKHR mSync = nullptr; uint64_t mFrameNum = 0; }; private: void loop(); GLESRenderEngine* const mEngine; std::thread mThread; std::condition_variable_any mCondition; std::mutex mMutex; std::queue<QueueEntry> mQueue GUARDED_BY(mMutex); uint64_t mFramesQueued GUARDED_BY(mMutex) = 0; bool mRunning = true; }; friend class FlushTracer; std::unique_ptr<FlushTracer> mFlushTracer; }; } // namespace gl Loading