Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
CompositingImagesBench.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 Google Inc.
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 <memory>
9
10#include "bench/Benchmark.h"
11#include "bench/GpuTools.h"
17#include "src/base/SkRandom.h"
18
19using namespace skia_private;
20
21enum class ClampingMode {
22 // Submit image set entries with the fast constraint
24 // Submit image set entries with the strict constraint
26 // Submit non-right/bottom tiles as fast, the bottom-right corner as strict, and bottom or right
27 // edge tiles as strict with geometry modification to match content area. These will be
28 // submitted from left-to-right, top-to-bottom so will necessarily be split into many batches.
30 // As above, but group all fast tiles first, then bottom and right edge tiles in a second batch.
32};
33
34enum class TransformMode {
35 // Tiles will be axis aligned on integer pixels
36 kNone,
37 // Subpixel, tiles will be axis aligned but adjusted to subpixel coordinates
39 // Rotated, tiles will be rotated globally; they won't overlap but their device space bounds may
41 // Perspective, tiles will have global perspective
43};
44
45/**
46 * Simulates drawing layers images in a grid a la a tile based compositor.
47 */
49public:
50 CompositingImages(SkISize imageSize, SkISize tileSize, SkISize tileGridSize,
51 ClampingMode clampMode, TransformMode transformMode, int layerCnt)
52 : fImageSize(imageSize)
53 , fTileSize(tileSize)
54 , fTileGridSize(tileGridSize)
55 , fClampMode(clampMode)
56 , fTransformMode(transformMode)
57 , fLayerCnt(layerCnt) {
58 fName.appendf("compositing_images_tile_size_%dx%d_grid_%dx%d_layers_%d",
59 fTileSize.fWidth, fTileSize.fHeight, fTileGridSize.fWidth,
60 fTileGridSize.fHeight, fLayerCnt);
61 if (imageSize != tileSize) {
62 fName.appendf("_image_%dx%d", imageSize.fWidth, imageSize.fHeight);
63 }
64 switch(clampMode) {
66 fName.append("_fast");
67 break;
69 fName.append("_strict");
70 break;
72 fName.append("_chrome");
73 break;
75 fName.append("_chrome_optimal");
76 break;
77 }
78 switch(transformMode) {
80 break;
82 fName.append("_subpixel");
83 break;
85 fName.append("_rotated");
86 break;
88 fName.append("_persp");
89 break;
90 }
91 }
92
93 bool isSuitableFor(Backend backend) override { return Backend::kGanesh == backend; }
94
95protected:
96 const char* onGetName() override { return fName.c_str(); }
97
98 void onPerCanvasPreDraw(SkCanvas* canvas) override {
99 // Use image size, which may be larger than the tile size (emulating how Chrome specifies
100 // their tiles).
101 auto ii = SkImageInfo::Make(fImageSize.fWidth, fImageSize.fHeight, kRGBA_8888_SkColorType,
102 kPremul_SkAlphaType, nullptr);
103 SkRandom random;
104 int numImages = fLayerCnt * fTileGridSize.fWidth * fTileGridSize.fHeight;
105 fImages = std::make_unique<sk_sp<SkImage>[]>(numImages);
106 for (int i = 0; i < numImages; ++i) {
107 auto surf = canvas->makeSurface(ii);
108 SkColor color = random.nextU();
109 surf->getCanvas()->clear(color);
111 paint.setColor(~color);
112 paint.setBlendMode(SkBlendMode::kSrc);
113 // While the image may be bigger than fTileSize, prepare its content as if fTileSize
114 // is what will be visible.
115 surf->getCanvas()->drawRect(
116 SkRect::MakeLTRB(3, 3, fTileSize.fWidth - 3, fTileSize.fHeight - 3), paint);
117 fImages[i] = surf->makeImageSnapshot();
118 }
119 }
120
121 void onPerCanvasPostDraw(SkCanvas*) override { fImages.reset(); }
122
123 void onDraw(int loops, SkCanvas* canvas) override {
125 paint.setAntiAlias(true);
127
128 canvas->save();
129 canvas->concat(this->getTransform());
130
131 for (int loop = 0; loop < loops; ++loop) {
132 for (int l = 0; l < fLayerCnt; ++l) {
134 fTileGridSize.fWidth * fTileGridSize.fHeight);
135
136 if (fClampMode == ClampingMode::kAlwaysFast ||
137 fClampMode == ClampingMode::kAlwaysStrict) {
138 // Simple 2D for loop, submit everything as a single batch
139 int i = 0;
140 for (int y = 0; y < fTileGridSize.fHeight; ++y) {
141 for (int x = 0; x < fTileGridSize.fWidth; ++x) {
142 set[i++] = this->getEntry(x, y, l);
143 }
144 }
145
146 SkCanvas::SrcRectConstraint constraint =
147 fClampMode == ClampingMode::kAlwaysFast
150 canvas->experimental_DrawEdgeAAImageSet(set.get(), i, nullptr, nullptr,
151 sampling, &paint, constraint);
152 } else if (fClampMode == ClampingMode::kChromeTiling_RowMajor) {
153 // Same tile order, but break batching between fast and strict sections, and
154 // adjust bottom and right tiles to encode content area distinct from src rect.
155 int i = 0;
156 for (int y = 0; y < fTileGridSize.fHeight - 1; ++y) {
157 int rowStart = i;
158 for (int x = 0; x < fTileGridSize.fWidth - 1; ++x) {
159 set[i++] = this->getEntry(x, y, l);
160 }
161 // Flush "fast" horizontal row
162 canvas->experimental_DrawEdgeAAImageSet(set.get() + rowStart,
163 fTileGridSize.fWidth - 1, nullptr, nullptr, sampling, &paint,
165 // Then flush a single adjusted entry for the right edge
166 SkPoint dstQuad[4];
167 set[i++] = this->getAdjustedEntry(fTileGridSize.fWidth - 1, y, l, dstQuad);
169 set.get() + fTileGridSize.fWidth - 1, 1, dstQuad, nullptr, sampling,
171 }
172 // For last row, accumulate it as a single strict batch
173 int rowStart = i;
174 AutoTArray<SkPoint> dstQuads(4 * (fTileGridSize.fWidth - 1));
175 for (int x = 0; x < fTileGridSize.fWidth - 1; ++x) {
176 set[i++] = this->getAdjustedEntry(x, fTileGridSize.fHeight - 1, l,
177 dstQuads.get() + x * 4);
178 }
179 // The corner can use conventional strict mode without geometric adjustment
180 set[i++] = this->getEntry(
181 fTileGridSize.fWidth - 1, fTileGridSize.fHeight - 1, l);
182 canvas->experimental_DrawEdgeAAImageSet(set.get() + rowStart,
183 fTileGridSize.fWidth, dstQuads.get(), nullptr, sampling, &paint,
185 } else {
187 int i = 0;
188 // Interior fast tiles
189 for (int y = 0; y < fTileGridSize.fHeight - 1; ++y) {
190 for (int x = 0; x < fTileGridSize.fWidth - 1; ++x) {
191 set[i++] = this->getEntry(x, y, l);
192 }
193 }
194 canvas->experimental_DrawEdgeAAImageSet(set.get(), i, nullptr, nullptr,
195 sampling, &paint,
197
198 // Right edge
199 int strictStart = i;
200 AutoTArray<SkPoint> dstQuads(
201 4 * (fTileGridSize.fWidth + fTileGridSize.fHeight - 2));
202 for (int y = 0; y < fTileGridSize.fHeight - 1; ++y) {
203 set[i++] = this->getAdjustedEntry(fTileGridSize.fWidth - 1, y, l,
204 dstQuads.get() + y * 4);
205 }
206 canvas->experimental_DrawEdgeAAImageSet(set.get() + strictStart,
207 i - strictStart, dstQuads.get(), nullptr, sampling, &paint,
209 int quadStart = 4 * (fTileGridSize.fHeight - 1);
210 strictStart = i;
211 for (int x = 0; x < fTileGridSize.fWidth - 1; ++x) {
212 set[i++] = this->getAdjustedEntry(x, fTileGridSize.fHeight - 1, l,
213 dstQuads.get() + quadStart + x * 4);
214 }
215 set[i++] = this->getEntry(
216 fTileGridSize.fWidth - 1, fTileGridSize.fHeight - 1, l);
217 canvas->experimental_DrawEdgeAAImageSet(set.get() + strictStart,
218 i - strictStart, dstQuads.get() + quadStart, nullptr, sampling, &paint,
220 }
221 }
222 // Prevent any batching between composited "frames".
223 skgpu::Flush(canvas->getSurface());
224 }
225 canvas->restore();
226 }
227
228private:
229 SkMatrix getTransform() const {
230 SkMatrix m;
231 switch(fTransformMode) {
233 m.setIdentity();
234 break;
236 m.setTranslate(0.5f, 0.5f);
237 break;
239 m.setRotate(15.f);
240 break;
242 m.setIdentity();
243 m.setPerspY(0.001f);
244 m.setSkewX(SkIntToScalar(8) / 25);
245 break;
246 }
247 }
248 return m;
249 }
250
251 SkISize onGetSize() override {
252 SkRect size = SkRect::MakeWH(1.25f * fTileSize.fWidth * fTileGridSize.fWidth,
253 1.25f * fTileSize.fHeight * fTileGridSize.fHeight);
254 this->getTransform().mapRect(&size);
255 return SkISize::Make(SkScalarCeilToInt(size.width()), SkScalarCeilToInt(size.height()));
256 }
257
258 unsigned getEdgeFlags(int x, int y) const {
260 if (x == 0) {
262 } else if (x == fTileGridSize.fWidth - 1) {
264 }
265
266 if (y == 0) {
268 } else if (y == fTileGridSize.fHeight - 1) {
270 }
271 return flags;
272 }
273
274 SkCanvas::ImageSetEntry getEntry(int x, int y, int layer) const {
275 int imageIdx =
276 fTileGridSize.fWidth * fTileGridSize.fHeight * layer + fTileGridSize.fWidth * y + x;
277 SkRect srcRect = SkRect::Make(fTileSize);
278 // Make a non-identity transform between src and dst so bilerp isn't disabled.
279 float dstWidth = srcRect.width() * 1.25f;
280 float dstHeight = srcRect.height() * 1.25f;
281 SkRect dstRect = SkRect::MakeXYWH(dstWidth * x, dstHeight * y, dstWidth, dstHeight);
282 return SkCanvas::ImageSetEntry(fImages[imageIdx], srcRect, dstRect, 1.f,
283 this->getEdgeFlags(x, y));
284 }
285
286 SkCanvas::ImageSetEntry getAdjustedEntry(int x, int y, int layer, SkPoint dstQuad[4]) const {
287 SkASSERT(x == fTileGridSize.fWidth - 1 || y == fTileGridSize.fHeight - 1);
288
289 SkCanvas::ImageSetEntry entry = this->getEntry(x, y, layer);
290 SkRect contentRect = SkRect::Make(fImageSize);
291 if (x == fTileGridSize.fWidth - 1) {
292 // Right edge, so restrict horizontal content to tile width
293 contentRect.fRight = fTileSize.fWidth;
294 }
295 if (y == fTileGridSize.fHeight - 1) {
296 // Bottom edge, so restrict vertical content to tile height
297 contentRect.fBottom = fTileSize.fHeight;
298 }
299
300 SkMatrix srcToDst = SkMatrix::RectToRect(entry.fSrcRect, entry.fDstRect);
301
302 // Story entry's dstRect into dstQuad, and use contentRect and contentDst as its src and dst
303 entry.fDstRect.toQuad(dstQuad);
304 entry.fSrcRect = contentRect;
305 entry.fDstRect = srcToDst.mapRect(contentRect);
306 entry.fHasClip = true;
307
308 return entry;
309 }
310
311 std::unique_ptr<sk_sp<SkImage>[]> fImages;
312 SkString fName;
313 SkISize fImageSize;
314 SkISize fTileSize;
315 SkISize fTileGridSize;
316 ClampingMode fClampMode;
317 TransformMode fTransformMode;
318 int fLayerCnt;
319
320 using INHERITED = Benchmark;
321};
322
323// Subpixel = false; all of the draw commands align with integer pixels so AA will be automatically
324// turned off within the operation
325DEF_BENCH(return new CompositingImages({256, 256}, {256, 256}, {8, 8}, ClampingMode::kAlwaysFast, TransformMode::kNone, 1));
326DEF_BENCH(return new CompositingImages({512, 512}, {512, 512}, {4, 4}, ClampingMode::kAlwaysFast, TransformMode::kNone, 1));
327DEF_BENCH(return new CompositingImages({1024, 512}, {1024, 512}, {2, 4}, ClampingMode::kAlwaysFast, TransformMode::kNone, 1));
328
329DEF_BENCH(return new CompositingImages({256, 256}, {256, 256}, {8, 8}, ClampingMode::kAlwaysFast, TransformMode::kNone, 4));
330DEF_BENCH(return new CompositingImages({512, 512}, {512, 512}, {4, 4}, ClampingMode::kAlwaysFast, TransformMode::kNone, 4));
331DEF_BENCH(return new CompositingImages({1024, 512}, {1024, 512}, {2, 4}, ClampingMode::kAlwaysFast, TransformMode::kNone, 4));
332
333DEF_BENCH(return new CompositingImages({256, 256}, {256, 256}, {8, 8}, ClampingMode::kAlwaysFast, TransformMode::kNone, 16));
334DEF_BENCH(return new CompositingImages({512, 512}, {512, 512}, {4, 4}, ClampingMode::kAlwaysFast, TransformMode::kNone, 16));
335DEF_BENCH(return new CompositingImages({1024, 512}, {1024, 512}, {2, 4}, ClampingMode::kAlwaysFast, TransformMode::kNone, 16));
336
337// Subpixel = true; force the draw commands to not align with pixels exactly so AA remains on
338DEF_BENCH(return new CompositingImages({256, 256}, {256, 256}, {8, 8}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 1));
339DEF_BENCH(return new CompositingImages({512, 512}, {512, 512}, {4, 4}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 1));
340DEF_BENCH(return new CompositingImages({1024, 512}, {1024, 512}, {2, 4}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 1));
341
342DEF_BENCH(return new CompositingImages({256, 256}, {256, 256}, {8, 8}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 4));
343DEF_BENCH(return new CompositingImages({512, 512}, {512, 512}, {4, 4}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 4));
344DEF_BENCH(return new CompositingImages({1024, 512}, {1024, 512}, {2, 4}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 4));
345
346DEF_BENCH(return new CompositingImages({256, 256}, {256, 256}, {8, 8}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 16));
347DEF_BENCH(return new CompositingImages({512, 512}, {512, 512}, {4, 4}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 16));
348DEF_BENCH(return new CompositingImages({1024, 512}, {1024, 512}, {2, 4}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 16));
349
350// Test different tiling scenarios inspired by Chrome's compositor
351DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kAlwaysFast, TransformMode::kNone, 1));
352DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kAlwaysStrict, TransformMode::kNone, 1));
355
356DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 1));
360
361DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kAlwaysFast, TransformMode::kRotated, 1));
365
#define DEF_BENCH(code)
Definition Benchmark.h:20
const char * backend
@ kChromeTiling_RowMajor
SkColor4f color
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkASSERT(cond)
Definition SkAssert.h:116
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition SkColorType.h:24
uint32_t SkColor
Definition SkColor.h:37
#define SkScalarCeilToInt(x)
Definition SkScalar.h:36
#define SkIntToScalar(x)
Definition SkScalar.h:57
SkISize onGetSize() override
void onPerCanvasPostDraw(SkCanvas *) override
bool isSuitableFor(Backend backend) override
void onDraw(int loops, SkCanvas *canvas) override
void onPerCanvasPreDraw(SkCanvas *canvas) override
CompositingImages(SkISize imageSize, SkISize tileSize, SkISize tileGridSize, ClampingMode clampMode, TransformMode transformMode, int layerCnt)
const char * onGetName() override
SkSurface * getSurface() const
Definition SkCanvas.cpp:369
void restore()
Definition SkCanvas.cpp:465
sk_sp< SkSurface > makeSurface(const SkImageInfo &info, const SkSurfaceProps *props=nullptr)
SrcRectConstraint
Definition SkCanvas.h:1541
@ kStrict_SrcRectConstraint
sample only inside bounds; slower
Definition SkCanvas.h:1542
@ kFast_SrcRectConstraint
sample outside bounds; faster
Definition SkCanvas.h:1543
void experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt, const SkPoint dstClips[], const SkMatrix preViewMatrices[], const SkSamplingOptions &, const SkPaint *paint=nullptr, SrcRectConstraint constraint=kStrict_SrcRectConstraint)
int save()
Definition SkCanvas.cpp:451
void concat(const SkMatrix &matrix)
@ kTop_QuadAAFlag
Definition SkCanvas.h:1660
@ kRight_QuadAAFlag
Definition SkCanvas.h:1661
@ kLeft_QuadAAFlag
Definition SkCanvas.h:1659
@ kBottom_QuadAAFlag
Definition SkCanvas.h:1662
@ kNone_QuadAAFlags
Definition SkCanvas.h:1664
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
Definition SkMatrix.h:157
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
uint32_t nextU()
Definition SkRandom.h:42
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
const Paint & paint
FlutterSemanticsFlag flags
double y
double x
void Flush(SkSurface *surface)
Definition GpuTools.h:25
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
int32_t fHeight
Definition SkSize.h:18
int32_t fWidth
Definition SkSize.h:17
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
SkScalar fBottom
larger y-axis bounds
Definition extension.cpp:17
void toQuad(SkPoint quad[4]) const
Definition SkRect.cpp:50
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659
SkScalar fRight
larger x-axis bounds
Definition extension.cpp:16
constexpr float height() const
Definition SkRect.h:769
constexpr float width() const
Definition SkRect.h:762
static constexpr SkRect MakeWH(float w, float h)
Definition SkRect.h:609
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition SkRect.h:646