Merge "Add initial benchmarks for CanvasOp"

This commit is contained in:
TreeHugger Robot
2020-12-10 23:26:27 +00:00
committed by Android (Google) Code Review
13 changed files with 160 additions and 29 deletions

View File

@@ -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",

View File

@@ -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;
/**

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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()));
}
};

View File

@@ -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,

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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

View 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);

View File

@@ -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);

View File

@@ -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();