skia2/bench/BulkRectBench.cpp
Michael Ludwig 1beb8ae9a2 Reland "Add variety of bulk API benchmarks"
This reverts commit 659b21d480.

Reason for revert: Fixed skipping nonrendering benchmark

Original change's description:
> Revert "Add variety of bulk API benchmarks"
>
> This reverts commit e63595dd85.
>
> Reason for revert: Breaking the Perf tests:
>
> ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
> Command exited with code 139
> #######################################
> symbolized stacktrace follows
> #######################################
> build/nanobench BulkRectBench<1000, (RectangleLayout)1, (ImageMode)2, (DrawMode)2>::onPerCanvasPreDraw(SkCanvas*) at skia/bench/BulkRectBench.cpp:218
> build/nanobench main at skia/bench/nanobench.cpp:1277
> /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f1213dad2e1]
> build/nanobench _start at ??:?
>
>
>
>
>
> Original change's description:
> > Add variety of bulk API benchmarks
> >
> > Covers drawing 1000 anti-aliased rectangles, either sharing 1 image, using
> > a unique image, or as a solid color. Tests using the bulk APIs and regular
> > one-at-a-time drawing.
> >
> > Change-Id: Icdf5a1f6df229aed785212d0941b89c11aa785c0
> > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/251003
> > Commit-Queue: Michael Ludwig <michaelludwig@google.com>
> > Reviewed-by: Robert Phillips <robertphillips@google.com>
>
> TBR=robertphillips@google.com,egdaniel@chromium.org,michaelludwig@google.com
>
> Change-Id: I3b26d5a04c472993585242a108c2764ea2b96940
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/251213
> Reviewed-by: Joe Gregorio <jcgregorio@google.com>
> Commit-Queue: Joe Gregorio <jcgregorio@google.com>

Change-Id: I83538faa29ada5ab1b02ff07ae9fe90734ed198e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/251238
Auto-Submit: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Joe Gregorio <jcgregorio@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
2019-10-28 18:48:32 +00:00

272 lines
10 KiB
C++

/*
* Copyright 2019 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "bench/Benchmark.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkImage.h"
#include "include/core/SkPaint.h"
#include "include/gpu/GrContext.h"
#include "include/utils/SkRandom.h"
#include "src/gpu/GrClip.h"
#include "src/gpu/GrRenderTargetContext.h"
#include "src/gpu/SkGr.h"
// Benchmarks that exercise the bulk image and solid color quad APIs, under a variety of patterns:
enum class ImageMode {
kShared, // 1. One shared image referenced by every rectangle
kUnique, // 2. Unique image for every rectangle
kNone // 3. No image, solid color shading per rectangle
};
// X
enum class DrawMode {
kBatch, // Bulk API submission, one call to draw every rectangle
kRef, // One standard SkCanvas draw call per rectangle
kQuad // One experimental draw call per rectangle, only for solid color draws
};
// X
enum class RectangleLayout {
kRandom, // Random overlapping rectangles
kGrid // Small, non-overlapping rectangles in a grid covering the output surface
};
// Benchmark runner that can be configured by template arguments.
template<int kRectCount, RectangleLayout kLayout, ImageMode kImageMode, DrawMode kDrawMode>
class BulkRectBench : public Benchmark {
public:
static_assert(kImageMode == ImageMode::kNone || kDrawMode != DrawMode::kQuad,
"kQuad only supported for solid color draws");
static constexpr int kWidth = 1024;
static constexpr int kHeight = 1024;
// There will either be 0 images, 1 image, or 1 image per rect
static constexpr int kImageCount = kImageMode == ImageMode::kShared ?
1 : (kImageMode == ImageMode::kNone ? 0 : kRectCount);
bool isSuitableFor(Backend backend) override {
if (kDrawMode == DrawMode::kBatch && kImageMode == ImageMode::kNone) {
// Currently the bulk color quad API is only available on GrRenderTargetContext
return backend == kGPU_Backend;
} else {
return this->INHERITED::isSuitableFor(backend);
}
}
protected:
SkRect fRects[kRectCount];
sk_sp<SkImage> fImages[kImageCount];
SkColor4f fColors[kRectCount];
SkString fName;
void computeName() {
fName = "bulkrect";
fName.appendf("_%d", kRectCount);
if (kLayout == RectangleLayout::kRandom) {
fName.append("_random");
} else {
fName.append("_grid");
}
if (kImageMode == ImageMode::kShared) {
fName.append("_sharedimage");
} else if (kImageMode == ImageMode::kUnique) {
fName.append("_uniqueimages");
} else {
fName.append("_solidcolor");
}
if (kDrawMode == DrawMode::kBatch) {
fName.append("_batch");
} else if (kDrawMode == DrawMode::kRef) {
fName.append("_ref");
} else {
fName.append("_quad");
}
}
void drawImagesBatch(SkCanvas* canvas) const {
SkASSERT(kImageMode != ImageMode::kNone);
SkASSERT(kDrawMode == DrawMode::kBatch);
SkCanvas::ImageSetEntry batch[kRectCount];
for (int i = 0; i < kRectCount; ++i) {
int imageIndex = kImageMode == ImageMode::kShared ? 0 : i;
batch[i].fImage = fImages[imageIndex];
batch[i].fSrcRect = SkRect::MakeIWH(fImages[imageIndex]->width(),
fImages[imageIndex]->height());
batch[i].fDstRect = fRects[i];
batch[i].fAAFlags = SkCanvas::kAll_QuadAAFlags;
}
SkPaint paint;
paint.setAntiAlias(true);
paint.setFilterQuality(kLow_SkFilterQuality);
canvas->experimental_DrawEdgeAAImageSet(batch, kRectCount, nullptr, nullptr, &paint,
SkCanvas::kFast_SrcRectConstraint);
}
void drawImagesRef(SkCanvas* canvas) const {
SkASSERT(kImageMode != ImageMode::kNone);
SkASSERT(kDrawMode == DrawMode::kRef);
SkPaint paint;
paint.setAntiAlias(true);
paint.setFilterQuality(kLow_SkFilterQuality);
for (int i = 0; i < kRectCount; ++i) {
int imageIndex = kImageMode == ImageMode::kShared ? 0 : i;
SkIRect srcRect = SkIRect::MakeWH(fImages[imageIndex]->width(),
fImages[imageIndex]->height());
canvas->drawImageRect(fImages[imageIndex].get(), srcRect, fRects[i], &paint,
SkCanvas::kFast_SrcRectConstraint);
}
}
void drawSolidColorsBatch(SkCanvas* canvas) const {
SkASSERT(kImageMode == ImageMode::kNone);
SkASSERT(kDrawMode == DrawMode::kBatch);
GrContext* context = canvas->getGrContext();
SkASSERT(context);
GrRenderTargetContext::QuadSetEntry batch[kRectCount];
for (int i = 0; i < kRectCount; ++i) {
batch[i].fRect = fRects[i];
batch[i].fColor = fColors[i].premul();
batch[i].fLocalMatrix = SkMatrix::I();
batch[i].fAAFlags = GrQuadAAFlags::kAll;
}
SkPaint paint;
paint.setColor(SK_ColorWHITE);
paint.setAntiAlias(true);
GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
SkMatrix view = canvas->getTotalMatrix();
GrPaint grPaint;
SkPaintToGrPaint(context, rtc->colorInfo(), paint, view, &grPaint);
rtc->drawQuadSet(GrNoClip(), std::move(grPaint), GrAA::kYes, view, batch, kRectCount);
}
void drawSolidColorsRef(SkCanvas* canvas) const {
SkASSERT(kImageMode == ImageMode::kNone);
SkASSERT(kDrawMode == DrawMode::kRef || kDrawMode == DrawMode::kQuad);
SkPaint paint;
paint.setAntiAlias(true);
for (int i = 0; i < kRectCount; ++i) {
if (kDrawMode == DrawMode::kRef) {
paint.setColor4f(fColors[i]);
canvas->drawRect(fRects[i], paint);
} else {
canvas->experimental_DrawEdgeAAQuad(fRects[i], nullptr, SkCanvas::kAll_QuadAAFlags,
fColors[i], SkBlendMode::kSrcOver);
}
}
}
const char* onGetName() override {
if (fName.isEmpty()) {
this->computeName();
}
return fName.c_str();
}
void onDelayedSetup() override {
static constexpr SkScalar kMinRectSize = 0.2f;
static constexpr SkScalar kMaxRectSize = 300.f;
SkRandom rand;
for (int i = 0; i < kRectCount; i++) {
if (kLayout == RectangleLayout::kRandom) {
SkScalar w = rand.nextF() * (kMaxRectSize - kMinRectSize) + kMinRectSize;
SkScalar h = rand.nextF() * (kMaxRectSize - kMinRectSize) + kMinRectSize;
SkScalar x = rand.nextF() * (kWidth - w);
SkScalar y = rand.nextF() * (kHeight - h);
fRects[i].setXYWH(x, y, w, h);
} else {
int gridSize = SkScalarCeilToInt(SkScalarSqrt(kRectCount));
SkASSERT(gridSize * gridSize >= kRectCount);
SkScalar w = (kWidth - 1.f) / gridSize;
SkScalar h = (kHeight - 1.f) / gridSize;
SkScalar x = (i % gridSize) * w + 0.5f; // Offset to ensure AA doesn't get disabled
SkScalar y = (i / gridSize) * h + 0.5f;
fRects[i].setXYWH(x, y, w, h);
}
// Make sure we don't extend outside the render target, don't want to include clipping
// in the benchmark.
SkASSERT(SkRect::MakeWH(kWidth, kHeight).contains(fRects[i]));
fColors[i] = {rand.nextF(), rand.nextF(), rand.nextF(), 1.f};
}
}
void onPerCanvasPreDraw(SkCanvas* canvas) override {
// Push the skimages to the GPU when using the GPU backend so that the texture creation is
// not part of the bench measurements. Always remake the images since they are so simple,
// and since they are context-specific, this works when the bench runs multiple GPU backends
GrContext* context = canvas->getGrContext();
for (int i = 0; i < kImageCount; ++i) {
SkBitmap bm;
bm.allocN32Pixels(256, 256);
bm.eraseColor(fColors[i].toSkColor());
auto image = SkImage::MakeFromBitmap(bm);
fImages[i] = context ? image->makeTextureImage(context) : std::move(image);
}
}
void onDraw(int loops, SkCanvas* canvas) override {
for (int i = 0; i < loops; i++) {
if (kImageMode == ImageMode::kNone) {
if (kDrawMode == DrawMode::kBatch) {
this->drawSolidColorsBatch(canvas);
} else {
this->drawSolidColorsRef(canvas);
}
} else {
if (kDrawMode == DrawMode::kBatch) {
this->drawImagesBatch(canvas);
} else {
this->drawImagesRef(canvas);
}
}
}
}
SkIPoint onGetSize() override {
return { kWidth, kHeight };
}
typedef Benchmark INHERITED;
};
// constructor call is wrapped in () so the macro doesn't break parsing the commas in the template
#define ADD_BENCH(n, layout, imageMode, drawMode) \
DEF_BENCH( return (new BulkRectBench<n, layout, imageMode, drawMode>()); )
#define ADD_BENCH_FAMILY(n, layout) \
ADD_BENCH(n, layout, ImageMode::kShared, DrawMode::kBatch) \
ADD_BENCH(n, layout, ImageMode::kShared, DrawMode::kRef) \
ADD_BENCH(n, layout, ImageMode::kUnique, DrawMode::kBatch) \
ADD_BENCH(n, layout, ImageMode::kUnique, DrawMode::kRef) \
ADD_BENCH(n, layout, ImageMode::kNone, DrawMode::kBatch) \
ADD_BENCH(n, layout, ImageMode::kNone, DrawMode::kRef) \
ADD_BENCH(n, layout, ImageMode::kNone, DrawMode::kQuad)
ADD_BENCH_FAMILY(1000, RectangleLayout::kRandom)
ADD_BENCH_FAMILY(1000, RectangleLayout::kGrid)
#undef ADD_BENCH_FAMILY
#undef ADD_BENCH