skia2/bench/ClearBench.cpp
Michael Ludwig 1374c85fbf Prevent op batching in clear benchmark
This is a different way of fixing the clear benchmark measurements,
since https://skia-review.googlesource.com/c/skia/+/184064 seemed to
cause device issues on several bots.

Instead of forcing a flush, this takes extra steps to prevent the clear
ops from batching in Ganesh, and from resetting the op list, which has
the same effect of ensuring "loop" count clears are actually sent to
the GPU.

Bug: skia:
Change-Id: Id7f58894f42ca55a6cb663b65c27901d65432f82
Reviewed-on: https://skia-review.googlesource.com/c/184384
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
Auto-Submit: Michael Ludwig <michaelludwig@google.com>
2019-01-16 16:11:34 +00:00

105 lines
3.8 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.
*/
// This benchmark attempts to measure the time to do a fullscreen clear, an axis-aligned partial
// clear, and a clear restricted to an axis-aligned rounded rect. The fullscreen and axis-aligned
// partial clears on the GPU should follow a fast path that maps to backend-specialized clear
// operations, whereas the rounded-rect clear cannot be.
#include "Benchmark.h"
#include "SkCanvas.h"
#include "SkGradientShader.h"
#include "SkPaint.h"
#include "SkRect.h"
#include "SkRRect.h"
#include "GrRenderTargetContext.h"
static sk_sp<SkShader> make_shader() {
static const SkPoint kPts[] = {{0, 0}, {10, 10}};
static const SkColor kColors[] = {SK_ColorBLUE, SK_ColorWHITE};
return SkGradientShader::MakeLinear(kPts, kColors, nullptr, 2, SkShader::kClamp_TileMode);
}
class ClearBench : public Benchmark {
public:
enum ClearType {
kFull_ClearType,
kPartial_ClearType,
kComplex_ClearType
};
ClearBench(ClearType type) : fType(type) {}
protected:
const char* onGetName() override {
switch(fType) {
case kFull_ClearType:
return "Clear-Full";
case kPartial_ClearType:
return "Clear-Partial";
case kComplex_ClearType:
return "Clear-Complex";
}
SkASSERT(false);
return "Unreachable";
}
void onDraw(int loops, SkCanvas* canvas) override {
static const SkRect kPartialClip = SkRect::MakeLTRB(50, 50, 400, 400);
static const SkRRect kComplexClip = SkRRect::MakeRectXY(kPartialClip, 15, 15);
// Small to limit fill cost, but intersects the clips to confound batching
static const SkRect kInterruptRect = SkRect::MakeXYWH(200, 200, 3, 3);
// For the draw that sits between consecutive clears, use a shader that is simple but
// requires local coordinates so that Ganesh does not convert it into a solid color rect,
// which could then turn into a scissored-clear behind the scenes.
SkPaint interruptPaint;
interruptPaint.setShader(make_shader());
GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
if (rtc) {
// Tricks the GrRenderTargetOpList into thinking it cannot reset its draw op list on
// a fullscreen clear. If we don't do this, fullscreen clear ops would be created and
// constantly discard the previous iteration's op so execution would only invoke one
// actual clear on the GPU (not what we want to measure).
rtc->setNeedsStencil();
}
for (int i = 0; i < loops; i++) {
canvas->save();
switch(fType) {
case kPartial_ClearType:
canvas->clipRect(kPartialClip);
break;
case kComplex_ClearType:
canvas->clipRRect(kComplexClip);
break;
case kFull_ClearType:
// Don't add any extra clipping, since it defaults to the entire "device"
break;
}
// The clear we care about measuring
canvas->clear(SK_ColorBLUE);
canvas->restore();
// Perform as minimal a draw as possible that intersects with the clear region in
// order to prevent the clear ops from being batched together.
canvas->drawRect(kInterruptRect, interruptPaint);
}
}
private:
ClearType fType;
};
DEF_BENCH( return new ClearBench(ClearBench::kFull_ClearType); )
DEF_BENCH( return new ClearBench(ClearBench::kPartial_ClearType); )
DEF_BENCH( return new ClearBench(ClearBench::kComplex_ClearType); )