blob: acbe7691c713eeb3bf12aa76f116ce656bf32e10 [file] [log] [blame]
Brian Salomon7eae3e02018-08-07 14:02:38 +00001/*
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
John Stilesfbd050b2020-08-03 13:21:46 -04008#include <memory>
9
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "bench/Benchmark.h"
Brian Salomon7eae3e02018-08-07 14:02:38 +000011
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkCanvas.h"
13#include "include/core/SkImage.h"
14#include "include/core/SkSurface.h"
Robert Phillips2c21a112020-11-20 13:49:37 -050015#include "include/gpu/GrDirectContext.h"
John Stiles9d5461f2020-07-27 15:53:49 -040016#include "include/private/SkTemplates.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "include/utils/SkRandom.h"
Brian Salomon7eae3e02018-08-07 14:02:38 +000018
Michael Ludwig377befa2019-04-19 13:04:41 -040019enum class ClampingMode {
20 // Submit image set entries with the fast constraint
21 kAlwaysFast,
22 // Submit image set entries with the strict constraint
23 kAlwaysStrict,
24 // Submit non-right/bottom tiles as fast, the bottom-right corner as strict, and bottom or right
25 // edge tiles as strict with geometry modification to match content area. These will be
26 // submitted from left-to-right, top-to-bottom so will necessarily be split into many batches.
27 kChromeTiling_RowMajor,
28 // As above, but group all fast tiles first, then bottom and right edge tiles in a second batch.
29 kChromeTiling_Optimal
30};
31
32enum class TransformMode {
33 // Tiles will be axis aligned on integer pixels
34 kNone,
35 // Subpixel, tiles will be axis aligned but adjusted to subpixel coordinates
36 kSubpixel,
37 // Rotated, tiles will be rotated globally; they won't overlap but their device space bounds may
38 kRotated,
39 // Perspective, tiles will have global perspective
40 kPerspective
41};
42
Brian Salomon7eae3e02018-08-07 14:02:38 +000043/**
Michael Ludwig377befa2019-04-19 13:04:41 -040044 * Simulates drawing layers images in a grid a la a tile based compositor.
Brian Salomon7eae3e02018-08-07 14:02:38 +000045 */
46class CompositingImages : public Benchmark {
47public:
Michael Ludwig377befa2019-04-19 13:04:41 -040048 CompositingImages(SkISize imageSize, SkISize tileSize, SkISize tileGridSize,
49 ClampingMode clampMode, TransformMode transformMode, int layerCnt)
50 : fImageSize(imageSize)
51 , fTileSize(tileSize)
Michael Ludwigeb356502018-11-20 09:43:17 -050052 , fTileGridSize(tileGridSize)
Michael Ludwig377befa2019-04-19 13:04:41 -040053 , fClampMode(clampMode)
54 , fTransformMode(transformMode)
55 , fLayerCnt(layerCnt) {
56 fName.appendf("compositing_images_tile_size_%dx%d_grid_%dx%d_layers_%d",
Brian Salomon7eae3e02018-08-07 14:02:38 +000057 fTileSize.fWidth, fTileSize.fHeight, fTileGridSize.fWidth,
58 fTileGridSize.fHeight, fLayerCnt);
Michael Ludwig377befa2019-04-19 13:04:41 -040059 if (imageSize != tileSize) {
60 fName.appendf("_image_%dx%d", imageSize.fWidth, imageSize.fHeight);
61 }
62 switch(clampMode) {
63 case ClampingMode::kAlwaysFast:
64 fName.append("_fast");
65 break;
66 case ClampingMode::kAlwaysStrict:
67 fName.append("_strict");
68 break;
69 case ClampingMode::kChromeTiling_RowMajor:
70 fName.append("_chrome");
71 break;
72 case ClampingMode::kChromeTiling_Optimal:
73 fName.append("_chrome_optimal");
74 break;
75 }
76 switch(transformMode) {
77 case TransformMode::kNone:
78 break;
79 case TransformMode::kSubpixel:
80 fName.append("_subpixel");
81 break;
82 case TransformMode::kRotated:
83 fName.append("_rotated");
84 break;
85 case TransformMode::kPerspective:
86 fName.append("_persp");
87 break;
Michael Ludwigeb356502018-11-20 09:43:17 -050088 }
Brian Salomon7eae3e02018-08-07 14:02:38 +000089 }
90
91 bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; }
92
93protected:
94 const char* onGetName() override { return fName.c_str(); }
95
96 void onPerCanvasPreDraw(SkCanvas* canvas) override {
Michael Ludwig377befa2019-04-19 13:04:41 -040097 // Use image size, which may be larger than the tile size (emulating how Chrome specifies
98 // their tiles).
99 auto ii = SkImageInfo::Make(fImageSize.fWidth, fImageSize.fHeight, kRGBA_8888_SkColorType,
Brian Salomon7eae3e02018-08-07 14:02:38 +0000100 kPremul_SkAlphaType, nullptr);
101 SkRandom random;
102 int numImages = fLayerCnt * fTileGridSize.fWidth * fTileGridSize.fHeight;
John Stilesfbd050b2020-08-03 13:21:46 -0400103 fImages = std::make_unique<sk_sp<SkImage>[]>(numImages);
Brian Salomon7eae3e02018-08-07 14:02:38 +0000104 for (int i = 0; i < numImages; ++i) {
105 auto surf = canvas->makeSurface(ii);
106 SkColor color = random.nextU();
107 surf->getCanvas()->clear(color);
108 SkPaint paint;
109 paint.setColor(~color);
110 paint.setBlendMode(SkBlendMode::kSrc);
Michael Ludwig377befa2019-04-19 13:04:41 -0400111 // While the image may be bigger than fTileSize, prepare its content as if fTileSize
112 // is what will be visible.
Brian Salomon7eae3e02018-08-07 14:02:38 +0000113 surf->getCanvas()->drawRect(
114 SkRect::MakeLTRB(3, 3, fTileSize.fWidth - 3, fTileSize.fHeight - 3), paint);
115 fImages[i] = surf->makeImageSnapshot();
116 }
117 }
118
119 void onPerCanvasPostDraw(SkCanvas*) override { fImages.reset(); }
120
121 void onDraw(int loops, SkCanvas* canvas) override {
122 SkPaint paint;
Brian Salomon7eae3e02018-08-07 14:02:38 +0000123 paint.setAntiAlias(true);
Mike Reed99116302021-01-25 11:37:10 -0500124 SkSamplingOptions sampling(SkFilterMode::kLinear);
Michael Ludwig377befa2019-04-19 13:04:41 -0400125
126 canvas->save();
127 canvas->concat(this->getTransform());
128
John Stiles73339ad2021-08-12 22:27:39 -0400129 for (int loop = 0; loop < loops; ++loop) {
Brian Salomon7eae3e02018-08-07 14:02:38 +0000130 for (int l = 0; l < fLayerCnt; ++l) {
Michael Ludwig377befa2019-04-19 13:04:41 -0400131 SkAutoTArray<SkCanvas::ImageSetEntry> set(
132 fTileGridSize.fWidth * fTileGridSize.fHeight);
133
134 if (fClampMode == ClampingMode::kAlwaysFast ||
135 fClampMode == ClampingMode::kAlwaysStrict) {
136 // Simple 2D for loop, submit everything as a single batch
137 int i = 0;
138 for (int y = 0; y < fTileGridSize.fHeight; ++y) {
139 for (int x = 0; x < fTileGridSize.fWidth; ++x) {
140 set[i++] = this->getEntry(x, y, l);
141 }
Brian Salomon7eae3e02018-08-07 14:02:38 +0000142 }
Michael Ludwig377befa2019-04-19 13:04:41 -0400143
144 SkCanvas::SrcRectConstraint constraint =
145 fClampMode == ClampingMode::kAlwaysFast
146 ? SkCanvas::kFast_SrcRectConstraint
147 : SkCanvas::kStrict_SrcRectConstraint;
Mike Reed99116302021-01-25 11:37:10 -0500148 canvas->experimental_DrawEdgeAAImageSet(set.get(), i, nullptr, nullptr,
149 sampling, &paint, constraint);
Michael Ludwig377befa2019-04-19 13:04:41 -0400150 } else if (fClampMode == ClampingMode::kChromeTiling_RowMajor) {
151 // Same tile order, but break batching between fast and strict sections, and
152 // adjust bottom and right tiles to encode content area distinct from src rect.
153 int i = 0;
154 for (int y = 0; y < fTileGridSize.fHeight - 1; ++y) {
155 int rowStart = i;
156 for (int x = 0; x < fTileGridSize.fWidth - 1; ++x) {
157 set[i++] = this->getEntry(x, y, l);
158 }
159 // Flush "fast" horizontal row
160 canvas->experimental_DrawEdgeAAImageSet(set.get() + rowStart,
Mike Reed99116302021-01-25 11:37:10 -0500161 fTileGridSize.fWidth - 1, nullptr, nullptr, sampling, &paint,
Michael Ludwig377befa2019-04-19 13:04:41 -0400162 SkCanvas::kFast_SrcRectConstraint);
163 // Then flush a single adjusted entry for the right edge
164 SkPoint dstQuad[4];
165 set[i++] = this->getAdjustedEntry(fTileGridSize.fWidth - 1, y, l, dstQuad);
166 canvas->experimental_DrawEdgeAAImageSet(
Mike Reed99116302021-01-25 11:37:10 -0500167 set.get() + fTileGridSize.fWidth - 1, 1, dstQuad, nullptr, sampling,
168 &paint, SkCanvas::kStrict_SrcRectConstraint);
Michael Ludwig377befa2019-04-19 13:04:41 -0400169 }
170 // For last row, accumulate it as a single strict batch
171 int rowStart = i;
172 SkAutoTArray<SkPoint> dstQuads(4 * (fTileGridSize.fWidth - 1));
173 for (int x = 0; x < fTileGridSize.fWidth - 1; ++x) {
174 set[i++] = this->getAdjustedEntry(x, fTileGridSize.fHeight - 1, l,
175 dstQuads.get() + x * 4);
176 }
177 // The corner can use conventional strict mode without geometric adjustment
178 set[i++] = this->getEntry(
179 fTileGridSize.fWidth - 1, fTileGridSize.fHeight - 1, l);
180 canvas->experimental_DrawEdgeAAImageSet(set.get() + rowStart,
Mike Reed99116302021-01-25 11:37:10 -0500181 fTileGridSize.fWidth, dstQuads.get(), nullptr, sampling, &paint,
Michael Ludwig377befa2019-04-19 13:04:41 -0400182 SkCanvas::kStrict_SrcRectConstraint);
183 } else {
184 SkASSERT(fClampMode == ClampingMode::kChromeTiling_Optimal);
185 int i = 0;
186 // Interior fast tiles
187 for (int y = 0; y < fTileGridSize.fHeight - 1; ++y) {
188 for (int x = 0; x < fTileGridSize.fWidth - 1; ++x) {
189 set[i++] = this->getEntry(x, y, l);
190 }
191 }
Mike Reed99116302021-01-25 11:37:10 -0500192 canvas->experimental_DrawEdgeAAImageSet(set.get(), i, nullptr, nullptr,
193 sampling, &paint,
Michael Ludwig377befa2019-04-19 13:04:41 -0400194 SkCanvas::kFast_SrcRectConstraint);
195
196 // Right edge
197 int strictStart = i;
198 SkAutoTArray<SkPoint> dstQuads(
199 4 * (fTileGridSize.fWidth + fTileGridSize.fHeight - 2));
200 for (int y = 0; y < fTileGridSize.fHeight - 1; ++y) {
201 set[i++] = this->getAdjustedEntry(fTileGridSize.fWidth - 1, y, l,
202 dstQuads.get() + y * 4);
203 }
204 canvas->experimental_DrawEdgeAAImageSet(set.get() + strictStart,
Mike Reed99116302021-01-25 11:37:10 -0500205 i - strictStart, dstQuads.get(), nullptr, sampling, &paint,
Michael Ludwig377befa2019-04-19 13:04:41 -0400206 SkCanvas::kStrict_SrcRectConstraint);
207 int quadStart = 4 * (fTileGridSize.fHeight - 1);
208 strictStart = i;
209 for (int x = 0; x < fTileGridSize.fWidth - 1; ++x) {
210 set[i++] = this->getAdjustedEntry(x, fTileGridSize.fHeight - 1, l,
211 dstQuads.get() + quadStart + x * 4);
212 }
213 set[i++] = this->getEntry(
214 fTileGridSize.fWidth - 1, fTileGridSize.fHeight - 1, l);
215 canvas->experimental_DrawEdgeAAImageSet(set.get() + strictStart,
Mike Reed99116302021-01-25 11:37:10 -0500216 i - strictStart, dstQuads.get() + quadStart, nullptr, sampling, &paint,
Michael Ludwig377befa2019-04-19 13:04:41 -0400217 SkCanvas::kStrict_SrcRectConstraint);
Brian Salomon7eae3e02018-08-07 14:02:38 +0000218 }
219 }
220 // Prevent any batching between composited "frames".
Robert Phillips2c21a112020-11-20 13:49:37 -0500221 auto surface = canvas->getSurface();
222 if (surface) {
223 surface->flush();
224 }
Brian Salomon7eae3e02018-08-07 14:02:38 +0000225 }
Michael Ludwig377befa2019-04-19 13:04:41 -0400226 canvas->restore();
Brian Salomon7eae3e02018-08-07 14:02:38 +0000227 }
228
229private:
Michael Ludwig377befa2019-04-19 13:04:41 -0400230 SkMatrix getTransform() const {
231 SkMatrix m;
232 switch(fTransformMode) {
233 case TransformMode::kNone:
234 m.setIdentity();
235 break;
236 case TransformMode::kSubpixel:
237 m.setTranslate(0.5f, 0.5f);
238 break;
239 case TransformMode::kRotated:
240 m.setRotate(15.f);
241 break;
242 case TransformMode::kPerspective: {
243 m.setIdentity();
244 m.setPerspY(0.001f);
245 m.setSkewX(SkIntToScalar(8) / 25);
246 break;
247 }
248 }
249 return m;
Michael Ludwigeb356502018-11-20 09:43:17 -0500250 }
251
Brian Salomon7eae3e02018-08-07 14:02:38 +0000252 SkIPoint onGetSize() override {
Michael Ludwig377befa2019-04-19 13:04:41 -0400253 SkRect size = SkRect::MakeWH(1.25f * fTileSize.fWidth * fTileGridSize.fWidth,
254 1.25f * fTileSize.fHeight * fTileGridSize.fHeight);
255 this->getTransform().mapRect(&size);
256 return SkIPoint::Make(SkScalarCeilToInt(size.width()), SkScalarCeilToInt(size.height()));
257 }
258
259 unsigned getEdgeFlags(int x, int y) const {
260 unsigned flags = SkCanvas::kNone_QuadAAFlags;
261 if (x == 0) {
262 flags |= SkCanvas::kLeft_QuadAAFlag;
263 } else if (x == fTileGridSize.fWidth - 1) {
264 flags |= SkCanvas::kRight_QuadAAFlag;
265 }
266
267 if (y == 0) {
268 flags |= SkCanvas::kTop_QuadAAFlag;
269 } else if (y == fTileGridSize.fHeight - 1) {
270 flags |= SkCanvas::kBottom_QuadAAFlag;
271 }
272 return flags;
273 }
274
275 SkCanvas::ImageSetEntry getEntry(int x, int y, int layer) const {
276 int imageIdx =
277 fTileGridSize.fWidth * fTileGridSize.fHeight * layer + fTileGridSize.fWidth * y + x;
278 SkRect srcRect = SkRect::Make(fTileSize);
279 // Make a non-identity transform between src and dst so bilerp isn't disabled.
280 float dstWidth = srcRect.width() * 1.25f;
281 float dstHeight = srcRect.height() * 1.25f;
282 SkRect dstRect = SkRect::MakeXYWH(dstWidth * x, dstHeight * y, dstWidth, dstHeight);
283 return SkCanvas::ImageSetEntry(fImages[imageIdx], srcRect, dstRect, 1.f,
284 this->getEdgeFlags(x, y));
285 }
286
287 SkCanvas::ImageSetEntry getAdjustedEntry(int x, int y, int layer, SkPoint dstQuad[4]) const {
288 SkASSERT(x == fTileGridSize.fWidth - 1 || y == fTileGridSize.fHeight - 1);
289
290 SkCanvas::ImageSetEntry entry = this->getEntry(x, y, layer);
291 SkRect contentRect = SkRect::Make(fImageSize);
292 if (x == fTileGridSize.fWidth - 1) {
293 // Right edge, so restrict horizontal content to tile width
294 contentRect.fRight = fTileSize.fWidth;
295 }
296 if (y == fTileGridSize.fHeight - 1) {
297 // Bottom edge, so restrict vertical content to tile height
298 contentRect.fBottom = fTileSize.fHeight;
299 }
300
Mike Reed2ac6ce82021-01-15 12:26:22 -0500301 SkMatrix srcToDst = SkMatrix::RectToRect(entry.fSrcRect, entry.fDstRect);
Michael Ludwig377befa2019-04-19 13:04:41 -0400302
303 // Story entry's dstRect into dstQuad, and use contentRect and contentDst as its src and dst
304 entry.fDstRect.toQuad(dstQuad);
305 entry.fSrcRect = contentRect;
306 entry.fDstRect = srcToDst.mapRect(contentRect);
307 entry.fHasClip = true;
308
309 return entry;
Brian Salomon7eae3e02018-08-07 14:02:38 +0000310 }
311
312 std::unique_ptr<sk_sp<SkImage>[]> fImages;
313 SkString fName;
Michael Ludwig377befa2019-04-19 13:04:41 -0400314 SkISize fImageSize;
Brian Salomon7eae3e02018-08-07 14:02:38 +0000315 SkISize fTileSize;
316 SkISize fTileGridSize;
Michael Ludwig377befa2019-04-19 13:04:41 -0400317 ClampingMode fClampMode;
318 TransformMode fTransformMode;
Brian Salomon7eae3e02018-08-07 14:02:38 +0000319 int fLayerCnt;
320
John Stiles7571f9e2020-09-02 22:42:33 -0400321 using INHERITED = Benchmark;
Brian Salomon7eae3e02018-08-07 14:02:38 +0000322};
323
Michael Ludwigeb356502018-11-20 09:43:17 -0500324// Subpixel = false; all of the draw commands align with integer pixels so AA will be automatically
325// turned off within the operation
Michael Ludwig377befa2019-04-19 13:04:41 -0400326DEF_BENCH(return new CompositingImages({256, 256}, {256, 256}, {8, 8}, ClampingMode::kAlwaysFast, TransformMode::kNone, 1));
327DEF_BENCH(return new CompositingImages({512, 512}, {512, 512}, {4, 4}, ClampingMode::kAlwaysFast, TransformMode::kNone, 1));
328DEF_BENCH(return new CompositingImages({1024, 512}, {1024, 512}, {2, 4}, ClampingMode::kAlwaysFast, TransformMode::kNone, 1));
Brian Salomon7eae3e02018-08-07 14:02:38 +0000329
Michael Ludwig377befa2019-04-19 13:04:41 -0400330DEF_BENCH(return new CompositingImages({256, 256}, {256, 256}, {8, 8}, ClampingMode::kAlwaysFast, TransformMode::kNone, 4));
331DEF_BENCH(return new CompositingImages({512, 512}, {512, 512}, {4, 4}, ClampingMode::kAlwaysFast, TransformMode::kNone, 4));
332DEF_BENCH(return new CompositingImages({1024, 512}, {1024, 512}, {2, 4}, ClampingMode::kAlwaysFast, TransformMode::kNone, 4));
Brian Salomon7eae3e02018-08-07 14:02:38 +0000333
Michael Ludwig377befa2019-04-19 13:04:41 -0400334DEF_BENCH(return new CompositingImages({256, 256}, {256, 256}, {8, 8}, ClampingMode::kAlwaysFast, TransformMode::kNone, 16));
335DEF_BENCH(return new CompositingImages({512, 512}, {512, 512}, {4, 4}, ClampingMode::kAlwaysFast, TransformMode::kNone, 16));
336DEF_BENCH(return new CompositingImages({1024, 512}, {1024, 512}, {2, 4}, ClampingMode::kAlwaysFast, TransformMode::kNone, 16));
Michael Ludwigeb356502018-11-20 09:43:17 -0500337
338// Subpixel = true; force the draw commands to not align with pixels exactly so AA remains on
Michael Ludwig377befa2019-04-19 13:04:41 -0400339DEF_BENCH(return new CompositingImages({256, 256}, {256, 256}, {8, 8}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 1));
340DEF_BENCH(return new CompositingImages({512, 512}, {512, 512}, {4, 4}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 1));
341DEF_BENCH(return new CompositingImages({1024, 512}, {1024, 512}, {2, 4}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 1));
Michael Ludwigeb356502018-11-20 09:43:17 -0500342
Michael Ludwig377befa2019-04-19 13:04:41 -0400343DEF_BENCH(return new CompositingImages({256, 256}, {256, 256}, {8, 8}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 4));
344DEF_BENCH(return new CompositingImages({512, 512}, {512, 512}, {4, 4}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 4));
345DEF_BENCH(return new CompositingImages({1024, 512}, {1024, 512}, {2, 4}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 4));
Michael Ludwigeb356502018-11-20 09:43:17 -0500346
Michael Ludwig377befa2019-04-19 13:04:41 -0400347DEF_BENCH(return new CompositingImages({256, 256}, {256, 256}, {8, 8}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 16));
348DEF_BENCH(return new CompositingImages({512, 512}, {512, 512}, {4, 4}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 16));
349DEF_BENCH(return new CompositingImages({1024, 512}, {1024, 512}, {2, 4}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 16));
350
351// Test different tiling scenarios inspired by Chrome's compositor
352DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kAlwaysFast, TransformMode::kNone, 1));
353DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kAlwaysStrict, TransformMode::kNone, 1));
354DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kChromeTiling_RowMajor, TransformMode::kNone, 1));
355DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kChromeTiling_Optimal, TransformMode::kNone, 1));
356
357DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kAlwaysFast, TransformMode::kSubpixel, 1));
358DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kAlwaysStrict, TransformMode::kSubpixel, 1));
359DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kChromeTiling_RowMajor, TransformMode::kSubpixel, 1));
360DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kChromeTiling_Optimal, TransformMode::kSubpixel, 1));
361
362DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kAlwaysFast, TransformMode::kRotated, 1));
363DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kAlwaysStrict, TransformMode::kRotated, 1));
364DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kChromeTiling_RowMajor, TransformMode::kRotated, 1));
365DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kChromeTiling_Optimal, TransformMode::kRotated, 1));
366
367DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kAlwaysFast, TransformMode::kPerspective, 1));
368DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kAlwaysStrict, TransformMode::kPerspective, 1));
369DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kChromeTiling_RowMajor, TransformMode::kPerspective, 1));
370DEF_BENCH(return new CompositingImages({512, 512}, {380, 380}, {5, 5}, ClampingMode::kChromeTiling_Optimal, TransformMode::kPerspective, 1));