DamageAccumulator.cpp revision ce9f308063cc2bc7851f3f58c881da8a7271eecc
1e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck/*
2e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * Copyright (C) 2014 The Android Open Source Project
3e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck *
4e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * Licensed under the Apache License, Version 2.0 (the "License");
5e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * you may not use this file except in compliance with the License.
6e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * You may obtain a copy of the License at
7e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck *
8e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck *      http://www.apache.org/licenses/LICENSE-2.0
9e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck *
10e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * Unless required by applicable law or agreed to in writing, software
11e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * distributed under the License is distributed on an "AS IS" BASIS,
12e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * See the License for the specific language governing permissions and
14e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck * limitations under the License.
15e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck */
16e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
17e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck#define LOG_TAG "DamageAccumulator"
18e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
19e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck#include "DamageAccumulator.h"
20e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
21e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck#include <cutils/log.h>
22e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
23e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck#include "RenderNode.h"
24e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck#include "utils/MathUtils.h"
25e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
26e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Recknamespace android {
27e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Recknamespace uirenderer {
28e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
29a447d29c65fb811cd184775a3476101a1cede929John ReckNullDamageAccumulator NullDamageAccumulator::sInstance;
30a447d29c65fb811cd184775a3476101a1cede929John Reck
31a447d29c65fb811cd184775a3476101a1cede929John ReckNullDamageAccumulator* NullDamageAccumulator::instance() {
32a447d29c65fb811cd184775a3476101a1cede929John Reck    return &sInstance;
33a447d29c65fb811cd184775a3476101a1cede929John Reck}
34a447d29c65fb811cd184775a3476101a1cede929John Reck
35a447d29c65fb811cd184775a3476101a1cede929John Reckenum TransformType {
362dc223d23764a78f052529e86a59a1979d03b811John Reck    TransformInvalid = 0,
37a447d29c65fb811cd184775a3476101a1cede929John Reck    TransformRenderNode,
38a447d29c65fb811cd184775a3476101a1cede929John Reck    TransformMatrix4,
3925fbb3fa1138675379102a44405852555cefccbdJohn Reck    TransformNone,
40a447d29c65fb811cd184775a3476101a1cede929John Reck};
41a447d29c65fb811cd184775a3476101a1cede929John Reck
42e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckstruct DirtyStack {
43a447d29c65fb811cd184775a3476101a1cede929John Reck    TransformType type;
44a447d29c65fb811cd184775a3476101a1cede929John Reck    union {
45a447d29c65fb811cd184775a3476101a1cede929John Reck        const RenderNode* renderNode;
46a447d29c65fb811cd184775a3476101a1cede929John Reck        const Matrix4* matrix4;
47a447d29c65fb811cd184775a3476101a1cede929John Reck    };
48e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // When this frame is pop'd, this rect is mapped through the above transform
49e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // and applied to the previous (aka parent) frame
50e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    SkRect pendingDirty;
51e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    DirtyStack* prev;
52e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    DirtyStack* next;
53e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck};
54e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
55e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn ReckDamageAccumulator::DamageAccumulator() {
56e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
57e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    memset(mHead, 0, sizeof(DirtyStack));
58e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // Create a root that we will not pop off
59e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->prev = mHead;
602dc223d23764a78f052529e86a59a1979d03b811John Reck    mHead->type = TransformNone;
61e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
62e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
63a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushCommon() {
64e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    if (!mHead->next) {
65e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
66e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        nextFrame->next = 0;
67e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        nextFrame->prev = mHead;
68e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        mHead->next = nextFrame;
69e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    }
70e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead = mHead->next;
71e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->pendingDirty.setEmpty();
72e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
73e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
74a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushTransform(const RenderNode* transform) {
75a447d29c65fb811cd184775a3476101a1cede929John Reck    pushCommon();
76a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->type = TransformRenderNode;
77a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->renderNode = transform;
78a447d29c65fb811cd184775a3476101a1cede929John Reck}
79a447d29c65fb811cd184775a3476101a1cede929John Reck
80a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushTransform(const Matrix4* transform) {
81a447d29c65fb811cd184775a3476101a1cede929John Reck    pushCommon();
82a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->type = TransformMatrix4;
83a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->matrix4 = transform;
84a447d29c65fb811cd184775a3476101a1cede929John Reck}
85a447d29c65fb811cd184775a3476101a1cede929John Reck
8625fbb3fa1138675379102a44405852555cefccbdJohn Reckvoid DamageAccumulator::pushNullTransform() {
8725fbb3fa1138675379102a44405852555cefccbdJohn Reck    pushCommon();
8825fbb3fa1138675379102a44405852555cefccbdJohn Reck    mHead->type = TransformNone;
8925fbb3fa1138675379102a44405852555cefccbdJohn Reck}
9025fbb3fa1138675379102a44405852555cefccbdJohn Reck
91a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::popTransform() {
92e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!");
93e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    DirtyStack* dirtyFrame = mHead;
94e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead = mHead->prev;
9525fbb3fa1138675379102a44405852555cefccbdJohn Reck    switch (dirtyFrame->type) {
9625fbb3fa1138675379102a44405852555cefccbdJohn Reck    case TransformRenderNode:
97a447d29c65fb811cd184775a3476101a1cede929John Reck        applyRenderNodeTransform(dirtyFrame);
9825fbb3fa1138675379102a44405852555cefccbdJohn Reck        break;
9925fbb3fa1138675379102a44405852555cefccbdJohn Reck    case TransformMatrix4:
100a447d29c65fb811cd184775a3476101a1cede929John Reck        applyMatrix4Transform(dirtyFrame);
10125fbb3fa1138675379102a44405852555cefccbdJohn Reck        break;
10225fbb3fa1138675379102a44405852555cefccbdJohn Reck    case TransformNone:
10325fbb3fa1138675379102a44405852555cefccbdJohn Reck        mHead->pendingDirty.join(dirtyFrame->pendingDirty);
10425fbb3fa1138675379102a44405852555cefccbdJohn Reck        break;
1052dc223d23764a78f052529e86a59a1979d03b811John Reck    default:
1062dc223d23764a78f052529e86a59a1979d03b811John Reck        LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type);
107a447d29c65fb811cd184775a3476101a1cede929John Reck    }
108a447d29c65fb811cd184775a3476101a1cede929John Reck}
109a447d29c65fb811cd184775a3476101a1cede929John Reck
110a447d29c65fb811cd184775a3476101a1cede929John Reckstatic inline void mapRect(const Matrix4* matrix, const SkRect& in, SkRect* out) {
111a447d29c65fb811cd184775a3476101a1cede929John Reck    if (in.isEmpty()) return;
112a447d29c65fb811cd184775a3476101a1cede929John Reck    Rect temp(in);
113a447d29c65fb811cd184775a3476101a1cede929John Reck    matrix->mapRect(temp);
114a447d29c65fb811cd184775a3476101a1cede929John Reck    out->join(RECT_ARGS(temp));
115a447d29c65fb811cd184775a3476101a1cede929John Reck}
116a447d29c65fb811cd184775a3476101a1cede929John Reck
117a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::applyMatrix4Transform(DirtyStack* frame) {
118a447d29c65fb811cd184775a3476101a1cede929John Reck    mapRect(frame->matrix4, frame->pendingDirty, &mHead->pendingDirty);
119a447d29c65fb811cd184775a3476101a1cede929John Reck}
120a447d29c65fb811cd184775a3476101a1cede929John Reck
121a447d29c65fb811cd184775a3476101a1cede929John Reckstatic inline void mapRect(const RenderProperties& props, const SkRect& in, SkRect* out) {
122a447d29c65fb811cd184775a3476101a1cede929John Reck    if (in.isEmpty()) return;
123a447d29c65fb811cd184775a3476101a1cede929John Reck    const SkMatrix* transform = props.getTransformMatrix();
124a447d29c65fb811cd184775a3476101a1cede929John Reck    SkRect temp(in);
125a447d29c65fb811cd184775a3476101a1cede929John Reck    if (transform && !transform->isIdentity()) {
126a447d29c65fb811cd184775a3476101a1cede929John Reck        transform->mapRect(&temp);
127a447d29c65fb811cd184775a3476101a1cede929John Reck    }
128a447d29c65fb811cd184775a3476101a1cede929John Reck    temp.offset(props.getLeft(), props.getTop());
129a447d29c65fb811cd184775a3476101a1cede929John Reck    out->join(temp);
130a447d29c65fb811cd184775a3476101a1cede929John Reck}
131a447d29c65fb811cd184775a3476101a1cede929John Reck
132a447d29c65fb811cd184775a3476101a1cede929John Reckstatic DirtyStack* findParentRenderNode(DirtyStack* frame) {
133a447d29c65fb811cd184775a3476101a1cede929John Reck    while (frame->prev != frame) {
134a447d29c65fb811cd184775a3476101a1cede929John Reck        frame = frame->prev;
135a447d29c65fb811cd184775a3476101a1cede929John Reck        if (frame->type == TransformRenderNode) {
136a447d29c65fb811cd184775a3476101a1cede929John Reck            return frame;
137e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        }
138a447d29c65fb811cd184775a3476101a1cede929John Reck    }
139a447d29c65fb811cd184775a3476101a1cede929John Reck    return NULL;
140a447d29c65fb811cd184775a3476101a1cede929John Reck}
141a447d29c65fb811cd184775a3476101a1cede929John Reck
142a447d29c65fb811cd184775a3476101a1cede929John Reckstatic DirtyStack* findProjectionReceiver(DirtyStack* frame) {
143a447d29c65fb811cd184775a3476101a1cede929John Reck    if (frame) {
144a447d29c65fb811cd184775a3476101a1cede929John Reck        while (frame->prev != frame) {
145a447d29c65fb811cd184775a3476101a1cede929John Reck            frame = frame->prev;
146a447d29c65fb811cd184775a3476101a1cede929John Reck            if (frame->type == TransformRenderNode
147a447d29c65fb811cd184775a3476101a1cede929John Reck                    && frame->renderNode->hasProjectionReceiver()) {
148a447d29c65fb811cd184775a3476101a1cede929John Reck                return frame;
149e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck            }
150a447d29c65fb811cd184775a3476101a1cede929John Reck        }
151a447d29c65fb811cd184775a3476101a1cede929John Reck    }
152a447d29c65fb811cd184775a3476101a1cede929John Reck    return NULL;
153a447d29c65fb811cd184775a3476101a1cede929John Reck}
154a447d29c65fb811cd184775a3476101a1cede929John Reck
155a447d29c65fb811cd184775a3476101a1cede929John Reckstatic void applyTransforms(DirtyStack* frame, DirtyStack* end) {
156a447d29c65fb811cd184775a3476101a1cede929John Reck    SkRect* rect = &frame->pendingDirty;
157a447d29c65fb811cd184775a3476101a1cede929John Reck    while (frame != end) {
158a447d29c65fb811cd184775a3476101a1cede929John Reck        if (frame->type == TransformRenderNode) {
159a447d29c65fb811cd184775a3476101a1cede929John Reck            mapRect(frame->renderNode->properties(), *rect, rect);
160a447d29c65fb811cd184775a3476101a1cede929John Reck        } else {
161a447d29c65fb811cd184775a3476101a1cede929John Reck            mapRect(frame->matrix4, *rect, rect);
162a447d29c65fb811cd184775a3476101a1cede929John Reck        }
163a447d29c65fb811cd184775a3476101a1cede929John Reck        frame = frame->prev;
164a447d29c65fb811cd184775a3476101a1cede929John Reck    }
165a447d29c65fb811cd184775a3476101a1cede929John Reck}
166a447d29c65fb811cd184775a3476101a1cede929John Reck
167a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::applyRenderNodeTransform(DirtyStack* frame) {
168a447d29c65fb811cd184775a3476101a1cede929John Reck    if (frame->pendingDirty.isEmpty()) {
169a447d29c65fb811cd184775a3476101a1cede929John Reck        return;
170a447d29c65fb811cd184775a3476101a1cede929John Reck    }
171a447d29c65fb811cd184775a3476101a1cede929John Reck
172a447d29c65fb811cd184775a3476101a1cede929John Reck    const RenderProperties& props = frame->renderNode->properties();
173ce9f308063cc2bc7851f3f58c881da8a7271eeccJohn Reck    if (props.getAlpha() <= 0) {
174ce9f308063cc2bc7851f3f58c881da8a7271eeccJohn Reck        return;
175ce9f308063cc2bc7851f3f58c881da8a7271eeccJohn Reck    }
176a447d29c65fb811cd184775a3476101a1cede929John Reck
177a447d29c65fb811cd184775a3476101a1cede929John Reck    // Perform clipping
178293e868bfc1b07aad2cb2ebeee5b07424852c510John Reck    if (props.getClipDamageToBounds() && !frame->pendingDirty.isEmpty()) {
179a447d29c65fb811cd184775a3476101a1cede929John Reck        if (!frame->pendingDirty.intersect(0, 0, props.getWidth(), props.getHeight())) {
180a447d29c65fb811cd184775a3476101a1cede929John Reck            frame->pendingDirty.setEmpty();
181a447d29c65fb811cd184775a3476101a1cede929John Reck        }
182a447d29c65fb811cd184775a3476101a1cede929John Reck    }
183a447d29c65fb811cd184775a3476101a1cede929John Reck
184a447d29c65fb811cd184775a3476101a1cede929John Reck    // apply all transforms
185a447d29c65fb811cd184775a3476101a1cede929John Reck    mapRect(props, frame->pendingDirty, &mHead->pendingDirty);
186a447d29c65fb811cd184775a3476101a1cede929John Reck
187a447d29c65fb811cd184775a3476101a1cede929John Reck    // project backwards if necessary
188a447d29c65fb811cd184775a3476101a1cede929John Reck    if (props.getProjectBackwards() && !frame->pendingDirty.isEmpty()) {
189a447d29c65fb811cd184775a3476101a1cede929John Reck        // First, find our parent RenderNode:
190a447d29c65fb811cd184775a3476101a1cede929John Reck        DirtyStack* parentNode = findParentRenderNode(frame);
191a447d29c65fb811cd184775a3476101a1cede929John Reck        // Find our parent's projection receiver, which is what we project onto
192a447d29c65fb811cd184775a3476101a1cede929John Reck        DirtyStack* projectionReceiver = findProjectionReceiver(parentNode);
193a447d29c65fb811cd184775a3476101a1cede929John Reck        if (projectionReceiver) {
194a447d29c65fb811cd184775a3476101a1cede929John Reck            applyTransforms(frame, projectionReceiver);
195a447d29c65fb811cd184775a3476101a1cede929John Reck            projectionReceiver->pendingDirty.join(frame->pendingDirty);
196e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        }
197a447d29c65fb811cd184775a3476101a1cede929John Reck
198a447d29c65fb811cd184775a3476101a1cede929John Reck        frame->pendingDirty.setEmpty();
199e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    }
200e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
201e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
202e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckvoid DamageAccumulator::dirty(float left, float top, float right, float bottom) {
203e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->pendingDirty.join(left, top, right, bottom);
204e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
205e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
20625fbb3fa1138675379102a44405852555cefccbdJohn Reckvoid DamageAccumulator::peekAtDirty(SkRect* dest) {
20725fbb3fa1138675379102a44405852555cefccbdJohn Reck    *dest = mHead->pendingDirty;
20825fbb3fa1138675379102a44405852555cefccbdJohn Reck}
20925fbb3fa1138675379102a44405852555cefccbdJohn Reck
210e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckvoid DamageAccumulator::finish(SkRect* totalDirty) {
211e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
212e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // Root node never has a transform, so this is the fully mapped dirty rect
213e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    *totalDirty = mHead->pendingDirty;
214e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    totalDirty->roundOut();
215e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->pendingDirty.setEmpty();
216e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
217e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
218e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} /* namespace uirenderer */
219e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} /* namespace android */
220