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