diff options
Diffstat (limited to 'libs/hwui/renderthread/EglManager.cpp')
-rw-r--r-- | libs/hwui/renderthread/EglManager.cpp | 154 |
1 files changed, 100 insertions, 54 deletions
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index eb332d59fee3..d2ce49f800fc 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -25,7 +25,8 @@ #include <cutils/properties.h> #include <EGL/eglext.h> -#define PROPERTY_RENDER_DIRTY_REGIONS "debug.hwui.render_dirty_regions" +#include <string> + #define GLES_VERSION 2 #define WAIT_FOR_GPU_COMPLETION 0 @@ -63,10 +64,27 @@ static const char* egl_error_str() { return egl_error_str(eglGetError()); } -static bool load_dirty_regions_property() { - char buf[PROPERTY_VALUE_MAX]; - int len = property_get(PROPERTY_RENDER_DIRTY_REGIONS, buf, "true"); - return !strncasecmp("true", buf, len); +static struct { + bool bufferAge = false; + bool setDamage = false; +} EglExtensions; + +void Frame::map(const SkRect& in, EGLint* out) const { + /* The rectangles are specified relative to the bottom-left of the surface + * and the x and y components of each rectangle specify the bottom-left + * position of that rectangle. + * + * HWUI does everything with 0,0 being top-left, so need to map + * the rect + */ + SkIRect idirty; + in.roundOut(&idirty); + EGLint y = mHeight - (idirty.y() + idirty.height()); + // layout: {x, y, width, height} + out[0] = idirty.x(); + out[1] = y; + out[2] = idirty.width(); + out[3] = idirty.height(); } EglManager::EglManager(RenderThread& thread) @@ -75,12 +93,9 @@ EglManager::EglManager(RenderThread& thread) , mEglConfig(nullptr) , mEglContext(EGL_NO_CONTEXT) , mPBufferSurface(EGL_NO_SURFACE) - , mAllowPreserveBuffer(load_dirty_regions_property()) , mCurrentSurface(EGL_NO_SURFACE) , mAtlasMap(nullptr) , mAtlasMapSize(0) { - mCanSetPreserveBuffer = mAllowPreserveBuffer; - ALOGD("Use EGL_SWAP_BEHAVIOR_PRESERVED: %s", mAllowPreserveBuffer ? "true" : "false"); } void EglManager::initialize() { @@ -98,6 +113,17 @@ void EglManager::initialize() { ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor); + initExtensions(); + + // Now that extensions are loaded, pick a swap behavior + if (Properties::enablePartialUpdates) { + if (Properties::useBufferAge && EglExtensions.bufferAge) { + mSwapBehavior = SwapBehavior::BufferAge; + } else { + mSwapBehavior = SwapBehavior::Preserved; + } + } + loadConfig(); createContext(); createPBufferSurface(); @@ -106,12 +132,23 @@ void EglManager::initialize() { initAtlas(); } +void EglManager::initExtensions() { + std::string extensions(eglQueryString(mEglDisplay, EGL_EXTENSIONS)); + auto has = [&](const char* ext) { + return extensions.find(ext) != std::string::npos; + }; + EglExtensions.bufferAge = has("EGL_EXT_buffer_age"); + EglExtensions.setDamage = has("EGL_KHR_partial_update"); +} + bool EglManager::hasEglContext() { return mEglDisplay != EGL_NO_DISPLAY; } void EglManager::loadConfig() { - EGLint swapBehavior = mCanSetPreserveBuffer ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0; + ALOGD("Swap behavior %d", static_cast<int>(mSwapBehavior)); + EGLint swapBehavior = (mSwapBehavior == SwapBehavior::Preserved) + ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0; EGLint attribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, @@ -128,13 +165,13 @@ void EglManager::loadConfig() { EGLint num_configs = 1; if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, num_configs, &num_configs) || num_configs != 1) { - // Failed to get a valid config - if (mCanSetPreserveBuffer) { - ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without..."); + if (mSwapBehavior == SwapBehavior::Preserved) { // Try again without dirty regions enabled - mCanSetPreserveBuffer = false; + ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without..."); + mSwapBehavior = SwapBehavior::Discard; loadConfig(); } else { + // Failed to get a valid config LOG_ALWAYS_FATAL("Failed to choose config, error = %s", egl_error_str()); } } @@ -238,21 +275,47 @@ bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) { return true; } -void EglManager::beginFrame(EGLSurface surface, EGLint* width, EGLint* height) { +EGLint EglManager::queryBufferAge(EGLSurface surface) { + switch (mSwapBehavior) { + case SwapBehavior::Discard: + return 0; + case SwapBehavior::Preserved: + return 1; + case SwapBehavior::BufferAge: + EGLint bufferAge; + eglQuerySurface(mEglDisplay, surface, EGL_BUFFER_AGE_EXT, &bufferAge); + return bufferAge; + } + return 0; +} + +Frame EglManager::beginFrame(EGLSurface surface) { LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE, "Tried to beginFrame on EGL_NO_SURFACE!"); makeCurrent(surface); - if (width) { - eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width); - } - if (height) { - eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height); - } + Frame frame; + frame.mSurface = surface; + eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, &frame.mWidth); + eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, &frame.mHeight); + frame.mBufferAge = queryBufferAge(surface); eglBeginFrame(mEglDisplay, surface); + return frame; +} + +void EglManager::damageFrame(const Frame& frame, const SkRect& dirty) { +#ifdef EGL_KHR_partial_update + if (EglExtensions.setDamage && mSwapBehavior == SwapBehavior::BufferAge) { + EGLint rects[4]; + frame.map(dirty, rects); + if (!eglSetDamageRegionKHR(mEglDisplay, frame.mSurface, rects, 1)) { + LOG_ALWAYS_FATAL("Failed to set damage region on surface %p, error=%s", + (void*)frame.mSurface, egl_error_str()); + } + } +#endif } -bool EglManager::swapBuffers(EGLSurface surface, const SkRect& dirty, - EGLint width, EGLint height) { +bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) { #if WAIT_FOR_GPU_COMPLETION { @@ -263,28 +326,15 @@ bool EglManager::swapBuffers(EGLSurface surface, const SkRect& dirty, #ifdef EGL_KHR_swap_buffers_with_damage if (CC_LIKELY(Properties::swapBuffersWithDamage)) { - SkIRect idirty; - dirty.roundOut(&idirty); - /* - * EGL_KHR_swap_buffers_with_damage spec states: - * - * The rectangles are specified relative to the bottom-left of the surface - * and the x and y components of each rectangle specify the bottom-left - * position of that rectangle. - * - * HWUI does everything with 0,0 being top-left, so need to map - * the rect - */ - EGLint y = height - (idirty.y() + idirty.height()); - // layout: {x, y, width, height} - EGLint rects[4] = { idirty.x(), y, idirty.width(), idirty.height() }; - EGLint numrects = dirty.isEmpty() ? 0 : 1; - eglSwapBuffersWithDamageKHR(mEglDisplay, surface, rects, numrects); + EGLint rects[4]; + frame.map(screenDirty, rects); + eglSwapBuffersWithDamageKHR(mEglDisplay, frame.mSurface, rects, + screenDirty.isEmpty() ? 0 : 1); } else { - eglSwapBuffers(mEglDisplay, surface); + eglSwapBuffers(mEglDisplay, frame.mSurface); } #else - eglSwapBuffers(mEglDisplay, surface); + eglSwapBuffers(mEglDisplay, frame.mSurface); #endif EGLint err = eglGetError(); @@ -295,7 +345,8 @@ bool EglManager::swapBuffers(EGLSurface surface, const SkRect& dirty, // For some reason our surface was destroyed out from under us // This really shouldn't happen, but if it does we can recover easily // by just not trying to use the surface anymore - ALOGW("swapBuffers encountered EGL_BAD_SURFACE on %p, halting rendering...", surface); + ALOGW("swapBuffers encountered EGL_BAD_SURFACE on %p, halting rendering...", + frame.mSurface); return false; } LOG_ALWAYS_FATAL("Encountered EGL error %d %s during rendering", @@ -312,18 +363,13 @@ void EglManager::fence() { } bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) { - if (CC_UNLIKELY(!mAllowPreserveBuffer)) return false; - - bool preserved = false; - if (mCanSetPreserveBuffer) { - preserved = eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, - preserve ? EGL_BUFFER_PRESERVED : EGL_BUFFER_DESTROYED); - if (CC_UNLIKELY(!preserved)) { - ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s", - (void*) surface, egl_error_str()); - } - } - if (CC_UNLIKELY(!preserved)) { + if (mSwapBehavior != SwapBehavior::Preserved) return false; + + bool preserved = eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, + preserve ? EGL_BUFFER_PRESERVED : EGL_BUFFER_DESTROYED); + if (!preserved) { + ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s", + (void*) surface, egl_error_str()); // Maybe it's already set? EGLint swapBehavior; if (eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &swapBehavior)) { |