1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2013 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/SkBitmap.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlurTypes.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMaskFilter.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/SkTiledImageUtils.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrContextOptions.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTDArray.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkBlurMask.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
33*c8dee2aaSAndroid Build Coastguard Worker
34*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
35*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/ContextOptions.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ContextOptionsPriv.h"
37*c8dee2aaSAndroid Build Coastguard Worker #endif
38*c8dee2aaSAndroid Build Coastguard Worker
39*c8dee2aaSAndroid Build Coastguard Worker /** Creates an image with two one-pixel wide borders around a checkerboard. The checkerboard is 2x2
40*c8dee2aaSAndroid Build Coastguard Worker checks where each check has as many pixels as is necessary to fill the interior. It returns
41*c8dee2aaSAndroid Build Coastguard Worker the image and a src rect that bounds the checkerboard portion. */
make_ringed_image(SkCanvas * canvas,int width,int height)42*c8dee2aaSAndroid Build Coastguard Worker std::tuple<sk_sp<SkImage>, SkRect> make_ringed_image(SkCanvas* canvas, int width, int height) {
43*c8dee2aaSAndroid Build Coastguard Worker
44*c8dee2aaSAndroid Build Coastguard Worker // These are kRGBA_8888_SkColorType values.
45*c8dee2aaSAndroid Build Coastguard Worker static constexpr uint32_t kOuterRingColor = 0xFFFF0000,
46*c8dee2aaSAndroid Build Coastguard Worker kInnerRingColor = 0xFF0000FF,
47*c8dee2aaSAndroid Build Coastguard Worker kCheckColor1 = 0xFF000000,
48*c8dee2aaSAndroid Build Coastguard Worker kCheckColor2 = 0xFFFFFFFF;
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(0 == width % 2 && 0 == height % 2);
51*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(width >= 6 && height >= 6);
52*c8dee2aaSAndroid Build Coastguard Worker
53*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo info = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
54*c8dee2aaSAndroid Build Coastguard Worker kPremul_SkAlphaType);
55*c8dee2aaSAndroid Build Coastguard Worker size_t rowBytes = SkAlign4(info.minRowBytes());
56*c8dee2aaSAndroid Build Coastguard Worker SkBitmap bitmap;
57*c8dee2aaSAndroid Build Coastguard Worker bitmap.allocPixels(info, rowBytes);
58*c8dee2aaSAndroid Build Coastguard Worker
59*c8dee2aaSAndroid Build Coastguard Worker uint32_t* scanline = bitmap.getAddr32(0, 0);
60*c8dee2aaSAndroid Build Coastguard Worker for (int x = 0; x < width; ++x) {
61*c8dee2aaSAndroid Build Coastguard Worker scanline[x] = kOuterRingColor;
62*c8dee2aaSAndroid Build Coastguard Worker }
63*c8dee2aaSAndroid Build Coastguard Worker scanline = bitmap.getAddr32(0, 1);
64*c8dee2aaSAndroid Build Coastguard Worker scanline[0] = kOuterRingColor;
65*c8dee2aaSAndroid Build Coastguard Worker for (int x = 1; x < width - 1; ++x) {
66*c8dee2aaSAndroid Build Coastguard Worker scanline[x] = kInnerRingColor;
67*c8dee2aaSAndroid Build Coastguard Worker }
68*c8dee2aaSAndroid Build Coastguard Worker scanline[width - 1] = kOuterRingColor;
69*c8dee2aaSAndroid Build Coastguard Worker
70*c8dee2aaSAndroid Build Coastguard Worker for (int y = 2; y < height / 2; ++y) {
71*c8dee2aaSAndroid Build Coastguard Worker scanline = bitmap.getAddr32(0, y);
72*c8dee2aaSAndroid Build Coastguard Worker scanline[0] = kOuterRingColor;
73*c8dee2aaSAndroid Build Coastguard Worker scanline[1] = kInnerRingColor;
74*c8dee2aaSAndroid Build Coastguard Worker for (int x = 2; x < width / 2; ++x) {
75*c8dee2aaSAndroid Build Coastguard Worker scanline[x] = kCheckColor1;
76*c8dee2aaSAndroid Build Coastguard Worker }
77*c8dee2aaSAndroid Build Coastguard Worker for (int x = width / 2; x < width - 2; ++x) {
78*c8dee2aaSAndroid Build Coastguard Worker scanline[x] = kCheckColor2;
79*c8dee2aaSAndroid Build Coastguard Worker }
80*c8dee2aaSAndroid Build Coastguard Worker scanline[width - 2] = kInnerRingColor;
81*c8dee2aaSAndroid Build Coastguard Worker scanline[width - 1] = kOuterRingColor;
82*c8dee2aaSAndroid Build Coastguard Worker }
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker for (int y = height / 2; y < height - 2; ++y) {
85*c8dee2aaSAndroid Build Coastguard Worker scanline = bitmap.getAddr32(0, y);
86*c8dee2aaSAndroid Build Coastguard Worker scanline[0] = kOuterRingColor;
87*c8dee2aaSAndroid Build Coastguard Worker scanline[1] = kInnerRingColor;
88*c8dee2aaSAndroid Build Coastguard Worker for (int x = 2; x < width / 2; ++x) {
89*c8dee2aaSAndroid Build Coastguard Worker scanline[x] = kCheckColor2;
90*c8dee2aaSAndroid Build Coastguard Worker }
91*c8dee2aaSAndroid Build Coastguard Worker for (int x = width / 2; x < width - 2; ++x) {
92*c8dee2aaSAndroid Build Coastguard Worker scanline[x] = kCheckColor1;
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker scanline[width - 2] = kInnerRingColor;
95*c8dee2aaSAndroid Build Coastguard Worker scanline[width - 1] = kOuterRingColor;
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker
98*c8dee2aaSAndroid Build Coastguard Worker scanline = bitmap.getAddr32(0, height - 2);
99*c8dee2aaSAndroid Build Coastguard Worker scanline[0] = kOuterRingColor;
100*c8dee2aaSAndroid Build Coastguard Worker for (int x = 1; x < width - 1; ++x) {
101*c8dee2aaSAndroid Build Coastguard Worker scanline[x] = kInnerRingColor;
102*c8dee2aaSAndroid Build Coastguard Worker }
103*c8dee2aaSAndroid Build Coastguard Worker scanline[width - 1] = kOuterRingColor;
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Worker scanline = bitmap.getAddr32(0, height - 1);
106*c8dee2aaSAndroid Build Coastguard Worker for (int x = 0; x < width; ++x) {
107*c8dee2aaSAndroid Build Coastguard Worker scanline[x] = kOuterRingColor;
108*c8dee2aaSAndroid Build Coastguard Worker }
109*c8dee2aaSAndroid Build Coastguard Worker bitmap.setImmutable();
110*c8dee2aaSAndroid Build Coastguard Worker return { bitmap.asImage(), SkRect::Make({2, 2, width - 2, height - 2})};
111*c8dee2aaSAndroid Build Coastguard Worker }
112*c8dee2aaSAndroid Build Coastguard Worker
113*c8dee2aaSAndroid Build Coastguard Worker /**
114*c8dee2aaSAndroid Build Coastguard Worker * These GMs exercise the behavior of the drawImageRect and its SrcRectConstraint parameter. They
115*c8dee2aaSAndroid Build Coastguard Worker * tests various matrices, filter qualities, and interaction with mask filters. They also exercise
116*c8dee2aaSAndroid Build Coastguard Worker * the tiling image draws of SkGpuDevice by overriding the maximum texture size of the GrContext.
117*c8dee2aaSAndroid Build Coastguard Worker */
118*c8dee2aaSAndroid Build Coastguard Worker class SrcRectConstraintGM : public skiagm::GM {
119*c8dee2aaSAndroid Build Coastguard Worker public:
SrcRectConstraintGM(const char * shortName,SkCanvas::SrcRectConstraint constraint,bool manual)120*c8dee2aaSAndroid Build Coastguard Worker SrcRectConstraintGM(const char* shortName, SkCanvas::SrcRectConstraint constraint, bool manual)
121*c8dee2aaSAndroid Build Coastguard Worker : fShortName(shortName)
122*c8dee2aaSAndroid Build Coastguard Worker , fConstraint(constraint)
123*c8dee2aaSAndroid Build Coastguard Worker , fManual(manual) {
124*c8dee2aaSAndroid Build Coastguard Worker // Make sure GPU SkSurfaces can be created for this GM.
125*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->getISize().width() <= kMaxTextureSize &&
126*c8dee2aaSAndroid Build Coastguard Worker this->getISize().height() <= kMaxTextureSize);
127*c8dee2aaSAndroid Build Coastguard Worker }
128*c8dee2aaSAndroid Build Coastguard Worker
129*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const130*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return fShortName; }
getISize()131*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return SkISize::Make(800, 1000); }
132*c8dee2aaSAndroid Build Coastguard Worker
drawImage(SkCanvas * canvas,sk_sp<SkImage> image,SkRect srcRect,SkRect dstRect,const SkSamplingOptions & sampling,SkPaint * paint)133*c8dee2aaSAndroid Build Coastguard Worker void drawImage(SkCanvas* canvas, sk_sp<SkImage> image, SkRect srcRect, SkRect dstRect,
134*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions& sampling, SkPaint* paint) {
135*c8dee2aaSAndroid Build Coastguard Worker if (fManual) {
136*c8dee2aaSAndroid Build Coastguard Worker SkTiledImageUtils::DrawImageRect(canvas, image.get(), srcRect, dstRect,
137*c8dee2aaSAndroid Build Coastguard Worker sampling, paint, fConstraint);
138*c8dee2aaSAndroid Build Coastguard Worker } else {
139*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImageRect(image.get(), srcRect, dstRect, sampling, paint, fConstraint);
140*c8dee2aaSAndroid Build Coastguard Worker }
141*c8dee2aaSAndroid Build Coastguard Worker }
142*c8dee2aaSAndroid Build Coastguard Worker
143*c8dee2aaSAndroid Build Coastguard Worker // Draw the area of interest of the small image
drawCase1(SkCanvas * canvas,int transX,int transY,bool aa,const SkSamplingOptions & sampling)144*c8dee2aaSAndroid Build Coastguard Worker void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
145*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions& sampling) {
146*c8dee2aaSAndroid Build Coastguard Worker SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
147*c8dee2aaSAndroid Build Coastguard Worker SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
148*c8dee2aaSAndroid Build Coastguard Worker
149*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
150*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorBLUE);
151*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(aa);
152*c8dee2aaSAndroid Build Coastguard Worker
153*c8dee2aaSAndroid Build Coastguard Worker this->drawImage(canvas, fSmallImage, fSmallSrcRect, dst, sampling, &paint);
154*c8dee2aaSAndroid Build Coastguard Worker }
155*c8dee2aaSAndroid Build Coastguard Worker
156*c8dee2aaSAndroid Build Coastguard Worker // Draw the area of interest of the large image
drawCase2(SkCanvas * canvas,int transX,int transY,bool aa,const SkSamplingOptions & sampling)157*c8dee2aaSAndroid Build Coastguard Worker void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
158*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions& sampling) {
159*c8dee2aaSAndroid Build Coastguard Worker SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
160*c8dee2aaSAndroid Build Coastguard Worker SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
161*c8dee2aaSAndroid Build Coastguard Worker
162*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
163*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorBLUE);
164*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(aa);
165*c8dee2aaSAndroid Build Coastguard Worker
166*c8dee2aaSAndroid Build Coastguard Worker this->drawImage(canvas, fBigImage, fBigSrcRect, dst, sampling, &paint);
167*c8dee2aaSAndroid Build Coastguard Worker }
168*c8dee2aaSAndroid Build Coastguard Worker
169*c8dee2aaSAndroid Build Coastguard Worker // Draw upper-left 1/4 of the area of interest of the large image
drawCase3(SkCanvas * canvas,int transX,int transY,bool aa,const SkSamplingOptions & sampling)170*c8dee2aaSAndroid Build Coastguard Worker void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
171*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions& sampling) {
172*c8dee2aaSAndroid Build Coastguard Worker SkRect src = SkRect::MakeXYWH(fBigSrcRect.fLeft,
173*c8dee2aaSAndroid Build Coastguard Worker fBigSrcRect.fTop,
174*c8dee2aaSAndroid Build Coastguard Worker fBigSrcRect.width()/2,
175*c8dee2aaSAndroid Build Coastguard Worker fBigSrcRect.height()/2);
176*c8dee2aaSAndroid Build Coastguard Worker SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
177*c8dee2aaSAndroid Build Coastguard Worker SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
178*c8dee2aaSAndroid Build Coastguard Worker
179*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
180*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorBLUE);
181*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(aa);
182*c8dee2aaSAndroid Build Coastguard Worker
183*c8dee2aaSAndroid Build Coastguard Worker this->drawImage(canvas, fBigImage, src, dst, sampling, &paint);
184*c8dee2aaSAndroid Build Coastguard Worker }
185*c8dee2aaSAndroid Build Coastguard Worker
186*c8dee2aaSAndroid Build Coastguard Worker // Draw the area of interest of the small image with a normal blur
drawCase4(SkCanvas * canvas,int transX,int transY,bool aa,const SkSamplingOptions & sampling)187*c8dee2aaSAndroid Build Coastguard Worker void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
188*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions& sampling) {
189*c8dee2aaSAndroid Build Coastguard Worker SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
190*c8dee2aaSAndroid Build Coastguard Worker SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
191*c8dee2aaSAndroid Build Coastguard Worker
192*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
193*c8dee2aaSAndroid Build Coastguard Worker paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle,
194*c8dee2aaSAndroid Build Coastguard Worker SkBlurMask::ConvertRadiusToSigma(3)));
195*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorBLUE);
196*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(aa);
197*c8dee2aaSAndroid Build Coastguard Worker
198*c8dee2aaSAndroid Build Coastguard Worker this->drawImage(canvas, fSmallImage, fSmallSrcRect, dst, sampling, &paint);
199*c8dee2aaSAndroid Build Coastguard Worker }
200*c8dee2aaSAndroid Build Coastguard Worker
201*c8dee2aaSAndroid Build Coastguard Worker // Draw the area of interest of the small image with a outer blur
drawCase5(SkCanvas * canvas,int transX,int transY,bool aa,const SkSamplingOptions & sampling)202*c8dee2aaSAndroid Build Coastguard Worker void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
203*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions& sampling) {
204*c8dee2aaSAndroid Build Coastguard Worker SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
205*c8dee2aaSAndroid Build Coastguard Worker SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
206*c8dee2aaSAndroid Build Coastguard Worker
207*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
208*c8dee2aaSAndroid Build Coastguard Worker paint.setMaskFilter(SkMaskFilter::MakeBlur(kOuter_SkBlurStyle,
209*c8dee2aaSAndroid Build Coastguard Worker SkBlurMask::ConvertRadiusToSigma(7)));
210*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorBLUE);
211*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(aa);
212*c8dee2aaSAndroid Build Coastguard Worker
213*c8dee2aaSAndroid Build Coastguard Worker this->drawImage(canvas, fSmallImage, fSmallSrcRect, dst, sampling, &paint);
214*c8dee2aaSAndroid Build Coastguard Worker }
215*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)216*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
217*c8dee2aaSAndroid Build Coastguard Worker if (!fSmallImage) {
218*c8dee2aaSAndroid Build Coastguard Worker std::tie(fBigImage, fBigSrcRect) = make_ringed_image(canvas,
219*c8dee2aaSAndroid Build Coastguard Worker 2*kMaxTextureSize,
220*c8dee2aaSAndroid Build Coastguard Worker 2*kMaxTextureSize);
221*c8dee2aaSAndroid Build Coastguard Worker std::tie(fSmallImage, fSmallSrcRect) = make_ringed_image(canvas,
222*c8dee2aaSAndroid Build Coastguard Worker kSmallSize, kSmallSize);
223*c8dee2aaSAndroid Build Coastguard Worker }
224*c8dee2aaSAndroid Build Coastguard Worker
225*c8dee2aaSAndroid Build Coastguard Worker canvas->clear(SK_ColorGRAY);
226*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkMatrix> matrices;
227*c8dee2aaSAndroid Build Coastguard Worker // Draw with identity
228*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back(SkMatrix::I());
229*c8dee2aaSAndroid Build Coastguard Worker
230*c8dee2aaSAndroid Build Coastguard Worker // Draw with rotation and scale down in x, up in y.
231*c8dee2aaSAndroid Build Coastguard Worker SkMatrix m;
232*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
233*c8dee2aaSAndroid Build Coastguard Worker m.setTranslate(0, kBottom);
234*c8dee2aaSAndroid Build Coastguard Worker m.preRotate(15.f, 0, kBottom + kBlockSpacing);
235*c8dee2aaSAndroid Build Coastguard Worker m.preScale(0.71f, 1.22f);
236*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back(m);
237*c8dee2aaSAndroid Build Coastguard Worker
238*c8dee2aaSAndroid Build Coastguard Worker // Align the next set with the middle of the previous in y, translated to the right in x.
239*c8dee2aaSAndroid Build Coastguard Worker SkPoint corners[] = {{0, 0}, {0, kBottom}, {kWidth, kBottom}, {kWidth, 0}};
240*c8dee2aaSAndroid Build Coastguard Worker matrices.back().mapPoints(corners, 4);
241*c8dee2aaSAndroid Build Coastguard Worker m.setTranslate(std::max({corners[0].fX, corners[1].fX, corners[2].fX, corners[3].fX}),
242*c8dee2aaSAndroid Build Coastguard Worker (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4);
243*c8dee2aaSAndroid Build Coastguard Worker m.preScale(0.2f, 0.2f);
244*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back(m);
245*c8dee2aaSAndroid Build Coastguard Worker
246*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions none(SkFilterMode::kNearest);
247*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions low(SkFilterMode::kLinear);
248*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions high(SkCubicResampler::Mitchell());
249*c8dee2aaSAndroid Build Coastguard Worker
250*c8dee2aaSAndroid Build Coastguard Worker SkScalar maxX = 0;
251*c8dee2aaSAndroid Build Coastguard Worker for (bool antiAlias : {false, true}) {
252*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
253*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(maxX, 0);
254*c8dee2aaSAndroid Build Coastguard Worker for (const SkMatrix& matrix : matrices) {
255*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
256*c8dee2aaSAndroid Build Coastguard Worker canvas->concat(matrix);
257*c8dee2aaSAndroid Build Coastguard Worker
258*c8dee2aaSAndroid Build Coastguard Worker // First draw a column with no filtering
259*c8dee2aaSAndroid Build Coastguard Worker this->drawCase1(canvas, kCol0X, kRow0Y, antiAlias, none);
260*c8dee2aaSAndroid Build Coastguard Worker this->drawCase2(canvas, kCol0X, kRow1Y, antiAlias, none);
261*c8dee2aaSAndroid Build Coastguard Worker this->drawCase3(canvas, kCol0X, kRow2Y, antiAlias, none);
262*c8dee2aaSAndroid Build Coastguard Worker this->drawCase4(canvas, kCol0X, kRow3Y, antiAlias, none);
263*c8dee2aaSAndroid Build Coastguard Worker this->drawCase5(canvas, kCol0X, kRow4Y, antiAlias, none);
264*c8dee2aaSAndroid Build Coastguard Worker
265*c8dee2aaSAndroid Build Coastguard Worker // Then draw a column with low filtering
266*c8dee2aaSAndroid Build Coastguard Worker this->drawCase1(canvas, kCol1X, kRow0Y, antiAlias, low);
267*c8dee2aaSAndroid Build Coastguard Worker this->drawCase2(canvas, kCol1X, kRow1Y, antiAlias, low);
268*c8dee2aaSAndroid Build Coastguard Worker this->drawCase3(canvas, kCol1X, kRow2Y, antiAlias, low);
269*c8dee2aaSAndroid Build Coastguard Worker this->drawCase4(canvas, kCol1X, kRow3Y, antiAlias, low);
270*c8dee2aaSAndroid Build Coastguard Worker this->drawCase5(canvas, kCol1X, kRow4Y, antiAlias, low);
271*c8dee2aaSAndroid Build Coastguard Worker
272*c8dee2aaSAndroid Build Coastguard Worker // Then draw a column with high filtering. Skip it if in kStrict mode and MIP
273*c8dee2aaSAndroid Build Coastguard Worker // mapping will be used. On GPU we allow bleeding at non-base levels because
274*c8dee2aaSAndroid Build Coastguard Worker // building a new MIP chain for the subset is expensive.
275*c8dee2aaSAndroid Build Coastguard Worker SkScalar scales[2];
276*c8dee2aaSAndroid Build Coastguard Worker SkAssertResult(matrix.getMinMaxScales(scales));
277*c8dee2aaSAndroid Build Coastguard Worker if (fConstraint != SkCanvas::kStrict_SrcRectConstraint || scales[0] >= 1.f) {
278*c8dee2aaSAndroid Build Coastguard Worker this->drawCase1(canvas, kCol2X, kRow0Y, antiAlias, high);
279*c8dee2aaSAndroid Build Coastguard Worker this->drawCase2(canvas, kCol2X, kRow1Y, antiAlias, high);
280*c8dee2aaSAndroid Build Coastguard Worker this->drawCase3(canvas, kCol2X, kRow2Y, antiAlias, high);
281*c8dee2aaSAndroid Build Coastguard Worker this->drawCase4(canvas, kCol2X, kRow3Y, antiAlias, high);
282*c8dee2aaSAndroid Build Coastguard Worker this->drawCase5(canvas, kCol2X, kRow4Y, antiAlias, high);
283*c8dee2aaSAndroid Build Coastguard Worker }
284*c8dee2aaSAndroid Build Coastguard Worker
285*c8dee2aaSAndroid Build Coastguard Worker SkPoint innerCorners[] = {{0, 0}, {0, kBottom}, {kWidth, kBottom}, {kWidth, 0}};
286*c8dee2aaSAndroid Build Coastguard Worker matrix.mapPoints(innerCorners, 4);
287*c8dee2aaSAndroid Build Coastguard Worker SkScalar x = kBlockSize + std::max({innerCorners[0].fX, innerCorners[1].fX,
288*c8dee2aaSAndroid Build Coastguard Worker innerCorners[2].fX, innerCorners[3].fX});
289*c8dee2aaSAndroid Build Coastguard Worker maxX = std::max(maxX, x);
290*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
291*c8dee2aaSAndroid Build Coastguard Worker }
292*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
293*c8dee2aaSAndroid Build Coastguard Worker }
294*c8dee2aaSAndroid Build Coastguard Worker }
295*c8dee2aaSAndroid Build Coastguard Worker
modifyGrContextOptions(GrContextOptions * options)296*c8dee2aaSAndroid Build Coastguard Worker void modifyGrContextOptions(GrContextOptions* options) override {
297*c8dee2aaSAndroid Build Coastguard Worker options->fMaxTextureSizeOverride = kMaxTextureSize;
298*c8dee2aaSAndroid Build Coastguard Worker }
299*c8dee2aaSAndroid Build Coastguard Worker
300*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
modifyGraphiteContextOptions(skgpu::graphite::ContextOptions * options) const301*c8dee2aaSAndroid Build Coastguard Worker void modifyGraphiteContextOptions(skgpu::graphite::ContextOptions* options) const override {
302*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(options->fOptionsPriv);
303*c8dee2aaSAndroid Build Coastguard Worker options->fOptionsPriv->fMaxTextureSizeOverride = kMaxTextureSize;
304*c8dee2aaSAndroid Build Coastguard Worker }
305*c8dee2aaSAndroid Build Coastguard Worker #endif
306*c8dee2aaSAndroid Build Coastguard Worker
307*c8dee2aaSAndroid Build Coastguard Worker private:
308*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kBlockSize = 70;
309*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kBlockSpacing = 12;
310*c8dee2aaSAndroid Build Coastguard Worker
311*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kCol0X = kBlockSpacing;
312*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
313*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
314*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kWidth = 4*kBlockSpacing + 3*kBlockSize;
315*c8dee2aaSAndroid Build Coastguard Worker
316*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kRow0Y = kBlockSpacing;
317*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
318*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
319*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
320*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
321*c8dee2aaSAndroid Build Coastguard Worker
322*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kSmallSize = 6;
323*c8dee2aaSAndroid Build Coastguard Worker // This must be at least as large as the GM width and height so that a surface can be made, and
324*c8dee2aaSAndroid Build Coastguard Worker // a power-of-2 to account for any approx-fitting that the backend may perform.
325*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kMaxTextureSize = 1024;
326*c8dee2aaSAndroid Build Coastguard Worker
327*c8dee2aaSAndroid Build Coastguard Worker SkString fShortName;
328*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> fBigImage;
329*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> fSmallImage;
330*c8dee2aaSAndroid Build Coastguard Worker SkRect fBigSrcRect;
331*c8dee2aaSAndroid Build Coastguard Worker SkRect fSmallSrcRect;
332*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::SrcRectConstraint fConstraint;
333*c8dee2aaSAndroid Build Coastguard Worker bool fManual;
334*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GM;
335*c8dee2aaSAndroid Build Coastguard Worker };
336*c8dee2aaSAndroid Build Coastguard Worker
337*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new SrcRectConstraintGM("strict_constraint_no_red_allowed",
338*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::kStrict_SrcRectConstraint,
339*c8dee2aaSAndroid Build Coastguard Worker /* manual= */ false););
340*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new SrcRectConstraintGM("strict_constraint_no_red_allowed_manual",
341*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::kStrict_SrcRectConstraint,
342*c8dee2aaSAndroid Build Coastguard Worker /* manual= */ true););
343*c8dee2aaSAndroid Build Coastguard Worker
344*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new SrcRectConstraintGM("strict_constraint_batch_no_red_allowed",
345*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::kStrict_SrcRectConstraint,
346*c8dee2aaSAndroid Build Coastguard Worker /* manual= */ false););
347*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new SrcRectConstraintGM("strict_constraint_batch_no_red_allowed_manual",
348*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::kStrict_SrcRectConstraint,
349*c8dee2aaSAndroid Build Coastguard Worker /* manual= */ true););
350*c8dee2aaSAndroid Build Coastguard Worker
351*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new SrcRectConstraintGM("fast_constraint_red_is_allowed",
352*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::kFast_SrcRectConstraint,
353*c8dee2aaSAndroid Build Coastguard Worker /* manual= */ false););
354*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new SrcRectConstraintGM("fast_constraint_red_is_allowed_manual",
355*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::kFast_SrcRectConstraint,
356*c8dee2aaSAndroid Build Coastguard Worker /* manual= */ true););
357*c8dee2aaSAndroid Build Coastguard Worker
358*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
359*c8dee2aaSAndroid Build Coastguard Worker
360*c8dee2aaSAndroid Build Coastguard Worker // Construct an image and return the inner "src" rect. Build the image such that the interior is
361*c8dee2aaSAndroid Build Coastguard Worker // blue, with a margin of blue (2px) but then an outer margin of red.
362*c8dee2aaSAndroid Build Coastguard Worker //
363*c8dee2aaSAndroid Build Coastguard Worker // Show that kFast_SrcRectConstraint sees even the red margin (due to mipmapping) when the image
364*c8dee2aaSAndroid Build Coastguard Worker // is scaled down far enough.
365*c8dee2aaSAndroid Build Coastguard Worker //
make_image(SkCanvas * canvas,SkRect * srcR)366*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkImage> make_image(SkCanvas* canvas, SkRect* srcR) {
367*c8dee2aaSAndroid Build Coastguard Worker // Intentially making the size a power of 2 to avoid the noise from how different GPUs will
368*c8dee2aaSAndroid Build Coastguard Worker // produce different mipmap filtering when we have an odd sized texture.
369*c8dee2aaSAndroid Build Coastguard Worker const int N = 10 + 2 + 8 + 2 + 10;
370*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
371*c8dee2aaSAndroid Build Coastguard Worker auto surface = ToolUtils::makeSurface(canvas, info);
372*c8dee2aaSAndroid Build Coastguard Worker SkCanvas* c = surface->getCanvas();
373*c8dee2aaSAndroid Build Coastguard Worker SkRect r = SkRect::MakeIWH(info.width(), info.height());
374*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
375*c8dee2aaSAndroid Build Coastguard Worker
376*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorRED);
377*c8dee2aaSAndroid Build Coastguard Worker c->drawRect(r, paint);
378*c8dee2aaSAndroid Build Coastguard Worker r.inset(10, 10);
379*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorBLUE);
380*c8dee2aaSAndroid Build Coastguard Worker c->drawRect(r, paint);
381*c8dee2aaSAndroid Build Coastguard Worker
382*c8dee2aaSAndroid Build Coastguard Worker *srcR = r.makeInset(2, 2);
383*c8dee2aaSAndroid Build Coastguard Worker return surface->makeImageSnapshot();
384*c8dee2aaSAndroid Build Coastguard Worker }
385*c8dee2aaSAndroid Build Coastguard Worker
386*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(bleed_downscale, canvas, 360, 240) {
387*c8dee2aaSAndroid Build Coastguard Worker SkRect src;
388*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> img = make_image(canvas, &src);
389*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
390*c8dee2aaSAndroid Build Coastguard Worker
391*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(10, 10);
392*c8dee2aaSAndroid Build Coastguard Worker
393*c8dee2aaSAndroid Build Coastguard Worker const SkCanvas::SrcRectConstraint constraints[] = {
394*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint
395*c8dee2aaSAndroid Build Coastguard Worker };
396*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions samplings[] = {
397*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions(SkFilterMode::kNearest),
398*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions(SkFilterMode::kLinear),
399*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
400*c8dee2aaSAndroid Build Coastguard Worker };
401*c8dee2aaSAndroid Build Coastguard Worker for (auto constraint : constraints) {
402*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
403*c8dee2aaSAndroid Build Coastguard Worker for (auto sampling : samplings) {
404*c8dee2aaSAndroid Build Coastguard Worker auto surf = ToolUtils::makeSurface(canvas, SkImageInfo::MakeN32Premul(1, 1));
405*c8dee2aaSAndroid Build Coastguard Worker surf->getCanvas()->drawImageRect(img, src, SkRect::MakeWH(1, 1), sampling,
406*c8dee2aaSAndroid Build Coastguard Worker nullptr, constraint);
407*c8dee2aaSAndroid Build Coastguard Worker // now blow up the 1 pixel result
408*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImageRect(surf->makeImageSnapshot(), SkRect::MakeWH(100, 100),
409*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions());
410*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(120, 0);
411*c8dee2aaSAndroid Build Coastguard Worker }
412*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
413*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, 120);
414*c8dee2aaSAndroid Build Coastguard Worker }
415*c8dee2aaSAndroid Build Coastguard Worker }
416