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#include "DamageAccumulator.h"
18e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
19e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck#include <cutils/log.h>
20e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
21e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck#include "RenderNode.h"
22e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck#include "utils/MathUtils.h"
23e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
24e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Recknamespace android {
25e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Recknamespace uirenderer {
26e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
27a447d29c65fb811cd184775a3476101a1cede929John Reckenum TransformType {
282dc223d23764a78f052529e86a59a1979d03b811John Reck    TransformInvalid = 0,
29a447d29c65fb811cd184775a3476101a1cede929John Reck    TransformRenderNode,
30a447d29c65fb811cd184775a3476101a1cede929John Reck    TransformMatrix4,
3125fbb3fa1138675379102a44405852555cefccbdJohn Reck    TransformNone,
32a447d29c65fb811cd184775a3476101a1cede929John Reck};
33a447d29c65fb811cd184775a3476101a1cede929John Reck
34e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckstruct DirtyStack {
35a447d29c65fb811cd184775a3476101a1cede929John Reck    TransformType type;
36a447d29c65fb811cd184775a3476101a1cede929John Reck    union {
37a447d29c65fb811cd184775a3476101a1cede929John Reck        const RenderNode* renderNode;
38a447d29c65fb811cd184775a3476101a1cede929John Reck        const Matrix4* matrix4;
39a447d29c65fb811cd184775a3476101a1cede929John Reck    };
40e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // When this frame is pop'd, this rect is mapped through the above transform
41e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // and applied to the previous (aka parent) frame
42e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    SkRect pendingDirty;
43e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    DirtyStack* prev;
44e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    DirtyStack* next;
45e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck};
46e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
47e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn ReckDamageAccumulator::DamageAccumulator() {
48e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
49e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    memset(mHead, 0, sizeof(DirtyStack));
50e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // Create a root that we will not pop off
51e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->prev = mHead;
522dc223d23764a78f052529e86a59a1979d03b811John Reck    mHead->type = TransformNone;
53e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
54e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
5569e5adffb19135d51bde8e458f4907d7265f3e23Chris Craikstatic void computeTransformImpl(const DirtyStack* currentFrame, Matrix4* outMatrix) {
5669e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    if (currentFrame->prev != currentFrame) {
5769e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        computeTransformImpl(currentFrame->prev, outMatrix);
5869e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    }
5969e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    switch (currentFrame->type) {
6069e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    case TransformRenderNode:
6169e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        currentFrame->renderNode->applyViewPropertyTransforms(*outMatrix);
6269e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        break;
6369e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    case TransformMatrix4:
6469e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        outMatrix->multiply(*currentFrame->matrix4);
6569e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        break;
6669e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    case TransformNone:
6769e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        // nothing to be done
6869e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        break;
6969e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    default:
7069e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        LOG_ALWAYS_FATAL("Tried to compute transform with an invalid type: %d", currentFrame->type);
7169e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    }
7269e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik}
7369e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik
7469e5adffb19135d51bde8e458f4907d7265f3e23Chris Craikvoid DamageAccumulator::computeCurrentTransform(Matrix4* outMatrix) const {
7569e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    outMatrix->loadIdentity();
7669e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik    computeTransformImpl(mHead, outMatrix);
7769e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik}
7869e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik
79a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushCommon() {
80e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    if (!mHead->next) {
81e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
82d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        nextFrame->next = nullptr;
83e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        nextFrame->prev = mHead;
84e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        mHead->next = nextFrame;
85e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    }
86e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead = mHead->next;
87e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->pendingDirty.setEmpty();
88e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
89e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
90a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushTransform(const RenderNode* transform) {
91a447d29c65fb811cd184775a3476101a1cede929John Reck    pushCommon();
92a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->type = TransformRenderNode;
93a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->renderNode = transform;
94a447d29c65fb811cd184775a3476101a1cede929John Reck}
95a447d29c65fb811cd184775a3476101a1cede929John Reck
96a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::pushTransform(const Matrix4* transform) {
97a447d29c65fb811cd184775a3476101a1cede929John Reck    pushCommon();
98a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->type = TransformMatrix4;
99a447d29c65fb811cd184775a3476101a1cede929John Reck    mHead->matrix4 = transform;
100a447d29c65fb811cd184775a3476101a1cede929John Reck}
101a447d29c65fb811cd184775a3476101a1cede929John Reck
102a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::popTransform() {
103e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!");
104e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    DirtyStack* dirtyFrame = mHead;
105e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead = mHead->prev;
10625fbb3fa1138675379102a44405852555cefccbdJohn Reck    switch (dirtyFrame->type) {
10725fbb3fa1138675379102a44405852555cefccbdJohn Reck    case TransformRenderNode:
108a447d29c65fb811cd184775a3476101a1cede929John Reck        applyRenderNodeTransform(dirtyFrame);
10925fbb3fa1138675379102a44405852555cefccbdJohn Reck        break;
11025fbb3fa1138675379102a44405852555cefccbdJohn Reck    case TransformMatrix4:
111a447d29c65fb811cd184775a3476101a1cede929John Reck        applyMatrix4Transform(dirtyFrame);
11225fbb3fa1138675379102a44405852555cefccbdJohn Reck        break;
11325fbb3fa1138675379102a44405852555cefccbdJohn Reck    case TransformNone:
11425fbb3fa1138675379102a44405852555cefccbdJohn Reck        mHead->pendingDirty.join(dirtyFrame->pendingDirty);
11525fbb3fa1138675379102a44405852555cefccbdJohn Reck        break;
1162dc223d23764a78f052529e86a59a1979d03b811John Reck    default:
1172dc223d23764a78f052529e86a59a1979d03b811John Reck        LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type);
118a447d29c65fb811cd184775a3476101a1cede929John Reck    }
119a447d29c65fb811cd184775a3476101a1cede929John Reck}
120a447d29c65fb811cd184775a3476101a1cede929John Reck
121a447d29c65fb811cd184775a3476101a1cede929John Reckstatic inline void mapRect(const Matrix4* matrix, const SkRect& in, SkRect* out) {
122a447d29c65fb811cd184775a3476101a1cede929John Reck    if (in.isEmpty()) return;
123a447d29c65fb811cd184775a3476101a1cede929John Reck    Rect temp(in);
124a447d29c65fb811cd184775a3476101a1cede929John Reck    matrix->mapRect(temp);
125a447d29c65fb811cd184775a3476101a1cede929John Reck    out->join(RECT_ARGS(temp));
126a447d29c65fb811cd184775a3476101a1cede929John Reck}
127a447d29c65fb811cd184775a3476101a1cede929John Reck
128a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::applyMatrix4Transform(DirtyStack* frame) {
129a447d29c65fb811cd184775a3476101a1cede929John Reck    mapRect(frame->matrix4, frame->pendingDirty, &mHead->pendingDirty);
130a447d29c65fb811cd184775a3476101a1cede929John Reck}
131a447d29c65fb811cd184775a3476101a1cede929John Reck
132a447d29c65fb811cd184775a3476101a1cede929John Reckstatic inline void mapRect(const RenderProperties& props, const SkRect& in, SkRect* out) {
133a447d29c65fb811cd184775a3476101a1cede929John Reck    if (in.isEmpty()) return;
134a447d29c65fb811cd184775a3476101a1cede929John Reck    const SkMatrix* transform = props.getTransformMatrix();
135a447d29c65fb811cd184775a3476101a1cede929John Reck    SkRect temp(in);
136a447d29c65fb811cd184775a3476101a1cede929John Reck    if (transform && !transform->isIdentity()) {
137a447d29c65fb811cd184775a3476101a1cede929John Reck        transform->mapRect(&temp);
138a447d29c65fb811cd184775a3476101a1cede929John Reck    }
139a447d29c65fb811cd184775a3476101a1cede929John Reck    temp.offset(props.getLeft(), props.getTop());
140a447d29c65fb811cd184775a3476101a1cede929John Reck    out->join(temp);
141a447d29c65fb811cd184775a3476101a1cede929John Reck}
142a447d29c65fb811cd184775a3476101a1cede929John Reck
143a447d29c65fb811cd184775a3476101a1cede929John Reckstatic DirtyStack* findParentRenderNode(DirtyStack* frame) {
144a447d29c65fb811cd184775a3476101a1cede929John Reck    while (frame->prev != frame) {
145a447d29c65fb811cd184775a3476101a1cede929John Reck        frame = frame->prev;
146a447d29c65fb811cd184775a3476101a1cede929John Reck        if (frame->type == TransformRenderNode) {
147a447d29c65fb811cd184775a3476101a1cede929John Reck            return frame;
148e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        }
149a447d29c65fb811cd184775a3476101a1cede929John Reck    }
150d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    return nullptr;
151a447d29c65fb811cd184775a3476101a1cede929John Reck}
152a447d29c65fb811cd184775a3476101a1cede929John Reck
153a447d29c65fb811cd184775a3476101a1cede929John Reckstatic DirtyStack* findProjectionReceiver(DirtyStack* frame) {
154a447d29c65fb811cd184775a3476101a1cede929John Reck    if (frame) {
155a447d29c65fb811cd184775a3476101a1cede929John Reck        while (frame->prev != frame) {
156a447d29c65fb811cd184775a3476101a1cede929John Reck            frame = frame->prev;
157a447d29c65fb811cd184775a3476101a1cede929John Reck            if (frame->type == TransformRenderNode
158a447d29c65fb811cd184775a3476101a1cede929John Reck                    && frame->renderNode->hasProjectionReceiver()) {
159a447d29c65fb811cd184775a3476101a1cede929John Reck                return frame;
160e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck            }
161a447d29c65fb811cd184775a3476101a1cede929John Reck        }
162a447d29c65fb811cd184775a3476101a1cede929John Reck    }
163d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    return nullptr;
164a447d29c65fb811cd184775a3476101a1cede929John Reck}
165a447d29c65fb811cd184775a3476101a1cede929John Reck
166a447d29c65fb811cd184775a3476101a1cede929John Reckstatic void applyTransforms(DirtyStack* frame, DirtyStack* end) {
167a447d29c65fb811cd184775a3476101a1cede929John Reck    SkRect* rect = &frame->pendingDirty;
168a447d29c65fb811cd184775a3476101a1cede929John Reck    while (frame != end) {
169a447d29c65fb811cd184775a3476101a1cede929John Reck        if (frame->type == TransformRenderNode) {
170a447d29c65fb811cd184775a3476101a1cede929John Reck            mapRect(frame->renderNode->properties(), *rect, rect);
171a447d29c65fb811cd184775a3476101a1cede929John Reck        } else {
172a447d29c65fb811cd184775a3476101a1cede929John Reck            mapRect(frame->matrix4, *rect, rect);
173a447d29c65fb811cd184775a3476101a1cede929John Reck        }
174a447d29c65fb811cd184775a3476101a1cede929John Reck        frame = frame->prev;
175a447d29c65fb811cd184775a3476101a1cede929John Reck    }
176a447d29c65fb811cd184775a3476101a1cede929John Reck}
177a447d29c65fb811cd184775a3476101a1cede929John Reck
178a447d29c65fb811cd184775a3476101a1cede929John Reckvoid DamageAccumulator::applyRenderNodeTransform(DirtyStack* frame) {
179a447d29c65fb811cd184775a3476101a1cede929John Reck    if (frame->pendingDirty.isEmpty()) {
180a447d29c65fb811cd184775a3476101a1cede929John Reck        return;
181a447d29c65fb811cd184775a3476101a1cede929John Reck    }
182a447d29c65fb811cd184775a3476101a1cede929John Reck
183a447d29c65fb811cd184775a3476101a1cede929John Reck    const RenderProperties& props = frame->renderNode->properties();
184ce9f308063cc2bc7851f3f58c881da8a7271eeccJohn Reck    if (props.getAlpha() <= 0) {
185ce9f308063cc2bc7851f3f58c881da8a7271eeccJohn Reck        return;
186ce9f308063cc2bc7851f3f58c881da8a7271eeccJohn Reck    }
187a447d29c65fb811cd184775a3476101a1cede929John Reck
188a447d29c65fb811cd184775a3476101a1cede929John Reck    // Perform clipping
189293e868bfc1b07aad2cb2ebeee5b07424852c510John Reck    if (props.getClipDamageToBounds() && !frame->pendingDirty.isEmpty()) {
190a447d29c65fb811cd184775a3476101a1cede929John Reck        if (!frame->pendingDirty.intersect(0, 0, props.getWidth(), props.getHeight())) {
191a447d29c65fb811cd184775a3476101a1cede929John Reck            frame->pendingDirty.setEmpty();
192a447d29c65fb811cd184775a3476101a1cede929John Reck        }
193a447d29c65fb811cd184775a3476101a1cede929John Reck    }
194a447d29c65fb811cd184775a3476101a1cede929John Reck
195a447d29c65fb811cd184775a3476101a1cede929John Reck    // apply all transforms
196a447d29c65fb811cd184775a3476101a1cede929John Reck    mapRect(props, frame->pendingDirty, &mHead->pendingDirty);
197a447d29c65fb811cd184775a3476101a1cede929John Reck
198a447d29c65fb811cd184775a3476101a1cede929John Reck    // project backwards if necessary
199a447d29c65fb811cd184775a3476101a1cede929John Reck    if (props.getProjectBackwards() && !frame->pendingDirty.isEmpty()) {
200a447d29c65fb811cd184775a3476101a1cede929John Reck        // First, find our parent RenderNode:
201a447d29c65fb811cd184775a3476101a1cede929John Reck        DirtyStack* parentNode = findParentRenderNode(frame);
202a447d29c65fb811cd184775a3476101a1cede929John Reck        // Find our parent's projection receiver, which is what we project onto
203a447d29c65fb811cd184775a3476101a1cede929John Reck        DirtyStack* projectionReceiver = findProjectionReceiver(parentNode);
204a447d29c65fb811cd184775a3476101a1cede929John Reck        if (projectionReceiver) {
205a447d29c65fb811cd184775a3476101a1cede929John Reck            applyTransforms(frame, projectionReceiver);
206a447d29c65fb811cd184775a3476101a1cede929John Reck            projectionReceiver->pendingDirty.join(frame->pendingDirty);
207e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        }
208a447d29c65fb811cd184775a3476101a1cede929John Reck
209a447d29c65fb811cd184775a3476101a1cede929John Reck        frame->pendingDirty.setEmpty();
210e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    }
211e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
212e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
213e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckvoid DamageAccumulator::dirty(float left, float top, float right, float bottom) {
214e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->pendingDirty.join(left, top, right, bottom);
215e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
216e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
217c71bfcaa182e3d4fd9874362d3b4781fda934a21Chris Craikvoid DamageAccumulator::peekAtDirty(SkRect* dest) const {
21825fbb3fa1138675379102a44405852555cefccbdJohn Reck    *dest = mHead->pendingDirty;
21925fbb3fa1138675379102a44405852555cefccbdJohn Reck}
22025fbb3fa1138675379102a44405852555cefccbdJohn Reck
221e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckvoid DamageAccumulator::finish(SkRect* totalDirty) {
222e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
223e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    // Root node never has a transform, so this is the fully mapped dirty rect
224e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    *totalDirty = mHead->pendingDirty;
22571487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed    totalDirty->roundOut(totalDirty);
226e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    mHead->pendingDirty.setEmpty();
227e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck}
228e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
229e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} /* namespace uirenderer */
230e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} /* namespace android */
231