Flutter Engine
The Flutter Engine
BulkRectBench.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "bench/Benchmark.h"
15#include "src/base/SkRandom.h"
19#include "src/gpu/ganesh/SkGr.h"
21
22// Benchmarks that exercise the bulk image and solid color quad APIs, under a variety of patterns:
23enum class ImageMode {
24 kShared, // 1. One shared image referenced by every rectangle
25 kUnique, // 2. Unique image for every rectangle
26 kNone // 3. No image, solid color shading per rectangle
27};
28// X
29enum class DrawMode {
30 kBatch, // Bulk API submission, one call to draw every rectangle
31 kRef, // One standard SkCanvas draw call per rectangle
32 kQuad // One experimental draw call per rectangle, only for solid color draws
33};
34// X
35enum class RectangleLayout {
36 kRandom, // Random overlapping rectangles
37 kGrid // Small, non-overlapping rectangles in a grid covering the output surface
38};
39
40// Benchmark runner that can be configured by template arguments.
41template<int kRectCount, RectangleLayout kLayout, ImageMode kImageMode, DrawMode kDrawMode>
42class BulkRectBench : public Benchmark {
43public:
44 static_assert(kImageMode == ImageMode::kNone || kDrawMode != DrawMode::kQuad,
45 "kQuad only supported for solid color draws");
46
47 inline static constexpr int kWidth = 1024;
48 inline static constexpr int kHeight = 1024;
49
50 // There will either be 0 images, 1 image, or 1 image per rect
51 inline static constexpr int kImageCount = kImageMode == ImageMode::kShared ?
52 1 : (kImageMode == ImageMode::kNone ? 0 : kRectCount);
53
54 bool isSuitableFor(Backend backend) override {
55 if (kDrawMode == DrawMode::kBatch && kImageMode == ImageMode::kNone) {
56 // Currently the bulk color quad API is only available on
57 // skgpu::ganesh::SurfaceDrawContext
58 return backend == Backend::kGanesh;
59 } else {
60 return this->INHERITED::isSuitableFor(backend);
61 }
62 }
63
64protected:
65 SkRect fRects[kRectCount];
67 SkColor4f fColors[kRectCount];
69
70 void computeName() {
71 fName = "bulkrect";
72 fName.appendf("_%d", kRectCount);
73 if (kLayout == RectangleLayout::kRandom) {
74 fName.append("_random");
75 } else {
76 fName.append("_grid");
77 }
78 if (kImageMode == ImageMode::kShared) {
79 fName.append("_sharedimage");
80 } else if (kImageMode == ImageMode::kUnique) {
81 fName.append("_uniqueimages");
82 } else {
83 fName.append("_solidcolor");
84 }
85 if (kDrawMode == DrawMode::kBatch) {
86 fName.append("_batch");
87 } else if (kDrawMode == DrawMode::kRef) {
88 fName.append("_ref");
89 } else {
90 fName.append("_quad");
91 }
92 }
93
94 void drawImagesBatch(SkCanvas* canvas) const {
95 SkASSERT(kImageMode != ImageMode::kNone);
96 SkASSERT(kDrawMode == DrawMode::kBatch);
97
98 SkCanvas::ImageSetEntry batch[kRectCount];
99 for (int i = 0; i < kRectCount; ++i) {
100 int imageIndex = kImageMode == ImageMode::kShared ? 0 : i;
101 batch[i].fImage = fImages[imageIndex];
102 batch[i].fSrcRect = SkRect::MakeIWH(fImages[imageIndex]->width(),
103 fImages[imageIndex]->height());
104 batch[i].fDstRect = fRects[i];
106 }
107
109 paint.setAntiAlias(true);
110
111 canvas->experimental_DrawEdgeAAImageSet(batch, kRectCount, nullptr, nullptr,
114 }
115
116 void drawImagesRef(SkCanvas* canvas) const {
117 SkASSERT(kImageMode != ImageMode::kNone);
118 SkASSERT(kDrawMode == DrawMode::kRef);
119
121 paint.setAntiAlias(true);
122
123 for (int i = 0; i < kRectCount; ++i) {
124 int imageIndex = kImageMode == ImageMode::kShared ? 0 : i;
125 SkRect srcRect = SkRect::MakeIWH(fImages[imageIndex]->width(),
126 fImages[imageIndex]->height());
127 canvas->drawImageRect(fImages[imageIndex].get(), srcRect, fRects[i],
130 }
131 }
132
133 void drawSolidColorsBatch(SkCanvas* canvas) const {
134 SkASSERT(kImageMode == ImageMode::kNone);
135 SkASSERT(kDrawMode == DrawMode::kBatch);
136
137 auto context = canvas->recordingContext();
138 SkASSERT(context);
139
140 GrQuadSetEntry batch[kRectCount];
141 for (int i = 0; i < kRectCount; ++i) {
142 batch[i].fRect = fRects[i];
143 batch[i].fColor = fColors[i].premul();
144 batch[i].fLocalMatrix = SkMatrix::I();
146 }
147
149 paint.setColor(SK_ColorWHITE);
150 paint.setAntiAlias(true);
151
153 SkMatrix view = canvas->getLocalToDeviceAs3x3();
154 SkSurfaceProps props;
155 GrPaint grPaint;
156 SkPaintToGrPaint(context, sdc->colorInfo(), paint, view, props, &grPaint);
157 sdc->drawQuadSet(nullptr, std::move(grPaint), view, batch, kRectCount);
158 }
159
160 void drawSolidColorsRef(SkCanvas* canvas) const {
161 SkASSERT(kImageMode == ImageMode::kNone);
162 SkASSERT(kDrawMode == DrawMode::kRef || kDrawMode == DrawMode::kQuad);
163
165 paint.setAntiAlias(true);
166 for (int i = 0; i < kRectCount; ++i) {
167 if (kDrawMode == DrawMode::kRef) {
168 paint.setColor4f(fColors[i]);
169 canvas->drawRect(fRects[i], paint);
170 } else {
173 }
174 }
175 }
176
177 const char* onGetName() override {
178 if (fName.isEmpty()) {
179 this->computeName();
180 }
181 return fName.c_str();
182 }
183
184 void onDelayedSetup() override {
185 static constexpr SkScalar kMinRectSize = 0.2f;
186 static constexpr SkScalar kMaxRectSize = 300.f;
187
188 SkRandom rand;
189 for (int i = 0; i < kRectCount; i++) {
190 if (kLayout == RectangleLayout::kRandom) {
191 SkScalar w = rand.nextF() * (kMaxRectSize - kMinRectSize) + kMinRectSize;
192 SkScalar h = rand.nextF() * (kMaxRectSize - kMinRectSize) + kMinRectSize;
193
194 SkScalar x = rand.nextF() * (kWidth - w);
195 SkScalar y = rand.nextF() * (kHeight - h);
196
197 fRects[i].setXYWH(x, y, w, h);
198 } else {
199 int gridSize = SkScalarCeilToInt(SkScalarSqrt(kRectCount));
200 SkASSERT(gridSize * gridSize >= kRectCount);
201
202 SkScalar w = (kWidth - 1.f) / gridSize;
203 SkScalar h = (kHeight - 1.f) / gridSize;
204
205 SkScalar x = (i % gridSize) * w + 0.5f; // Offset to ensure AA doesn't get disabled
206 SkScalar y = (i / gridSize) * h + 0.5f;
207
208 fRects[i].setXYWH(x, y, w, h);
209 }
210
211 // Make sure we don't extend outside the render target, don't want to include clipping
212 // in the benchmark.
214
215 fColors[i] = {rand.nextF(), rand.nextF(), rand.nextF(), 1.f};
216 }
217 }
218
219 void onPerCanvasPreDraw(SkCanvas* canvas) override {
220 // Push the skimages to the GPU when using the GPU backend so that the texture creation is
221 // not part of the bench measurements. Always remake the images since they are so simple,
222 // and since they are context-specific, this works when the bench runs multiple GPU backends
223 auto direct = GrAsDirectContext(canvas->recordingContext());
224 for (int i = 0; i < kImageCount; ++i) {
225 SkBitmap bm;
226 bm.allocN32Pixels(256, 256);
227 bm.eraseColor(fColors[i].toSkColor());
228 auto image = bm.asImage();
229
230 if (direct) {
232 } else {
233 fImages[i] = std::move(image);
234 }
235 }
236 }
237
238 void onPerCanvasPostDraw(SkCanvas* canvas) override {
239 for (int i = 0; i < kImageCount; ++i) {
240 // For Vulkan we need to make sure the bench isn't holding onto any refs to the
241 // GrContext when we go to delete the vulkan context (which happens before the bench is
242 // deleted). So reset all the images here so they aren't holding GrContext refs.
243 fImages[i].reset();
244 }
245 }
246
247 void onDraw(int loops, SkCanvas* canvas) override {
248 for (int i = 0; i < loops; i++) {
249 if (kImageMode == ImageMode::kNone) {
250 if (kDrawMode == DrawMode::kBatch) {
251 this->drawSolidColorsBatch(canvas);
252 } else {
253 this->drawSolidColorsRef(canvas);
254 }
255 } else {
256 if (kDrawMode == DrawMode::kBatch) {
257 this->drawImagesBatch(canvas);
258 } else {
259 this->drawImagesRef(canvas);
260 }
261 }
262 }
263 }
264
265 SkISize onGetSize() override {
266 return { kWidth, kHeight };
267 }
268
270};
271
272// constructor call is wrapped in () so the macro doesn't break parsing the commas in the template
273#define ADD_BENCH(n, layout, imageMode, drawMode) \
274 DEF_BENCH( return (new BulkRectBench<n, layout, imageMode, drawMode>()); )
275
276#define ADD_BENCH_FAMILY(n, layout) \
277 ADD_BENCH(n, layout, ImageMode::kShared, DrawMode::kBatch) \
278 ADD_BENCH(n, layout, ImageMode::kShared, DrawMode::kRef) \
279 ADD_BENCH(n, layout, ImageMode::kUnique, DrawMode::kBatch) \
280 ADD_BENCH(n, layout, ImageMode::kUnique, DrawMode::kRef) \
281 ADD_BENCH(n, layout, ImageMode::kNone, DrawMode::kBatch) \
282 ADD_BENCH(n, layout, ImageMode::kNone, DrawMode::kRef) \
283 ADD_BENCH(n, layout, ImageMode::kNone, DrawMode::kQuad)
284
287
288#undef ADD_BENCH_FAMILY
289#undef ADD_BENCH
#define ADD_BENCH_FAMILY(n, layout)
RectangleLayout
DrawMode
ImageMode
const char * backend
static GrDirectContext * GrAsDirectContext(GrContext_Base *base)
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kSrcOver
r = s + (1-sa)*d
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
bool SkPaintToGrPaint(GrRecordingContext *context, const GrColorInfo &dstColorInfo, const SkPaint &skPaint, const SkMatrix &ctm, const SkSurfaceProps &surfaceProps, GrPaint *grPaint)
Definition: SkGr.cpp:553
#define SkScalarCeilToInt(x)
Definition: SkScalar.h:36
#define SkScalarSqrt(x)
Definition: SkScalar.h:42
virtual bool isSuitableFor(Backend backend)
Definition: Benchmark.h:55
void onPerCanvasPreDraw(SkCanvas *canvas) override
static constexpr int kHeight
static constexpr int kImageCount
SkRect fRects[kRectCount]
bool isSuitableFor(Backend backend) override
void drawSolidColorsRef(SkCanvas *canvas) const
SkISize onGetSize() override
void onDelayedSetup() override
sk_sp< SkImage > fImages[kImageCount > 0 ? kImageCount :1]
static constexpr int kWidth
SkColor4f fColors[kRectCount]
void drawSolidColorsBatch(SkCanvas *canvas) const
void drawImagesBatch(SkCanvas *canvas) const
void drawImagesRef(SkCanvas *canvas) const
void onDraw(int loops, SkCanvas *canvas) override
void onPerCanvasPostDraw(SkCanvas *canvas) override
const char * onGetName() override
sk_sp< SkImage > asImage() const
Definition: SkBitmap.cpp:645
void allocN32Pixels(int width, int height, bool isOpaque=false)
Definition: SkBitmap.cpp:232
void eraseColor(SkColor4f) const
Definition: SkBitmap.cpp:442
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
SkMatrix getLocalToDeviceAs3x3() const
Definition: SkCanvas.h:2222
virtual GrRecordingContext * recordingContext() const
Definition: SkCanvas.cpp:1637
@ kFast_SrcRectConstraint
sample outside bounds; faster
Definition: SkCanvas.h:1543
void experimental_DrawEdgeAAQuad(const SkRect &rect, const SkPoint clip[4], QuadAAFlags aaFlags, const SkColor4f &color, SkBlendMode mode)
Definition: SkCanvas.cpp:1845
void experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt, const SkPoint dstClips[], const SkMatrix preViewMatrices[], const SkSamplingOptions &, const SkPaint *paint=nullptr, SrcRectConstraint constraint=kStrict_SrcRectConstraint)
Definition: SkCanvas.cpp:1853
void drawImageRect(const SkImage *, const SkRect &src, const SkRect &dst, const SkSamplingOptions &, const SkPaint *, SrcRectConstraint)
Definition: SkCanvas.cpp:2333
@ kAll_QuadAAFlags
Definition: SkCanvas.h:1665
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
float nextF()
Definition: SkRandom.h:55
bool isEmpty() const
Definition: SkString.h:130
void append(const char text[])
Definition: SkString.h:203
const char * c_str() const
Definition: SkString.h:133
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:550
void reset(T *ptr=nullptr)
Definition: SkRefCnt.h:310
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
double y
double x
SK_API sk_sp< SkImage > TextureFromImage(GrDirectContext *, const SkImage *, skgpu::Mipmapped=skgpu::Mipmapped::kNo, skgpu::Budgeted=skgpu::Budgeted::kYes)
sk_sp< const SkImage > image
Definition: SkRecords.h:269
const myers::Point & get(const myers::Segment &)
SurfaceDrawContext * TopDeviceSurfaceDrawContext(const SkCanvas *canvas)
Definition: GrCanvas.cpp:20
SkSamplingOptions(SkFilterMode::kLinear))
constexpr bool contains(std::string_view str, std::string_view needle)
Definition: SkStringView.h:41
SkScalar w
SkScalar h
int32_t height
int32_t width
SkPMColor4f fColor
Definition: GrOpsTypes.h:20
GrQuadAAFlags fAAFlags
Definition: GrOpsTypes.h:22
SkMatrix fLocalMatrix
Definition: GrOpsTypes.h:21
SkRect fRect
Definition: GrOpsTypes.h:19
sk_sp< const SkImage > fImage
Definition: SkCanvas.h:1681
Definition: SkSize.h:16
void setXYWH(float x, float y, float width, float height)
Definition: SkRect.h:931
static SkRect MakeIWH(int w, int h)
Definition: SkRect.h:623
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609