Fix crash when EGLSurface is no longer valid.

The EGLSurface stored in the pipeline can become obsolete if the
EglManager/RenderThread has to destroy the context.  This CL enables the
RenderThread to notify all active pipelines that their surface is invalid.

Bug: 115290937
Test: hwui_unit_tests
Change-Id: Ib3054822273bc35406630b7442229a81b39a2c91
This commit is contained in:
Derek Sollenberger
2018-09-19 13:52:13 -04:00
parent ee23340357
commit 5a5a648b69
7 changed files with 56 additions and 22 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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<IGpuContextCallback*> mContextCallbacks;
std::set<Layer*> mActiveLayers;
std::set<DeferredLayerUpdater*> mActiveLayerUpdaters;
std::set<renderthread::CanvasContext*> mRegisteredContexts;

View File

@@ -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<GrContext> context) {
mCacheManager->reset(context);
if (mGrContext) {
mRenderState->onContextDestroyed();
mGrContext->releaseResourcesAndAbandonContext();
}
mGrContext = std::move(context);
if (mGrContext) {
mRenderState->onContextCreated();
DeviceInfo::setMaxTextureSize(mGrContext->maxRenderTargetSize());
}
}

View File

@@ -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

View File

@@ -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<SkiaOpenGLPipeline>(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());
}