diff options
author | 2016-02-22 13:39:33 -0800 | |
---|---|---|
committer | 2016-02-23 18:52:54 +0000 | |
commit | 91eff22b5d7f8fe551bae01331948858ce932a96 (patch) | |
tree | 3a6c850a68142c40bc0c3f1ea7b84a942d1c67e8 | |
parent | eabebc1539b7e8b412da33c9e462665087cb1bfc (diff) |
Support op dumping in new pipeline
bug:26565102
Change-Id: I266e420a2f18ba9ad62942b8a0de295dfa3a2a88
-rw-r--r-- | libs/hwui/Android.mk | 2 | ||||
-rw-r--r-- | libs/hwui/Matrix.h | 27 | ||||
-rw-r--r-- | libs/hwui/OpDumper.cpp | 44 | ||||
-rw-r--r-- | libs/hwui/OpDumper.h | 32 | ||||
-rw-r--r-- | libs/hwui/RecordedOp.h | 3 | ||||
-rw-r--r-- | libs/hwui/Rect.h | 29 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 41 | ||||
-rw-r--r-- | libs/hwui/RenderNode.h | 4 | ||||
-rw-r--r-- | libs/hwui/RenderProperties.cpp | 20 | ||||
-rw-r--r-- | libs/hwui/tests/unit/OpDumperTests.cpp | 43 | ||||
-rw-r--r-- | libs/hwui/utils/StringUtils.h | 2 |
11 files changed, 214 insertions, 33 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 8660b75e702e..da7b7fb55330 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -119,6 +119,7 @@ ifeq (true, $(HWUI_NEW_OPS)) BakedOpState.cpp \ FrameBuilder.cpp \ LayerBuilder.cpp \ + OpDumper.cpp \ RecordingCanvas.cpp hwui_cflags += -DHWUI_NEW_OPS @@ -253,6 +254,7 @@ ifeq (true, $(HWUI_NEW_OPS)) tests/unit/BakedOpStateTests.cpp \ tests/unit/FrameBuilderTests.cpp \ tests/unit/LeakCheckTests.cpp \ + tests/unit/OpDumperTests.cpp \ tests/unit/RecordingCanvasTests.cpp endif diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index 1c25f26c0c25..36007cd5dc0e 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -14,14 +14,14 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_MATRIX_H -#define ANDROID_HWUI_MATRIX_H +#pragma once -#include <SkMatrix.h> +#include "Rect.h" #include <cutils/compiler.h> - -#include "Rect.h" +#include <iomanip> +#include <ostream> +#include <SkMatrix.h> namespace android { namespace uirenderer { @@ -218,6 +218,22 @@ public: void dump(const char* label = nullptr) const; + friend std::ostream& operator<<(std::ostream& os, const Matrix4& matrix) { + if (matrix.isSimple()) { + os << "offset " << matrix.getTranslateX() << "x" << matrix.getTranslateY(); + if (!matrix.isPureTranslate()) { + os << ", scale " << matrix[kScaleX] << "x" << matrix[kScaleY]; + } + } else { + os << "[" << matrix[0]; + for (int i = 1; i < 16; i++) { + os << ", " << matrix[i]; + } + os << "]"; + } + return os; + } + static const Matrix4& identity(); private: @@ -244,4 +260,3 @@ typedef Matrix4 mat4; }; // namespace uirenderer }; // namespace android -#endif // ANDROID_HWUI_MATRIX_H diff --git a/libs/hwui/OpDumper.cpp b/libs/hwui/OpDumper.cpp new file mode 100644 index 000000000000..c34cfbe1b259 --- /dev/null +++ b/libs/hwui/OpDumper.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 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 "OpDumper.h" + +#include "RecordedOp.h" + +namespace android { +namespace uirenderer { + +#define STRINGIFY(n) #n, +static const char* sOpNameLut[] = BUILD_FULL_OP_LUT(STRINGIFY); + +void OpDumper::dump(const RecordedOp& op, std::ostream& output, int level) { + for (int i = 0; i < level; i++) { + output << " "; + } + + Rect localBounds(op.unmappedBounds); + op.localMatrix.mapRect(localBounds); + output << sOpNameLut[op.opId] << " " << localBounds; + + if (op.localClip && !op.localClip->rect.contains(localBounds)) { + output << std::fixed << std::setprecision(0) + << " clip=" << op.localClip->rect + << " mode=" << (int)op.localClip->mode; + } +} + +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/OpDumper.h b/libs/hwui/OpDumper.h new file mode 100644 index 000000000000..c99b51796b5c --- /dev/null +++ b/libs/hwui/OpDumper.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include <ostream> + +namespace android { +namespace uirenderer { + +struct RecordedOp; + +class OpDumper { +public: + static void dump(const RecordedOp& op, std::ostream& output, int level = 0); +}; + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index bb26e2ec67a8..c37458d31029 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -119,6 +119,9 @@ class Tree; #define BUILD_RENDERABLE_OP_LUT(OP_FN) \ { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) } +#define BUILD_FULL_OP_LUT(OP_FN) \ + { MAP_OPS_BASED_ON_TYPE(OP_FN, OP_FN, OP_FN, OP_FN) } + /** * Op mapping functions, which skip unsupported ops. * diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h index 30c925c8775b..d9fce9b2c824 100644 --- a/libs/hwui/Rect.h +++ b/libs/hwui/Rect.h @@ -14,16 +14,17 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_RECT_H -#define ANDROID_HWUI_RECT_H +#pragma once -#include <cmath> -#include <algorithm> -#include <SkRect.h> +#include "Vertex.h" #include <utils/Log.h> -#include "Vertex.h" +#include <algorithm> +#include <cmath> +#include <iomanip> +#include <ostream> +#include <SkRect.h> namespace android { namespace uirenderer { @@ -282,9 +283,23 @@ public: void dump(const char* label = nullptr) const { ALOGD("%s[l=%.2f t=%.2f r=%.2f b=%.2f]", label ? label : "Rect", left, top, right, bottom); } + + friend std::ostream& operator<<(std::ostream& os, const Rect& rect) { + if (rect.isEmpty()) { + return os << "empty"; + } + + if (rect.left == 0 && rect.top == 0) { + return os << "[" << rect.right << " x " << rect.bottom << "]"; + } + + return os << "[" << rect.left + << " " << rect.top + << " " << rect.right + << " " << rect.bottom << "]"; + } }; // class Rect }; // namespace uirenderer }; // namespace android -#endif // ANDROID_HWUI_RECT_H diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 9ac76a4339e1..61441ce9b16e 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -19,8 +19,9 @@ #include "DamageAccumulator.h" #include "Debug.h" #if HWUI_NEW_OPS -#include "RecordedOp.h" #include "BakedOpRenderer.h" +#include "RecordedOp.h" +#include "OpDumper.h" #endif #include "DisplayListOp.h" #include "LayerRenderer.h" @@ -95,6 +96,34 @@ void RenderNode::setStagingDisplayList(DisplayList* displayList) { * This function is a simplified version of replay(), where we simply retrieve and log the * display list. This function should remain in sync with the replay() function. */ +#if HWUI_NEW_OPS +void RenderNode::output(uint32_t level, const char* label) { + ALOGD("%s (%s %p%s%s%s%s%s)", + label, + getName(), + this, + (MathUtils::isZero(properties().getAlpha()) ? ", zero alpha" : ""), + (properties().hasShadow() ? ", casting shadow" : ""), + (isRenderable() ? "" : ", empty"), + (properties().getProjectBackwards() ? ", projected" : ""), + (mLayer != nullptr ? ", on HW Layer" : "")); + properties().debugOutputProperties(level + 1); + + if (mDisplayList) { + for (auto&& op : mDisplayList->getOps()) { + std::stringstream strout; + OpDumper::dump(*op, strout, level + 1); + if (op->opId == RecordedOpId::RenderNodeOp) { + auto rnOp = reinterpret_cast<const RenderNodeOp*>(op); + rnOp->renderNode->output(level + 1, strout.str().c_str()); + } else { + ALOGD("%s", strout.str().c_str()); + } + } + } + ALOGD("%*s/RenderNode(%s %p)", level * 2, "", getName(), this); +} +#else void RenderNode::output(uint32_t level) { ALOGD("%*sStart display list (%p, %s%s%s%s%s%s)", (level - 1) * 2, "", this, getName(), @@ -104,22 +133,16 @@ void RenderNode::output(uint32_t level) { (properties().getProjectBackwards() ? ", projected" : ""), (mLayer != nullptr ? ", on HW Layer" : "")); ALOGD("%*s%s %d", level * 2, "", "Save", SaveFlags::MatrixClip); - properties().debugOutputProperties(level); - if (mDisplayList) { -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("op dumping unsupported"); -#else // TODO: consider printing the chunk boundaries here for (auto&& op : mDisplayList->getOps()) { op->output(level, DisplayListOp::kOpLogFlag_Recurse); } -#endif } - ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName()); -} + } +#endif void RenderNode::copyTo(proto::RenderNode *pnode) { pnode->set_id(static_cast<uint64_t>( diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index e0376450178f..838192552127 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -123,7 +123,11 @@ public: void defer(DeferStateStruct& deferStruct, const int level); void replay(ReplayStateStruct& replayStruct, const int level); +#if HWUI_NEW_OPS + ANDROID_API void output(uint32_t level = 0, const char* label = "Root"); +#else ANDROID_API void output(uint32_t level = 1); +#endif ANDROID_API int getDebugSize(); void copyTo(proto::RenderNode* node); diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp index b848af4e7b1e..0b0f0fa4f304 100644 --- a/libs/hwui/RenderProperties.cpp +++ b/libs/hwui/RenderProperties.cpp @@ -102,22 +102,23 @@ RenderProperties& RenderProperties::operator=(const RenderProperties& other) { void RenderProperties::debugOutputProperties(const int level) const { if (mPrimitiveFields.mLeft != 0 || mPrimitiveFields.mTop != 0) { - ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mPrimitiveFields.mLeft, mPrimitiveFields.mTop); + ALOGD("%*s(Translate (left, top) %d, %d)", level * 2, "", + mPrimitiveFields.mLeft, mPrimitiveFields.mTop); } if (mStaticMatrix) { - ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING, + ALOGD("%*s(ConcatMatrix (static) %p: " SK_MATRIX_STRING ")", level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix)); } if (mAnimationMatrix) { - ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING, + ALOGD("%*s(ConcatMatrix (animation) %p: " SK_MATRIX_STRING ")", level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix)); } if (hasTransformMatrix()) { if (isTransformTranslateOnly()) { - ALOGD("%*sTranslate %.2f, %.2f, %.2f", + ALOGD("%*s(Translate %.2f, %.2f, %.2f)", level * 2, "", getTranslationX(), getTranslationY(), getZ()); } else { - ALOGD("%*sConcatMatrix %p: " SK_MATRIX_STRING, + ALOGD("%*s(ConcatMatrix %p: " SK_MATRIX_STRING ")", level * 2, "", mComputedFields.mTransformMatrix, SK_MATRIX_ARGS(mComputedFields.mTransformMatrix)); } } @@ -132,7 +133,7 @@ void RenderProperties::debugOutputProperties(const int level) const { if (CC_LIKELY(isLayer || !getHasOverlappingRendering())) { // simply scale rendering content's alpha - ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha); + ALOGD("%*s(ScaleAlpha %.2f)", level * 2, "", mPrimitiveFields.mAlpha); } else { // savelayeralpha to create an offscreen buffer to apply alpha Rect layerBounds(0, 0, getWidth(), getHeight()); @@ -140,19 +141,18 @@ void RenderProperties::debugOutputProperties(const int level) const { getClippingRectForFlags(clipFlags, &layerBounds); clipFlags = 0; // all clipping done by savelayer } - ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "", + ALOGD("%*s(SaveLayerAlpha %d, %d, %d, %d, %d, 0x%x)", level * 2, "", (int)layerBounds.left, (int)layerBounds.top, (int)layerBounds.right, (int)layerBounds.bottom, (int)(mPrimitiveFields.mAlpha * 255), SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer); } - - } + if (clipFlags) { Rect clipRect; getClippingRectForFlags(clipFlags, &clipRect); - ALOGD("%*sClipRect %d, %d, %d, %d", level * 2, "", + ALOGD("%*s(ClipRect %d, %d, %d, %d)", level * 2, "", (int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom); } } diff --git a/libs/hwui/tests/unit/OpDumperTests.cpp b/libs/hwui/tests/unit/OpDumperTests.cpp new file mode 100644 index 000000000000..01840d72b766 --- /dev/null +++ b/libs/hwui/tests/unit/OpDumperTests.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 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 <gtest/gtest.h> + +#include "tests/common/TestUtils.h" +#include "OpDumper.h" + +using namespace android; +using namespace android::uirenderer; + +TEST(OpDumper, dump) { + SkPaint paint; + RectOp op(uirenderer::Rect(100, 100), Matrix4::identity(), nullptr, &paint); + + std::stringstream stream; + OpDumper::dump(op, stream); + EXPECT_STREQ("RectOp [100 x 100]", stream.str().c_str()); + + stream.str(""); + OpDumper::dump(op, stream, 2); + EXPECT_STREQ(" RectOp [100 x 100]", stream.str().c_str()); + + ClipRect clipRect(uirenderer::Rect(50, 50)); + op.localClip = &clipRect; + + stream.str(""); + OpDumper::dump(op, stream, 2); + EXPECT_STREQ(" RectOp [100 x 100] clip=[50 x 50] mode=0", stream.str().c_str()); +} diff --git a/libs/hwui/utils/StringUtils.h b/libs/hwui/utils/StringUtils.h index 05a3d5931e5d..5add95711f2d 100644 --- a/libs/hwui/utils/StringUtils.h +++ b/libs/hwui/utils/StringUtils.h @@ -42,7 +42,7 @@ struct SizePrinter { static const char* SUFFIXES[] = {"B", "KiB", "MiB"}; size_t suffix = 0; double temp = d.bytes; - while (temp > 1000 && suffix < 2) { + while (temp > 1024 && suffix < 2) { temp /= 1024.0; suffix++; } |