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

Commit 4a12d7bd authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Destroy prefetched layers when the context is destroyed" into main

parents bf7b6d33 20a4d683
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -64,12 +64,13 @@ public:
    void unregisterCanvasContext(CanvasContext* context);
    void onContextStopped(CanvasContext* context);

    bool areAllContextsStopped();

private:
    friend class RenderThread;

    explicit CacheManager(RenderThread& thread);
    void setupCacheLimits();
    bool areAllContextsStopped();
    void checkUiHidden();
    void scheduleDestroyContext();
    void cancelDestroyContext();
+6 −0
Original line number Diff line number Diff line
@@ -125,6 +125,7 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode*
        , mRenderPipeline(std::move(renderPipeline))
        , mHintSessionWrapper(uiThreadId, renderThreadId) {
    mRenderThread.cacheManager().registerCanvasContext(this);
    mRenderThread.renderState().registerContextCallback(this);
    rootRenderNode->makeRoot();
    mRenderNodes.emplace_back(rootRenderNode);
    mProfiler.setDensity(DeviceInfo::getDensity());
@@ -137,6 +138,7 @@ CanvasContext::~CanvasContext() {
    }
    mRenderNodes.clear();
    mRenderThread.cacheManager().unregisterCanvasContext(this);
    mRenderThread.renderState().removeContextCallback(this);
}

void CanvasContext::addRenderNode(RenderNode* node, bool placeFront) {
@@ -963,6 +965,10 @@ void CanvasContext::destroyHardwareResources() {
    }
}

void CanvasContext::onContextDestroyed() {
    destroyHardwareResources();
}

DeferredLayerUpdater* CanvasContext::createTextureLayer() {
    return mRenderPipeline->createTextureLayer();
}
+3 −1
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#include "Lighting.h"
#include "ReliableSurface.h"
#include "RenderNode.h"
#include "renderstate/RenderState.h"
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
#include "utils/RingBuffer.h"
@@ -64,7 +65,7 @@ class Frame;
// This per-renderer class manages the bridge between the global EGL context
// and the render surface.
// TODO: Rename to Renderer or some other per-window, top-level manager
class CanvasContext : public IFrameCallback {
class CanvasContext : public IFrameCallback, public IGpuContextCallback {
public:
    static CanvasContext* create(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
                                 IContextFactory* contextFactory, pid_t uiThreadId,
@@ -154,6 +155,7 @@ public:
    void markLayerInUse(RenderNode* node);

    void destroyHardwareResources();
    void onContextDestroyed() override;

    DeferredLayerUpdater* createTextureLayer();

+25 −4
Original line number Diff line number Diff line
@@ -307,13 +307,21 @@ public:
        int destroyed = 0;
        int removeOverlays = 0;
        int glesDraw = 0;
        int vkInitialize = 0;
        int vkDraw = 0;
        int vkPostDraw = 0;
    };

    static void expectOnRenderThread(const std::string_view& function = "unknown") {
        EXPECT_EQ(gettid(), TestUtils::getRenderThreadTid()) << "Called on wrong thread: " << function;
    }

    static WebViewFunctorCallbacks createMockFunctor(RenderMode mode) {
    static int createMockFunctor() {
        const auto renderMode = WebViewFunctor_queryPlatformRenderMode();
        return WebViewFunctor_create(nullptr, createMockFunctorCallbacks(renderMode), renderMode);
    }

    static WebViewFunctorCallbacks createMockFunctorCallbacks(RenderMode mode) {
        auto callbacks = WebViewFunctorCallbacks{
                .onSync =
                        [](int functor, void* client_data, const WebViewSyncData& data) {
@@ -345,9 +353,22 @@ public:
                    sMockFunctorCounts[functor].glesDraw++;
                };
                break;
            default:
                ADD_FAILURE();
                return WebViewFunctorCallbacks{};
            case RenderMode::Vulkan:
                callbacks.vk.initialize = [](int functor, void* data,
                                             const VkFunctorInitParams& params) {
                    expectOnRenderThread("initialize");
                    sMockFunctorCounts[functor].vkInitialize++;
                };
                callbacks.vk.draw = [](int functor, void* data, const VkFunctorDrawParams& params,
                                       const WebViewOverlayData& overlayParams) {
                    expectOnRenderThread("draw");
                    sMockFunctorCounts[functor].vkDraw++;
                };
                callbacks.vk.postDraw = [](int functor, void* data) {
                    expectOnRenderThread("postDraw");
                    sMockFunctorCounts[functor].vkPostDraw++;
                };
                break;
        }
        return callbacks;
    }
+36 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "AnimationContext.h"
#include "IContextFactory.h"
#include "renderthread/CanvasContext.h"
#include "renderthread/VulkanManager.h"
#include "tests/common/TestUtils.h"

using namespace android;
@@ -42,3 +43,38 @@ RENDERTHREAD_TEST(CanvasContext, create) {

    canvasContext->destroy();
}

RENDERTHREAD_TEST(CanvasContext, buildLayerDoesntLeak) {
    auto node = TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
        canvas.drawColor(0xFFFF0000, SkBlendMode::kSrc);
    });
    ASSERT_TRUE(node->isValid());
    EXPECT_EQ(LayerType::None, node->stagingProperties().effectiveLayerType());
    node->mutateStagingProperties().mutateLayerProperties().setType(LayerType::RenderLayer);

    auto& cacheManager = renderThread.cacheManager();
    EXPECT_TRUE(cacheManager.areAllContextsStopped());
    ContextFactory contextFactory;
    std::unique_ptr<CanvasContext> canvasContext(
            CanvasContext::create(renderThread, false, node.get(), &contextFactory, 0, 0));
    canvasContext->buildLayer(node.get());
    EXPECT_TRUE(node->hasLayer());
    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
        auto instance = VulkanManager::peekInstance();
        if (instance) {
            EXPECT_TRUE(instance->hasVkContext());
        } else {
            ADD_FAILURE() << "VulkanManager wasn't initialized to buildLayer?";
        }
    }
    renderThread.destroyRenderingContext();
    EXPECT_FALSE(node->hasLayer()) << "Node still has a layer after rendering context destroyed";

    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
        auto instance = VulkanManager::peekInstance();
        if (instance) {
            ADD_FAILURE() << "VulkanManager still exists";
            EXPECT_FALSE(instance->hasVkContext());
        }
    }
}
Loading