1e4db79de127cfe961195f52907af8451026eaa20Chris Craik/* 2e4db79de127cfe961195f52907af8451026eaa20Chris Craik * Copyright (C) 2015 The Android Open Source Project 3e4db79de127cfe961195f52907af8451026eaa20Chris Craik * 4e4db79de127cfe961195f52907af8451026eaa20Chris Craik * Licensed under the Apache License, Version 2.0 (the "License"); 5e4db79de127cfe961195f52907af8451026eaa20Chris Craik * you may not use this file except in compliance with the License. 6e4db79de127cfe961195f52907af8451026eaa20Chris Craik * You may obtain a copy of the License at 7e4db79de127cfe961195f52907af8451026eaa20Chris Craik * 8e4db79de127cfe961195f52907af8451026eaa20Chris Craik * http://www.apache.org/licenses/LICENSE-2.0 9e4db79de127cfe961195f52907af8451026eaa20Chris Craik * 10e4db79de127cfe961195f52907af8451026eaa20Chris Craik * Unless required by applicable law or agreed to in writing, software 11e4db79de127cfe961195f52907af8451026eaa20Chris Craik * distributed under the License is distributed on an "AS IS" BASIS, 12e4db79de127cfe961195f52907af8451026eaa20Chris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e4db79de127cfe961195f52907af8451026eaa20Chris Craik * See the License for the specific language governing permissions and 14e4db79de127cfe961195f52907af8451026eaa20Chris Craik * limitations under the License. 15e4db79de127cfe961195f52907af8451026eaa20Chris Craik */ 16e4db79de127cfe961195f52907af8451026eaa20Chris Craik 17e4db79de127cfe961195f52907af8451026eaa20Chris Craik#include "BakedOpState.h" 18e4db79de127cfe961195f52907af8451026eaa20Chris Craik 19e4db79de127cfe961195f52907af8451026eaa20Chris Craik#include "ClipArea.h" 20e4db79de127cfe961195f52907af8451026eaa20Chris Craik 21e4db79de127cfe961195f52907af8451026eaa20Chris Craiknamespace android { 22e4db79de127cfe961195f52907af8451026eaa20Chris Craiknamespace uirenderer { 23e4db79de127cfe961195f52907af8451026eaa20Chris Craik 244876de16e34622634266d09522c9153c78c7c2fbChris Craikstatic int computeClipSideFlags(const Rect& clip, const Rect& bounds) { 254876de16e34622634266d09522c9153c78c7c2fbChris Craik int clipSideFlags = 0; 264876de16e34622634266d09522c9153c78c7c2fbChris Craik if (clip.left > bounds.left) clipSideFlags |= OpClipSideFlags::Left; 274876de16e34622634266d09522c9153c78c7c2fbChris Craik if (clip.top > bounds.top) clipSideFlags |= OpClipSideFlags::Top; 284876de16e34622634266d09522c9153c78c7c2fbChris Craik if (clip.right < bounds.right) clipSideFlags |= OpClipSideFlags::Right; 294876de16e34622634266d09522c9153c78c7c2fbChris Craik if (clip.bottom < bounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom; 304876de16e34622634266d09522c9153c78c7c2fbChris Craik return clipSideFlags; 314876de16e34622634266d09522c9153c78c7c2fbChris Craik} 324876de16e34622634266d09522c9153c78c7c2fbChris Craik 33e4db79de127cfe961195f52907af8451026eaa20Chris CraikResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, 34e4db79de127cfe961195f52907af8451026eaa20Chris Craik const RecordedOp& recordedOp, bool expandForStroke) { 35e4db79de127cfe961195f52907af8451026eaa20Chris Craik // resolvedMatrix = parentMatrix * localMatrix 36e4db79de127cfe961195f52907af8451026eaa20Chris Craik transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix); 37e4db79de127cfe961195f52907af8451026eaa20Chris Craik 38e4db79de127cfe961195f52907af8451026eaa20Chris Craik // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect) 39e4db79de127cfe961195f52907af8451026eaa20Chris Craik clippedBounds = recordedOp.unmappedBounds; 40e4db79de127cfe961195f52907af8451026eaa20Chris Craik if (CC_UNLIKELY(expandForStroke)) { 41e4db79de127cfe961195f52907af8451026eaa20Chris Craik // account for non-hairline stroke 42e4db79de127cfe961195f52907af8451026eaa20Chris Craik clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f); 43e4db79de127cfe961195f52907af8451026eaa20Chris Craik } 44e4db79de127cfe961195f52907af8451026eaa20Chris Craik transform.mapRect(clippedBounds); 45e4db79de127cfe961195f52907af8451026eaa20Chris Craik if (CC_UNLIKELY(expandForStroke 46e4db79de127cfe961195f52907af8451026eaa20Chris Craik && (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) { 47e4db79de127cfe961195f52907af8451026eaa20Chris Craik // account for hairline stroke when stroke may be < 1 scaled pixel 48e4db79de127cfe961195f52907af8451026eaa20Chris Craik // Non translate || strokeWidth < 1 is conservative, but will cover all cases 49e4db79de127cfe961195f52907af8451026eaa20Chris Craik clippedBounds.outset(0.5f); 50e4db79de127cfe961195f52907af8451026eaa20Chris Craik } 51e4db79de127cfe961195f52907af8451026eaa20Chris Craik 52e4db79de127cfe961195f52907af8451026eaa20Chris Craik // resolvedClipRect = intersect(parentMatrix * localClip, parentClip) 5304d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik clipState = snapshot.serializeIntersectedClip(allocator, 54e4db79de127cfe961195f52907af8451026eaa20Chris Craik recordedOp.localClip, *(snapshot.transform)); 55e4db79de127cfe961195f52907af8451026eaa20Chris Craik LOG_ALWAYS_FATAL_IF(!clipState, "must clip!"); 56e4db79de127cfe961195f52907af8451026eaa20Chris Craik 57e4db79de127cfe961195f52907af8451026eaa20Chris Craik const Rect& clipRect = clipState->rect; 58e4db79de127cfe961195f52907af8451026eaa20Chris Craik if (CC_UNLIKELY(clipRect.isEmpty() || !clippedBounds.intersects(clipRect))) { 59e4db79de127cfe961195f52907af8451026eaa20Chris Craik // Rejected based on either empty clip, or bounds not intersecting with clip 6015f046866cb650d78f55d03327cfa4a474fc9471Chris Craik 6115f046866cb650d78f55d03327cfa4a474fc9471Chris Craik // Note: we could rewind the clipState object in situations where the clipRect is empty, 6215f046866cb650d78f55d03327cfa4a474fc9471Chris Craik // but *only* if the caching logic within ClipArea was aware of the rewind. 6315f046866cb650d78f55d03327cfa4a474fc9471Chris Craik clipState = nullptr; 64e4db79de127cfe961195f52907af8451026eaa20Chris Craik clippedBounds.setEmpty(); 65e4db79de127cfe961195f52907af8451026eaa20Chris Craik } else { 66678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik // Not rejected! compute true clippedBounds, clipSideFlags, and path mask 674876de16e34622634266d09522c9153c78c7c2fbChris Craik clipSideFlags = computeClipSideFlags(clipRect, clippedBounds); 68e4db79de127cfe961195f52907af8451026eaa20Chris Craik clippedBounds.doIntersect(clipRect); 69678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik 70678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik if (CC_UNLIKELY(snapshot.projectionPathMask)) { 71678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik // map projection path mask from render target space into op space, 72678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik // so intersection with op geometry is possible 73678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik Matrix4 inverseTransform; 74678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik inverseTransform.loadInverse(transform); 75678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik SkMatrix skInverseTransform; 76678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik inverseTransform.copyTo(skInverseTransform); 77678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik 78678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik auto localMask = allocator.create<SkPath>(); 79678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik snapshot.projectionPathMask->transform(skInverseTransform, localMask); 80678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik localProjectionPathMask = localMask; 81678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik } 82e4db79de127cfe961195f52907af8451026eaa20Chris Craik } 83e4db79de127cfe961195f52907af8451026eaa20Chris Craik} 84e4db79de127cfe961195f52907af8451026eaa20Chris Craik 854c3980b6e43cc7c0541f54b8e7e2d9d6108be622Chris CraikResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, 864c3980b6e43cc7c0541f54b8e7e2d9d6108be622Chris Craik const Matrix4& localTransform, const ClipBase* localClip) { 874c3980b6e43cc7c0541f54b8e7e2d9d6108be622Chris Craik transform.loadMultiply(*snapshot.transform, localTransform); 8804d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik clipState = snapshot.serializeIntersectedClip(allocator, localClip, *(snapshot.transform)); 894c3980b6e43cc7c0541f54b8e7e2d9d6108be622Chris Craik clippedBounds = clipState->rect; 904c3980b6e43cc7c0541f54b8e7e2d9d6108be622Chris Craik clipSideFlags = OpClipSideFlags::Full; 914c3980b6e43cc7c0541f54b8e7e2d9d6108be622Chris Craik localProjectionPathMask = nullptr; 924c3980b6e43cc7c0541f54b8e7e2d9d6108be622Chris Craik} 934c3980b6e43cc7c0541f54b8e7e2d9d6108be622Chris Craik 946e068c0182f6f85bccb855a647510724d1c65a13Chris CraikResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot) 956e068c0182f6f85bccb855a647510724d1c65a13Chris Craik : transform(*snapshot.transform) 966e068c0182f6f85bccb855a647510724d1c65a13Chris Craik , clipState(snapshot.mutateClipArea().serializeClip(allocator)) 976e068c0182f6f85bccb855a647510724d1c65a13Chris Craik , clippedBounds(clipState->rect) 98678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik , clipSideFlags(OpClipSideFlags::Full) 99678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik , localProjectionPathMask(nullptr) {} 100e4db79de127cfe961195f52907af8451026eaa20Chris Craik 1014876de16e34622634266d09522c9153c78c7c2fbChris CraikResolvedRenderState::ResolvedRenderState(const ClipRect* clipRect, const Rect& dstRect) 102b87eadda1818034ce03d85f30388384d1ac65916Chris Craik : transform(Matrix4::identity()) 1034876de16e34622634266d09522c9153c78c7c2fbChris Craik , clipState(clipRect) 104b87eadda1818034ce03d85f30388384d1ac65916Chris Craik , clippedBounds(dstRect) 105678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik , clipSideFlags(computeClipSideFlags(clipRect->rect, dstRect)) 106678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik , localProjectionPathMask(nullptr) { 1074876de16e34622634266d09522c9153c78c7c2fbChris Craik clippedBounds.doIntersect(clipRect->rect); 1084876de16e34622634266d09522c9153c78c7c2fbChris Craik} 109b87eadda1818034ce03d85f30388384d1ac65916Chris Craik 11080d2ade939153da87b3cd3b0a69a713bf68b64baChris CraikBakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator, 11180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik Snapshot& snapshot, const RecordedOp& recordedOp) { 11280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; 11380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik BakedOpState* bakedState = allocator.create_trivial<BakedOpState>( 11480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik allocator, snapshot, recordedOp, false); 11580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik if (bakedState->computedState.clippedBounds.isEmpty()) { 11680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik // bounds are empty, so op is rejected 11780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik allocator.rewindIfLastAlloc(bakedState); 11880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik return nullptr; 11980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik } 12080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik return bakedState; 12180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik} 12280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik 12380d2ade939153da87b3cd3b0a69a713bf68b64baChris CraikBakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator, 12480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik Snapshot& snapshot, const RecordedOp& recordedOp) { 12580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; 12680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik return allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp); 12780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik} 12880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik 12980d2ade939153da87b3cd3b0a69a713bf68b64baChris CraikBakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator, 13080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) { 13180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; 13280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined) 13380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style) 13480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik : true; 13580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik 13680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik BakedOpState* bakedState = allocator.create_trivial<BakedOpState>( 13780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik allocator, snapshot, recordedOp, expandForStroke); 13880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik if (bakedState->computedState.clippedBounds.isEmpty()) { 13980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik // bounds are empty, so op is rejected 14080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik // NOTE: this won't succeed if a clip was allocated 14180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik allocator.rewindIfLastAlloc(bakedState); 14280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik return nullptr; 14380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik } 14480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik return bakedState; 14580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik} 14680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik 14780d2ade939153da87b3cd3b0a69a713bf68b64baChris CraikBakedOpState* BakedOpState::tryShadowOpConstruct(LinearAllocator& allocator, 14880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik Snapshot& snapshot, const ShadowOp* shadowOpPtr) { 14980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; 15080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik 15180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik // clip isn't empty, so construct the op 15280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr); 15380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik} 15480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik 15580d2ade939153da87b3cd3b0a69a713bf68b64baChris CraikBakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator, 15680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) { 15780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp); 15880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik} 15980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik 16080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craikvoid BakedOpState::setupOpacity(const SkPaint* paint) { 16180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik computedState.opaqueOverClippedBounds = computedState.transform.isSimple() 16280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik && computedState.clipState->mode == ClipMode::Rectangle 16380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik && MathUtils::areEqual(alpha, 1.0f) 16480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik && !roundRectClipState 16580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik && PaintUtils::isOpaquePaint(paint); 16680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik} 16780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik 168e4db79de127cfe961195f52907af8451026eaa20Chris Craik} // namespace uirenderer 169e4db79de127cfe961195f52907af8451026eaa20Chris Craik} // namespace android 170