Support op dumping in new pipeline
am: 91eff22b5d
* commit '91eff22b5d7f8fe551bae01331948858ce932a96':
Support op dumping in new pipeline
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_HWUI_MATRIX_H
|
||||
#define ANDROID_HWUI_MATRIX_H
|
||||
|
||||
#include <SkMatrix.h>
|
||||
|
||||
#include <cutils/compiler.h>
|
||||
#pragma once
|
||||
|
||||
#include "Rect.h"
|
||||
|
||||
#include <cutils/compiler.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
|
||||
|
||||
44
libs/hwui/OpDumper.cpp
Normal file
44
libs/hwui/OpDumper.cpp
Normal file
@@ -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
|
||||
32
libs/hwui/OpDumper.h
Normal file
32
libs/hwui/OpDumper.h
Normal file
@@ -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
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>(
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
43
libs/hwui/tests/unit/OpDumperTests.cpp
Normal file
43
libs/hwui/tests/unit/OpDumperTests.cpp
Normal file
@@ -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());
|
||||
}
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user