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

Commit f42e9b1b authored by Chris Craik's avatar Chris Craik Committed by android-build-merger
Browse files

Merge "Overdraw avoidance in new pipeline" into nyc-dev

am: 80a67f36

* commit '80a67f36':
  Overdraw avoidance in new pipeline

Change-Id: I139d5172d2913ecce6f8ab91d5f5b5f34988039a
parents d071808b 80a67f36
Loading
Loading
Loading
Loading
+58 −0
Original line number Diff line number Diff line
@@ -108,5 +108,63 @@ ResolvedRenderState::ResolvedRenderState(const ClipRect* clipRect, const Rect& d
    clippedBounds.doIntersect(clipRect->rect);
}

BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator,
        Snapshot& snapshot, const RecordedOp& recordedOp) {
    if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
    BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
            allocator, snapshot, recordedOp, false);
    if (bakedState->computedState.clippedBounds.isEmpty()) {
        // bounds are empty, so op is rejected
        allocator.rewindIfLastAlloc(bakedState);
        return nullptr;
    }
    return bakedState;
}

BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator,
        Snapshot& snapshot, const RecordedOp& recordedOp) {
    if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
    return allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp);
}

BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator,
        Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
    if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
    bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined)
            ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
            : true;

    BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
           allocator, snapshot, recordedOp, expandForStroke);
    if (bakedState->computedState.clippedBounds.isEmpty()) {
        // bounds are empty, so op is rejected
        // NOTE: this won't succeed if a clip was allocated
        allocator.rewindIfLastAlloc(bakedState);
        return nullptr;
    }
    return bakedState;
}

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

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

BakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator,
        const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
    return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
}

void BakedOpState::setupOpacity(const SkPaint* paint) {
    computedState.opaqueOverClippedBounds = computedState.transform.isSimple()
            && computedState.clipState->mode == ClipMode::Rectangle
            && MathUtils::areEqual(alpha, 1.0f)
            && !roundRectClipState
            && PaintUtils::isOpaquePaint(paint);
}

} // namespace uirenderer
} // namespace android
+9 −40
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ public:
    Rect clippedBounds;
    int clipSideFlags = 0;
    const SkPath* localProjectionPathMask = nullptr;
    bool opaqueOverClippedBounds = false;
};

/**
@@ -103,23 +104,10 @@ public:
class BakedOpState {
public:
    static BakedOpState* tryConstruct(LinearAllocator& allocator,
            Snapshot& snapshot, const RecordedOp& recordedOp) {
        if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
        BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
                allocator, snapshot, recordedOp, false);
        if (bakedState->computedState.clippedBounds.isEmpty()) {
            // bounds are empty, so op is rejected
            allocator.rewindIfLastAlloc(bakedState);
            return nullptr;
        }
        return bakedState;
    }
            Snapshot& snapshot, const RecordedOp& recordedOp);

    static BakedOpState* tryConstructUnbounded(LinearAllocator& allocator,
            Snapshot& snapshot, const RecordedOp& recordedOp) {
        if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
        return allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp);
    }
            Snapshot& snapshot, const RecordedOp& recordedOp);

    enum class StrokeBehavior {
        // stroking is forced, regardless of style on paint (such as for lines)
@@ -129,35 +117,16 @@ public:
    };

    static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator,
            Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
        if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
        bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined)
                ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
                : true;

        BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
                allocator, snapshot, recordedOp, expandForStroke);
        if (bakedState->computedState.clippedBounds.isEmpty()) {
            // bounds are empty, so op is rejected
            // NOTE: this won't succeed if a clip was allocated
            allocator.rewindIfLastAlloc(bakedState);
            return nullptr;
        }
        return bakedState;
    }
            Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior);

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

        // clip isn't empty, so construct the op
        return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr);
    }
            Snapshot& snapshot, const ShadowOp* shadowOpPtr);

    static BakedOpState* directConstruct(LinearAllocator& allocator,
            const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
        return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
    }
            const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp);

    // Set opaqueOverClippedBounds. If this method isn't called, the op is assumed translucent.
    void setupOpacity(const SkPaint* paint);

    // computed state:
    ResolvedRenderState computedState;
+7 −1
Original line number Diff line number Diff line
@@ -481,12 +481,17 @@ void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) {
 * Defers an unmergeable, strokeable op, accounting correctly
 * for paint's style on the bounds being computed.
 */
const BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
        BakedOpState::StrokeBehavior strokeBehavior) {
    // Note: here we account for stroke when baking the op
    BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
            mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior);
    if (!bakedState) return nullptr; // quick rejected

    if (op.opId == RecordedOpId::RectOp && op.paint->getStyle() != SkPaint::kStroke_Style) {
        bakedState->setupOpacity(op.paint);
    }

    currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
    return bakedState;
}
@@ -516,6 +521,7 @@ static bool hasMergeableClip(const BakedOpState& state) {
void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
    BakedOpState* bakedState = tryBakeOpState(op);
    if (!bakedState) return; // quick rejected
    bakedState->setupOpacity(op.paint);

    // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
    // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
+1 −1
Original line number Diff line number Diff line
@@ -201,7 +201,7 @@ private:
        return mAllocator.create<SkPath>();
    }

    const BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
    BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
            BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined);

    /**
+25 −9
Original line number Diff line number Diff line
@@ -236,6 +236,21 @@ void LayerBuilder::deferLayerClear(const Rect& rect) {
    mClearRects.push_back(rect);
}

void LayerBuilder::onDeferOp(LinearAllocator& allocator, const BakedOpState* bakedState) {
    if (bakedState->op->opId != RecordedOpId::CopyToLayerOp) {
        // First non-CopyToLayer, so stop stashing up layer clears for unclipped save layers,
        // and issue them together in one draw.
        flushLayerClears(allocator);

        if (CC_UNLIKELY(activeUnclippedSaveLayers.empty()
                && bakedState->computedState.opaqueOverClippedBounds
                && bakedState->computedState.clippedBounds.contains(repaintRect))) {
            // discard all deferred drawing ops, since new one will occlude them
            clear();
        }
    }
}

void LayerBuilder::flushLayerClears(LinearAllocator& allocator) {
    if (CC_UNLIKELY(!mClearRects.empty())) {
        const int vertCount = mClearRects.size() * 4;
@@ -270,11 +285,7 @@ void LayerBuilder::flushLayerClears(LinearAllocator& allocator) {

void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator,
        BakedOpState* op, batchid_t batchId) {
    if (batchId != OpBatchType::CopyToLayer) {
        // if first op after one or more unclipped saveLayers, flush the layer clears
        flushLayerClears(allocator);
    }

    onDeferOp(allocator, op);
    OpBatch* targetBatch = mBatchLookup[batchId];

    size_t insertBatchIndex = mBatches.size();
@@ -295,10 +306,7 @@ void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator,

void LayerBuilder::deferMergeableOp(LinearAllocator& allocator,
        BakedOpState* op, batchid_t batchId, mergeid_t mergeId) {
    if (batchId != OpBatchType::CopyToLayer) {
        // if first op after one or more unclipped saveLayers, flush the layer clears
        flushLayerClears(allocator);
    }
    onDeferOp(allocator, op);
    MergingOpBatch* targetBatch = nullptr;

    // Try to merge with any existing batch with same mergeId
@@ -348,6 +356,14 @@ void LayerBuilder::replayBakedOpsImpl(void* arg,
    }
}

void LayerBuilder::clear() {
    mBatches.clear();
    for (int i = 0; i < OpBatchType::Count; i++) {
        mBatchLookup[i] = nullptr;
        mMergingBatchLookup[i].clear();
    }
}

void LayerBuilder::dump() const {
    ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p (%s)",
            this, width, height, offscreenBuffer, beginLayerOp,
Loading