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

Commit e5b50197 authored by Chris Craik's avatar Chris Craik
Browse files

Support for stencil clipping in layers

bug:22480459

Change-Id: Ic9e8652379524ccc46d8722ce49f9190b08a2abc
parent e4db79de
Loading
Loading
Loading
Loading
+47 −22
Original line number Original line Diff line number Diff line
@@ -60,10 +60,18 @@ void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const
}
}


void BakedOpRenderer::endLayer() {
void BakedOpRenderer::endLayer() {
    mRenderTarget.offscreenBuffer->updateMeshFromRegion();
    if (mRenderTarget.stencil) {
    mRenderTarget.offscreenBuffer = nullptr;
        // if stencil was used for clipping, detach it and return it to pool
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
        LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "glfbrb endlayer failed");
        mCaches.renderBufferCache.put(mRenderTarget.stencil);
        mRenderTarget.stencil = nullptr;
    }
    mRenderTarget.lastStencilClip = nullptr;
    mRenderTarget.lastStencilClip = nullptr;


    mRenderTarget.offscreenBuffer->updateMeshFromRegion();
    mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.

    // Detach the texture from the FBO
    // Detach the texture from the FBO
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
@@ -75,7 +83,6 @@ void BakedOpRenderer::startFrame(uint32_t width, uint32_t height, const Rect& re
    LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "primary framebufferId must be 0");
    LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "primary framebufferId must be 0");
    mRenderState.bindFramebuffer(0);
    mRenderState.bindFramebuffer(0);
    setViewport(width, height);
    setViewport(width, height);
    mCaches.clearGarbage();


    if (!mOpaque) {
    if (!mOpaque) {
        clearColorBuffer(repaintRect);
        clearColorBuffer(repaintRect);
@@ -113,6 +120,7 @@ void BakedOpRenderer::endFrame(const Rect& repaintRect) {
        mRenderState.stencil().disable();
        mRenderState.stencil().disable();
    }
    }


    mCaches.clearGarbage();
    mCaches.pathCache.trim();
    mCaches.pathCache.trim();
    mCaches.tessellationCache.trim();
    mCaches.tessellationCache.trim();


@@ -232,17 +240,25 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* cli
    mRenderState.scissor().setEnabled(clip != nullptr);
    mRenderState.scissor().setEnabled(clip != nullptr);
    if (clip) {
    if (clip) {
        mRenderState.scissor().set(mRenderTarget.viewportHeight, clip->rect);
        mRenderState.scissor().set(mRenderTarget.viewportHeight, clip->rect);
    }

    if (CC_LIKELY(!Properties::debugOverdraw)) {
    if (CC_LIKELY(!Properties::debugOverdraw)) {
        // only modify stencil mode and content when it's not used for overdraw visualization
        // only modify stencil mode and content when it's not used for overdraw visualization
            if (CC_UNLIKELY(clip->mode != ClipMode::Rectangle)) {
        if (CC_UNLIKELY(clip && clip->mode != ClipMode::Rectangle)) {
            // NOTE: this pointer check is only safe for non-rect clips,
            // NOTE: this pointer check is only safe for non-rect clips,
            // since rect clips may be created on the stack
            // since rect clips may be created on the stack
            if (mRenderTarget.lastStencilClip != clip) {
            if (mRenderTarget.lastStencilClip != clip) {
                // Stencil needed, but current stencil isn't up to date
                // Stencil needed, but current stencil isn't up to date
                mRenderTarget.lastStencilClip = clip;
                mRenderTarget.lastStencilClip = clip;


                    if (mRenderTarget.offscreenBuffer) {
                if (mRenderTarget.frameBufferId != 0 && !mRenderTarget.stencil) {
                        LOG_ALWAYS_FATAL("prepare layer stencil");
                    OffscreenBuffer* layer = mRenderTarget.offscreenBuffer;
                    mRenderTarget.stencil = mCaches.renderBufferCache.get(
                            Stencil::getLayerStencilFormat(),
                            layer->texture.width, layer->texture.height);
                    // stencil is bound + allocated - associate it with current FBO
                    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                            GL_RENDERBUFFER, mRenderTarget.stencil->getName());
                }
                }


                if (clip->mode == ClipMode::RectangleList) {
                if (clip->mode == ClipMode::RectangleList) {
@@ -250,12 +266,21 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* cli
                } else {
                } else {
                    setupStencilRegion(clip);
                    setupStencilRegion(clip);
                }
                }
            } else {
                // stencil is up to date - just need to ensure it's enabled (since an unclipped
                // or scissor-only clipped op may have been drawn, disabling the stencil)
                int incrementThreshold = 0;
                if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
                    auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
                    incrementThreshold = rectList.getTransformedRectanglesCount();
                }
                mRenderState.stencil().enableTest(incrementThreshold);
            }
            }
        } else {
        } else {
            // either scissor or no clip, so disable stencil test
            mRenderState.stencil().disable();
            mRenderState.stencil().disable();
        }
        }
    }
    }
    }


    // dirty offscreenbuffer
    // dirty offscreenbuffer
    if (dirtyBounds && mRenderTarget.offscreenBuffer) {
    if (dirtyBounds && mRenderTarget.offscreenBuffer) {
+13 −1
Original line number Original line Diff line number Diff line
@@ -95,12 +95,24 @@ private:
    // render target state - setup by start/end layer/frame
    // render target state - setup by start/end layer/frame
    // only valid to use in between start/end pairs.
    // only valid to use in between start/end pairs.
    struct {
    struct {
        // If not drawing to a layer: fbo = 0, offscreenBuffer = null,
        // Otherwise these refer to currently painting layer's state
        GLuint frameBufferId = 0;
        GLuint frameBufferId = 0;
        OffscreenBuffer* offscreenBuffer = nullptr;
        OffscreenBuffer* offscreenBuffer = nullptr;

        // Used when drawing to a layer and using stencil clipping. otherwise null.
        RenderBuffer* stencil = nullptr;

        // value representing the ClipRectList* or ClipRegion* currently stored in
        // the stencil of the current render target
        const ClipBase* lastStencilClip = nullptr;

        // Size of renderable region in current render target - for layers, may not match actual
        // bounds of FBO texture. offscreenBuffer->texture has this information.
        uint32_t viewportWidth = 0;
        uint32_t viewportWidth = 0;
        uint32_t viewportHeight = 0;
        uint32_t viewportHeight = 0;

        Matrix4 orthoMatrix;
        Matrix4 orthoMatrix;
        const ClipBase* lastStencilClip = nullptr;
    } mRenderTarget;
    } mRenderTarget;


    const LightInfo mLightInfo;
    const LightInfo mLightInfo;
+1 −1
Original line number Original line Diff line number Diff line
@@ -78,7 +78,7 @@ GlopBuilder& GlopBuilder::setMeshTexturedIndexedVbo(GLuint vbo, GLsizei elementC
    mOutGlop->mesh.vertices = {
    mOutGlop->mesh.vertices = {
            vbo,
            vbo,
            VertexAttribFlags::TextureCoord,
            VertexAttribFlags::TextureCoord,
            nullptr, nullptr, nullptr,
            nullptr, (const void*) kMeshTextureOffset, nullptr,
            kTextureVertexStride };
            kTextureVertexStride };
    mOutGlop->mesh.elementCount = elementCount;
    mOutGlop->mesh.elementCount = elementCount;
    return *this;
    return *this;
+2 −2
Original line number Original line Diff line number Diff line
@@ -391,9 +391,9 @@ struct LayerOp : RecordedOp {
    LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
    LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
            : SUPER_PAINTLESS(LayerOp)
            : SUPER_PAINTLESS(LayerOp)
            , layerHandle(layerHandle)
            , layerHandle(layerHandle)
            , alpha(paint->getAlpha() / 255.0f)
            , alpha(paint ? paint->getAlpha() / 255.0f : 1.0f)
            , mode(PaintUtils::getXfermodeDirect(paint))
            , mode(PaintUtils::getXfermodeDirect(paint))
            , colorFilter(paint->getColorFilter())
            , colorFilter(paint ? paint->getColorFilter() : nullptr)
            , destroy(true) {}
            , destroy(true) {}


    LayerOp(RenderNode& node)
    LayerOp(RenderNode& node)
+4 −4
Original line number Original line Diff line number Diff line
@@ -30,8 +30,6 @@ public:
    sp<RenderNode> card;
    sp<RenderNode> card;
    void createContent(int width, int height, TestCanvas& canvas) override {
    void createContent(int width, int height, TestCanvas& canvas) override {
        canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
        canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
        canvas.insertReorderBarrier(true);

        card = TestUtils::createNode(0, 0, 200, 400,
        card = TestUtils::createNode(0, 0, 200, 400,
                [](RenderProperties& props, TestCanvas& canvas) {
                [](RenderProperties& props, TestCanvas& canvas) {
            canvas.save(SkCanvas::kMatrixClip_SaveFlag);
            canvas.save(SkCanvas::kMatrixClip_SaveFlag);
@@ -53,10 +51,12 @@ public:
                canvas.drawColor(Color::Red_500, SkXfermode::kSrcOver_Mode);
                canvas.drawColor(Color::Red_500, SkXfermode::kSrcOver_Mode);
            }
            }
            canvas.restore();
            canvas.restore();

            // put on a layer, to test stencil attachment
            props.mutateLayerProperties().setType(LayerType::RenderLayer);
            props.setAlpha(0.9f);
        });
        });
        canvas.drawRenderNode(card.get());
        canvas.drawRenderNode(card.get());

        canvas.insertReorderBarrier(false);
    }
    }
    void doFrame(int frameNr) override {
    void doFrame(int frameNr) override {
        int curFrame = frameNr % 150;
        int curFrame = frameNr % 150;