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

Commit 982dcf3e authored by Chris Craik's avatar Chris Craik Committed by Android (Google) Code Review
Browse files

Merge "Support for stencil clipping in layers"

parents f5baedb0 e5b50197
Loading
Loading
Loading
Loading
+47 −22
Original line number Diff line number Diff line
@@ -60,10 +60,18 @@ void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const
}

void BakedOpRenderer::endLayer() {
    mRenderTarget.offscreenBuffer->updateMeshFromRegion();
    mRenderTarget.offscreenBuffer = nullptr;
    if (mRenderTarget.stencil) {
        // 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.offscreenBuffer->updateMeshFromRegion();
    mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.

    // Detach the texture from the FBO
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
    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");
    mRenderState.bindFramebuffer(0);
    setViewport(width, height);
    mCaches.clearGarbage();

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

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

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

    if (CC_LIKELY(!Properties::debugOverdraw)) {
        // 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,
            // since rect clips may be created on the stack
            if (mRenderTarget.lastStencilClip != clip) {
                // Stencil needed, but current stencil isn't up to date
                mRenderTarget.lastStencilClip = clip;

                    if (mRenderTarget.offscreenBuffer) {
                        LOG_ALWAYS_FATAL("prepare layer stencil");
                if (mRenderTarget.frameBufferId != 0 && !mRenderTarget.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) {
@@ -250,12 +266,21 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* cli
                } else {
                    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 {
            // either scissor or no clip, so disable stencil test
            mRenderState.stencil().disable();
        }
    }
    }

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

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

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

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

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

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

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