Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5a5a648b authored by Derek Sollenberger's avatar Derek Sollenberger
Browse files

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
parent ee233403
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -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);
+7 −2
Original line number Diff line number Diff line
@@ -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;
+8 −9
Original line number Diff line number Diff line
@@ -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);
+15 −5
Original line number Diff line number Diff line
@@ -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;
+2 −2
Original line number Diff line number Diff line
@@ -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());
    }
}
Loading