blob: bc1b10f39c88058b88754432a80f508ac6e7e218 [file] [log] [blame]
robertphillips@google.comaaa9b292013-07-25 21:34:00 +00001/*
2 * Copyright 2013 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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -04009#include "include/core/SkBitmap.h"
10#include "include/core/SkBlurTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/core/SkCanvas.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040012#include "include/core/SkColor.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkImage.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040014#include "include/core/SkImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "include/core/SkMaskFilter.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040016#include "include/core/SkMatrix.h"
17#include "include/core/SkPaint.h"
18#include "include/core/SkPoint.h"
19#include "include/core/SkRect.h"
20#include "include/core/SkRefCnt.h"
21#include "include/core/SkScalar.h"
22#include "include/core/SkShader.h"
23#include "include/core/SkSize.h"
24#include "include/core/SkString.h"
25#include "include/core/SkSurface.h"
26#include "include/core/SkTileMode.h"
Robert Phillips01f3be42023-06-16 13:22:18 -040027#include "include/core/SkTiledImageUtils.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040028#include "include/core/SkTypes.h"
Ben Wagner6a34f3a2019-05-01 10:59:30 -040029#include "include/gpu/GrContextOptions.h"
Kevin Lubickdc6cc022023-01-13 11:24:27 -050030#include "include/private/base/SkTDArray.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050031#include "src/core/SkBlurMask.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050032#include "tools/ToolUtils.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000033
Robert Phillips9360fae2023-06-20 13:34:37 -040034#if defined(SK_GRAPHITE)
35#include "include/gpu/graphite/ContextOptions.h"
Jim Van Verth18bdcfb2023-09-15 13:57:36 -040036#include "include/private/gpu/graphite/ContextOptionsPriv.h"
Robert Phillips9360fae2023-06-20 13:34:37 -040037#endif
38
Brian Salomon6ef29332020-05-15 09:52:29 -040039/** Creates an image with two one-pixel wide borders around a checkerboard. The checkerboard is 2x2
40 checks where each check has as many pixels as is necessary to fill the interior. It returns
41 the image and a src rect that bounds the checkerboard portion. */
Robert Phillips0fb10ab2022-04-20 14:57:03 -040042std::tuple<sk_sp<SkImage>, SkRect> make_ringed_image(SkCanvas* canvas, int width, int height) {
reeda5517e22015-07-14 10:54:12 -070043
Brian Salomon6ef29332020-05-15 09:52:29 -040044 // These are kRGBA_8888_SkColorType values.
45 static constexpr uint32_t kOuterRingColor = 0xFFFF0000,
46 kInnerRingColor = 0xFF0000FF,
47 kCheckColor1 = 0xFF000000,
48 kCheckColor2 = 0xFFFFFFFF;
49
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000050 SkASSERT(0 == width % 2 && 0 == height % 2);
bsalomon5c1262d2015-11-09 10:06:06 -080051 SkASSERT(width >= 6 && height >= 6);
skia.committer@gmail.comed000842013-11-09 07:02:23 +000052
Brian Salomon6ef29332020-05-15 09:52:29 -040053 SkImageInfo info = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
54 kPremul_SkAlphaType);
bsalomon5c1262d2015-11-09 10:06:06 -080055 size_t rowBytes = SkAlign4(info.minRowBytes());
Brian Salomon6ef29332020-05-15 09:52:29 -040056 SkBitmap bitmap;
57 bitmap.allocPixels(info, rowBytes);
bsalomon5c1262d2015-11-09 10:06:06 -080058
Brian Salomon6ef29332020-05-15 09:52:29 -040059 uint32_t* scanline = bitmap.getAddr32(0, 0);
bsalomon5c1262d2015-11-09 10:06:06 -080060 for (int x = 0; x < width; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040061 scanline[x] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080062 }
Brian Salomon6ef29332020-05-15 09:52:29 -040063 scanline = bitmap.getAddr32(0, 1);
64 scanline[0] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080065 for (int x = 1; x < width - 1; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040066 scanline[x] = kInnerRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080067 }
Brian Salomon6ef29332020-05-15 09:52:29 -040068 scanline[width - 1] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080069
70 for (int y = 2; y < height / 2; ++y) {
Brian Salomon6ef29332020-05-15 09:52:29 -040071 scanline = bitmap.getAddr32(0, y);
72 scanline[0] = kOuterRingColor;
73 scanline[1] = kInnerRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080074 for (int x = 2; x < width / 2; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040075 scanline[x] = kCheckColor1;
bsalomon5c1262d2015-11-09 10:06:06 -080076 }
77 for (int x = width / 2; x < width - 2; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040078 scanline[x] = kCheckColor2;
bsalomon5c1262d2015-11-09 10:06:06 -080079 }
Brian Salomon6ef29332020-05-15 09:52:29 -040080 scanline[width - 2] = kInnerRingColor;
81 scanline[width - 1] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080082 }
83
84 for (int y = height / 2; y < height - 2; ++y) {
Brian Salomon6ef29332020-05-15 09:52:29 -040085 scanline = bitmap.getAddr32(0, y);
86 scanline[0] = kOuterRingColor;
87 scanline[1] = kInnerRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080088 for (int x = 2; x < width / 2; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040089 scanline[x] = kCheckColor2;
bsalomon5c1262d2015-11-09 10:06:06 -080090 }
91 for (int x = width / 2; x < width - 2; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -040092 scanline[x] = kCheckColor1;
bsalomon5c1262d2015-11-09 10:06:06 -080093 }
Brian Salomon6ef29332020-05-15 09:52:29 -040094 scanline[width - 2] = kInnerRingColor;
95 scanline[width - 1] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -080096 }
97
Brian Salomon6ef29332020-05-15 09:52:29 -040098 scanline = bitmap.getAddr32(0, height - 2);
99 scanline[0] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -0800100 for (int x = 1; x < width - 1; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -0400101 scanline[x] = kInnerRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -0800102 }
Brian Salomon6ef29332020-05-15 09:52:29 -0400103 scanline[width - 1] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -0800104
Brian Salomon6ef29332020-05-15 09:52:29 -0400105 scanline = bitmap.getAddr32(0, height - 1);
bsalomon5c1262d2015-11-09 10:06:06 -0800106 for (int x = 0; x < width; ++x) {
Brian Salomon6ef29332020-05-15 09:52:29 -0400107 scanline[x] = kOuterRingColor;
bsalomon5c1262d2015-11-09 10:06:06 -0800108 }
Brian Salomon6ef29332020-05-15 09:52:29 -0400109 bitmap.setImmutable();
Robert Phillips97b9b722023-06-27 11:17:43 -0400110 return { bitmap.asImage(), SkRect::Make({2, 2, width - 2, height - 2})};
bsalomon5c1262d2015-11-09 10:06:06 -0800111}
112
Brian Salomon6ef29332020-05-15 09:52:29 -0400113/**
Brian Salomonca769202020-05-18 16:40:59 -0400114 * These GMs exercise the behavior of the drawImageRect and its SrcRectConstraint parameter. They
115 * tests various matrices, filter qualities, and interaction with mask filters. They also exercise
Brian Salomon6ef29332020-05-15 09:52:29 -0400116 * the tiling image draws of SkGpuDevice by overriding the maximum texture size of the GrContext.
117 */
Brian Salomonca769202020-05-18 16:40:59 -0400118class SrcRectConstraintGM : public skiagm::GM {
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000119public:
Robert Phillipsdd6456e2023-06-26 10:01:01 -0400120 SrcRectConstraintGM(const char* shortName, SkCanvas::SrcRectConstraint constraint, bool manual)
John Stilesd20a1342020-05-26 10:38:24 -0400121 : fShortName(shortName)
122 , fConstraint(constraint)
Robert Phillips01f3be42023-06-16 13:22:18 -0400123 , fManual(manual) {
Brian Salomon010bb462021-01-29 14:42:38 -0500124 // Make sure GPU SkSurfaces can be created for this GM.
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000125 SkASSERT(this->getISize().width() <= kMaxTextureSize &&
126 this->getISize().height() <= kMaxTextureSize);
Brian Salomon010bb462021-01-29 14:42:38 -0500127 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000128
129protected:
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000130 SkString getName() const override { return fShortName; }
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000131 SkISize getISize() override { return SkISize::Make(800, 1000); }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000132
Mike Reed8d29ab62021-01-23 18:10:39 -0500133 void drawImage(SkCanvas* canvas, sk_sp<SkImage> image, SkRect srcRect, SkRect dstRect,
134 const SkSamplingOptions& sampling, SkPaint* paint) {
Robert Phillipsdd6456e2023-06-26 10:01:01 -0400135 if (fManual) {
136 SkTiledImageUtils::DrawImageRect(canvas, image.get(), srcRect, dstRect,
137 sampling, paint, fConstraint);
John Stilesd20a1342020-05-26 10:38:24 -0400138 } else {
Robert Phillipsdd6456e2023-06-26 10:01:01 -0400139 canvas->drawImageRect(image.get(), srcRect, dstRect, sampling, paint, fConstraint);
John Stilesd20a1342020-05-26 10:38:24 -0400140 }
141 }
142
bsalomon5c1262d2015-11-09 10:06:06 -0800143 // Draw the area of interest of the small image
Mike Reed8d29ab62021-01-23 18:10:39 -0500144 void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
145 const SkSamplingOptions& sampling) {
reeda5517e22015-07-14 10:54:12 -0700146 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
147 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000148
149 SkPaint paint;
bsalomon9003d1e2015-10-23 11:13:01 -0700150 paint.setColor(SK_ColorBLUE);
151 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000152
Robert Phillips0fb10ab2022-04-20 14:57:03 -0400153 this->drawImage(canvas, fSmallImage, fSmallSrcRect, dst, sampling, &paint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000154 }
155
bsalomon5c1262d2015-11-09 10:06:06 -0800156 // Draw the area of interest of the large image
Mike Reed8d29ab62021-01-23 18:10:39 -0500157 void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
158 const SkSamplingOptions& sampling) {
reeda5517e22015-07-14 10:54:12 -0700159 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
160 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000161
162 SkPaint paint;
bsalomon9003d1e2015-10-23 11:13:01 -0700163 paint.setColor(SK_ColorBLUE);
164 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000165
Robert Phillips0fb10ab2022-04-20 14:57:03 -0400166 this->drawImage(canvas, fBigImage, fBigSrcRect, dst, sampling, &paint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000167 }
168
bsalomon5c1262d2015-11-09 10:06:06 -0800169 // Draw upper-left 1/4 of the area of interest of the large image
Mike Reed8d29ab62021-01-23 18:10:39 -0500170 void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
171 const SkSamplingOptions& sampling) {
172 SkRect src = SkRect::MakeXYWH(fBigSrcRect.fLeft,
173 fBigSrcRect.fTop,
174 fBigSrcRect.width()/2,
175 fBigSrcRect.height()/2);
reeda5517e22015-07-14 10:54:12 -0700176 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
177 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000178
179 SkPaint paint;
bsalomon9003d1e2015-10-23 11:13:01 -0700180 paint.setColor(SK_ColorBLUE);
181 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000182
Robert Phillips0fb10ab2022-04-20 14:57:03 -0400183 this->drawImage(canvas, fBigImage, src, dst, sampling, &paint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000184 }
185
bsalomon5c1262d2015-11-09 10:06:06 -0800186 // Draw the area of interest of the small image with a normal blur
Mike Reed8d29ab62021-01-23 18:10:39 -0500187 void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
188 const SkSamplingOptions& sampling) {
reeda5517e22015-07-14 10:54:12 -0700189 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
190 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000191
192 SkPaint paint;
Mike Reed1be1f8d2018-03-14 13:01:17 -0400193 paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle,
reedefdfd512016-04-04 10:02:58 -0700194 SkBlurMask::ConvertRadiusToSigma(3)));
bsalomon9003d1e2015-10-23 11:13:01 -0700195 paint.setColor(SK_ColorBLUE);
196 paint.setAntiAlias(aa);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000197
Robert Phillips0fb10ab2022-04-20 14:57:03 -0400198 this->drawImage(canvas, fSmallImage, fSmallSrcRect, dst, sampling, &paint);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000199 }
200
bsalomon5c1262d2015-11-09 10:06:06 -0800201 // Draw the area of interest of the small image with a outer blur
Mike Reed8d29ab62021-01-23 18:10:39 -0500202 void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
203 const SkSamplingOptions& sampling) {
bsalomonf57ef1c2015-11-04 04:36:12 -0800204 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
205 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
206
207 SkPaint paint;
Mike Reed1be1f8d2018-03-14 13:01:17 -0400208 paint.setMaskFilter(SkMaskFilter::MakeBlur(kOuter_SkBlurStyle,
reedefdfd512016-04-04 10:02:58 -0700209 SkBlurMask::ConvertRadiusToSigma(7)));
bsalomonf57ef1c2015-11-04 04:36:12 -0800210 paint.setColor(SK_ColorBLUE);
211 paint.setAntiAlias(aa);
212
Robert Phillips0fb10ab2022-04-20 14:57:03 -0400213 this->drawImage(canvas, fSmallImage, fSmallSrcRect, dst, sampling, &paint);
bsalomona2e08372016-07-13 14:50:17 -0700214 }
215
mtklein36352bf2015-03-25 18:17:31 -0700216 void onDraw(SkCanvas* canvas) override {
Robert Phillips0fb10ab2022-04-20 14:57:03 -0400217 if (!fSmallImage) {
218 std::tie(fBigImage, fBigSrcRect) = make_ringed_image(canvas,
219 2*kMaxTextureSize,
220 2*kMaxTextureSize);
221 std::tie(fSmallImage, fSmallSrcRect) = make_ringed_image(canvas,
222 kSmallSize, kSmallSize);
223 }
224
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000225 canvas->clear(SK_ColorGRAY);
John Stilescbe4e282020-06-01 10:38:31 -0400226 std::vector<SkMatrix> matrices;
bsalomon9003d1e2015-10-23 11:13:01 -0700227 // Draw with identity
John Stilescbe4e282020-06-01 10:38:31 -0400228 matrices.push_back(SkMatrix::I());
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000229
bsalomon9003d1e2015-10-23 11:13:01 -0700230 // Draw with rotation and scale down in x, up in y.
231 SkMatrix m;
mtkleindbfd7ab2016-09-01 11:24:54 -0700232 constexpr SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
bsalomon9003d1e2015-10-23 11:13:01 -0700233 m.setTranslate(0, kBottom);
234 m.preRotate(15.f, 0, kBottom + kBlockSpacing);
235 m.preScale(0.71f, 1.22f);
John Stilescbe4e282020-06-01 10:38:31 -0400236 matrices.push_back(m);
bsalomon9003d1e2015-10-23 11:13:01 -0700237
238 // Align the next set with the middle of the previous in y, translated to the right in x.
John Stilescbe4e282020-06-01 10:38:31 -0400239 SkPoint corners[] = {{0, 0}, {0, kBottom}, {kWidth, kBottom}, {kWidth, 0}};
240 matrices.back().mapPoints(corners, 4);
John Stilesacf71642021-08-12 22:33:57 -0400241 m.setTranslate(std::max({corners[0].fX, corners[1].fX, corners[2].fX, corners[3].fX}),
242 (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4);
bsalomon9003d1e2015-10-23 11:13:01 -0700243 m.preScale(0.2f, 0.2f);
John Stilescbe4e282020-06-01 10:38:31 -0400244 matrices.push_back(m);
bsalomon9003d1e2015-10-23 11:13:01 -0700245
Mike Reed8d29ab62021-01-23 18:10:39 -0500246 const SkSamplingOptions none(SkFilterMode::kNearest);
247 const SkSamplingOptions low(SkFilterMode::kLinear);
Mike Reedf3ac2af2021-02-05 12:55:38 -0500248 const SkSamplingOptions high(SkCubicResampler::Mitchell());
Mike Reed8d29ab62021-01-23 18:10:39 -0500249
bsalomon9003d1e2015-10-23 11:13:01 -0700250 SkScalar maxX = 0;
John Stilescbe4e282020-06-01 10:38:31 -0400251 for (bool antiAlias : {false, true}) {
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000252 canvas->save();
bsalomon9003d1e2015-10-23 11:13:01 -0700253 canvas->translate(maxX, 0);
John Stilescbe4e282020-06-01 10:38:31 -0400254 for (const SkMatrix& matrix : matrices) {
bsalomon9003d1e2015-10-23 11:13:01 -0700255 canvas->save();
John Stilescbe4e282020-06-01 10:38:31 -0400256 canvas->concat(matrix);
bsalomon9003d1e2015-10-23 11:13:01 -0700257
Brian Salomonca769202020-05-18 16:40:59 -0400258 // First draw a column with no filtering
Mike Reed8d29ab62021-01-23 18:10:39 -0500259 this->drawCase1(canvas, kCol0X, kRow0Y, antiAlias, none);
260 this->drawCase2(canvas, kCol0X, kRow1Y, antiAlias, none);
261 this->drawCase3(canvas, kCol0X, kRow2Y, antiAlias, none);
262 this->drawCase4(canvas, kCol0X, kRow3Y, antiAlias, none);
263 this->drawCase5(canvas, kCol0X, kRow4Y, antiAlias, none);
bsalomon9003d1e2015-10-23 11:13:01 -0700264
Brian Salomonca769202020-05-18 16:40:59 -0400265 // Then draw a column with low filtering
Mike Reed8d29ab62021-01-23 18:10:39 -0500266 this->drawCase1(canvas, kCol1X, kRow0Y, antiAlias, low);
267 this->drawCase2(canvas, kCol1X, kRow1Y, antiAlias, low);
268 this->drawCase3(canvas, kCol1X, kRow2Y, antiAlias, low);
269 this->drawCase4(canvas, kCol1X, kRow3Y, antiAlias, low);
270 this->drawCase5(canvas, kCol1X, kRow4Y, antiAlias, low);
bsalomon9003d1e2015-10-23 11:13:01 -0700271
Brian Salomon2a7eff92020-05-19 10:22:03 -0400272 // Then draw a column with high filtering. Skip it if in kStrict mode and MIP
273 // mapping will be used. On GPU we allow bleeding at non-base levels because
274 // building a new MIP chain for the subset is expensive.
275 SkScalar scales[2];
John Stilescbe4e282020-06-01 10:38:31 -0400276 SkAssertResult(matrix.getMinMaxScales(scales));
Brian Salomon2a7eff92020-05-19 10:22:03 -0400277 if (fConstraint != SkCanvas::kStrict_SrcRectConstraint || scales[0] >= 1.f) {
Mike Reed8d29ab62021-01-23 18:10:39 -0500278 this->drawCase1(canvas, kCol2X, kRow0Y, antiAlias, high);
279 this->drawCase2(canvas, kCol2X, kRow1Y, antiAlias, high);
280 this->drawCase3(canvas, kCol2X, kRow2Y, antiAlias, high);
281 this->drawCase4(canvas, kCol2X, kRow3Y, antiAlias, high);
282 this->drawCase5(canvas, kCol2X, kRow4Y, antiAlias, high);
Brian Salomon2a7eff92020-05-19 10:22:03 -0400283 }
bsalomon9003d1e2015-10-23 11:13:01 -0700284
John Stilescbe4e282020-06-01 10:38:31 -0400285 SkPoint innerCorners[] = {{0, 0}, {0, kBottom}, {kWidth, kBottom}, {kWidth, 0}};
286 matrix.mapPoints(innerCorners, 4);
287 SkScalar x = kBlockSize + std::max({innerCorners[0].fX, innerCorners[1].fX,
288 innerCorners[2].fX, innerCorners[3].fX});
Brian Osman788b9162020-02-07 10:36:46 -0500289 maxX = std::max(maxX, x);
bsalomon9003d1e2015-10-23 11:13:01 -0700290 canvas->restore();
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000291 }
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000292 canvas->restore();
293 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000294 }
295
bsalomon4ee6bd82015-05-27 13:23:23 -0700296 void modifyGrContextOptions(GrContextOptions* options) override {
Brian Salomon010bb462021-01-29 14:42:38 -0500297 options->fMaxTextureSizeOverride = kMaxTextureSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700298 }
bsalomon4ee6bd82015-05-27 13:23:23 -0700299
Robert Phillips9360fae2023-06-20 13:34:37 -0400300#if defined(SK_GRAPHITE)
301 void modifyGraphiteContextOptions(skgpu::graphite::ContextOptions* options) const override {
Jim Van Verth18bdcfb2023-09-15 13:57:36 -0400302 SkASSERT(options->fOptionsPriv);
303 options->fOptionsPriv->fMaxTextureSizeOverride = kMaxTextureSize;
Robert Phillips9360fae2023-06-20 13:34:37 -0400304 }
305#endif
306
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000307private:
Brian Salomon9fa47cc2021-10-08 18:48:26 -0400308 inline static constexpr int kBlockSize = 70;
309 inline static constexpr int kBlockSpacing = 12;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000310
Brian Salomon9fa47cc2021-10-08 18:48:26 -0400311 inline static constexpr int kCol0X = kBlockSpacing;
312 inline static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
313 inline static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
314 inline static constexpr int kWidth = 4*kBlockSpacing + 3*kBlockSize;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000315
Brian Salomon9fa47cc2021-10-08 18:48:26 -0400316 inline static constexpr int kRow0Y = kBlockSpacing;
317 inline static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
318 inline static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
319 inline static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
320 inline static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000321
Brian Salomon9fa47cc2021-10-08 18:48:26 -0400322 inline static constexpr int kSmallSize = 6;
Brian Salomon010bb462021-01-29 14:42:38 -0500323 // This must be at least as large as the GM width and height so that a surface can be made.
Brian Salomon9fa47cc2021-10-08 18:48:26 -0400324 inline static constexpr int kMaxTextureSize = 1000;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000325
John Stilesd20a1342020-05-26 10:38:24 -0400326 SkString fShortName;
Brian Salomon6ef29332020-05-15 09:52:29 -0400327 sk_sp<SkImage> fBigImage;
328 sk_sp<SkImage> fSmallImage;
Mike Reed8d29ab62021-01-23 18:10:39 -0500329 SkRect fBigSrcRect;
330 SkRect fSmallSrcRect;
Brian Salomonca769202020-05-18 16:40:59 -0400331 SkCanvas::SrcRectConstraint fConstraint;
Robert Phillips01f3be42023-06-16 13:22:18 -0400332 bool fManual;
John Stiles7571f9e2020-09-02 22:42:33 -0400333 using INHERITED = GM;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000334};
335
John Stilesd20a1342020-05-26 10:38:24 -0400336DEF_GM(return new SrcRectConstraintGM("strict_constraint_no_red_allowed",
337 SkCanvas::kStrict_SrcRectConstraint,
Robert Phillips01f3be42023-06-16 13:22:18 -0400338 /* manual= */ false););
339DEF_GM(return new SrcRectConstraintGM("strict_constraint_no_red_allowed_manual",
340 SkCanvas::kStrict_SrcRectConstraint,
Robert Phillips01f3be42023-06-16 13:22:18 -0400341 /* manual= */ true););
342
John Stilesd20a1342020-05-26 10:38:24 -0400343DEF_GM(return new SrcRectConstraintGM("strict_constraint_batch_no_red_allowed",
344 SkCanvas::kStrict_SrcRectConstraint,
Robert Phillips01f3be42023-06-16 13:22:18 -0400345 /* manual= */ false););
346DEF_GM(return new SrcRectConstraintGM("strict_constraint_batch_no_red_allowed_manual",
347 SkCanvas::kStrict_SrcRectConstraint,
Robert Phillips01f3be42023-06-16 13:22:18 -0400348 /* manual= */ true););
349
John Stilesd20a1342020-05-26 10:38:24 -0400350DEF_GM(return new SrcRectConstraintGM("fast_constraint_red_is_allowed",
351 SkCanvas::kFast_SrcRectConstraint,
Robert Phillips01f3be42023-06-16 13:22:18 -0400352 /* manual= */ false););
353DEF_GM(return new SrcRectConstraintGM("fast_constraint_red_is_allowed_manual",
354 SkCanvas::kFast_SrcRectConstraint,
Robert Phillips01f3be42023-06-16 13:22:18 -0400355 /* manual= */ true););
reed2adecda2016-07-25 08:11:58 -0700356
357///////////////////////////////////////////////////////////////////////////////////////////////////
reed2adecda2016-07-25 08:11:58 -0700358
reed2adecda2016-07-25 08:11:58 -0700359// Construct an image and return the inner "src" rect. Build the image such that the interior is
360// blue, with a margin of blue (2px) but then an outer margin of red.
361//
362// Show that kFast_SrcRectConstraint sees even the red margin (due to mipmapping) when the image
363// is scaled down far enough.
364//
365static sk_sp<SkImage> make_image(SkCanvas* canvas, SkRect* srcR) {
egdaniel26318c92016-07-26 08:26:46 -0700366 // Intentially making the size a power of 2 to avoid the noise from how different GPUs will
367 // produce different mipmap filtering when we have an odd sized texture.
368 const int N = 10 + 2 + 8 + 2 + 10;
reed2adecda2016-07-25 08:11:58 -0700369 SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
Mike Kleinea3f0142019-03-20 11:12:10 -0500370 auto surface = ToolUtils::makeSurface(canvas, info);
reed2adecda2016-07-25 08:11:58 -0700371 SkCanvas* c = surface->getCanvas();
372 SkRect r = SkRect::MakeIWH(info.width(), info.height());
373 SkPaint paint;
374
375 paint.setColor(SK_ColorRED);
376 c->drawRect(r, paint);
egdaniel26318c92016-07-26 08:26:46 -0700377 r.inset(10, 10);
reed2adecda2016-07-25 08:11:58 -0700378 paint.setColor(SK_ColorBLUE);
379 c->drawRect(r, paint);
380
381 *srcR = r.makeInset(2, 2);
382 return surface->makeImageSnapshot();
383}
384
385DEF_SIMPLE_GM(bleed_downscale, canvas, 360, 240) {
386 SkRect src;
387 sk_sp<SkImage> img = make_image(canvas, &src);
388 SkPaint paint;
389
390 canvas->translate(10, 10);
391
392 const SkCanvas::SrcRectConstraint constraints[] = {
393 SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint
394 };
Mike Reedd396cd52021-01-23 21:14:47 -0500395 const SkSamplingOptions samplings[] = {
396 SkSamplingOptions(SkFilterMode::kNearest),
397 SkSamplingOptions(SkFilterMode::kLinear),
398 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
reed2adecda2016-07-25 08:11:58 -0700399 };
400 for (auto constraint : constraints) {
401 canvas->save();
Mike Reedd396cd52021-01-23 21:14:47 -0500402 for (auto sampling : samplings) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500403 auto surf = ToolUtils::makeSurface(canvas, SkImageInfo::MakeN32Premul(1, 1));
Mike Reedd396cd52021-01-23 21:14:47 -0500404 surf->getCanvas()->drawImageRect(img, src, SkRect::MakeWH(1, 1), sampling,
405 nullptr, constraint);
reed2adecda2016-07-25 08:11:58 -0700406 // now blow up the 1 pixel result
Mike Reedd396cd52021-01-23 21:14:47 -0500407 canvas->drawImageRect(surf->makeImageSnapshot(), SkRect::MakeWH(100, 100),
408 SkSamplingOptions());
reed2adecda2016-07-25 08:11:58 -0700409 canvas->translate(120, 0);
410 }
411 canvas->restore();
412 canvas->translate(0, 120);
413 }
414}