diff --git a/libs/hwui/EglReadback.cpp b/libs/hwui/EglReadback.cpp index a836afe97c794..2d5367b2508a5 100644 --- a/libs/hwui/EglReadback.cpp +++ b/libs/hwui/EglReadback.cpp @@ -58,7 +58,7 @@ CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) { - mRenderThread.eglManager().initialize(); + mRenderThread.requireGlContext(); // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES // to be able to properly sample from the buffer. diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index b7aa78b7afae3..5b2adbf9c2c31 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -166,7 +166,7 @@ static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_ } DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() { - mEglManager.initialize(); + mRenderThread.requireGlContext(); return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL); } @@ -184,6 +184,7 @@ bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, } if (surface) { + mRenderThread.requireGlContext(); const bool wideColorGamut = colorMode == ColorMode::WideColorGamut; mEglSurface = mEglManager.createSurface(surface, wideColorGamut); } @@ -221,24 +222,6 @@ void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* func #define FENCE_TIMEOUT 2000000000 -class AutoEglFence { -public: - AutoEglFence(EGLDisplay display) : mDisplay(display) { - fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL); - } - - ~AutoEglFence() { - if (fence != EGL_NO_SYNC_KHR) { - eglDestroySyncKHR(mDisplay, fence); - } - } - - EGLSyncKHR fence = EGL_NO_SYNC_KHR; - -private: - EGLDisplay mDisplay = EGL_NO_DISPLAY; -}; - class AutoEglImage { public: AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) { @@ -272,73 +255,102 @@ private: GLuint mTexture = 0; }; -sk_sp SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread, - SkBitmap& skBitmap) { - renderThread.eglManager().initialize(); +struct FormatInfo { - sk_sp grContext = sk_ref_sp(renderThread.getGrContext()); - const SkImageInfo& info = skBitmap.info(); PixelFormat pixelFormat; GLint format, type; bool isSupported = false; + bool valid = true; +}; +static bool gpuSupportsHalfFloatTextures(renderthread::RenderThread& renderThread) { + static bool isSupported = renderThread.queue().runSync([&renderThread]() -> bool { + renderThread.requireGlContext(); + sk_sp grContext = sk_ref_sp(renderThread.getGrContext()); + return grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType); + }); + return isSupported; +} + +static FormatInfo determineFormat(renderthread::RenderThread& renderThread, + const SkBitmap& skBitmap) { + FormatInfo formatInfo; // TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined) - switch (info.colorType()) { + switch (skBitmap.info().colorType()) { case kRGBA_8888_SkColorType: - isSupported = true; + formatInfo.isSupported = true; // ARGB_4444 is upconverted to RGBA_8888 case kARGB_4444_SkColorType: - pixelFormat = PIXEL_FORMAT_RGBA_8888; - format = GL_RGBA; - type = GL_UNSIGNED_BYTE; + formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; + formatInfo.format = GL_RGBA; + formatInfo.type = GL_UNSIGNED_BYTE; break; case kRGBA_F16_SkColorType: - isSupported = grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType); - if (isSupported) { - type = GL_HALF_FLOAT; - pixelFormat = PIXEL_FORMAT_RGBA_FP16; + formatInfo.isSupported = gpuSupportsHalfFloatTextures(renderThread); + if (formatInfo.isSupported) { + formatInfo.type = GL_HALF_FLOAT; + formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16; } else { - type = GL_UNSIGNED_BYTE; - pixelFormat = PIXEL_FORMAT_RGBA_8888; + formatInfo.type = GL_UNSIGNED_BYTE; + formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; } - format = GL_RGBA; + formatInfo.format = GL_RGBA; break; case kRGB_565_SkColorType: - isSupported = true; - pixelFormat = PIXEL_FORMAT_RGB_565; - format = GL_RGB; - type = GL_UNSIGNED_SHORT_5_6_5; + formatInfo.isSupported = true; + formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565; + formatInfo.format = GL_RGB; + formatInfo.type = GL_UNSIGNED_SHORT_5_6_5; break; case kGray_8_SkColorType: - isSupported = true; - pixelFormat = PIXEL_FORMAT_RGBA_8888; - format = GL_LUMINANCE; - type = GL_UNSIGNED_BYTE; + formatInfo.isSupported = true; + formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; + formatInfo.format = GL_LUMINANCE; + formatInfo.type = GL_UNSIGNED_BYTE; break; default: - ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType()); - return nullptr; + ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType()); + formatInfo.valid = false; } + return formatInfo; +} - SkBitmap bitmap; - if (isSupported) { - bitmap = skBitmap; +static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) { + if (format.isSupported) { + return source; } else { + SkBitmap bitmap; + const SkImageInfo& info = source.info(); bitmap.allocPixels( SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr)); bitmap.eraseColor(0); if (info.colorType() == kRGBA_F16_SkColorType) { // Drawing RGBA_F16 onto ARGB_8888 is not supported - skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()), - bitmap.getPixels(), bitmap.rowBytes(), 0, 0); + source.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()), + bitmap.getPixels(), bitmap.rowBytes(), 0, 0); } else { SkCanvas canvas(bitmap); - canvas.drawBitmap(skBitmap, 0.0f, 0.0f, nullptr); + canvas.drawBitmap(source, 0.0f, 0.0f, nullptr); } + return bitmap; + } +} + +sk_sp SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& thread, + const SkBitmap& sourceBitmap) { + ATRACE_CALL(); + + LOG_ALWAYS_FATAL_IF(thread.isCurrent(), "Must not be called on RenderThread"); + + FormatInfo format = determineFormat(thread, sourceBitmap); + if (!format.valid) { + return nullptr; } + SkBitmap bitmap = makeHwCompatible(format, sourceBitmap); sp buffer = new GraphicBuffer( - info.width(), info.height(), pixelFormat, + static_cast(bitmap.width()), static_cast(bitmap.height()), + format.pixelFormat, GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | GraphicBuffer::USAGE_SW_READ_NEVER, std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) + @@ -350,8 +362,11 @@ sk_sp SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr return nullptr; } - // upload the bitmap into a texture - EGLDisplay display = eglGetCurrentDisplay(); + EGLDisplay display = thread.queue().runSync([&]() -> EGLDisplay { + thread.requireGlContext(); + return eglGetCurrentDisplay(); + }); + LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s", uirenderer::renderthread::EglManager::eglErrorString()); // We use an EGLImage to access the content of the GraphicBuffer @@ -363,35 +378,40 @@ sk_sp SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr uirenderer::renderthread::EglManager::eglErrorString()); return nullptr; } - AutoSkiaGlTexture glTexture; - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image); - GL_CHECKPOINT(MODERATE); - // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we provide. - // But asynchronous in sense that driver may upload texture onto hardware buffer when we first - // use it in drawing - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, info.width(), info.height(), format, type, - bitmap.getPixels()); - GL_CHECKPOINT(MODERATE); + { + ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height()); + EGLSyncKHR fence = thread.queue().runSync([&]() -> EGLSyncKHR { + thread.requireGlContext(); + sk_sp grContext = sk_ref_sp(thread.getGrContext()); + AutoSkiaGlTexture glTexture; + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image); + GL_CHECKPOINT(MODERATE); - // The fence is used to wait for the texture upload to finish - // properly. We cannot rely on glFlush() and glFinish() as - // some drivers completely ignore these API calls - AutoEglFence autoFence(display); - if (autoFence.fence == EGL_NO_SYNC_KHR) { - LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError()); - return nullptr; + // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we + // provide. + // But asynchronous in sense that driver may upload texture onto hardware buffer when we + // first + // use it in drawing + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format.format, + format.type, bitmap.getPixels()); + GL_CHECKPOINT(MODERATE); + + EGLSyncKHR uploadFence = + eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL); + LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, "Could not create sync fence %#x", + eglGetError()); + glFlush(); + grContext->resetContext(kTextureBinding_GrGLBackendState); + return uploadFence; + }); + + EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT); + LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR, + "Failed to wait for the fence %#x", eglGetError()); + + eglDestroySyncKHR(display, fence); } - // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a - // pipeline flush (similar to what a glFlush() would do.) - EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence, - EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT); - if (waitStatus != EGL_CONDITION_SATISFIED_KHR) { - LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError()); - return nullptr; - } - - grContext->resetContext(kTextureBinding_GrGLBackendState); return sk_sp(new Bitmap(buffer.get(), bitmap.info())); } diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index 5e013b6697a7a..ef5d9347a3ea2 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -49,8 +49,10 @@ public: bool isContextReady() override; static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); + + // May be called by any thread except RenderThread. static sk_sp allocateHardwareBitmap(renderthread::RenderThread& thread, - SkBitmap& skBitmap); + const SkBitmap& skBitmap); private: renderthread::EglManager& mEglManager; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 95ca8d9d26123..a36dae44ede97 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -552,7 +552,7 @@ void CanvasContext::trimMemory(RenderThread& thread, int level) { ATRACE_CALL(); if (level >= TRIM_MEMORY_COMPLETE) { thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete); - thread.eglManager().destroy(); + thread.destroyGlContext(); thread.vulkanManager().destroy(); } else if (level >= TRIM_MEMORY_UI_HIDDEN) { thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden); diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 6e239e357cf62..cd21822df5b16 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -16,27 +16,19 @@ #include "EglManager.h" -#include - #include #include +#include #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 -#include -#include -#ifdef HWUI_GLES_WRAP_ENABLED -#include "debug/GlesDriver.h" -#endif +#include +#include #define GLES_VERSION 2 @@ -83,17 +75,21 @@ static struct { bool glColorSpace = false; bool scRGB = 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 +122,8 @@ void EglManager::initialize() { loadConfigs(); createContext(); createPBufferSurface(); - makeCurrent(mPBufferSurface); + makeCurrent(mPBufferSurface, nullptr, /* force */ true); DeviceInfo::initialize(); - mRenderThread.renderState().onGLContextCreated(); - - if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { -#ifdef HWUI_GLES_WRAP_ENABLED - debug::GlesDriver* driver = debug::GlesDriver::get(); - sk_sp glInterface(driver->getSkiaInterface()); -#else - sk_sp glInterface(GrGLCreateNativeInterface()); -#endif - LOG_ALWAYS_FATAL_IF(!glInterface.get()); - - GrContextOptions options; - options.fDisableDistanceFieldPaths = true; - mRenderThread.cacheManager().configureContext(&options); - sk_sp grContext(GrContext::MakeGL(std::move(glInterface), options)); - LOG_ALWAYS_FATAL_IF(!grContext.get()); - mRenderThread.setGrContext(grContext); - } } void EglManager::initExtensions() { @@ -170,6 +148,7 @@ void EglManager::initExtensions() { EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb"); #endif EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority"); + EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context"); } bool EglManager::hasEglContext() { @@ -195,7 +174,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 +211,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,14 +248,14 @@ 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(); + LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized"); wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB && EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext; @@ -350,10 +329,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 +343,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 diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index ef9effbf99535..ca6d1b8b74c60 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -33,8 +33,12 @@ class RenderThread; // and EGLConfig, which are re-used by CanvasContext class EglManager { public: + explicit EglManager(); + + ~EglManager(); + static const char* eglErrorString(); - // Returns true on success, false on failure + void initialize(); bool hasEglContext(); @@ -46,7 +50,7 @@ public: bool isCurrent(EGLSurface surface) { return mCurrentSurface == surface; } // Returns true if the current surface changed, false if it was already current - bool makeCurrent(EGLSurface surface, EGLint* errOut = nullptr); + bool makeCurrent(EGLSurface surface, EGLint* errOut = nullptr, bool force = false); Frame beginFrame(EGLSurface surface); void damageFrame(const Frame& frame, const SkRect& dirty); // If this returns true it is mandatory that swapBuffers is called @@ -61,10 +65,6 @@ public: void fence(); private: - friend class RenderThread; - explicit EglManager(RenderThread& thread); - // EglContext is never destroyed, method is purposely not implemented - ~EglManager(); void initExtensions(); void createPBufferSurface(); @@ -72,8 +72,6 @@ private: void createContext(); EGLint queryBufferAge(EGLSurface surface); - RenderThread& mRenderThread; - EGLDisplay mEglDisplay; EGLConfig mEglConfig; EGLConfig mEglConfigWideGamut; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 4b948f8c6b362..0caf59b422026 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -21,6 +21,7 @@ #include "Properties.h" #include "Readback.h" #include "Rect.h" +#include "pipeline/skia/SkiaOpenGLPipeline.h" #include "pipeline/skia/VectorDrawableAtlas.h" #include "renderstate/RenderState.h" #include "renderthread/CanvasContext.h" @@ -323,7 +324,13 @@ void RenderProxy::prepareToDraw(Bitmap& bitmap) { sk_sp RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) { auto& thread = RenderThread::getInstance(); - return thread.queue().runSync([&]() -> auto { return thread.allocateHardwareBitmap(bitmap); }); + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { + return skiapipeline::SkiaOpenGLPipeline::allocateHardwareBitmap(thread, bitmap); + } else { + return thread.queue().runSync([&]() -> auto { + return thread.allocateHardwareBitmap(bitmap); + }); + } } int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) { diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 5e067dafed039..5dcfc3f579df8 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -24,12 +24,19 @@ #include "hwui/Bitmap.h" #include "pipeline/skia/SkiaOpenGLPipeline.h" #include "pipeline/skia/SkiaOpenGLReadback.h" -#include "pipeline/skia/SkiaVulkanReadback.h" #include "pipeline/skia/SkiaVulkanPipeline.h" +#include "pipeline/skia/SkiaVulkanReadback.h" #include "renderstate/RenderState.h" #include "utils/FatVector.h" #include "utils/TimeUtils.h" +#ifdef HWUI_GLES_WRAP_ENABLED +#include "debug/GlesDriver.h" +#endif + +#include +#include + #include #include #include @@ -91,14 +98,11 @@ public: DummyVsyncSource(RenderThread* renderThread) : mRenderThread(renderThread) {} virtual void requestNextVsync() override { - mRenderThread->queue().postDelayed(16_ms, [this]() { - mRenderThread->drainDisplayEventQueue(); - }); + mRenderThread->queue().postDelayed(16_ms, + [this]() { mRenderThread->drainDisplayEventQueue(); }); } - virtual nsecs_t latestVsyncEvent() override { - return systemTime(CLOCK_MONOTONIC); - } + virtual nsecs_t latestVsyncEvent() override { return systemTime(CLOCK_MONOTONIC); } private: RenderThread* mRenderThread; @@ -145,13 +149,13 @@ void RenderThread::initializeDisplayEventReceiver() { auto receiver = std::make_unique(); status_t status = receiver->initCheck(); LOG_ALWAYS_FATAL_IF(status != NO_ERROR, - "Initialization of DisplayEventReceiver " - "failed with status: %d", - status); + "Initialization of DisplayEventReceiver " + "failed with status: %d", + status); // Register the FD mLooper->addFd(receiver->getFd(), 0, Looper::EVENT_INPUT, - RenderThread::displayEventReceiverCallback, this); + RenderThread::displayEventReceiverCallback, this); mVsyncSource = new DisplayEventReceiverWrapper(std::move(receiver)); } else { mVsyncSource = new DummyVsyncSource(this); @@ -163,12 +167,45 @@ void RenderThread::initThreadLocals() { nsecs_t frameIntervalNanos = static_cast(1000000000 / mDisplayInfo.fps); mTimeLord.setFrameInterval(frameIntervalNanos); initializeDisplayEventReceiver(); - mEglManager = new EglManager(*this); + mEglManager = new EglManager(); mRenderState = new RenderState(*this); mVkManager = new VulkanManager(*this); mCacheManager = new CacheManager(mDisplayInfo); } +void RenderThread::requireGlContext() { + if (mEglManager->hasEglContext()) { + return; + } + mEglManager->initialize(); + renderState().onGLContextCreated(); + + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { +#ifdef HWUI_GLES_WRAP_ENABLED + debug::GlesDriver* driver = debug::GlesDriver::get(); + sk_sp glInterface(driver->getSkiaInterface()); +#else + sk_sp glInterface(GrGLCreateNativeInterface()); +#endif + LOG_ALWAYS_FATAL_IF(!glInterface.get()); + + GrContextOptions options; + options.fDisableDistanceFieldPaths = true; + cacheManager().configureContext(&options); + sk_sp grContext(GrContext::MakeGL(std::move(glInterface), options)); + LOG_ALWAYS_FATAL_IF(!grContext.get()); + setGrContext(grContext); + } +} + +void RenderThread::destroyGlContext() { + if (mEglManager->hasEglContext()) { + setGrContext(nullptr); + renderState().onGLContextDestroyed(); + mEglManager->destroy(); + } +} + void RenderThread::dumpGraphicsMemory(int fd) { globalProfileData()->dump(fd); @@ -332,8 +369,6 @@ void RenderThread::pushBackFrameCallback(IFrameCallback* callback) { sk_sp RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { - case RenderPipelineType::SkiaGL: - return skiapipeline::SkiaOpenGLPipeline::allocateHardwareBitmap(*this, skBitmap); case RenderPipelineType::SkiaVulkan: return skiapipeline::SkiaVulkanPipeline::allocateHardwareBitmap(*this, skBitmap); default: diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 689f518bad1b3..4a1fd9ee3d479 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -103,6 +103,9 @@ public: sk_sp allocateHardwareBitmap(SkBitmap& skBitmap); void dumpGraphicsMemory(int fd); + void requireGlContext(); + void destroyGlContext(); + /** * isCurrent provides a way to query, if the caller is running on * the render thread. diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index 16c5afdc3dcf1..b2fccd4cac53d 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -140,7 +140,7 @@ void TestUtils::TestTask::run() { if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { renderThread.vulkanManager().initialize(); } else { - renderThread.eglManager().initialize(); + renderThread.requireGlContext(); } rtCallback(renderThread); @@ -149,7 +149,7 @@ void TestUtils::TestTask::run() { renderThread.vulkanManager().destroy(); } else { renderThread.renderState().flush(Caches::FlushMode::Full); - renderThread.eglManager().destroy(); + renderThread.destroyGlContext(); } } diff --git a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp index 9bfb08292be2d..08b967964c59b 100644 --- a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp +++ b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp @@ -39,7 +39,7 @@ public: // current thread can spoof being a GPU thread static void destroyEglContext() { if (TestUtils::isRenderThreadRunning()) { - TestUtils::runOnRenderThread([](RenderThread& thread) { thread.eglManager().destroy(); }); + TestUtils::runOnRenderThread([](RenderThread& thread) { thread.destroyGlContext(); }); } }