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