DamageAccumulator.cpp revision 25fbb3fa1138675379102a44405852555cefccbd
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 {
36a447d29c65fb811cd184775a3476101a1cede929John Reck    TransformRenderNode,
37a447d29c65fb811cd184775a3476101a1cede929John Reck    TransformMatrix4,
3825fbb3fa1138675379102a44405852555cefccbdJohn Reck    TransformNone,
39a447d29c65fb811cd184775a3476101a1cede929John Reck};
40a447d29c65fb811cd184775a3476101a1cede929John Reck
41e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckstruct DirtyStack {
42a447d29c65fb811cd184775a3476101a1cede929John Reck    TransformType type;
43a447d29c65fb811cd184775a3476101a1cede929John Reck    union {
44a447d29c65fb811cd184775a3476101a1cede929John Reck        const RenderNode* renderNode;
45a447d29c65fb811cd184775a3476101a1cede929John Reck        const Matrix4* matrix4;
46a447d29c65fb811cd184775a3476101a1cede929John Reck    };
47e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // When this frame is pop'd, this rect is mapped through the above transform
48e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // and applied to the previous (aka parent) frame
49e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    SkRect pendingDirty;
50e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    DirtyStack* prev;
51e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    DirtyStack* next;
52e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck};
53e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
54e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn ReckDamageAccumulator::DamageAccumulator() {
55e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
56e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    memset(mHead, 0, sizeof(DirtyStack));
57e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // Create a root that we will not pop off
58e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->prev = mHead;
59e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
60e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
61a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushCommon() {
62e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    if (!mHead->next) {
63e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
64e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        nextFrame->next = 0;
65e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        nextFrame->prev = mHead;
66e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        mHead->next = nextFrame;
67e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    }
68e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead = mHead->next;
69e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->pendingDirty.setEmpty();
70e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
71e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
72a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushTransform(const RenderNode* transform) {
73a447d29c65fb811cd184775a3476101a1cede929John Reck    pushCommon();
74a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->type = TransformRenderNode;
75a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->renderNode = transform;
76a447d29c65fb811cd184775a3476101a1cede929John Reck}
77a447d29c65fb811cd184775a3476101a1cede929John Reck
78a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushTransform(const Matrix4* transform) {
79a447d29c65fb811cd184775a3476101a1cede929John Reck    pushCommon();
80a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->type = TransformMatrix4;
81a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->matrix4 = transform;
82a447d29c65fb811cd184775a3476101a1cede929John Reck}
83a447d29c65fb811cd184775a3476101a1cede929John Reck
8425fbb3fa1138675379102a44405852555cefccbdJohn Reckvoid DamageAccumulator::pushNullTransform() {
8525fbb3fa1138675379102a44405852555cefccbdJohn Reck    pushCommon();
8625fbb3fa1138675379102a44405852555cefccbdJohn Reck    mHead->type = TransformNone;
8725fbb3fa1138675379102a44405852555cefccbdJohn Reck}
8825fbb3fa1138675379102a44405852555cefccbdJohn Reck
89a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::popTransform() {
90e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!");
91e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    DirtyStack* dirtyFrame = mHead;
92e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead = mHead->prev;
9325fbb3fa1138675379102a44405852555cefccbdJohn Reck    switch (dirtyFrame->type) {
9425fbb3fa1138675379102a44405852555cefccbdJohn Reck    case TransformRenderNode:
95a447d29c65fb811cd184775a3476101a1cede929John Reck        applyRenderNodeTransform(dirtyFrame);
9625fbb3fa1138675379102a44405852555cefccbdJohn Reck        break;
9725fbb3fa1138675379102a44405852555cefccbdJohn Reck    case TransformMatrix4:
98a447d29c65fb811cd184775a3476101a1cede929John Reck        applyMatrix4Transform(dirtyFrame);
9925fbb3fa1138675379102a44405852555cefccbdJohn Reck        break;
10025fbb3fa1138675379102a44405852555cefccbdJohn Reck    case TransformNone:
10125fbb3fa1138675379102a44405852555cefccbdJohn Reck        mHead->pendingDirty.join(dirtyFrame->pendingDirty);
10225fbb3fa1138675379102a44405852555cefccbdJohn Reck        break;
103a447d29c65fb811cd184775a3476101a1cede929John Reck    }
104a447d29c65fb811cd184775a3476101a1cede929John Reck}
105a447d29c65fb811cd184775a3476101a1cede929John Reck
106a447d29c65fb811cd184775a3476101a1cede929John Reckstatic inline void mapRect(const Matrix4* matrix, const SkRect& in, SkRect* out) {
107a447d29c65fb811cd184775a3476101a1cede929John Reck    if (in.isEmpty()) return;
108a447d29c65fb811cd184775a3476101a1cede929John Reck    Rect temp(in);
109a447d29c65fb811cd184775a3476101a1cede929John Reck    matrix->mapRect(temp);
110a447d29c65fb811cd184775a3476101a1cede929John Reck    out->join(RECT_ARGS(temp));
111a447d29c65fb811cd184775a3476101a1cede929John Reck}
112a447d29c65fb811cd184775a3476101a1cede929John Reck
113a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::applyMatrix4Transform(DirtyStack* frame) {
114a447d29c65fb811cd184775a3476101a1cede929John Reck    mapRect(frame->matrix4, frame->pendingDirty, &mHead->pendingDirty);
115a447d29c65fb811cd184775a3476101a1cede929John Reck}
116a447d29c65fb811cd184775a3476101a1cede929John Reck
117a447d29c65fb811cd184775a3476101a1cede929John Reckstatic inline void mapRect(const RenderProperties& props, const SkRect& in, SkRect* out) {
118a447d29c65fb811cd184775a3476101a1cede929John Reck    if (in.isEmpty()) return;
119a447d29c65fb811cd184775a3476101a1cede929John Reck    const SkMatrix* transform = props.getTransformMatrix();
120a447d29c65fb811cd184775a3476101a1cede929John Reck    SkRect temp(in);
121a447d29c65fb811cd184775a3476101a1cede929John Reck    if (transform && !transform->isIdentity()) {
122a447d29c65fb811cd184775a3476101a1cede929John Reck        transform->mapRect(&temp);
123a447d29c65fb811cd184775a3476101a1cede929John Reck    }
124a447d29c65fb811cd184775a3476101a1cede929John Reck    temp.offset(props.getLeft(), props.getTop());
125a447d29c65fb811cd184775a3476101a1cede929John Reck    out->join(temp);
126a447d29c65fb811cd184775a3476101a1cede929John Reck}
127a447d29c65fb811cd184775a3476101a1cede929John Reck
128a447d29c65fb811cd184775a3476101a1cede929John Reckstatic DirtyStack* findParentRenderNode(DirtyStack* frame) {
129a447d29c65fb811cd184775a3476101a1cede929John Reck    while (frame->prev != frame) {
130a447d29c65fb811cd184775a3476101a1cede929John Reck        frame = frame->prev;
131a447d29c65fb811cd184775a3476101a1cede929John Reck        if (frame->type == TransformRenderNode) {
132a447d29c65fb811cd184775a3476101a1cede929John Reck            return frame;
133e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        }
134a447d29c65fb811cd184775a3476101a1cede929John Reck    }
135a447d29c65fb811cd184775a3476101a1cede929John Reck    return NULL;
136a447d29c65fb811cd184775a3476101a1cede929John Reck}
137a447d29c65fb811cd184775a3476101a1cede929John Reck
138a447d29c65fb811cd184775a3476101a1cede929John Reckstatic DirtyStack* findProjectionReceiver(DirtyStack* frame) {
139a447d29c65fb811cd184775a3476101a1cede929John Reck    if (frame) {
140a447d29c65fb811cd184775a3476101a1cede929John Reck        while (frame->prev != frame) {
141a447d29c65fb811cd184775a3476101a1cede929John Reck            frame = frame->prev;
142a447d29c65fb811cd184775a3476101a1cede929John Reck            if (frame->type == TransformRenderNode
143a447d29c65fb811cd184775a3476101a1cede929John Reck                    && frame->renderNode->hasProjectionReceiver()) {
144a447d29c65fb811cd184775a3476101a1cede929John Reck                return frame;
145e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck            }
146a447d29c65fb811cd184775a3476101a1cede929John Reck        }
147a447d29c65fb811cd184775a3476101a1cede929John Reck    }
148a447d29c65fb811cd184775a3476101a1cede929John Reck    return NULL;
149a447d29c65fb811cd184775a3476101a1cede929John Reck}
150a447d29c65fb811cd184775a3476101a1cede929John Reck
151a447d29c65fb811cd184775a3476101a1cede929John Reckstatic void applyTransforms(DirtyStack* frame, DirtyStack* end) {
152a447d29c65fb811cd184775a3476101a1cede929John Reck    SkRect* rect = &frame->pendingDirty;
153a447d29c65fb811cd184775a3476101a1cede929John Reck    while (frame != end) {
154a447d29c65fb811cd184775a3476101a1cede929John Reck        if (frame->type == TransformRenderNode) {
155a447d29c65fb811cd184775a3476101a1cede929John Reck            mapRect(frame->renderNode->properties(), *rect, rect);
156a447d29c65fb811cd184775a3476101a1cede929John Reck        } else {
157a447d29c65fb811cd184775a3476101a1cede929John Reck            mapRect(frame->matrix4, *rect, rect);
158a447d29c65fb811cd184775a3476101a1cede929John Reck        }
159a447d29c65fb811cd184775a3476101a1cede929John Reck        frame = frame->prev;
160a447d29c65fb811cd184775a3476101a1cede929John Reck    }
161a447d29c65fb811cd184775a3476101a1cede929John Reck}
162a447d29c65fb811cd184775a3476101a1cede929John Reck
163a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::applyRenderNodeTransform(DirtyStack* frame) {
164a447d29c65fb811cd184775a3476101a1cede929John Reck    if (frame->pendingDirty.isEmpty()) {
165a447d29c65fb811cd184775a3476101a1cede929John Reck        return;
166a447d29c65fb811cd184775a3476101a1cede929John Reck    }
167a447d29c65fb811cd184775a3476101a1cede929John Reck
168a447d29c65fb811cd184775a3476101a1cede929John Reck    const RenderProperties& props = frame->renderNode->properties();
169a447d29c65fb811cd184775a3476101a1cede929John Reck
170a447d29c65fb811cd184775a3476101a1cede929John Reck    // Perform clipping
171a447d29c65fb811cd184775a3476101a1cede929John Reck    if (props.getClipToBounds() && !frame->pendingDirty.isEmpty()) {
172a447d29c65fb811cd184775a3476101a1cede929John Reck        if (!frame->pendingDirty.intersect(0, 0, props.getWidth(), props.getHeight())) {
173a447d29c65fb811cd184775a3476101a1cede929John Reck            frame->pendingDirty.setEmpty();
174a447d29c65fb811cd184775a3476101a1cede929John Reck        }
175a447d29c65fb811cd184775a3476101a1cede929John Reck    }
176a447d29c65fb811cd184775a3476101a1cede929John Reck
177a447d29c65fb811cd184775a3476101a1cede929John Reck    // apply all transforms
178a447d29c65fb811cd184775a3476101a1cede929John Reck    mapRect(props, frame->pendingDirty, &mHead->pendingDirty);
179a447d29c65fb811cd184775a3476101a1cede929John Reck
180a447d29c65fb811cd184775a3476101a1cede929John Reck    // project backwards if necessary
181a447d29c65fb811cd184775a3476101a1cede929John Reck    if (props.getProjectBackwards() && !frame->pendingDirty.isEmpty()) {
182a447d29c65fb811cd184775a3476101a1cede929John Reck        // First, find our parent RenderNode:
183a447d29c65fb811cd184775a3476101a1cede929John Reck        DirtyStack* parentNode = findParentRenderNode(frame);
184a447d29c65fb811cd184775a3476101a1cede929John Reck        // Find our parent's projection receiver, which is what we project onto
185a447d29c65fb811cd184775a3476101a1cede929John Reck        DirtyStack* projectionReceiver = findProjectionReceiver(parentNode);
186a447d29c65fb811cd184775a3476101a1cede929John Reck        if (projectionReceiver) {
187a447d29c65fb811cd184775a3476101a1cede929John Reck            applyTransforms(frame, projectionReceiver);
188a447d29c65fb811cd184775a3476101a1cede929John Reck            projectionReceiver->pendingDirty.join(frame->pendingDirty);
189e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        } else {
190a447d29c65fb811cd184775a3476101a1cede929John Reck            ALOGW("Failed to find projection receiver? Dropping on the floor...");
191e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        }
192a447d29c65fb811cd184775a3476101a1cede929John Reck
193a447d29c65fb811cd184775a3476101a1cede929John Reck        frame->pendingDirty.setEmpty();
194e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    }
195e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
196e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
197e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckvoid DamageAccumulator::dirty(float left, float top, float right, float bottom) {
198e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->pendingDirty.join(left, top, right, bottom);
199e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
200e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
20125fbb3fa1138675379102a44405852555cefccbdJohn Reckvoid DamageAccumulator::peekAtDirty(SkRect* dest) {
20225fbb3fa1138675379102a44405852555cefccbdJohn Reck    *dest = mHead->pendingDirty;
20325fbb3fa1138675379102a44405852555cefccbdJohn Reck}
20425fbb3fa1138675379102a44405852555cefccbdJohn Reck
205e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckvoid DamageAccumulator::finish(SkRect* totalDirty) {
206e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
207e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // Root node never has a transform, so this is the fully mapped dirty rect
208e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    *totalDirty = mHead->pendingDirty;
209e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    totalDirty->roundOut();
210e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->pendingDirty.setEmpty();
211e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
212e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
213e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} /* namespace uirenderer */
214e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} /* namespace android */
215