summaryrefslogtreecommitdiff
path: root/libs/hwui/renderthread/EglManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/renderthread/EglManager.cpp')
-rw-r--r--libs/hwui/renderthread/EglManager.cpp192
1 files changed, 141 insertions, 51 deletions
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 6e239e357cf6..d4ffddde8def 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -16,27 +16,21 @@
#include "EglManager.h"
-#include <string>
-
#include <cutils/properties.h>
#include <log/log.h>
+#include <private/gui/SyncFeatures.h>
+#include <utils/Trace.h>
+#include "utils/Color.h"
#include "utils/StringUtils.h"
-#include "Caches.h"
-#include "DeviceInfo.h"
#include "Frame.h"
#include "Properties.h"
-#include "RenderThread.h"
-#include "Texture.h"
-#include "renderstate/RenderState.h"
#include <EGL/eglext.h>
-#include <GrContextOptions.h>
-#include <gl/GrGLInterface.h>
+#include <GLES/gl.h>
-#ifdef HWUI_GLES_WRAP_ENABLED
-#include "debug/GlesDriver.h"
-#endif
+#include <string>
+#include <vector>
#define GLES_VERSION 2
@@ -82,18 +76,23 @@ static struct {
bool pixelFormatFloat = false;
bool glColorSpace = false;
bool scRGB = false;
+ bool displayP3 = false;
bool contextPriority = false;
+ bool surfacelessContext = false;
} EglExtensions;
-EglManager::EglManager(RenderThread& thread)
- : mRenderThread(thread)
- , mEglDisplay(EGL_NO_DISPLAY)
+EglManager::EglManager()
+ : mEglDisplay(EGL_NO_DISPLAY)
, mEglConfig(nullptr)
, mEglConfigWideGamut(nullptr)
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
, mCurrentSurface(EGL_NO_SURFACE) {}
+EglManager::~EglManager() {
+ destroy();
+}
+
void EglManager::initialize() {
if (hasEglContext()) return;
@@ -126,26 +125,7 @@ void EglManager::initialize() {
loadConfigs();
createContext();
createPBufferSurface();
- makeCurrent(mPBufferSurface);
- DeviceInfo::initialize();
- mRenderThread.renderState().onGLContextCreated();
-
- if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
-#ifdef HWUI_GLES_WRAP_ENABLED
- debug::GlesDriver* driver = debug::GlesDriver::get();
- sk_sp<const GrGLInterface> glInterface(driver->getSkiaInterface());
-#else
- sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
-#endif
- LOG_ALWAYS_FATAL_IF(!glInterface.get());
-
- GrContextOptions options;
- options.fDisableDistanceFieldPaths = true;
- mRenderThread.cacheManager().configureContext(&options);
- sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options));
- LOG_ALWAYS_FATAL_IF(!grContext.get());
- mRenderThread.setGrContext(grContext);
- }
+ makeCurrent(mPBufferSurface, nullptr, /* force */ true);
}
void EglManager::initExtensions() {
@@ -169,7 +149,9 @@ void EglManager::initExtensions() {
#else
EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb");
#endif
+ EglExtensions.displayP3 = extensions.has("EGL_EXT_gl_colorspace_display_p3");
EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority");
+ EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context");
}
bool EglManager::hasEglContext() {
@@ -180,6 +162,10 @@ void EglManager::loadConfigs() {
ALOGD("Swap behavior %d", static_cast<int>(mSwapBehavior));
EGLint swapBehavior =
(mSwapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+
+ // Note: The default pixel format is RGBA_8888, when other formats are
+ // available, we should check the target pixel format and configure the
+ // attributes list properly.
EGLint attribs[] = {EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE,
@@ -195,7 +181,7 @@ void EglManager::loadConfigs() {
EGL_CONFIG_CAVEAT,
EGL_NONE,
EGL_STENCIL_SIZE,
- Stencil::getStencilSize(),
+ STENCIL_BUFFER_SIZE,
EGL_SURFACE_TYPE,
EGL_WINDOW_BIT | swapBehavior,
EGL_NONE};
@@ -232,7 +218,7 @@ void EglManager::loadConfigs() {
EGL_DEPTH_SIZE,
0,
EGL_STENCIL_SIZE,
- Stencil::getStencilSize(),
+ STENCIL_BUFFER_SIZE,
EGL_SURFACE_TYPE,
EGL_WINDOW_BIT | swapBehavior,
EGL_NONE};
@@ -269,17 +255,18 @@ void EglManager::createPBufferSurface() {
LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
"usePBufferSurface() called on uninitialized GlobalContext!");
- if (mPBufferSurface == EGL_NO_SURFACE) {
+ if (mPBufferSurface == EGL_NO_SURFACE && !EglExtensions.surfacelessContext) {
EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
}
}
-EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorGamut) {
- initialize();
+EGLSurface EglManager::createSurface(EGLNativeWindowType window, ColorMode colorMode) {
+ LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized");
- wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB &&
- EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext;
+ bool wideColorGamut = colorMode == ColorMode::WideColorGamut && EglExtensions.glColorSpace &&
+ EglExtensions.scRGB && EglExtensions.pixelFormatFloat &&
+ EglExtensions.noConfigContext;
// The color space we want to use depends on whether linear blending is turned
// on and whether the app has requested wide color gamut rendering. When wide
@@ -289,9 +276,9 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorG
// When wide gamut rendering is off:
// - Blending is done by default in gamma space, which requires using a
// linear EGL color space (the GPU uses the color values as is)
- // - If linear blending is on, we must use the sRGB EGL color space (the
- // GPU will perform sRGB to linear and linear to SRGB conversions before
- // and after blending)
+ // - If linear blending is on, we must use the non-linear EGL color space
+ // (the GPU will perform sRGB to linear and linear to SRGB conversions
+ // before and after blending)
//
// When wide gamut rendering is on we cannot rely on the GPU performing
// linear blending for us. We use two different color spaces to tag the
@@ -299,7 +286,7 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorG
// - Gamma blending (default) requires the use of the scRGB-nl color space
// - Linear blending requires the use of the scRGB color space
- // Not all Android targets support the EGL_GL_COLOR_SPACE_KHR extension
+ // Not all Android targets support the EGL_GL_COLORSPACE_KHR extension
// We insert to placeholders to set EGL_GL_COLORSPACE_KHR and its value.
// According to section 3.4.1 of the EGL specification, the attributes
// list is considered empty if the first entry is EGL_NONE
@@ -350,10 +337,10 @@ void EglManager::destroySurface(EGLSurface surface) {
void EglManager::destroy() {
if (mEglDisplay == EGL_NO_DISPLAY) return;
- mRenderThread.setGrContext(nullptr);
- mRenderThread.renderState().onGLContextDestroyed();
eglDestroyContext(mEglDisplay, mEglContext);
- eglDestroySurface(mEglDisplay, mPBufferSurface);
+ if (mPBufferSurface != EGL_NO_SURFACE) {
+ eglDestroySurface(mEglDisplay, mPBufferSurface);
+ }
eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(mEglDisplay);
eglReleaseThread();
@@ -364,8 +351,8 @@ void EglManager::destroy() {
mCurrentSurface = EGL_NO_SURFACE;
}
-bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) {
- if (isCurrent(surface)) return false;
+bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut, bool force) {
+ if (!force && isCurrent(surface)) return false;
if (surface == EGL_NO_SURFACE) {
// Ensure we always have a valid surface & context
@@ -485,6 +472,109 @@ bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) {
return preserved;
}
+status_t EglManager::fenceWait(sp<Fence>& fence) {
+ if (!hasEglContext()) {
+ ALOGE("EglManager::fenceWait: EGLDisplay not initialized");
+ return INVALID_OPERATION;
+ }
+
+ if (SyncFeatures::getInstance().useWaitSync() &&
+ SyncFeatures::getInstance().useNativeFenceSync()) {
+ // Block GPU on the fence.
+ // Create an EGLSyncKHR from the current fence.
+ int fenceFd = fence->dup();
+ if (fenceFd == -1) {
+ ALOGE("EglManager::fenceWait: error dup'ing fence fd: %d", errno);
+ return -errno;
+ }
+ EGLint attribs[] = {
+ EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
+ EGL_NONE
+ };
+ EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync == EGL_NO_SYNC_KHR) {
+ close(fenceFd);
+ ALOGE("EglManager::fenceWait: error creating EGL fence: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ }
+
+ // XXX: The spec draft is inconsistent as to whether this should
+ // return an EGLint or void. Ignore the return value for now, as
+ // it's not strictly needed.
+ eglWaitSyncKHR(mEglDisplay, sync, 0);
+ EGLint eglErr = eglGetError();
+ eglDestroySyncKHR(mEglDisplay, sync);
+ if (eglErr != EGL_SUCCESS) {
+ ALOGE("EglManager::fenceWait: error waiting for EGL fence: %#x", eglErr);
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ // Block CPU on the fence.
+ status_t err = fence->waitForever("EglManager::fenceWait");
+ if (err != NO_ERROR) {
+ ALOGE("EglManager::fenceWait: error waiting for fence: %d", err);
+ return err;
+ }
+ }
+ return OK;
+}
+
+status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence,
+ sp<Fence>& nativeFence) {
+ if (!hasEglContext()) {
+ ALOGE("EglManager::createReleaseFence: EGLDisplay not initialized");
+ return INVALID_OPERATION;
+ }
+
+ if (SyncFeatures::getInstance().useNativeFenceSync()) {
+ EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGE("EglManager::createReleaseFence: error creating EGL fence: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ glFlush();
+ int fenceFd = eglDupNativeFenceFDANDROID(mEglDisplay, sync);
+ eglDestroySyncKHR(mEglDisplay, sync);
+ if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ALOGE("EglManager::createReleaseFence: error dup'ing native fence "
+ "fd: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ nativeFence = new Fence(fenceFd);
+ *eglFence = EGL_NO_SYNC_KHR;
+ } else if (useFenceSync && SyncFeatures::getInstance().useFenceSync()) {
+ if (*eglFence != EGL_NO_SYNC_KHR) {
+ // There is already a fence for the current slot. We need to
+ // wait on that before replacing it with another fence to
+ // ensure that all outstanding buffer accesses have completed
+ // before the producer accesses it.
+ EGLint result = eglClientWaitSyncKHR(mEglDisplay, *eglFence, 0, 1000000000);
+ if (result == EGL_FALSE) {
+ ALOGE("EglManager::createReleaseFence: error waiting for previous fence: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ALOGE("EglManager::createReleaseFence: timeout waiting for previous fence");
+ return TIMED_OUT;
+ }
+ eglDestroySyncKHR(mEglDisplay, *eglFence);
+ }
+
+ // Create a fence for the outstanding accesses in the current
+ // OpenGL ES context.
+ *eglFence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, nullptr);
+ if (*eglFence == EGL_NO_SYNC_KHR) {
+ ALOGE("EglManager::createReleaseFence: error creating fence: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ glFlush();
+ }
+ return OK;
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */