DamageAccumulator.cpp revision 69e5adffb19135d51bde8e458f4907d7265f3e23
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)); 82e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck nextFrame->next = 0; 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 } 150a447d29c65fb811cd184775a3476101a1cede929John Reck return NULL; 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 } 163a447d29c65fb811cd184775a3476101a1cede929John Reck return NULL; 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 21725fbb3fa1138675379102a44405852555cefccbdJohn Reckvoid DamageAccumulator::peekAtDirty(SkRect* dest) { 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; 225e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck totalDirty->roundOut(); 226e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck mHead->pendingDirty.setEmpty(); 227e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} 228e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck 229e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} /* namespace uirenderer */ 230e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck} /* namespace android */ 231