xref: /aosp_15_r20/external/skia/gm/drawimageset.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2018 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorFilter.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "tools/GpuToolUtils.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
34*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
35*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker // Makes a set of m x n tiled images to be drawn with SkCanvas::experimental_drawImageSetV1().
make_image_tiles(int tileW,int tileH,int m,int n,const SkColor colors[4],SkCanvas::ImageSetEntry set[],const SkColor bgColor=SK_ColorLTGRAY)38*c8dee2aaSAndroid Build Coastguard Worker static void make_image_tiles(int tileW, int tileH, int m, int n, const SkColor colors[4],
39*c8dee2aaSAndroid Build Coastguard Worker                              SkCanvas::ImageSetEntry set[], const SkColor bgColor=SK_ColorLTGRAY) {
40*c8dee2aaSAndroid Build Coastguard Worker     const int w = tileW * m;
41*c8dee2aaSAndroid Build Coastguard Worker     const int h = tileH * n;
42*c8dee2aaSAndroid Build Coastguard Worker     auto surf = SkSurfaces::Raster(
43*c8dee2aaSAndroid Build Coastguard Worker             SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType));
44*c8dee2aaSAndroid Build Coastguard Worker     surf->getCanvas()->clear(bgColor);
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker     static constexpr SkScalar kStripeW = 10;
47*c8dee2aaSAndroid Build Coastguard Worker     static constexpr SkScalar kStripeSpacing = 30;
48*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
49*c8dee2aaSAndroid Build Coastguard Worker 
50*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pts1[] = {{0.f, 0.f}, {(SkScalar)w, (SkScalar)h}};
51*c8dee2aaSAndroid Build Coastguard Worker     auto grad = SkGradientShader::MakeLinear(pts1, colors, nullptr, 2, SkTileMode::kClamp);
52*c8dee2aaSAndroid Build Coastguard Worker     paint.setShader(std::move(grad));
53*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
54*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kStroke_Style);
55*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeWidth(kStripeW);
56*c8dee2aaSAndroid Build Coastguard Worker     SkPoint stripePts[] = {{-w - kStripeW, -kStripeW}, {kStripeW, h + kStripeW}};
57*c8dee2aaSAndroid Build Coastguard Worker     while (stripePts[0].fX <= w) {
58*c8dee2aaSAndroid Build Coastguard Worker         surf->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, 2, stripePts, paint);
59*c8dee2aaSAndroid Build Coastguard Worker         stripePts[0].fX += kStripeSpacing;
60*c8dee2aaSAndroid Build Coastguard Worker         stripePts[1].fX += kStripeSpacing;
61*c8dee2aaSAndroid Build Coastguard Worker     }
62*c8dee2aaSAndroid Build Coastguard Worker 
63*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pts2[] = {{0.f, (SkScalar)h}, {(SkScalar)w, 0.f}};
64*c8dee2aaSAndroid Build Coastguard Worker     grad = SkGradientShader::MakeLinear(pts2, colors + 2, nullptr, 2, SkTileMode::kClamp);
65*c8dee2aaSAndroid Build Coastguard Worker     paint.setShader(std::move(grad));
66*c8dee2aaSAndroid Build Coastguard Worker     paint.setBlendMode(SkBlendMode::kMultiply);
67*c8dee2aaSAndroid Build Coastguard Worker     stripePts[0] = {-w - kStripeW, h + kStripeW};
68*c8dee2aaSAndroid Build Coastguard Worker     stripePts[1] = {kStripeW, -kStripeW};
69*c8dee2aaSAndroid Build Coastguard Worker     while (stripePts[0].fX <= w) {
70*c8dee2aaSAndroid Build Coastguard Worker         surf->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, 2, stripePts, paint);
71*c8dee2aaSAndroid Build Coastguard Worker         stripePts[0].fX += kStripeSpacing;
72*c8dee2aaSAndroid Build Coastguard Worker         stripePts[1].fX += kStripeSpacing;
73*c8dee2aaSAndroid Build Coastguard Worker     }
74*c8dee2aaSAndroid Build Coastguard Worker     auto fullImage = surf->makeImageSnapshot();
75*c8dee2aaSAndroid Build Coastguard Worker     for (int y = 0; y < n; ++y) {
76*c8dee2aaSAndroid Build Coastguard Worker         for (int x = 0; x < m; ++x) {
77*c8dee2aaSAndroid Build Coastguard Worker             // Images will have 1 pixel of overlap at interior seams for filtering continuity.
78*c8dee2aaSAndroid Build Coastguard Worker             SkIRect subset = SkIRect::MakeXYWH(x * tileW - 1, y * tileH - 1, tileW + 2, tileH + 2);
79*c8dee2aaSAndroid Build Coastguard Worker             set[y * m + x].fAAFlags = SkCanvas::kNone_QuadAAFlags;
80*c8dee2aaSAndroid Build Coastguard Worker             if (x == 0) {
81*c8dee2aaSAndroid Build Coastguard Worker                 subset.fLeft = 0;
82*c8dee2aaSAndroid Build Coastguard Worker                 set[y * m + x].fAAFlags |= SkCanvas::kLeft_QuadAAFlag;
83*c8dee2aaSAndroid Build Coastguard Worker             }
84*c8dee2aaSAndroid Build Coastguard Worker             if (x == m - 1) {
85*c8dee2aaSAndroid Build Coastguard Worker                 subset.fRight = w;
86*c8dee2aaSAndroid Build Coastguard Worker                 set[y * m + x].fAAFlags |= SkCanvas::kRight_QuadAAFlag;
87*c8dee2aaSAndroid Build Coastguard Worker             }
88*c8dee2aaSAndroid Build Coastguard Worker             if (y == 0) {
89*c8dee2aaSAndroid Build Coastguard Worker                 subset.fTop = 0;
90*c8dee2aaSAndroid Build Coastguard Worker                 set[y * m + x].fAAFlags |= SkCanvas::kTop_QuadAAFlag;
91*c8dee2aaSAndroid Build Coastguard Worker             }
92*c8dee2aaSAndroid Build Coastguard Worker             if (y == n - 1) {
93*c8dee2aaSAndroid Build Coastguard Worker                 subset.fBottom = h;
94*c8dee2aaSAndroid Build Coastguard Worker                 set[y * m + x].fAAFlags |= SkCanvas::kBottom_QuadAAFlag;
95*c8dee2aaSAndroid Build Coastguard Worker             }
96*c8dee2aaSAndroid Build Coastguard Worker             set[y * m + x].fImage = fullImage->makeSubset(nullptr, subset);
97*c8dee2aaSAndroid Build Coastguard Worker             set[y * m + x].fSrcRect =
98*c8dee2aaSAndroid Build Coastguard Worker                     SkRect::MakeXYWH(x == 0 ? 0 : 1, y == 0 ? 0 : 1, tileW, tileH);
99*c8dee2aaSAndroid Build Coastguard Worker             set[y * m + x].fDstRect = SkRect::MakeXYWH(x * tileW, y * tileH, tileW, tileH);
100*c8dee2aaSAndroid Build Coastguard Worker             set[y * m + x].fAlpha = 1.f;
101*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(set[y * m + x].fImage);
102*c8dee2aaSAndroid Build Coastguard Worker         }
103*c8dee2aaSAndroid Build Coastguard Worker     }
104*c8dee2aaSAndroid Build Coastguard Worker }
105*c8dee2aaSAndroid Build Coastguard Worker 
106*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm {
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker class DrawImageSetGM : public GM {
109*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const110*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("draw_image_set"); }
getISize()111*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {1000, 725}; }
onOnceBeforeDraw()112*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
113*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkColor kColors[] = {SK_ColorCYAN,    SK_ColorBLACK,
114*c8dee2aaSAndroid Build Coastguard Worker                                               SK_ColorMAGENTA, SK_ColorBLACK};
115*c8dee2aaSAndroid Build Coastguard Worker         make_image_tiles(kTileW, kTileH, kM, kN, kColors, fSet);
116*c8dee2aaSAndroid Build Coastguard Worker     }
117*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas)118*c8dee2aaSAndroid Build Coastguard Worker     void onDraw(SkCanvas* canvas) override {
119*c8dee2aaSAndroid Build Coastguard Worker         SkScalar d = SkVector{kM * kTileW, kN * kTileH}.length();
120*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrices[4];
121*c8dee2aaSAndroid Build Coastguard Worker         // rotation
122*c8dee2aaSAndroid Build Coastguard Worker         matrices[0].setRotate(30);
123*c8dee2aaSAndroid Build Coastguard Worker         matrices[0].postTranslate(d / 3, 0);
124*c8dee2aaSAndroid Build Coastguard Worker         // perespective
125*c8dee2aaSAndroid Build Coastguard Worker         SkPoint src[4];
126*c8dee2aaSAndroid Build Coastguard Worker         SkRect::MakeWH(kM * kTileW, kN * kTileH).toQuad(src);
127*c8dee2aaSAndroid Build Coastguard Worker         SkPoint dst[4] = {{0, 0},
128*c8dee2aaSAndroid Build Coastguard Worker                           {kM * kTileW + 10.f, -5.f},
129*c8dee2aaSAndroid Build Coastguard Worker                           {kM * kTileW - 28.f, kN * kTileH + 40.f},
130*c8dee2aaSAndroid Build Coastguard Worker                           {45.f, kN * kTileH - 25.f}};
131*c8dee2aaSAndroid Build Coastguard Worker         SkAssertResult(matrices[1].setPolyToPoly(src, dst, 4));
132*c8dee2aaSAndroid Build Coastguard Worker         matrices[1].postTranslate(d, 50.f);
133*c8dee2aaSAndroid Build Coastguard Worker         // skew
134*c8dee2aaSAndroid Build Coastguard Worker         matrices[2].setRotate(-60.f);
135*c8dee2aaSAndroid Build Coastguard Worker         matrices[2].postSkew(0.5f, -1.15f);
136*c8dee2aaSAndroid Build Coastguard Worker         matrices[2].postScale(0.6f, 1.05f);
137*c8dee2aaSAndroid Build Coastguard Worker         matrices[2].postTranslate(d, 2.6f * d);
138*c8dee2aaSAndroid Build Coastguard Worker         // perspective + mirror in x.
139*c8dee2aaSAndroid Build Coastguard Worker         dst[1] = {-.25 * kM * kTileW, 0};
140*c8dee2aaSAndroid Build Coastguard Worker         dst[0] = {5.f / 4.f * kM * kTileW, 0};
141*c8dee2aaSAndroid Build Coastguard Worker         dst[3] = {2.f / 3.f * kM * kTileW, 1 / 2.f * kN * kTileH};
142*c8dee2aaSAndroid Build Coastguard Worker         dst[2] = {1.f / 3.f * kM * kTileW, 1 / 2.f * kN * kTileH - 0.1f * kTileH};
143*c8dee2aaSAndroid Build Coastguard Worker         SkAssertResult(matrices[3].setPolyToPoly(src, dst, 4));
144*c8dee2aaSAndroid Build Coastguard Worker         matrices[3].postTranslate(100.f, d);
145*c8dee2aaSAndroid Build Coastguard Worker         for (auto fm : {SkFilterMode::kNearest, SkFilterMode::kLinear}) {
146*c8dee2aaSAndroid Build Coastguard Worker             SkPaint setPaint;
147*c8dee2aaSAndroid Build Coastguard Worker             setPaint.setBlendMode(SkBlendMode::kSrcOver);
148*c8dee2aaSAndroid Build Coastguard Worker             SkSamplingOptions sampling(fm);
149*c8dee2aaSAndroid Build Coastguard Worker 
150*c8dee2aaSAndroid Build Coastguard Worker             for (size_t m = 0; m < std::size(matrices); ++m) {
151*c8dee2aaSAndroid Build Coastguard Worker                 // Draw grid of red lines at interior tile boundaries.
152*c8dee2aaSAndroid Build Coastguard Worker                 static constexpr SkScalar kLineOutset = 10.f;
153*c8dee2aaSAndroid Build Coastguard Worker                 SkPaint paint;
154*c8dee2aaSAndroid Build Coastguard Worker                 paint.setAntiAlias(true);
155*c8dee2aaSAndroid Build Coastguard Worker                 paint.setColor(SK_ColorRED);
156*c8dee2aaSAndroid Build Coastguard Worker                 paint.setStyle(SkPaint::kStroke_Style);
157*c8dee2aaSAndroid Build Coastguard Worker                 paint.setStrokeWidth(0.f);
158*c8dee2aaSAndroid Build Coastguard Worker                 for (int x = 1; x < kM; ++x) {
159*c8dee2aaSAndroid Build Coastguard Worker                     SkPoint pts[] = {{x * kTileW, 0}, {x * kTileW, kN * kTileH}};
160*c8dee2aaSAndroid Build Coastguard Worker                     matrices[m].mapPoints(pts, 2);
161*c8dee2aaSAndroid Build Coastguard Worker                     SkVector v = pts[1] - pts[0];
162*c8dee2aaSAndroid Build Coastguard Worker                     v.setLength(v.length() + kLineOutset);
163*c8dee2aaSAndroid Build Coastguard Worker                     canvas->drawLine(pts[1] - v, pts[0] + v, paint);
164*c8dee2aaSAndroid Build Coastguard Worker                 }
165*c8dee2aaSAndroid Build Coastguard Worker                 for (int y = 1; y < kN; ++y) {
166*c8dee2aaSAndroid Build Coastguard Worker                     SkPoint pts[] = {{0, y * kTileH}, {kTileW * kM, y * kTileH}};
167*c8dee2aaSAndroid Build Coastguard Worker                     matrices[m].mapPoints(pts, 2);
168*c8dee2aaSAndroid Build Coastguard Worker                     SkVector v = pts[1] - pts[0];
169*c8dee2aaSAndroid Build Coastguard Worker                     v.setLength(v.length() + kLineOutset);
170*c8dee2aaSAndroid Build Coastguard Worker                     canvas->drawLine(pts[1] - v, pts[0] + v, paint);
171*c8dee2aaSAndroid Build Coastguard Worker                 }
172*c8dee2aaSAndroid Build Coastguard Worker                 canvas->save();
173*c8dee2aaSAndroid Build Coastguard Worker                 canvas->concat(matrices[m]);
174*c8dee2aaSAndroid Build Coastguard Worker                 canvas->experimental_DrawEdgeAAImageSet(fSet, kM * kN, nullptr, nullptr, sampling,
175*c8dee2aaSAndroid Build Coastguard Worker                                                         &setPaint,
176*c8dee2aaSAndroid Build Coastguard Worker                                                         SkCanvas::kFast_SrcRectConstraint);
177*c8dee2aaSAndroid Build Coastguard Worker                 canvas->restore();
178*c8dee2aaSAndroid Build Coastguard Worker             }
179*c8dee2aaSAndroid Build Coastguard Worker             // A more exotic case with an unusual blend mode, mixed aa flags set, and alpha,
180*c8dee2aaSAndroid Build Coastguard Worker             // subsets the image. And another with all the above plus a color filter.
181*c8dee2aaSAndroid Build Coastguard Worker             SkCanvas::ImageSetEntry entry;
182*c8dee2aaSAndroid Build Coastguard Worker             entry.fSrcRect = SkRect::MakeWH(kTileW, kTileH).makeInset(kTileW / 4.f, kTileH / 4.f);
183*c8dee2aaSAndroid Build Coastguard Worker             entry.fDstRect = SkRect::MakeWH(1.5 * kTileW, 1.5 * kTileH).makeOffset(d / 4, 2 * d);
184*c8dee2aaSAndroid Build Coastguard Worker             entry.fImage = fSet[0].fImage;
185*c8dee2aaSAndroid Build Coastguard Worker             entry.fAlpha = 0.7f;
186*c8dee2aaSAndroid Build Coastguard Worker             entry.fAAFlags = SkCanvas::kLeft_QuadAAFlag | SkCanvas::kTop_QuadAAFlag;
187*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
188*c8dee2aaSAndroid Build Coastguard Worker             canvas->rotate(3.f);
189*c8dee2aaSAndroid Build Coastguard Worker 
190*c8dee2aaSAndroid Build Coastguard Worker             setPaint.setBlendMode(SkBlendMode::kExclusion);
191*c8dee2aaSAndroid Build Coastguard Worker             canvas->experimental_DrawEdgeAAImageSet(&entry, 1, nullptr, nullptr, sampling,
192*c8dee2aaSAndroid Build Coastguard Worker                                                     &setPaint, SkCanvas::kFast_SrcRectConstraint);
193*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(entry.fDstRect.width() + 8.f, 0);
194*c8dee2aaSAndroid Build Coastguard Worker             SkPaint cfPaint = setPaint;
195*c8dee2aaSAndroid Build Coastguard Worker             cfPaint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
196*c8dee2aaSAndroid Build Coastguard Worker             canvas->experimental_DrawEdgeAAImageSet(&entry, 1, nullptr, nullptr, sampling,
197*c8dee2aaSAndroid Build Coastguard Worker                                                     &cfPaint, SkCanvas::kFast_SrcRectConstraint);
198*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
199*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(2 * d, 0);
200*c8dee2aaSAndroid Build Coastguard Worker         }
201*c8dee2aaSAndroid Build Coastguard Worker     }
202*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kM = 4;
203*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kN = 3;
204*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr SkScalar kTileW = 30;
205*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr SkScalar kTileH = 60;
206*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas::ImageSetEntry fSet[kM * kN];
207*c8dee2aaSAndroid Build Coastguard Worker };
208*c8dee2aaSAndroid Build Coastguard Worker 
209*c8dee2aaSAndroid Build Coastguard Worker // This GM exercises rect-stays-rect type matrices to test that filtering and antialiasing are not
210*c8dee2aaSAndroid Build Coastguard Worker // incorrectly disabled.
211*c8dee2aaSAndroid Build Coastguard Worker class DrawImageSetRectToRectGM : public GM {
212*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const213*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("draw_image_set_rect_to_rect"); }
getISize()214*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {1250, 850}; }
onOnceBeforeDraw()215*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
216*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkColor kColors[] = {SK_ColorBLUE, SK_ColorWHITE,
217*c8dee2aaSAndroid Build Coastguard Worker                                               SK_ColorRED,  SK_ColorWHITE};
218*c8dee2aaSAndroid Build Coastguard Worker         make_image_tiles(kTileW, kTileH, kM, kN, kColors, fSet);
219*c8dee2aaSAndroid Build Coastguard Worker     }
220*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas)221*c8dee2aaSAndroid Build Coastguard Worker     void onDraw(SkCanvas* canvas) override {
222*c8dee2aaSAndroid Build Coastguard Worker         ToolUtils::draw_checkerboard(canvas, SK_ColorBLACK, SK_ColorWHITE, 50);
223*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkScalar kW = kM * kTileW;
224*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkScalar kH = kN * kTileH;
225*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrices[5];
226*c8dee2aaSAndroid Build Coastguard Worker         // Identity
227*c8dee2aaSAndroid Build Coastguard Worker         matrices[0].reset();
228*c8dee2aaSAndroid Build Coastguard Worker         // 90 degree rotation
229*c8dee2aaSAndroid Build Coastguard Worker         matrices[1].setRotate(90, kW / 2.f, kH / 2.f);
230*c8dee2aaSAndroid Build Coastguard Worker         // Scaling
231*c8dee2aaSAndroid Build Coastguard Worker         matrices[2].setScale(2.f, 0.5f);
232*c8dee2aaSAndroid Build Coastguard Worker         // Mirror in x and y
233*c8dee2aaSAndroid Build Coastguard Worker         matrices[3].setScale(-1.f, -1.f);
234*c8dee2aaSAndroid Build Coastguard Worker         matrices[3].postTranslate(kW, kH);
235*c8dee2aaSAndroid Build Coastguard Worker         // Mirror in y, rotate, and scale.
236*c8dee2aaSAndroid Build Coastguard Worker         matrices[4].setScale(1.f, -1.f);
237*c8dee2aaSAndroid Build Coastguard Worker         matrices[4].postTranslate(0, kH);
238*c8dee2aaSAndroid Build Coastguard Worker         matrices[4].postRotate(90, kW / 2.f, kH / 2.f);
239*c8dee2aaSAndroid Build Coastguard Worker         matrices[4].postScale(2.f, 0.5f);
240*c8dee2aaSAndroid Build Coastguard Worker 
241*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
242*c8dee2aaSAndroid Build Coastguard Worker         paint.setBlendMode(SkBlendMode::kSrcOver);
243*c8dee2aaSAndroid Build Coastguard Worker 
244*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkScalar kTranslate = std::max(kW, kH) * 2.f + 10.f;
245*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(5.f, 5.f);
246*c8dee2aaSAndroid Build Coastguard Worker         canvas->save();
247*c8dee2aaSAndroid Build Coastguard Worker         for (SkScalar frac : {0.f, 0.5f}) {
248*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
249*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(frac, frac);
250*c8dee2aaSAndroid Build Coastguard Worker             for (size_t m = 0; m < std::size(matrices); ++m) {
251*c8dee2aaSAndroid Build Coastguard Worker                 canvas->save();
252*c8dee2aaSAndroid Build Coastguard Worker                 canvas->concat(matrices[m]);
253*c8dee2aaSAndroid Build Coastguard Worker                 canvas->experimental_DrawEdgeAAImageSet(fSet, kM * kN, nullptr, nullptr,
254*c8dee2aaSAndroid Build Coastguard Worker                                                         SkSamplingOptions(SkFilterMode::kLinear),
255*c8dee2aaSAndroid Build Coastguard Worker                                                         &paint, SkCanvas::kFast_SrcRectConstraint);
256*c8dee2aaSAndroid Build Coastguard Worker                 canvas->restore();
257*c8dee2aaSAndroid Build Coastguard Worker                 canvas->translate(kTranslate, 0);
258*c8dee2aaSAndroid Build Coastguard Worker             }
259*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
260*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
261*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(0, kTranslate);
262*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
263*c8dee2aaSAndroid Build Coastguard Worker         }
264*c8dee2aaSAndroid Build Coastguard Worker         for (SkVector scale : {SkVector{2.f, 0.5f}, SkVector{0.5, 2.f}}) {
265*c8dee2aaSAndroid Build Coastguard Worker             SkCanvas::ImageSetEntry scaledSet[kM * kN];
266*c8dee2aaSAndroid Build Coastguard Worker             std::copy_n(fSet, kM * kN, scaledSet);
267*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < kM * kN; ++i) {
268*c8dee2aaSAndroid Build Coastguard Worker                 scaledSet[i].fDstRect.fLeft *= scale.fX;
269*c8dee2aaSAndroid Build Coastguard Worker                 scaledSet[i].fDstRect.fTop *= scale.fY;
270*c8dee2aaSAndroid Build Coastguard Worker                 scaledSet[i].fDstRect.fRight *= scale.fX;
271*c8dee2aaSAndroid Build Coastguard Worker                 scaledSet[i].fDstRect.fBottom *= scale.fY;
272*c8dee2aaSAndroid Build Coastguard Worker                 scaledSet[i].fAlpha = 0 == (i % 3) ? 0.4f : 1.f;
273*c8dee2aaSAndroid Build Coastguard Worker             }
274*c8dee2aaSAndroid Build Coastguard Worker             for (size_t m = 0; m < std::size(matrices); ++m) {
275*c8dee2aaSAndroid Build Coastguard Worker                 canvas->save();
276*c8dee2aaSAndroid Build Coastguard Worker                 canvas->concat(matrices[m]);
277*c8dee2aaSAndroid Build Coastguard Worker                 canvas->experimental_DrawEdgeAAImageSet(scaledSet, kM * kN, nullptr, nullptr,
278*c8dee2aaSAndroid Build Coastguard Worker                                                         SkSamplingOptions(SkFilterMode::kLinear),
279*c8dee2aaSAndroid Build Coastguard Worker                                                         &paint, SkCanvas::kFast_SrcRectConstraint);
280*c8dee2aaSAndroid Build Coastguard Worker                 canvas->restore();
281*c8dee2aaSAndroid Build Coastguard Worker                 canvas->translate(kTranslate, 0);
282*c8dee2aaSAndroid Build Coastguard Worker             }
283*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
284*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(0, kTranslate);
285*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
286*c8dee2aaSAndroid Build Coastguard Worker         }
287*c8dee2aaSAndroid Build Coastguard Worker     }
288*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kM = 2;
289*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kN = 2;
290*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kTileW = 40;
291*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kTileH = 50;
292*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas::ImageSetEntry fSet[kM * kN];
293*c8dee2aaSAndroid Build Coastguard Worker };
294*c8dee2aaSAndroid Build Coastguard Worker 
295*c8dee2aaSAndroid Build Coastguard Worker // This GM exercises alpha-only and color textures being combined correctly with the paint's color.
296*c8dee2aaSAndroid Build Coastguard Worker class DrawImageSetAlphaOnlyGM : public GM {
297*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const298*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("draw_image_set_alpha_only"); }
getISize()299*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {kM * kTileW, 2 * kN * kTileH}; }
300*c8dee2aaSAndroid Build Coastguard Worker 
onGpuSetup(SkCanvas * canvas,SkString *,GraphiteTestContext *)301*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onGpuSetup(SkCanvas* canvas, SkString*, GraphiteTestContext*) override {
302*c8dee2aaSAndroid Build Coastguard Worker         auto direct = GrAsDirectContext(canvas->recordingContext());
303*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
304*c8dee2aaSAndroid Build Coastguard Worker         auto recorder = canvas->recorder();
305*c8dee2aaSAndroid Build Coastguard Worker #endif
306*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkColor kColors[] = {SK_ColorBLUE, SK_ColorTRANSPARENT,
307*c8dee2aaSAndroid Build Coastguard Worker                                               SK_ColorRED,  SK_ColorTRANSPARENT};
308*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkColor kBGColor = SkColorSetARGB(128, 128, 128, 128);
309*c8dee2aaSAndroid Build Coastguard Worker         make_image_tiles(kTileW, kTileH, kM, kN, kColors, fSet, kBGColor);
310*c8dee2aaSAndroid Build Coastguard Worker 
311*c8dee2aaSAndroid Build Coastguard Worker         // Modify the alpha of the entries, decreasing by column, and convert even rows to
312*c8dee2aaSAndroid Build Coastguard Worker         // alpha-only textures.
313*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkColorSpace> alphaSpace = SkColorSpace::MakeSRGB();
314*c8dee2aaSAndroid Build Coastguard Worker         for (int y = 0; y < kN; ++y) {
315*c8dee2aaSAndroid Build Coastguard Worker             for (int x = 0; x < kM; ++x) {
316*c8dee2aaSAndroid Build Coastguard Worker                 int i = y * kM + x;
317*c8dee2aaSAndroid Build Coastguard Worker                 fSet[i].fAlpha = (kM - x) / (float) kM;
318*c8dee2aaSAndroid Build Coastguard Worker                 if (y % 2 == 0) {
319*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
320*c8dee2aaSAndroid Build Coastguard Worker                     if (recorder) {
321*c8dee2aaSAndroid Build Coastguard Worker                         fSet[i].fImage = fSet[i].fImage->makeColorTypeAndColorSpace(
322*c8dee2aaSAndroid Build Coastguard Worker                                 recorder, kAlpha_8_SkColorType, alphaSpace, {});
323*c8dee2aaSAndroid Build Coastguard Worker                     } else
324*c8dee2aaSAndroid Build Coastguard Worker #endif
325*c8dee2aaSAndroid Build Coastguard Worker                     {
326*c8dee2aaSAndroid Build Coastguard Worker                         fSet[i].fImage = fSet[i].fImage->makeColorTypeAndColorSpace(
327*c8dee2aaSAndroid Build Coastguard Worker                                 direct, kAlpha_8_SkColorType, alphaSpace);
328*c8dee2aaSAndroid Build Coastguard Worker                     }
329*c8dee2aaSAndroid Build Coastguard Worker                 }
330*c8dee2aaSAndroid Build Coastguard Worker             }
331*c8dee2aaSAndroid Build Coastguard Worker         }
332*c8dee2aaSAndroid Build Coastguard Worker         return skiagm::DrawResult::kOk;
333*c8dee2aaSAndroid Build Coastguard Worker     }
334*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas)335*c8dee2aaSAndroid Build Coastguard Worker     void onDraw(SkCanvas* canvas) override {
336*c8dee2aaSAndroid Build Coastguard Worker         ToolUtils::draw_checkerboard(canvas, SK_ColorGRAY, SK_ColorDKGRAY, 25);
337*c8dee2aaSAndroid Build Coastguard Worker 
338*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
339*c8dee2aaSAndroid Build Coastguard Worker         paint.setBlendMode(SkBlendMode::kSrcOver);
340*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor4f({0.2f, 0.8f, 0.4f, 1.f}); // colorizes even rows, no effect on odd rows
341*c8dee2aaSAndroid Build Coastguard Worker 
342*c8dee2aaSAndroid Build Coastguard Worker         // Top rows use experimental edge set API
343*c8dee2aaSAndroid Build Coastguard Worker         canvas->experimental_DrawEdgeAAImageSet(fSet, kM * kN, nullptr, nullptr,
344*c8dee2aaSAndroid Build Coastguard Worker                                                 SkSamplingOptions(SkFilterMode::kLinear), &paint,
345*c8dee2aaSAndroid Build Coastguard Worker                                                 SkCanvas::kFast_SrcRectConstraint);
346*c8dee2aaSAndroid Build Coastguard Worker 
347*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(0.f, kN * kTileH);
348*c8dee2aaSAndroid Build Coastguard Worker 
349*c8dee2aaSAndroid Build Coastguard Worker         // Bottom rows draw each image from the set using the regular API
350*c8dee2aaSAndroid Build Coastguard Worker         for (int y = 0; y < kN; ++y) {
351*c8dee2aaSAndroid Build Coastguard Worker             for (int x = 0; x < kM; ++x) {
352*c8dee2aaSAndroid Build Coastguard Worker                 int i = y * kM + x;
353*c8dee2aaSAndroid Build Coastguard Worker                 SkPaint entryPaint = paint;
354*c8dee2aaSAndroid Build Coastguard Worker                 entryPaint.setAlphaf(fSet[i].fAlpha * paint.getAlphaf());
355*c8dee2aaSAndroid Build Coastguard Worker                 sk_sp<SkImage> orig = sk_ref_sp(const_cast<SkImage*>(fSet[i].fImage.get()));
356*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawImageRect(ToolUtils::MakeTextureImage(canvas, std::move(orig)),
357*c8dee2aaSAndroid Build Coastguard Worker                                       fSet[i].fSrcRect, fSet[i].fDstRect,
358*c8dee2aaSAndroid Build Coastguard Worker                                       SkSamplingOptions(), &entryPaint,
359*c8dee2aaSAndroid Build Coastguard Worker                                       SkCanvas::kFast_SrcRectConstraint);
360*c8dee2aaSAndroid Build Coastguard Worker             }
361*c8dee2aaSAndroid Build Coastguard Worker         }
362*c8dee2aaSAndroid Build Coastguard Worker     }
363*c8dee2aaSAndroid Build Coastguard Worker 
364*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kM = 4;
365*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kN = 4;
366*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kTileW = 50;
367*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr int kTileH = 50;
368*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas::ImageSetEntry fSet[kM * kN];
369*c8dee2aaSAndroid Build Coastguard Worker };
370*c8dee2aaSAndroid Build Coastguard Worker 
371*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new DrawImageSetGM();)
372*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new DrawImageSetRectToRectGM();)
373*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new DrawImageSetAlphaOnlyGM();)
374*c8dee2aaSAndroid Build Coastguard Worker 
375*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skiagm
376