diff options
| author | 2015-12-10 20:43:56 +0000 | |
|---|---|---|
| committer | 2015-12-10 20:43:56 +0000 | |
| commit | a38b75b09502f1096f9344e03fc27e27d6df8dd8 (patch) | |
| tree | aa362596cd3b4e5e1e4b0cd6545d4debfb14de08 | |
| parent | 5a86c99d885246ac3058e4e06724ba38b7ed2f68 (diff) | |
| parent | 268a9c0f29c16a64d5819c7dbe8b0633baedab83 (diff) | |
Merge "Add property animations to new reorderer/renderer"
| -rw-r--r-- | libs/hwui/BakedOpDispatcher.cpp | 8 | ||||
| -rw-r--r-- | libs/hwui/OpReorderer.cpp | 94 | ||||
| -rw-r--r-- | libs/hwui/OpReorderer.h | 8 | ||||
| -rw-r--r-- | libs/hwui/RecordedOp.h | 33 | ||||
| -rw-r--r-- | libs/hwui/RecordingCanvas.cpp | 38 | ||||
| -rw-r--r-- | libs/hwui/RecordingCanvas.h | 11 | ||||
| -rw-r--r-- | libs/hwui/tests/common/scenes/OpPropAnimation.cpp | 72 |
7 files changed, 225 insertions, 39 deletions
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index f1c89b895048..d4dbb00aa207 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -309,6 +309,14 @@ void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer&, const EndLayerOp&, const LOG_ALWAYS_FATAL("unsupported operation"); } +void BakedOpDispatcher::onCirclePropsOp(BakedOpRenderer&, const CirclePropsOp&, const BakedOpState&) { + LOG_ALWAYS_FATAL("unsupported operation"); +} + +void BakedOpDispatcher::onRoundRectPropsOp(BakedOpRenderer&, const RoundRectPropsOp&, const BakedOpState&) { + LOG_ALWAYS_FATAL("unsupported operation"); +} + namespace VertexBufferRenderFlags { enum { Offset = 0x1, diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp index b936e6d5b062..ec03e8310a36 100644 --- a/libs/hwui/OpReorderer.cpp +++ b/libs/hwui/OpReorderer.cpp @@ -467,13 +467,13 @@ void OpReorderer::deferNodePropsAndOps(RenderNode& node) { // (temp layers are clipped to viewport, since they don't persist offscreen content) SkPaint saveLayerPaint; saveLayerPaint.setAlpha(properties.getAlpha()); - onBeginLayerOp(*new (mAllocator) BeginLayerOp( + deferBeginLayerOp(*new (mAllocator) BeginLayerOp( saveLayerBounds, Matrix4::identity(), saveLayerBounds, &saveLayerPaint)); deferNodeOps(node); - onEndLayerOp(*new (mAllocator) EndLayerOp()); + deferEndLayerOp(*new (mAllocator) EndLayerOp()); } else { deferNodeOps(node); } @@ -559,7 +559,7 @@ void OpReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedN } const RenderNodeOp* childOp = zTranslatedNodes[drawIndex].value; - deferRenderNodeOp(*childOp); + deferRenderNodeOpImpl(*childOp); drawIndex++; } } @@ -645,7 +645,7 @@ void OpReorderer::deferProjectedChildren(const RenderNode& renderNode) { int restoreTo = mCanvasState.save(SkCanvas::kMatrix_SaveFlag); mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor); - deferRenderNodeOp(*childOp); + deferRenderNodeOpImpl(*childOp); mCanvasState.restoreToCount(restoreTo); } @@ -653,13 +653,13 @@ void OpReorderer::deferProjectedChildren(const RenderNode& renderNode) { } /** - * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods. + * Used to define a list of lambdas referencing private OpReorderer::onXX::defer() methods. * * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. * E.g. a BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&) */ #define OP_RECEIVER(Type) \ - [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); }, + [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.defer##Type(static_cast<const Type&>(op)); }, void OpReorderer::deferNodeOps(const RenderNode& renderNode) { typedef void (*OpDispatcher) (OpReorderer& reorderer, const RecordedOp& op); static OpDispatcher receivers[] = { @@ -687,7 +687,7 @@ void OpReorderer::deferNodeOps(const RenderNode& renderNode) { } } -void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) { +void OpReorderer::deferRenderNodeOpImpl(const RenderNodeOp& op) { if (op.renderNode->nothingToDraw()) return; int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); @@ -702,9 +702,9 @@ void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) { mCanvasState.restoreToCount(count); } -void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) { +void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) { if (!op.skipInOrderDraw) { - deferRenderNodeOp(op); + deferRenderNodeOpImpl(op); } } @@ -712,7 +712,7 @@ void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) { * Defers an unmergeable, strokeable op, accounting correctly * for paint's style on the bounds being computed. */ -void OpReorderer::onStrokeableOp(const RecordedOp& op, batchid_t batchId, +void OpReorderer::deferStrokeableOp(const RecordedOp& op, batchid_t batchId, BakedOpState::StrokeBehavior strokeBehavior) { // Note: here we account for stroke when baking the op BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( @@ -734,11 +734,11 @@ static batchid_t tessBatchId(const RecordedOp& op) { : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices); } -void OpReorderer::onArcOp(const ArcOp& op) { - onStrokeableOp(op, tessBatchId(op)); +void OpReorderer::deferArcOp(const ArcOp& op) { + deferStrokeableOp(op, tessBatchId(op)); } -void OpReorderer::onBitmapOp(const BitmapOp& op) { +void OpReorderer::deferBitmapOp(const BitmapOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected @@ -757,28 +757,43 @@ void OpReorderer::onBitmapOp(const BitmapOp& op) { } } -void OpReorderer::onBitmapMeshOp(const BitmapMeshOp& op) { +void OpReorderer::deferBitmapMeshOp(const BitmapMeshOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); } -void OpReorderer::onBitmapRectOp(const BitmapRectOp& op) { +void OpReorderer::deferBitmapRectOp(const BitmapRectOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); } -void OpReorderer::onLinesOp(const LinesOp& op) { +void OpReorderer::deferCirclePropsOp(const CirclePropsOp& op) { + // allocate a temporary oval op (with mAllocator, so it persists until render), so the + // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. + float x = *(op.x); + float y = *(op.y); + float radius = *(op.radius); + Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius); + const OvalOp* resolvedOp = new (mAllocator) OvalOp( + unmappedBounds, + op.localMatrix, + op.localClipRect, + op.paint); + deferOvalOp(*resolvedOp); +} + +void OpReorderer::deferLinesOp(const LinesOp& op) { batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; - onStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); + deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); } -void OpReorderer::onOvalOp(const OvalOp& op) { - onStrokeableOp(op, tessBatchId(op)); +void OpReorderer::deferOvalOp(const OvalOp& op) { + deferStrokeableOp(op, tessBatchId(op)); } -void OpReorderer::onPatchOp(const PatchOp& op) { +void OpReorderer::deferPatchOp(const PatchOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected @@ -795,30 +810,41 @@ void OpReorderer::onPatchOp(const PatchOp& op) { } } -void OpReorderer::onPathOp(const PathOp& op) { - onStrokeableOp(op, OpBatchType::Bitmap); +void OpReorderer::deferPathOp(const PathOp& op) { + deferStrokeableOp(op, OpBatchType::Bitmap); } -void OpReorderer::onPointsOp(const PointsOp& op) { +void OpReorderer::deferPointsOp(const PointsOp& op) { batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; - onStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); + deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); +} + +void OpReorderer::deferRectOp(const RectOp& op) { + deferStrokeableOp(op, tessBatchId(op)); } -void OpReorderer::onRectOp(const RectOp& op) { - onStrokeableOp(op, tessBatchId(op)); +void OpReorderer::deferRoundRectOp(const RoundRectOp& op) { + deferStrokeableOp(op, tessBatchId(op)); } -void OpReorderer::onRoundRectOp(const RoundRectOp& op) { - onStrokeableOp(op, tessBatchId(op)); +void OpReorderer::deferRoundRectPropsOp(const RoundRectPropsOp& op) { + // allocate a temporary round rect op (with mAllocator, so it persists until render), so the + // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. + const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp( + Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)), + op.localMatrix, + op.localClipRect, + op.paint, *op.rx, *op.ry); + deferRoundRectOp(*resolvedOp); } -void OpReorderer::onSimpleRectsOp(const SimpleRectsOp& op) { +void OpReorderer::deferSimpleRectsOp(const SimpleRectsOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); } -void OpReorderer::onTextOp(const TextOp& op) { +void OpReorderer::deferTextOp(const TextOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected @@ -861,7 +887,7 @@ void OpReorderer::restoreForLayer() { } // TODO: test rejection at defer time, where the bounds become empty -void OpReorderer::onBeginLayerOp(const BeginLayerOp& op) { +void OpReorderer::deferBeginLayerOp(const BeginLayerOp& op) { uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth(); uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight(); @@ -906,7 +932,7 @@ void OpReorderer::onBeginLayerOp(const BeginLayerOp& op) { &op, nullptr); } -void OpReorderer::onEndLayerOp(const EndLayerOp& /* ignored */) { +void OpReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) { const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp; int finishedLayerIndex = mLayerStack.back(); @@ -932,11 +958,11 @@ void OpReorderer::onEndLayerOp(const EndLayerOp& /* ignored */) { } } -void OpReorderer::onLayerOp(const LayerOp& op) { +void OpReorderer::deferLayerOp(const LayerOp& op) { LOG_ALWAYS_FATAL("unsupported"); } -void OpReorderer::onShadowOp(const ShadowOp& op) { +void OpReorderer::deferShadowOp(const ShadowOp& op) { LOG_ALWAYS_FATAL("unsupported"); } diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h index 0b88f049b583..35343c8b4358 100644 --- a/libs/hwui/OpReorderer.h +++ b/libs/hwui/OpReorderer.h @@ -237,7 +237,7 @@ private: void deferNodeOps(const RenderNode& renderNode); - void deferRenderNodeOp(const RenderNodeOp& op); + void deferRenderNodeOpImpl(const RenderNodeOp& op); void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers); @@ -246,17 +246,17 @@ private: return mFrameAllocatedPaths.back().get(); } - void onStrokeableOp(const RecordedOp& op, batchid_t batchId, + void deferStrokeableOp(const RecordedOp& op, batchid_t batchId, BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined); /** - * Declares all OpReorderer::onXXXXOp() methods for every RecordedOp type. + * Declares all OpReorderer::deferXXXXOp() methods for every RecordedOp type. * * These private methods are called from within deferImpl to defer each individual op * type differently. */ #define INTERNAL_OP_HANDLER(Type) \ - void on##Type(const Type& op); + void defer##Type(const Type& op); MAP_OPS(INTERNAL_OP_HANDLER) std::vector<std::unique_ptr<SkPath> > mFrameAllocatedPaths; diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index 75ecdae3aa6f..d1a486600e4c 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -48,6 +48,7 @@ struct Vertex; M_OP_FN(BitmapOp) \ U_OP_FN(BitmapMeshOp) \ U_OP_FN(BitmapRectOp) \ + U_OP_FN(CirclePropsOp) \ U_OP_FN(LinesOp) \ U_OP_FN(OvalOp) \ M_OP_FN(PatchOp) \ @@ -56,6 +57,7 @@ struct Vertex; U_OP_FN(RectOp) \ U_OP_FN(RenderNodeOp) \ U_OP_FN(RoundRectOp) \ + U_OP_FN(RoundRectPropsOp) \ U_OP_FN(ShadowOp) \ U_OP_FN(SimpleRectsOp) \ M_OP_FN(TextOp) \ @@ -181,6 +183,18 @@ struct BitmapRectOp : RecordedOp { const Rect src; }; +struct CirclePropsOp : RecordedOp { + CirclePropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint, + float* x, float* y, float* radius) + : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClipRect, paint) + , x(x) + , y(y) + , radius(radius) {} + const float* x; + const float* y; + const float* radius; +}; + struct LinesOp : RecordedOp { LinesOp(BASE_PARAMS, const float* points, const int floatCount) : SUPER(LinesOp) @@ -195,7 +209,6 @@ struct OvalOp : RecordedOp { : SUPER(OvalOp) {} }; - struct PatchOp : RecordedOp { PatchOp(BASE_PARAMS, const SkBitmap* bitmap, const Res_png_9patch* patch) : SUPER(PatchOp) @@ -235,6 +248,24 @@ struct RoundRectOp : RecordedOp { const float ry; }; +struct RoundRectPropsOp : RecordedOp { + RoundRectPropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint, + float* left, float* top, float* right, float* bottom, float *rx, float *ry) + : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClipRect, paint) + , left(left) + , top(top) + , right(right) + , bottom(bottom) + , rx(rx) + , ry(ry) {} + const float* left; + const float* top; + const float* right; + const float* bottom; + const float* rx; + const float* ry; +}; + /** * Real-time, dynamic-lit shadow. * diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 57f0d349172c..1bf92be18687 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -343,11 +343,49 @@ void RecordingCanvas::drawRoundRect(float left, float top, float right, float bo refPaint(&paint), rx, ry)); } +void RecordingCanvas::drawRoundRect( + CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, + CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, + CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, + CanvasPropertyPaint* paint) { + mDisplayList->ref(left); + mDisplayList->ref(top); + mDisplayList->ref(right); + mDisplayList->ref(bottom); + mDisplayList->ref(rx); + mDisplayList->ref(ry); + mDisplayList->ref(paint); + refBitmapsInShader(paint->value.getShader()); + addOp(new (alloc()) RoundRectPropsOp( + *(mState.currentSnapshot()->transform), + mState.getRenderTargetClipBounds(), + &paint->value, + &left->value, &top->value, &right->value, &bottom->value, + &rx->value, &ry->value)); +} + void RecordingCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { + // TODO: move to Canvas.h if (radius <= 0) return; drawOval(x - radius, y - radius, x + radius, y + radius, paint); } +void RecordingCanvas::drawCircle( + CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, + CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) { + mDisplayList->ref(x); + mDisplayList->ref(y); + mDisplayList->ref(radius); + mDisplayList->ref(paint); + refBitmapsInShader(paint->value.getShader()); + addOp(new (alloc()) CirclePropsOp( + *(mState.currentSnapshot()->transform), + mState.getRenderTargetClipBounds(), + &paint->value, + &x->value, &y->value, &radius->value)); +} + + void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) { addOp(new (alloc()) OvalOp( Rect(left, top, right, bottom), diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index 16a277162738..6fbaa8ae75c3 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -69,6 +69,17 @@ public: virtual GLuint getTargetFbo() const override { return -1; } // ---------------------------------------------------------------------------- +// HWUI Canvas draw operations +// ---------------------------------------------------------------------------- + + void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, + CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, + CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, + CanvasPropertyPaint* paint); + void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, + CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint); + +// ---------------------------------------------------------------------------- // android/graphics/Canvas interface // ---------------------------------------------------------------------------- virtual SkCanvas* asSkCanvas() override; diff --git a/libs/hwui/tests/common/scenes/OpPropAnimation.cpp b/libs/hwui/tests/common/scenes/OpPropAnimation.cpp new file mode 100644 index 000000000000..5dfb2b4a8b33 --- /dev/null +++ b/libs/hwui/tests/common/scenes/OpPropAnimation.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TestSceneBase.h" +#include "utils/Color.h" + +class OpPropAnimation; + +static TestScene::Registrar _Shapes(TestScene::Info{ + "opprops", + "A minimal demonstration of CanvasProperty drawing operations.", + TestScene::simpleCreateScene<OpPropAnimation> +}); + +class OpPropAnimation : public TestScene { +public: + sp<CanvasPropertyPaint> mPaint = new CanvasPropertyPaint(SkPaint()); + + sp<CanvasPropertyPrimitive> mRoundRectLeft = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mRoundRectTop = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mRoundRectRight = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mRoundRectBottom = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mRoundRectRx = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mRoundRectRy = new CanvasPropertyPrimitive(0); + + sp<CanvasPropertyPrimitive> mCircleX = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mCircleY = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mCircleRadius = new CanvasPropertyPrimitive(0); + + sp<RenderNode> content; + void createContent(int width, int height, TestCanvas& canvas) override { + content = TestUtils::createNode(0, 0, width, height, + [this, width, height](RenderProperties& props, TestCanvas& canvas) { + mPaint->value.setAntiAlias(true); + mPaint->value.setColor(Color::Blue_500); + + mRoundRectRight->value = width / 2; + mRoundRectBottom->value = height / 2; + + mCircleX->value = width * 0.75; + mCircleY->value = height * 0.75; + + canvas.drawColor(Color::White, SkXfermode::Mode::kSrcOver_Mode); + canvas.drawRoundRect(mRoundRectLeft.get(), mRoundRectTop.get(), + mRoundRectRight.get(), mRoundRectBottom.get(), + mRoundRectRx.get(), mRoundRectRy.get(), mPaint.get()); + canvas.drawCircle(mCircleX.get(), mCircleY.get(), mCircleRadius.get(), mPaint.get()); + }); + canvas.drawRenderNode(content.get()); + } + + void doFrame(int frameNr) override { + float value = (abs((frameNr % 200) - 100)) / 100.0f; + mRoundRectRx->value = dp(10) + value * dp(40); + mRoundRectRy->value = dp(10) + value * dp(80); + mCircleRadius->value = value * dp(200); + content->setPropertyFieldsDirty(RenderNode::GENERIC); + } +}; |