renderthread: add EGL_EXT_buffer_age support
EGL_EXT_buffer_age is better than EGL_BUFFER_PRESERVED
because it can save memory bandwidth used to blit
back buffer into front buffer.
Change-Id: I2fea0ee08dc7dd66e348b04dd694d075d509d01b
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index eb332d5..ac36f53 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -76,6 +76,7 @@
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
, mAllowPreserveBuffer(load_dirty_regions_property())
+ , mHasBufferAgeExt(false)
, mCurrentSurface(EGL_NO_SURFACE)
, mAtlasMap(nullptr)
, mAtlasMapSize(0) {
@@ -98,7 +99,10 @@
ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor);
- loadConfig();
+ findExtensions(eglQueryString(mEglDisplay, EGL_EXTENSIONS), mEglExtensionList);
+ mHasBufferAgeExt = hasEglExtension("EGL_EXT_buffer_age");
+
+ loadConfig(mHasBufferAgeExt);
createContext();
createPBufferSurface();
makeCurrent(mPBufferSurface);
@@ -110,8 +114,13 @@
return mEglDisplay != EGL_NO_DISPLAY;
}
-void EglManager::loadConfig() {
- EGLint swapBehavior = mCanSetPreserveBuffer ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+bool EglManager::hasEglExtension(const char* extension) const {
+ const std::string s(extension);
+ return mEglExtensionList.find(s) != mEglExtensionList.end();
+}
+
+void EglManager::loadConfig(bool useBufferAgeExt) {
+ EGLint swapBehavior = (!useBufferAgeExt && mCanSetPreserveBuffer) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
EGLint attribs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
@@ -133,7 +142,7 @@
ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...");
// Try again without dirty regions enabled
mCanSetPreserveBuffer = false;
- loadConfig();
+ loadConfig(useBufferAgeExt);
} else {
LOG_ALWAYS_FATAL("Failed to choose config, error = %s", egl_error_str());
}
@@ -238,7 +247,7 @@
return true;
}
-void EglManager::beginFrame(EGLSurface surface, EGLint* width, EGLint* height) {
+void EglManager::beginFrame(EGLSurface surface, EGLint* width, EGLint* height, EGLint* framebufferAge) {
LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
"Tried to beginFrame on EGL_NO_SURFACE!");
makeCurrent(surface);
@@ -248,6 +257,9 @@
if (height) {
eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
}
+ if (useBufferAgeExt()) {
+ eglQuerySurface(mEglDisplay, surface, EGL_BUFFER_AGE_EXT, framebufferAge);
+ }
eglBeginFrame(mEglDisplay, surface);
}
@@ -304,6 +316,10 @@
return false;
}
+bool EglManager::useBufferAgeExt() {
+ return mAllowPreserveBuffer && mHasBufferAgeExt;
+}
+
void EglManager::fence() {
EGLSyncKHR fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL);
eglClientWaitSyncKHR(mEglDisplay, fence,
@@ -314,6 +330,9 @@
bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) {
if (CC_UNLIKELY(!mAllowPreserveBuffer)) return false;
+ // Use EGL_EXT_buffer_age instead if supported
+ if (mHasBufferAgeExt) return true;
+
bool preserved = false;
if (mCanSetPreserveBuffer) {
preserved = eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR,
@@ -337,6 +356,19 @@
return preserved;
}
+void EglManager::findExtensions(const char* extensions, std::set<std::string>& list) const {
+ const char* current = extensions;
+ const char* head = current;
+ do {
+ head = strchr(current, ' ');
+ std::string s(current, head ? head - current : strlen(current));
+ if (s.length()) {
+ list.insert(s);
+ }
+ current = head + 1;
+ } while (head);
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */