skia2/bench/BulkRectBench.cpp
Michael Ludwig 7c12e28cf4 Reland "GrClips provided as pointers to GrRTC"
This reverts commit 074414fed5.

Reason for revert: updated to guard against nullptr before calling
quickContains(rrect).

Original change's description:
> Revert "GrClips provided as pointers to GrRTC"
>
> This reverts commit 226b689471.
>
> Reason for revert: Breaks Android roller
>
> Original change's description:
> > GrClips provided as pointers to GrRTC
> >
> > A null clip represents no high-level clipping is necessary (the implicit
> > clip to the render target's logical dimensions is fine).
> >
> > This also removes GrNoClip and GrFixedClip::Disabled() since they are
> > replaced with just nullptr.
> >
> > By allowing nullptr to represent no intended clipping, it makes it easier
> > to require GrClip and GrAppliedClip objects to know about the dimensions
> > of the device. If we required a non-null clip object to represent no
> > clipping, we'd have to have an instance for each device based on its
> > size and that just became cumbersome.
> >
> > Bug: skia:10205
> > Change-Id: Ie30cc71820b92d99356d393a4c98c8677082e761
> > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/290539
> > Commit-Queue: Michael Ludwig <michaelludwig@google.com>
> > Reviewed-by: Brian Salomon <bsalomon@google.com>
>
> TBR=bsalomon@google.com,csmartdalton@google.com,michaelludwig@google.com
>
> Change-Id: I42c4828bcf016ee3d30d5c20b771be96e125817b
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: skia:10205
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/292856
> Reviewed-by: Weston Tracey <westont@google.com>
> Commit-Queue: Weston Tracey <westont@google.com>

TBR=bsalomon@google.com,csmartdalton@google.com,michaelludwig@google.com,westont@google.com

# Not skipping CQ checks because this is a reland.

Bug: skia:10205
Change-Id: I5715a4de3b7c8847b73020dc4937d3816d879803
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/292876
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
2020-05-29 15:09:54 +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/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();
SkSimpleMatrixProvider matrixProvider(view);
GrPaint grPaint;
SkPaintToGrPaint(context, rtc->colorInfo(), paint, matrixProvider, &grPaint);
rtc->drawQuadSet(nullptr, 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