Merge "Add ListView rendering benchmark"
This commit is contained in:
@ -1383,7 +1383,10 @@ class DrawRenderNodeOp : public DrawBoundedOp {
|
||||
friend class TestUtils;
|
||||
public:
|
||||
DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent, bool clipIsSimple)
|
||||
: DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr)
|
||||
: DrawBoundedOp(0, 0,
|
||||
renderNode->stagingProperties().getWidth(),
|
||||
renderNode->stagingProperties().getHeight(),
|
||||
nullptr)
|
||||
, renderNode(renderNode)
|
||||
, mRecordedWithPotentialStencilClip(!clipIsSimple || !transformFromParent.isSimple())
|
||||
, localMatrix(transformFromParent)
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "FrameInfoVisualizer.h"
|
||||
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "utils/Color.h"
|
||||
|
||||
#include <cutils/compiler.h>
|
||||
#include <array>
|
||||
@ -27,19 +28,19 @@
|
||||
#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
|
||||
#define PROFILE_DRAW_DP_PER_MS 7
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
// Must be NUM_ELEMENTS in size
|
||||
static const SkColor THRESHOLD_COLOR = 0xff5faa4d;
|
||||
static const SkColor BAR_FAST_ALPHA = 0x8F000000;
|
||||
static const SkColor BAR_JANKY_ALPHA = 0xDF000000;
|
||||
static const SkColor THRESHOLD_COLOR = Color::Green_500;
|
||||
static const SkColor BAR_FAST_MASK = 0x8FFFFFFF;
|
||||
static const SkColor BAR_JANKY_MASK = 0xDFFFFFFF;
|
||||
|
||||
// We could get this from TimeLord and use the actual frame interval, but
|
||||
// this is good enough
|
||||
#define FRAME_THRESHOLD 16
|
||||
#define FRAME_THRESHOLD_NS 16000000
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
struct BarSegment {
|
||||
FrameInfoIndex start;
|
||||
FrameInfoIndex end;
|
||||
@ -47,13 +48,13 @@ struct BarSegment {
|
||||
};
|
||||
|
||||
static const std::array<BarSegment,7> Bar {{
|
||||
{ FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, 0x00796B },
|
||||
{ FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart, 0x388E3C },
|
||||
{ FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, 0x689F38},
|
||||
{ FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, 0x2196F3},
|
||||
{ FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, 0x4FC3F7},
|
||||
{ FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, 0xF44336},
|
||||
{ FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, 0xFF9800},
|
||||
{ FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, Color::Teal_700 },
|
||||
{ FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart, Color::Green_700 },
|
||||
{ FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, Color::LightGreen_700 },
|
||||
{ FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, Color::Blue_500 },
|
||||
{ FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, Color::LightBlue_300 },
|
||||
{ FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, Color::Red_500},
|
||||
{ FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, Color::Orange_500},
|
||||
}};
|
||||
|
||||
static int dpToPx(int dp, float density) {
|
||||
@ -197,9 +198,9 @@ void FrameInfoVisualizer::drawGraph(OpenGLRenderer* canvas) {
|
||||
SkPaint paint;
|
||||
for (size_t i = 0; i < Bar.size(); i++) {
|
||||
nextBarSegment(Bar[i].start, Bar[i].end);
|
||||
paint.setColor(Bar[i].color | BAR_FAST_ALPHA);
|
||||
paint.setColor(Bar[i].color & BAR_FAST_MASK);
|
||||
canvas->drawRects(mFastRects.get(), mNumFastRects * 4, &paint);
|
||||
paint.setColor(Bar[i].color | BAR_JANKY_ALPHA);
|
||||
paint.setColor(Bar[i].color & BAR_JANKY_MASK);
|
||||
canvas->drawRects(mJankyRects.get(), mNumJankyRects * 4, &paint);
|
||||
}
|
||||
}
|
||||
|
@ -435,8 +435,9 @@ void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
|
||||
refPaint(paint), refBitmap(*bitmap)));
|
||||
}
|
||||
void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
|
||||
auto&& stagingProps = renderNode->stagingProperties();
|
||||
RenderNodeOp* op = new (alloc()) RenderNodeOp(
|
||||
Rect(0, 0, renderNode->getWidth(), renderNode->getHeight()), // are these safe? they're theoretically dynamic
|
||||
Rect(stagingProps.getWidth(), stagingProps.getHeight()),
|
||||
*(mState.currentSnapshot()->transform),
|
||||
mState.getRenderTargetClipBounds(),
|
||||
renderNode);
|
||||
|
146
libs/hwui/tests/scenes/ListViewAnimation.cpp
Normal file
146
libs/hwui/tests/scenes/ListViewAnimation.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
class ListViewAnimation;
|
||||
|
||||
static Benchmark _ListView(BenchmarkInfo{
|
||||
"listview",
|
||||
"A mock ListView of scrolling content. Doesn't re-bind/re-record views as they are recycled, so"
|
||||
"won't upload much content (either glyphs, or bitmaps).",
|
||||
simpleCreateScene<ListViewAnimation>
|
||||
});
|
||||
|
||||
class ListViewAnimation : public TestScene {
|
||||
public:
|
||||
int cardHeight;
|
||||
int cardSpacing;
|
||||
int cardWidth;
|
||||
int cardLeft;
|
||||
sp<RenderNode> listView;
|
||||
std::vector< sp<RenderNode> > cards;
|
||||
void createContent(int width, int height, TestCanvas& canvas) override {
|
||||
srand(0);
|
||||
cardHeight = dp(60);
|
||||
cardSpacing = dp(16);
|
||||
cardWidth = std::min((height - cardSpacing * 2), (int)dp(300));
|
||||
cardLeft = (width - cardWidth) / 2;
|
||||
|
||||
for (int y = 0; y < height + (cardHeight + cardSpacing - 1); y += (cardHeight + cardSpacing)) {
|
||||
cards.push_back(createCard(cards.size(), y));
|
||||
}
|
||||
listView = TestUtils::createNode(0, 0, width, height,
|
||||
[this](RenderProperties& props, TestCanvas& canvas) {
|
||||
for (size_t ci = 0; ci < cards.size(); ci++) {
|
||||
canvas.drawRenderNode(cards[ci].get());
|
||||
}
|
||||
});
|
||||
|
||||
canvas.drawColor(Color::Grey_500, SkXfermode::kSrcOver_Mode);
|
||||
canvas.drawRenderNode(listView.get());
|
||||
}
|
||||
|
||||
void doFrame(int frameNr) override {
|
||||
int scrollPx = dp(frameNr) * 3;
|
||||
int cardIndexOffset = scrollPx / (cardSpacing + cardHeight);
|
||||
int pxOffset = -(scrollPx % (cardSpacing + cardHeight));
|
||||
|
||||
TestCanvas canvas(cardWidth, cardHeight);
|
||||
for (size_t ci = 0; ci < cards.size(); ci++) {
|
||||
// update card position
|
||||
auto card = cards[(ci + cardIndexOffset) % cards.size()];
|
||||
int top = ((int)ci) * (cardSpacing + cardHeight) + pxOffset;
|
||||
card->mutateStagingProperties().setLeftTopRightBottom(
|
||||
cardLeft, top, cardLeft + cardWidth, top + cardHeight);
|
||||
card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
|
||||
|
||||
// draw it to parent DisplayList
|
||||
canvas.drawRenderNode(cards[ci].get());
|
||||
}
|
||||
listView->setStagingDisplayList(canvas.finishRecording());
|
||||
}
|
||||
private:
|
||||
SkBitmap createRandomCharIcon() {
|
||||
int size = cardHeight - (dp(10) * 2);
|
||||
SkBitmap bitmap = TestUtils::createSkBitmap(size, size);
|
||||
SkCanvas canvas(bitmap);
|
||||
canvas.clear(0);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
SkColor randomColor = BrightColors[rand() % BrightColorsCount];
|
||||
paint.setColor(randomColor);
|
||||
canvas.drawCircle(size / 2, size / 2, size / 2, paint);
|
||||
|
||||
bool bgDark = SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor)
|
||||
< 128 * 3;
|
||||
paint.setColor(bgDark ? Color::White : Color::Grey_700);
|
||||
paint.setTextAlign(SkPaint::kCenter_Align);
|
||||
paint.setTextSize(size / 2);
|
||||
char charToShow = 'A' + (rand() % 26);
|
||||
canvas.drawText(&charToShow, 1, size / 2, /*approximate centering*/ size * 0.7, paint);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
static SkBitmap createBoxBitmap(bool filled) {
|
||||
int size = dp(20);
|
||||
int stroke = dp(2);
|
||||
SkBitmap bitmap = TestUtils::createSkBitmap(size, size);
|
||||
SkCanvas canvas(bitmap);
|
||||
canvas.clear(Color::Transparent);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(filled ? Color::Yellow_500 : Color::Grey_700);
|
||||
paint.setStyle(filled ? SkPaint::kStrokeAndFill_Style : SkPaint::kStroke_Style);
|
||||
paint.setStrokeWidth(stroke);
|
||||
canvas.drawRect(SkRect::MakeLTRB(stroke, stroke, size - stroke, size - stroke), paint);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
sp<RenderNode> createCard(int cardId, int top) {
|
||||
return TestUtils::createNode(cardLeft, top, cardLeft + cardWidth, top + cardHeight,
|
||||
[this, cardId](RenderProperties& props, TestCanvas& canvas) {
|
||||
static SkBitmap filledBox = createBoxBitmap(true);
|
||||
static SkBitmap strokedBox = createBoxBitmap(false);
|
||||
|
||||
props.mutableOutline().setRoundRect(0, 0, cardWidth, cardHeight, dp(6), 1);
|
||||
props.mutableOutline().setShouldClip(true);
|
||||
canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
|
||||
|
||||
SkPaint textPaint;
|
||||
textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
||||
textPaint.setColor(rand() % 2 ? Color::Black : Color::Grey_500);
|
||||
textPaint.setTextSize(dp(20));
|
||||
textPaint.setAntiAlias(true);
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "This card is #%d", cardId);
|
||||
TestUtils::drawTextToCanvas(&canvas, buf, textPaint, cardHeight, dp(25));
|
||||
textPaint.setTextSize(dp(15));
|
||||
TestUtils::drawTextToCanvas(&canvas, "This is some more text on the card", textPaint,
|
||||
cardHeight, dp(45));
|
||||
|
||||
canvas.drawBitmap(createRandomCharIcon(), dp(10), dp(10), nullptr);
|
||||
|
||||
const SkBitmap& boxBitmap = rand() % 2 ? filledBox : strokedBox;
|
||||
canvas.drawBitmap(boxBitmap, cardWidth - dp(10) - boxBitmap.width(), dp(10), nullptr);
|
||||
});
|
||||
}
|
||||
};
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include "TestSceneBase.h"
|
||||
#include "utils/Color.h"
|
||||
|
||||
class RecentsAnimation;
|
||||
|
||||
@ -29,16 +30,16 @@ class RecentsAnimation : public TestScene {
|
||||
public:
|
||||
void createContent(int width, int height, TestCanvas& renderer) override {
|
||||
static SkColor COLORS[] = {
|
||||
0xFFF44336,
|
||||
0xFF9C27B0,
|
||||
0xFF2196F3,
|
||||
0xFF4CAF50,
|
||||
Color::Red_500,
|
||||
Color::Purple_500,
|
||||
Color::Blue_500,
|
||||
Color::Green_500,
|
||||
};
|
||||
|
||||
thumbnailSize = std::min(std::min(width, height) / 2, 720);
|
||||
int cardsize = std::min(width, height) - dp(64);
|
||||
|
||||
renderer.drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
|
||||
renderer.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
|
||||
renderer.insertReorderBarrier(true);
|
||||
|
||||
int x = dp(32);
|
||||
@ -63,7 +64,7 @@ public:
|
||||
mCards[ci]->setPropertyFieldsDirty(RenderNode::Y);
|
||||
}
|
||||
mThumbnail.eraseColor(TestUtils::interpolateColor(
|
||||
curFrame / 150.0f, 0xFF4CAF50, 0xFFFF5722));
|
||||
curFrame / 150.0f, Color::Green_500, Color::DeepOrange_500));
|
||||
}
|
||||
|
||||
private:
|
||||
@ -75,7 +76,7 @@ private:
|
||||
props.mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
|
||||
props.mutableOutline().setShouldClip(true);
|
||||
|
||||
canvas.drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
|
||||
canvas.drawColor(Color::Grey_200, SkXfermode::kSrcOver_Mode);
|
||||
canvas.drawBitmap(thumb, 0, 0, thumb.width(), thumb.height(),
|
||||
0, 0, width, height, nullptr);
|
||||
});
|
||||
|
86
libs/hwui/utils/Color.h
Normal file
86
libs/hwui/utils/Color.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef COLOR_H
|
||||
#define COLOR_H
|
||||
|
||||
#include <SkColor.h>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
namespace Color {
|
||||
enum Color {
|
||||
Red_500 = 0xFFF44336,
|
||||
Pink_500 = 0xFFE91E63,
|
||||
Purple_500 = 0xFF9C27B0,
|
||||
DeepPurple_500 = 0xFF673AB7,
|
||||
Indigo_500 = 0xFF3F51B5,
|
||||
Blue_500 = 0xFF2196F3,
|
||||
LightBlue_300 = 0xFF4FC3F7,
|
||||
LightBlue_500 = 0xFF03A9F4,
|
||||
Cyan_500 = 0xFF00BCD4,
|
||||
Teal_500 = 0xFF009688,
|
||||
Teal_700 = 0xFF00796B,
|
||||
Green_500 = 0xFF4CAF50,
|
||||
Green_700 = 0xFF388E3C,
|
||||
LightGreen_500 = 0xFF8BC34A,
|
||||
LightGreen_700 = 0xFF689F38,
|
||||
Lime_500 = 0xFFCDDC39,
|
||||
Yellow_500 = 0xFFFFEB3B,
|
||||
Amber_500 = 0xFFFFC107,
|
||||
Orange_500 = 0xFFFF9800,
|
||||
DeepOrange_500 = 0xFFFF5722,
|
||||
Brown_500 = 0xFF795548,
|
||||
Grey_200 = 0xFFEEEEEE,
|
||||
Grey_500 = 0xFF9E9E9E,
|
||||
Grey_700 = 0xFF616161,
|
||||
BlueGrey_500 = 0xFF607D8B,
|
||||
Transparent = 0x00000000,
|
||||
Black = 0xFF000000,
|
||||
White = 0xFFFFFFFF,
|
||||
};
|
||||
}
|
||||
|
||||
static_assert(Color::White == SK_ColorWHITE, "color format has changed");
|
||||
static_assert(Color::Black == SK_ColorBLACK, "color format has changed");
|
||||
|
||||
// Array of bright (500 intensity) colors for synthetic content
|
||||
static const Color::Color BrightColors[] = {
|
||||
Color::Red_500,
|
||||
Color::Pink_500,
|
||||
Color::Purple_500,
|
||||
Color::DeepPurple_500,
|
||||
Color::Indigo_500,
|
||||
Color::Blue_500,
|
||||
Color::LightBlue_500,
|
||||
Color::Cyan_500,
|
||||
Color::Teal_500,
|
||||
Color::Green_500,
|
||||
Color::LightGreen_500,
|
||||
Color::Lime_500,
|
||||
Color::Yellow_500,
|
||||
Color::Amber_500,
|
||||
Color::Orange_500,
|
||||
Color::DeepOrange_500,
|
||||
Color::Brown_500,
|
||||
Color::Grey_500,
|
||||
Color::BlueGrey_500,
|
||||
};
|
||||
static constexpr int BrightColorsCount = sizeof(BrightColors) / sizeof(Color::Color);
|
||||
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
|
||||
#endif /* TEST_UTILS_H */
|
Reference in New Issue
Block a user