skia2/bench/ImageCycleBench.cpp
Brian Salomon 986f64c601 Remove multitexturing support from GrTextureOp.
This turned out to be an optimization mostly for draws with small device
space areas. Moreover, to be an optimization rather than deoptimization
requires complicated per-GPU tuning where even different devices within
the same architecture require different tuning and tuning is different
between GL and VK.

We've decided to go another direction where we *don't* coalesce draws
but rather make it possible to switch textures quickly from within an
op. This should be a GPU-independent optimization that is also
independent of device space area covered.

Replaces the multitexturing benchmarks with a pair of benchmarks.

composting_images* simulates a layered tile-based compositor.

image_cycle draws tiny images N times each such that they can be
batched. This is to catch a particular possible regression in a
planned change to GrTextureOp where it will use "dynamic state" to
batch across textures. We want to catch a slowdown that might result
from putting draws that use the same texture into the same op but no
longer batching the actual GL level draws and instead using the dynamic
state to "switch" textures between draws.

Change-Id: Ib1cc437525b0b0d56969c30dcb66bb1effb42dc5
Reviewed-on: https://skia-review.googlesource.com/145423
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
2018-08-06 19:59:01 +00:00

95 lines
3.5 KiB
C++

/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Benchmark.h"
#include "SkCanvas.h"
#include "SkImage.h"
#include "SkRandom.h"
#include "SkSurface.h"
/**
* Draws a small set of small images multiple times each with no overlaps so that each image could
* be batched. This was originally added to detect regressions as GrTextureOp is refactored to
* use "dynamic state" for texture bindings. Everything is kept small as we're mostly interested in
* CPU overhead.
*/
class ImageCycle : public Benchmark {
public:
/**
* imageCnt is the number of images and repeat cnt is how many times each image is drawn per
* logical "frame."
*/
ImageCycle(int imageCnt, int repeatCnt) : fImageCnt(imageCnt), fRepeatCnt(repeatCnt) {
fName.appendf("image_cycle_image_cnt_%d_repeat_cnt_%d", fImageCnt, fRepeatCnt);
}
bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; }
protected:
const char* onGetName() override { return fName.c_str(); }
void onPerCanvasPreDraw(SkCanvas* canvas) override {
auto ii = SkImageInfo::Make(kImageSize.fWidth, kImageSize.fHeight, kRGBA_8888_SkColorType,
kPremul_SkAlphaType, nullptr);
SkRandom random;
fImages.reset(new sk_sp<SkImage>[fImageCnt]);
for (int i = 0; i < fImageCnt; ++i) {
auto surf = canvas->makeSurface(ii);
SkColor color = random.nextU();
surf->getCanvas()->clear(color);
SkPaint paint;
paint.setColor(~color);
paint.setBlendMode(SkBlendMode::kSrc);
surf->getCanvas()->drawRect(
SkRect::MakeLTRB(1, 1, kImageSize.fWidth - 1, kImageSize.fHeight - 1), paint);
fImages[i] = surf->makeImageSnapshot();
}
}
void onPerCanvasPostDraw(SkCanvas*) override { fImages.reset(); }
void onDraw(int loops, SkCanvas* canvas) override {
SkPaint paint;
paint.setFilterQuality(kNone_SkFilterQuality);
paint.setAntiAlias(true);
static constexpr SkScalar kPad = 2;
// To avoid tripping up bounds tracking we position the draws such that all the
// draws of image 0 are above those of image 1, etc.
static const int imagesPerRow =
SkScalarFloorToInt(kDeviceSize.fWidth / (kImageSize.fWidth + kPad));
int rowsPerImage = SkScalarCeilToInt((SkScalar)fRepeatCnt / imagesPerRow);
for (int l = 0; l < loops; ++l) {
for (int r = 0; r < fRepeatCnt; ++r) {
for (int i = 0; i < fImageCnt; ++i) {
SkScalar imageYOffset = i * rowsPerImage * (kImageSize.fHeight + kPad);
SkScalar rowYOffset = (r / imagesPerRow) * (kImageSize.fHeight + kPad);
SkScalar x = (r % imagesPerRow) * (kImageSize.fWidth + kPad);
canvas->drawImage(fImages[i].get(), x, imageYOffset + rowYOffset, &paint);
}
}
// Prevent any batching between "frames".
canvas->flush();
}
}
private:
SkIPoint onGetSize() override { return {kDeviceSize.fWidth, kDeviceSize.fHeight}; }
static constexpr SkISize kImageSize{4, 4};
static constexpr SkISize kDeviceSize{64, 64};
std::unique_ptr<sk_sp<SkImage>[]> fImages;
SkString fName;
int fImageCnt;
int fRepeatCnt;
typedef Benchmark INHERITED;
};
DEF_BENCH(return new ImageCycle(5, 10));