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

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

Merge "Add shadow support to new reorderer/renderer"

parents b74b802e d3daa319
Loading
Loading
Loading
Loading
+73 −7
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "Caches.h"
#include "Glop.h"
#include "GlopBuilder.h"
#include "VertexBuffer.h"
#include "renderstate/RenderState.h"
#include "utils/FatVector.h"
#include "utils/GLUtils.h"
@@ -45,7 +46,7 @@ OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches,
    caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id);

    texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D);
    // not setting filter on texture, since it's set when drawing, based on transform
    // not setting filter on texture, since it's set when rendering, based on transform

    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0,
@@ -55,7 +56,7 @@ OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches,
void OffscreenBuffer::updateMeshFromRegion() {
    // avoid T-junctions as they cause artifacts in between the resultant
    // geometry when complex transforms occur.
    // TODO: generate the safeRegion only if necessary based on drawing transform
    // TODO: generate the safeRegion only if necessary based on rendering transform
    Region safeRegion = Region::createTJunctionFreeRegion(region);

    size_t count;
@@ -108,15 +109,15 @@ void BakedOpRenderer::destroyOffscreenBuffer(OffscreenBuffer* offscreenBuffer) {
    delete offscreenBuffer;
}

OffscreenBuffer* BakedOpRenderer::createLayer(uint32_t width, uint32_t height) {
    LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");

OffscreenBuffer* BakedOpRenderer::startTemporaryLayer(uint32_t width, uint32_t height) {
    OffscreenBuffer* buffer = createOffscreenBuffer(mRenderState, width, height);
    startLayer(buffer);
    startRepaintLayer(buffer);
    return buffer;
}

void BakedOpRenderer::startLayer(OffscreenBuffer* offscreenBuffer) {
void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer) {
    LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");

    mRenderTarget.offscreenBuffer = offscreenBuffer;

    // create and bind framebuffer
@@ -261,6 +262,71 @@ void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, co
    renderer.renderGlop(state, glop);
}

namespace VertexBufferRenderFlags {
    enum {
        Offset = 0x1,
        ShadowInterp = 0x2,
    };
}

static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state,
        const VertexBuffer& vertexBuffer, float translateX, float translateY,
        SkPaint& paint, int vertexBufferRenderFlags) {
    if (CC_LIKELY(vertexBuffer.getVertexCount())) {
        bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp;
        const int transformFlags = TransformFlags::OffsetByFudgeFactor;
        Glop glop;
        GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
                .setRoundRectClipState(state.roundRectClipState)
                .setMeshVertexBuffer(vertexBuffer, shadowInterp)
                .setFillPaint(paint, state.alpha)
                .setTransform(state.computedState.transform, transformFlags)
                .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
                .build();
        renderer.renderGlop(state, glop);
    }
}

static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, float casterAlpha,
        const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
    SkPaint paint;
    paint.setAntiAlias(true); // want to use AlphaVertex

    // The caller has made sure casterAlpha > 0.
    uint8_t ambientShadowAlpha = 128u; //TODO: mAmbientShadowAlpha;
    if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) {
        ambientShadowAlpha = Properties::overrideAmbientShadowStrength;
    }
    if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
        paint.setAlpha((uint8_t)(casterAlpha * ambientShadowAlpha));
        renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0,
                paint, VertexBufferRenderFlags::ShadowInterp);
    }

    uint8_t spotShadowAlpha = 128u; //TODO: mSpotShadowAlpha;
    if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) {
        spotShadowAlpha = Properties::overrideSpotShadowStrength;
    }
    if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
        paint.setAlpha((uint8_t)(casterAlpha * spotShadowAlpha));
        renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0,
                paint, VertexBufferRenderFlags::ShadowInterp);
    }
}

