1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci// This benchmark attempts to measure the time to do a fullscreen clear, an axis-aligned partial 9cb93a386Sopenharmony_ci// clear, and a clear restricted to an axis-aligned rounded rect. The fullscreen and axis-aligned 10cb93a386Sopenharmony_ci// partial clears on the GPU should follow a fast path that maps to backend-specialized clear 11cb93a386Sopenharmony_ci// operations, whereas the rounded-rect clear cannot be. 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_ci#include "bench/Benchmark.h" 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 16cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 17cb93a386Sopenharmony_ci#include "include/core/SkRRect.h" 18cb93a386Sopenharmony_ci#include "include/core/SkRect.h" 19cb93a386Sopenharmony_ci#include "include/effects/SkGradientShader.h" 20cb93a386Sopenharmony_ci#include "src/core/SkCanvasPriv.h" 21cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_cistatic sk_sp<SkShader> make_shader() { 24cb93a386Sopenharmony_ci static const SkPoint kPts[] = {{0, 0}, {10, 10}}; 25cb93a386Sopenharmony_ci static const SkColor kColors[] = {SK_ColorBLUE, SK_ColorWHITE}; 26cb93a386Sopenharmony_ci return SkGradientShader::MakeLinear(kPts, kColors, nullptr, 2, SkTileMode::kClamp); 27cb93a386Sopenharmony_ci} 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ciclass ClearBench : public Benchmark { 30cb93a386Sopenharmony_cipublic: 31cb93a386Sopenharmony_ci enum ClearType { 32cb93a386Sopenharmony_ci kFull_ClearType, 33cb93a386Sopenharmony_ci kPartial_ClearType, 34cb93a386Sopenharmony_ci kComplex_ClearType 35cb93a386Sopenharmony_ci }; 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci ClearBench(ClearType type) : fType(type) {} 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ciprotected: 40cb93a386Sopenharmony_ci const char* onGetName() override { 41cb93a386Sopenharmony_ci switch(fType) { 42cb93a386Sopenharmony_ci case kFull_ClearType: 43cb93a386Sopenharmony_ci return "Clear-Full"; 44cb93a386Sopenharmony_ci case kPartial_ClearType: 45cb93a386Sopenharmony_ci return "Clear-Partial"; 46cb93a386Sopenharmony_ci case kComplex_ClearType: 47cb93a386Sopenharmony_ci return "Clear-Complex"; 48cb93a386Sopenharmony_ci } 49cb93a386Sopenharmony_ci SkASSERT(false); 50cb93a386Sopenharmony_ci return "Unreachable"; 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci void onDraw(int loops, SkCanvas* canvas) override { 54cb93a386Sopenharmony_ci static const SkRect kPartialClip = SkRect::MakeLTRB(50, 50, 400, 400); 55cb93a386Sopenharmony_ci static const SkRRect kComplexClip = SkRRect::MakeRectXY(kPartialClip, 15, 15); 56cb93a386Sopenharmony_ci // Small to limit fill cost, but intersects the clips to confound batching 57cb93a386Sopenharmony_ci static const SkRect kInterruptRect = SkRect::MakeXYWH(200, 200, 3, 3); 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci // For the draw that sits between consecutive clears, use a shader that is simple but 60cb93a386Sopenharmony_ci // requires local coordinates so that Ganesh does not convert it into a solid color rect, 61cb93a386Sopenharmony_ci // which could then turn into a scissored-clear behind the scenes. 62cb93a386Sopenharmony_ci SkPaint interruptPaint; 63cb93a386Sopenharmony_ci interruptPaint.setShader(make_shader()); 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas); 66cb93a386Sopenharmony_ci if (sdc) { 67cb93a386Sopenharmony_ci // Tell the skgpu::v1::SurfaceDrawContext to not reset its draw op list on a 68cb93a386Sopenharmony_ci // fullscreen clear. 69cb93a386Sopenharmony_ci // If we don't do this, fullscreen clear ops would be created and constantly discard the 70cb93a386Sopenharmony_ci // previous iteration's op so execution would only invoke one actual clear on the GPU 71cb93a386Sopenharmony_ci // (not what we want to measure). 72cb93a386Sopenharmony_ci sdc->testingOnly_SetPreserveOpsOnFullClear(); 73cb93a386Sopenharmony_ci } 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci for (int i = 0; i < loops; i++) { 76cb93a386Sopenharmony_ci canvas->save(); 77cb93a386Sopenharmony_ci switch(fType) { 78cb93a386Sopenharmony_ci case kPartial_ClearType: 79cb93a386Sopenharmony_ci canvas->clipRect(kPartialClip); 80cb93a386Sopenharmony_ci break; 81cb93a386Sopenharmony_ci case kComplex_ClearType: 82cb93a386Sopenharmony_ci canvas->clipRRect(kComplexClip); 83cb93a386Sopenharmony_ci break; 84cb93a386Sopenharmony_ci case kFull_ClearType: 85cb93a386Sopenharmony_ci // Don't add any extra clipping, since it defaults to the entire "device" 86cb93a386Sopenharmony_ci break; 87cb93a386Sopenharmony_ci } 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci // The clear we care about measuring 90cb93a386Sopenharmony_ci canvas->clear(SK_ColorBLUE); 91cb93a386Sopenharmony_ci canvas->restore(); 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci // Perform as minimal a draw as possible that intersects with the clear region in 94cb93a386Sopenharmony_ci // order to prevent the clear ops from being batched together. 95cb93a386Sopenharmony_ci canvas->drawRect(kInterruptRect, interruptPaint); 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ciprivate: 100cb93a386Sopenharmony_ci ClearType fType; 101cb93a386Sopenharmony_ci}; 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ciDEF_BENCH( return new ClearBench(ClearBench::kFull_ClearType); ) 104cb93a386Sopenharmony_ciDEF_BENCH( return new ClearBench(ClearBench::kPartial_ClearType); ) 105cb93a386Sopenharmony_ciDEF_BENCH( return new ClearBench(ClearBench::kComplex_ClearType); ) 106