diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 3b1ebd690465a..e586be1d07088 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -43,7 +43,13 @@ namespace uirenderer { namespace skiapipeline { SkiaOpenGLPipeline::SkiaOpenGLPipeline(RenderThread& thread) - : SkiaPipeline(thread), mEglManager(thread.eglManager()) {} + : SkiaPipeline(thread), mEglManager(thread.eglManager()) { + thread.renderState().registerContextCallback(this); +} + +SkiaOpenGLPipeline::~SkiaOpenGLPipeline() { + mRenderThread.renderState().removeContextCallback(this); +} MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() { // TODO: Figure out why this workaround is needed, see b/13913604 @@ -135,6 +141,13 @@ DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() { return new DeferredLayerUpdater(mRenderThread.renderState()); } +void SkiaOpenGLPipeline::onContextDestroyed() { + if (mEglSurface != EGL_NO_SURFACE) { + mEglManager.destroySurface(mEglSurface); + mEglSurface = EGL_NO_SURFACE; + } +} + void SkiaOpenGLPipeline::onStop() { if (mEglManager.isCurrent(mEglSurface)) { mEglManager.makeCurrent(EGL_NO_SURFACE); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index fbdf3139dabd1..086a76088a75a 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -18,6 +18,8 @@ #include "SkiaPipeline.h" +#include "renderstate/RenderState.h" + namespace android { class Bitmap; @@ -25,10 +27,10 @@ class Bitmap; namespace uirenderer { namespace skiapipeline { -class SkiaOpenGLPipeline : public SkiaPipeline { +class SkiaOpenGLPipeline : public SkiaPipeline, public IGpuContextCallback { public: SkiaOpenGLPipeline(renderthread::RenderThread& thread); - virtual ~SkiaOpenGLPipeline() {} + virtual ~SkiaOpenGLPipeline(); renderthread::MakeCurrentResult makeCurrent() override; renderthread::Frame getFrame() override; @@ -50,6 +52,9 @@ public: static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); +protected: + void onContextDestroyed() override; + private: renderthread::EglManager& mEglManager; EGLSurface mEglSurface = EGL_NO_SURFACE; diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index b524bcb096dab..b595ab859a61d 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -41,8 +41,15 @@ void RenderState::onContextCreated() { GpuMemoryTracker::onGpuContextCreated(); } +static void destroyLayerInUpdater(DeferredLayerUpdater* layerUpdater) { + layerUpdater->destroyLayer(); +} + void RenderState::onContextDestroyed() { - destroyLayersInUpdater(); + std::for_each(mActiveLayerUpdaters.begin(), mActiveLayerUpdaters.end(), destroyLayerInUpdater); + for(auto callback : mContextCallbacks) { + callback->onContextDestroyed(); + } GpuMemoryTracker::onGpuContextDestroyed(); } @@ -91,14 +98,6 @@ void RenderState::debugOverdraw(bool enable, bool clear) { // DEAD CODE } -static void destroyLayerInUpdater(DeferredLayerUpdater* layerUpdater) { - layerUpdater->destroyLayer(); -} - -void RenderState::destroyLayersInUpdater() { - std::for_each(mActiveLayerUpdaters.begin(), mActiveLayerUpdaters.end(), destroyLayerInUpdater); -} - void RenderState::postDecStrong(VirtualLightRefBase* object) { if (pthread_equal(mThreadId, pthread_self())) { object->decStrong(nullptr); diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h index f39aa4b96547d..dee02e9873d8d 100644 --- a/libs/hwui/renderstate/RenderState.h +++ b/libs/hwui/renderstate/RenderState.h @@ -41,6 +41,13 @@ class CanvasContext; class RenderThread; } +class IGpuContextCallback { +public: + virtual void onContextDestroyed() = 0; +protected: + virtual ~IGpuContextCallback() {} +}; + // wrapper of Caches for users to migrate to. class RenderState { PREVENT_COPY_AND_ASSIGN(RenderState); @@ -48,9 +55,6 @@ class RenderState { friend class renderthread::CacheManager; public: - void onContextCreated(); - void onContextDestroyed(); - void onBitmapDestroyed(uint32_t pixelRefId); void setViewport(GLsizei width, GLsizei height); @@ -63,6 +67,9 @@ public: void debugOverdraw(bool enable, bool clear); + void registerContextCallback(IGpuContextCallback* cb) { mContextCallbacks.insert(cb); } + void removeContextCallback(IGpuContextCallback* cb) { mContextCallbacks.erase(cb); } + void registerLayer(Layer* layer) { mActiveLayers.insert(layer); } void unregisterLayer(Layer* layer) { mActiveLayers.erase(layer); } @@ -93,13 +100,16 @@ public: renderthread::RenderThread& getRenderThread(); private: - void destroyLayersInUpdater(); - explicit RenderState(renderthread::RenderThread& thread); ~RenderState(); + // Context notifications are only to be triggered by renderthread::RenderThread + void onContextCreated(); + void onContextDestroyed(); + renderthread::RenderThread& mRenderThread; + std::set mContextCallbacks; std::set mActiveLayers; std::set mActiveLayerUpdaters; std::set mRegisteredContexts; diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index a5dcc72636d14..207673c1c8dd4 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -177,7 +177,6 @@ void RenderThread::requireGlContext() { return; } mEglManager->initialize(); - renderState().onContextCreated(); #ifdef HWUI_GLES_WRAP_ENABLED debug::GlesDriver* driver = debug::GlesDriver::get(); @@ -201,7 +200,6 @@ void RenderThread::requireGlContext() { void RenderThread::destroyGlContext() { if (mEglManager->hasEglContext()) { setGrContext(nullptr); - renderState().onContextDestroyed(); mEglManager->destroy(); } } @@ -243,10 +241,12 @@ Readback& RenderThread::readback() { void RenderThread::setGrContext(sk_sp context) { mCacheManager->reset(context); if (mGrContext) { + mRenderState->onContextDestroyed(); mGrContext->releaseResourcesAndAbandonContext(); } mGrContext = std::move(context); if (mGrContext) { + mRenderState->onContextCreated(); DeviceInfo::setMaxTextureSize(mGrContext->maxRenderTargetSize()); } } diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 488117253e7a4..e60d43e4001e3 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -39,7 +39,6 @@ namespace renderthread { VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {} void VulkanManager::destroy() { - mRenderThread.renderState().onContextDestroyed(); mRenderThread.setGrContext(nullptr); if (VK_NULL_HANDLE != mCommandPool) { @@ -401,8 +400,6 @@ void VulkanManager::initialize() { if (Properties::enablePartialUpdates && Properties::useBufferAge) { mSwapBehavior = SwapBehavior::BufferAge; } - - mRenderThread.renderState().onContextCreated(); } // Returns the next BackbufferInfo to use for the next draw. The function will make sure all diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index 5e5d13485942c..680fcb3a732b9 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -382,3 +382,13 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) { SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface); EXPECT_EQ(1, surface->canvas()->mDrawCounter); } + +RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) { + auto pipeline = std::make_unique(renderThread); + EXPECT_FALSE(pipeline->isSurfaceReady()); + EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::Legacy)); + EXPECT_TRUE(pipeline->isSurfaceReady()); + renderThread.destroyGlContext(); + EXPECT_FALSE(pipeline->isSurfaceReady()); +} +