void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) {
    TessellationCache::vertexBuffer_pair_t buffers;
    Vector3 lightCenter = { 300, 300, 300 }; // TODO!
    float lightRadius = 150; // TODO!

    renderer.caches().tessellationCache.getShadowBuffers(&state.computedState.transform,
            op.localClipRect, op.casterAlpha >= 1.0f, op.casterPath,
            &op.shadowMatrixXY, &op.shadowMatrixZ, lightCenter, lightRadius,
            buffers);

    renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second);
}

void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) {
    Glop glop;
    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+2 −2
Original line number Diff line number Diff line
@@ -81,8 +81,8 @@ public:

    void startFrame(uint32_t width, uint32_t height);
    void endFrame();
    OffscreenBuffer* createLayer(uint32_t width, uint32_t height);
    void startLayer(OffscreenBuffer* offscreenBuffer);
    OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height);
    void startRepaintLayer(OffscreenBuffer* offscreenBuffer);
    void endLayer();

    Texture* getTexture(const SkBitmap* bitmap);
+31 −2
Original line number Diff line number Diff line
@@ -89,6 +89,21 @@ public:
         *         and early return null in one place.
         */
    }

    /**
     * Constructor for unbounded ops without transform/clip (namely shadows)
     *
     * Since the op doesn't have known bounds, we conservatively set the mapped bounds
     * to the current clipRect, and clipSideFlags to Full.
     */
    ResolvedRenderState(const Snapshot& snapshot) {
        transform = *snapshot.transform;
        clipRect = snapshot.getRenderTargetClip();
        clippedBounds = clipRect;
        transform.mapRect(clippedBounds);
        clipSideFlags = OpClipSideFlags::Full;
    }

    Matrix4 transform;
    Rect clipRect;
    int clipSideFlags = 0;
@@ -104,8 +119,7 @@ class BakedOpState {
public:
    static BakedOpState* tryConstruct(LinearAllocator& allocator,
            const Snapshot& snapshot, const RecordedOp& recordedOp) {
        BakedOpState* bakedOp = new (allocator) BakedOpState(
                snapshot, recordedOp);
        BakedOpState* bakedOp = new (allocator) BakedOpState(snapshot, recordedOp);
        if (bakedOp->computedState.clippedBounds.isEmpty()) {
            // bounds are empty, so op is rejected
            allocator.rewindIfLastAlloc(bakedOp);
@@ -114,6 +128,14 @@ public:
        return bakedOp;
    }

    static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
            const Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
        if (snapshot.getRenderTargetClip().isEmpty()) return nullptr;

        // clip isn't empty, so construct the op
        return new (allocator) BakedOpState(snapshot, shadowOpPtr);
    }

    static void* operator new(size_t size, LinearAllocator& allocator) {
        return allocator.alloc(size);
    }
@@ -134,6 +156,13 @@ private:
            , roundRectClipState(snapshot.roundRectClipState)
            , projectionPathMask(snapshot.projectionPathMask)
            , op(&recordedOp) {}

    BakedOpState(const Snapshot& snapshot, const ShadowOp* shadowOpPtr)
            : computedState(snapshot)
            , alpha(snapshot.alpha)
            , roundRectClipState(snapshot.roundRectClipState)
            , projectionPathMask(snapshot.projectionPathMask)
            , op(shadowOpPtr) {}
};

}; // namespace uirenderer
+59 −3
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include "utils/PaintUtils.h"

#include <SkCanvas.h>
#include <SkPathOps.h>
#include <utils/Trace.h>
#include <utils/TypeHelpers.h>

@@ -347,7 +348,6 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip,
OpReorderer::OpReorderer(int viewportWidth, int viewportHeight, const DisplayList& displayList)
        : mCanvasState(*this) {
    ATRACE_NAME("prepare drawing commands");

    mLayerReorderers.emplace_back(viewportWidth, viewportHeight);
    mLayerStack.push_back(0);

@@ -462,8 +462,60 @@ void OpReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedN
}

