Merge "Add initial benchmarks for CanvasOp"
This commit is contained in:
committed by
Android (Google) Code Review
commit
ab5dac8dc9
@@ -672,6 +672,7 @@ cc_benchmark {
|
||||
|
||||
srcs: [
|
||||
"tests/microbench/main.cpp",
|
||||
"tests/microbench/CanvasOpBench.cpp",
|
||||
"tests/microbench/DisplayListCanvasBench.cpp",
|
||||
"tests/microbench/LinearAllocatorBench.cpp",
|
||||
"tests/microbench/PathParserBench.cpp",
|
||||
|
||||
@@ -16,14 +16,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pipeline/skia/SkiaDisplayList.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
namespace VectorDrawable {
|
||||
class Tree;
|
||||
};
|
||||
namespace skiapipeline {
|
||||
class SkiaDisplayList;
|
||||
}
|
||||
typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot;
|
||||
|
||||
/**
|
||||
|
||||
@@ -380,7 +380,7 @@ void RenderNode::deleteDisplayList(TreeObserver& observer, TreeInfo* info) {
|
||||
if (mDisplayList) {
|
||||
mDisplayList->updateChildren(
|
||||
[&observer, info](RenderNode* child) { child->decParentRefCount(observer, info); });
|
||||
if (!mDisplayList->reuseDisplayList(this, info ? &info->canvasContext : nullptr)) {
|
||||
if (!mDisplayList->reuseDisplayList(this)) {
|
||||
delete mDisplayList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,14 @@
|
||||
namespace android::uirenderer {
|
||||
|
||||
CanvasStateHelper::CanvasStateHelper(int width, int height) {
|
||||
resetState(width, height);
|
||||
}
|
||||
|
||||
void CanvasStateHelper::resetState(int width, int height) {
|
||||
mInitialBounds = SkIRect::MakeWH(width, height);
|
||||
mSaveStack.clear();
|
||||
mClipStack.clear();
|
||||
mTransformStack.clear();
|
||||
mSaveStack.emplace_back();
|
||||
mClipStack.emplace_back().setRect(mInitialBounds);
|
||||
mTransformStack.emplace_back();
|
||||
|
||||
@@ -57,9 +57,7 @@ protected:
|
||||
}
|
||||
|
||||
bool internalSave(SaveEntry saveEntry);
|
||||
bool internalSave(SaveFlags::Flags flags) {
|
||||
return internalSave(flagsToSaveEntry(flags));
|
||||
}
|
||||
|
||||
void internalSaveLayer(const SkCanvas::SaveLayerRec& layerRec) {
|
||||
internalSave({
|
||||
.clip = true,
|
||||
@@ -90,6 +88,8 @@ protected:
|
||||
return mClipStack[mCurrentClipIndex];
|
||||
}
|
||||
|
||||
void resetState(int width, int height);
|
||||
|
||||
public:
|
||||
int saveCount() const { return mSaveStack.size(); }
|
||||
|
||||
@@ -186,14 +186,26 @@ public:
|
||||
submit(std::move(op));
|
||||
}
|
||||
|
||||
const CanvasOpReceiver& receiver() const { return mReceiver; }
|
||||
const CanvasOpReceiver& receiver() const { return *mReceiver; }
|
||||
|
||||
CanvasOpReceiver finish() {
|
||||
auto ret = std::move(mReceiver.value());
|
||||
mReceiver.reset();
|
||||
return std::move(ret);
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
void reset(int newWidth, int newHeight, Args&&... args) {
|
||||
resetState(newWidth, newHeight);
|
||||
mReceiver.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
CanvasOpReceiver mReceiver;
|
||||
std::optional<CanvasOpReceiver> mReceiver;
|
||||
|
||||
template <CanvasOpType T>
|
||||
void submit(CanvasOp<T>&& op) {
|
||||
mReceiver.push_container(CanvasOpContainer(std::move(op), transform()));
|
||||
mReceiver->push_container(CanvasOpContainer(std::move(op), transform()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -310,7 +310,7 @@ struct CanvasOp<CanvasOpType::DrawVertices> {
|
||||
template<>
|
||||
struct CanvasOp<CanvasOpType::DrawImage> {
|
||||
|
||||
CanvasOp<CanvasOpType::DrawImageRect>(
|
||||
CanvasOp(
|
||||
const sk_sp<Bitmap>& bitmap,
|
||||
float left,
|
||||
float top,
|
||||
@@ -336,7 +336,7 @@ struct CanvasOp<CanvasOpType::DrawImage> {
|
||||
template<>
|
||||
struct CanvasOp<CanvasOpType::DrawImageRect> {
|
||||
|
||||
CanvasOp<CanvasOpType::DrawImageRect>(
|
||||
CanvasOp(
|
||||
const sk_sp<Bitmap>& bitmap,
|
||||
SkRect src,
|
||||
SkRect dst,
|
||||
@@ -367,7 +367,7 @@ struct CanvasOp<CanvasOpType::DrawImageRect> {
|
||||
template<>
|
||||
struct CanvasOp<CanvasOpType::DrawImageLattice> {
|
||||
|
||||
CanvasOp<CanvasOpType::DrawImageLattice>(
|
||||
CanvasOp(
|
||||
const sk_sp<Bitmap>& bitmap,
|
||||
SkRect dst,
|
||||
SkCanvas::Lattice lattice,
|
||||
|
||||
@@ -60,9 +60,8 @@ class OpBuffer {
|
||||
return (size + (Alignment - 1)) & -Alignment;
|
||||
}
|
||||
|
||||
static constexpr auto STARTING_SIZE = PadAlign(sizeof(BufferHeader));
|
||||
|
||||
public:
|
||||
static constexpr auto STARTING_SIZE = PadAlign(sizeof(BufferHeader));
|
||||
using ItemHeader = OpBufferItemHeader<ItemTypes>;
|
||||
|
||||
OpBuffer() = default;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <SaveFlags.h>
|
||||
|
||||
#include <androidfw/ResourceTypes.h>
|
||||
#include "DisplayList.h"
|
||||
#include "Properties.h"
|
||||
#include "utils/Macros.h"
|
||||
|
||||
@@ -47,18 +48,6 @@ class CanvasPropertyPaint;
|
||||
class CanvasPropertyPrimitive;
|
||||
class DeferredLayerUpdater;
|
||||
class RenderNode;
|
||||
|
||||
namespace skiapipeline {
|
||||
class SkiaDisplayList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data structure that holds the list of commands used in display list stream
|
||||
*/
|
||||
using DisplayList = skiapipeline::SkiaDisplayList;
|
||||
}
|
||||
|
||||
namespace uirenderer {
|
||||
namespace VectorDrawable {
|
||||
class Tree;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ void SkiaDisplayList::syncContents(const WebViewSyncData& data) {
|
||||
}
|
||||
}
|
||||
|
||||
bool SkiaDisplayList::reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) {
|
||||
bool SkiaDisplayList::reuseDisplayList(RenderNode* node) {
|
||||
reset();
|
||||
node->attachAvailableList(this);
|
||||
return true;
|
||||
|
||||
@@ -98,7 +98,7 @@ public:
|
||||
*
|
||||
* @return true if the displayList will be reused and therefore should not be deleted
|
||||
*/
|
||||
bool reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context);
|
||||
bool reuseDisplayList(RenderNode* node);
|
||||
|
||||
/**
|
||||
* ONLY to be called by RenderNode::syncDisplayList so that we can notify any
|
||||
|
||||
96
libs/hwui/tests/microbench/CanvasOpBench.cpp
Normal file
96
libs/hwui/tests/microbench/CanvasOpBench.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 <benchmark/benchmark.h>
|
||||
|
||||
#include "DisplayList.h"
|
||||
#include "hwui/Paint.h"
|
||||
#include "canvas/CanvasOpBuffer.h"
|
||||
#include "canvas/CanvasFrontend.h"
|
||||
#include "tests/common/TestUtils.h"
|
||||
|
||||
using namespace android;
|
||||
using namespace android::uirenderer;
|
||||
|
||||
void BM_CanvasOpBuffer_alloc(benchmark::State& benchState) {
|
||||
while (benchState.KeepRunning()) {
|
||||
auto displayList = new CanvasOpBuffer();
|
||||
benchmark::DoNotOptimize(displayList);
|
||||
delete displayList;
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_CanvasOpBuffer_alloc);
|
||||
|
||||
void BM_CanvasOpBuffer_record_saverestore(benchmark::State& benchState) {
|
||||
CanvasFrontend<CanvasOpBuffer> canvas(100, 100);
|
||||
while (benchState.KeepRunning()) {
|
||||
canvas.reset(100, 100);
|
||||
canvas.save(SaveFlags::MatrixClip);
|
||||
canvas.save(SaveFlags::MatrixClip);
|
||||
benchmark::DoNotOptimize(&canvas);
|
||||
canvas.restore();
|
||||
canvas.restore();
|
||||
canvas.finish();
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_CanvasOpBuffer_record_saverestore);
|
||||
|
||||
void BM_CanvasOpBuffer_record_saverestoreWithReuse(benchmark::State& benchState) {
|
||||
CanvasFrontend<CanvasOpBuffer> canvas(100, 100);
|
||||
|
||||
while (benchState.KeepRunning()) {
|
||||
canvas.reset(100, 100);
|
||||
canvas.save(SaveFlags::MatrixClip);
|
||||
canvas.save(SaveFlags::MatrixClip);
|
||||
benchmark::DoNotOptimize(&canvas);
|
||||
canvas.restore();
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_CanvasOpBuffer_record_saverestoreWithReuse);
|
||||
|
||||
void BM_CanvasOpBuffer_record_simpleBitmapView(benchmark::State& benchState) {
|
||||
CanvasFrontend<CanvasOpBuffer> canvas(100, 100);
|
||||
|
||||
Paint rectPaint;
|
||||
sk_sp<Bitmap> iconBitmap(TestUtils::createBitmap(80, 80));
|
||||
|
||||
while (benchState.KeepRunning()) {
|
||||
canvas.reset(100, 100);
|
||||
{
|
||||
canvas.save(SaveFlags::MatrixClip);
|
||||
canvas.draw(CanvasOp<CanvasOpType::DrawRect> {
|
||||
.rect = SkRect::MakeWH(100, 100),
|
||||
.paint = rectPaint,
|
||||
});
|
||||
canvas.restore();
|
||||
}
|
||||
{
|
||||
canvas.save(SaveFlags::MatrixClip);
|
||||
canvas.translate(10, 10);
|
||||
canvas.draw(CanvasOp<CanvasOpType::DrawImage> {
|
||||
iconBitmap,
|
||||
0,
|
||||
0,
|
||||
SkPaint{}
|
||||
});
|
||||
canvas.restore();
|
||||
}
|
||||
benchmark::DoNotOptimize(&canvas);
|
||||
canvas.finish();
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_CanvasOpBuffer_record_simpleBitmapView);
|
||||
@@ -30,3 +30,29 @@ void BM_RenderNode_create(benchmark::State& state) {
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_RenderNode_create);
|
||||
|
||||
void BM_RenderNode_recordSimple(benchmark::State& state) {
|
||||
sp<RenderNode> node = new RenderNode();
|
||||
std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(100, 100));
|
||||
delete canvas->finishRecording();
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
canvas->resetRecording(100, 100, node.get());
|
||||
canvas->drawColor(0x00000000, SkBlendMode::kSrcOver);
|
||||
node->setStagingDisplayList(canvas->finishRecording());
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_RenderNode_recordSimple);
|
||||
|
||||
void BM_RenderNode_recordSimpleWithReuse(benchmark::State& state) {
|
||||
sp<RenderNode> node = new RenderNode();
|
||||
std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(100, 100));
|
||||
delete canvas->finishRecording();
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
canvas->resetRecording(100, 100, node.get());
|
||||
canvas->drawColor(0x00000000, SkBlendMode::kSrcOver);
|
||||
canvas->finishRecording()->reuseDisplayList(node.get());
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_RenderNode_recordSimpleWithReuse);
|
||||
@@ -84,7 +84,7 @@ TEST(SkiaDisplayList, reuseDisplayList) {
|
||||
|
||||
// attach a displayList for reuse
|
||||
SkiaDisplayList skiaDL;
|
||||
ASSERT_TRUE(skiaDL.reuseDisplayList(renderNode.get(), nullptr));
|
||||
ASSERT_TRUE(skiaDL.reuseDisplayList(renderNode.get()));
|
||||
|
||||
// detach the list that you just attempted to reuse
|
||||
availableList = renderNode->detachAvailableList();
|
||||
|
||||
Reference in New Issue
Block a user