void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) {
    // TODO
    auto& node = *casterNodeOp.renderNode;
    auto& properties = node.properties();

    if (properties.getAlpha() <= 0.0f
            || properties.getOutline().getAlpha() <= 0.0f
            || !properties.getOutline().getPath()
            || properties.getScaleX() == 0
            || properties.getScaleY() == 0) {
        // no shadow to draw
        return;
    }

    const SkPath* casterOutlinePath = properties.getOutline().getPath();
    const SkPath* revealClipPath = properties.getRevealClip().getPath();
    if (revealClipPath && revealClipPath->isEmpty()) return;

    float casterAlpha = properties.getAlpha() * properties.getOutline().getAlpha();

    // holds temporary SkPath to store the result of intersections
    SkPath* frameAllocatedPath = nullptr;
    const SkPath* casterPath = casterOutlinePath;

    // intersect the shadow-casting path with the reveal, if present
    if (revealClipPath) {
        frameAllocatedPath = createFrameAllocatedPath();

        Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, frameAllocatedPath);
        casterPath = frameAllocatedPath;
    }

    // intersect the shadow-casting path with the clipBounds, if present
    if (properties.getClippingFlags() & CLIP_TO_CLIP_BOUNDS) {
        if (!frameAllocatedPath) {
            frameAllocatedPath = createFrameAllocatedPath();
        }
        Rect clipBounds;
        properties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds);
        SkPath clipBoundsPath;
        clipBoundsPath.addRect(clipBounds.left, clipBounds.top,
                clipBounds.right, clipBounds.bottom);

        Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath);
        casterPath = frameAllocatedPath;
    }

    ShadowOp* shadowOp = new (mAllocator) ShadowOp(casterNodeOp, casterAlpha, casterPath,
            mCanvasState.getLocalClipBounds());
    BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
            mAllocator, *mCanvasState.currentSnapshot(), shadowOp);
    if (CC_LIKELY(bakedOpState)) {
        currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
    }
}

/**
 * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods.
 *
@@ -593,5 +645,9 @@ void OpReorderer::onLayerOp(const LayerOp& op) {
    LOG_ALWAYS_FATAL("unsupported");
}

void OpReorderer::onShadowOp(const ShadowOp& op) {
    LOG_ALWAYS_FATAL("unsupported");
}

} // namespace uirenderer
} // namespace android
+9 −2
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ namespace OpBatchType {
        AlphaMaskTexture,
        Text,
        ColorText,
        Shadow,

        Count // must be last
    };
@@ -152,11 +153,11 @@ public:
            LayerReorderer& layer = mLayerReorderers[i];
            if (layer.renderNode) {
                // cached HW layer - can't skip layer if empty
                renderer.startLayer(layer.offscreenBuffer);
                renderer.startRepaintLayer(layer.offscreenBuffer);
                layer.replayBakedOpsImpl((void*)&renderer, receivers);
                renderer.endLayer();
            } else if (!layer.empty()) { // save layer - skip entire layer if empty
                layer.offscreenBuffer = renderer.createLayer(layer.width, layer.height);
                layer.offscreenBuffer = renderer.startTemporaryLayer(layer.width, layer.height);
                layer.replayBakedOpsImpl((void*)&renderer, receivers);
                renderer.endLayer();
            }
@@ -210,6 +211,10 @@ private:

    void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers);

    SkPath* createFrameAllocatedPath() {
        mFrameAllocatedPaths.emplace_back(new SkPath);
        return mFrameAllocatedPaths.back().get();
    }
    /**
     * Declares all OpReorderer::onXXXXOp() methods for every RecordedOp type.
     *
@@ -220,6 +225,8 @@ private:
    void on##Type(const Type& op);
    MAP_OPS(INTERNAL_OP_HANDLER)

    std::vector<std::unique_ptr<SkPath> > mFrameAllocatedPaths;

    // List of every deferred layer's render state. Replayed in reverse order to render a frame.
    std::vector<LayerReorderer> mLayerReorderers;

Loading