blob: 23d65500962727728447e8f9dfdf0202ad995f41 [file] [log] [blame]
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +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 Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkBlendMode.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkCanvas.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040011#include "include/core/SkColor.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkColorFilter.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040013#include "include/core/SkMatrix.h"
14#include "include/core/SkPaint.h"
15#include "include/core/SkPoint.h"
16#include "include/core/SkRefCnt.h"
17#include "include/core/SkScalar.h"
18#include "include/core/SkShader.h"
19#include "include/core/SkSize.h"
20#include "include/core/SkString.h"
21#include "include/core/SkTileMode.h"
22#include "include/core/SkTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "include/core/SkVertices.h"
24#include "include/effects/SkGradientShader.h"
Brian Osman3c358422020-03-23 10:44:12 -040025#include "include/effects/SkRuntimeEffect.h"
Kevin Lubickdc6cc022023-01-13 11:24:27 -050026#include "include/private/base/SkTDArray.h"
Kevin Lubick0d4d1142023-02-13 09:13:10 -050027#include "src/base/SkRandom.h"
Brian Osman3c358422020-03-23 10:44:12 -040028#include "src/core/SkVerticesPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "src/shaders/SkLocalMatrixShader.h"
Brian Osman3c358422020-03-23 10:44:12 -040030#include "src/utils/SkPatchUtils.h"
Kevin Lubick8b741882023-10-06 11:41:38 -040031#include "tools/DecodeUtils.h"
Brian Osman3c358422020-03-23 10:44:12 -040032#include "tools/Resources.h"
Brian Osmane41fa2d2020-03-20 15:45:49 -040033#include "tools/ToolUtils.h"
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +000034
Ben Wagner7fde8e12019-05-01 17:28:53 -040035#include <initializer_list>
36#include <utility>
37
Brian Salomon3f363692017-02-02 21:05:19 -050038static constexpr SkScalar kShaderSize = 40;
Florin Malitaf614ba22017-02-16 22:12:41 -050039static sk_sp<SkShader> make_shader1(SkScalar shaderScale) {
reed@google.com85e143c2013-12-30 15:51:25 +000040 const SkColor colors[] = {
41 SK_ColorRED, SK_ColorCYAN, SK_ColorGREEN, SK_ColorWHITE,
42 SK_ColorMAGENTA, SK_ColorBLUE, SK_ColorYELLOW,
43 };
Brian Salomon3f363692017-02-02 21:05:19 -050044 const SkPoint pts[] = {{kShaderSize / 4, 0}, {3 * kShaderSize / 4, kShaderSize}};
Mike Reed1f607332020-05-21 12:11:27 -040045 const SkMatrix localMatrix = SkMatrix::Scale(shaderScale, shaderScale);
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +000046
Florin Malitaf614ba22017-02-16 22:12:41 -050047 sk_sp<SkShader> grad = SkGradientShader::MakeLinear(pts, colors, nullptr,
Herb Derbyc37b3862022-06-21 09:49:17 -040048 std::size(colors),
Mike Reedfae8fce2019-04-03 10:27:45 -040049 SkTileMode::kMirror, 0,
Florin Malitaf614ba22017-02-16 22:12:41 -050050 &localMatrix);
51 // Throw in a couple of local matrix wrappers for good measure.
52 return shaderScale == 1
53 ? grad
54 : sk_make_sp<SkLocalMatrixShader>(
Mike Reed1f607332020-05-21 12:11:27 -040055 sk_make_sp<SkLocalMatrixShader>(std::move(grad), SkMatrix::Translate(-10, 0)),
56 SkMatrix::Translate(10, 0));
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +000057}
58
reed1a9b9642016-03-13 14:13:58 -070059static sk_sp<SkShader> make_shader2() {
Mike Reedc8bea7d2019-04-09 13:55:36 -040060 return SkShaders::Color(SK_ColorBLUE);
bsalomon093779c2016-03-08 11:53:31 -080061}
62
reedd053ce92016-03-22 10:17:23 -070063static sk_sp<SkColorFilter> make_color_filter() {
Mike Reedb286bc22019-04-08 16:23:20 -040064 return SkColorFilters::Blend(0xFFAABBCC, SkBlendMode::kDarken);
bsalomon093779c2016-03-08 11:53:31 -080065}
66
Brian Salomon3f363692017-02-02 21:05:19 -050067static constexpr SkScalar kMeshSize = 30;
68
69// start with the center of a 3x3 grid of vertices.
70static constexpr uint16_t kMeshFan[] = {
71 4,
72 0, 1, 2, 5, 8, 7, 6, 3, 0
73};
74
Herb Derbyc37b3862022-06-21 09:49:17 -040075static const int kMeshIndexCnt = (int)std::size(kMeshFan);
Brian Salomon3f363692017-02-02 21:05:19 -050076static const int kMeshVertexCnt = 9;
77
78static void fill_mesh(SkPoint pts[kMeshVertexCnt], SkPoint texs[kMeshVertexCnt],
Florin Malitaf614ba22017-02-16 22:12:41 -050079 SkColor colors[kMeshVertexCnt], SkScalar shaderScale) {
Brian Salomon3f363692017-02-02 21:05:19 -050080 pts[0].set(0, 0);
81 pts[1].set(kMeshSize / 2, 3);
82 pts[2].set(kMeshSize, 0);
83 pts[3].set(3, kMeshSize / 2);
84 pts[4].set(kMeshSize / 2, kMeshSize / 2);
85 pts[5].set(kMeshSize - 3, kMeshSize / 2);
86 pts[6].set(0, kMeshSize);
87 pts[7].set(kMeshSize / 2, kMeshSize - 3);
88 pts[8].set(kMeshSize, kMeshSize);
89
Florin Malitaf614ba22017-02-16 22:12:41 -050090 const auto shaderSize = kShaderSize * shaderScale;
Brian Salomon3f363692017-02-02 21:05:19 -050091 texs[0].set(0, 0);
Florin Malitaf614ba22017-02-16 22:12:41 -050092 texs[1].set(shaderSize / 2, 0);
93 texs[2].set(shaderSize, 0);
94 texs[3].set(0, shaderSize / 2);
95 texs[4].set(shaderSize / 2, shaderSize / 2);
96 texs[5].set(shaderSize, shaderSize / 2);
97 texs[6].set(0, shaderSize);
98 texs[7].set(shaderSize / 2, shaderSize);
99 texs[8].set(shaderSize, shaderSize);
Brian Salomon3f363692017-02-02 21:05:19 -0500100
101 SkRandom rand;
102 for (size_t i = 0; i < kMeshVertexCnt; ++i) {
103 colors[i] = rand.nextU() | 0xFF000000;
104 }
105}
106
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000107class VerticesGM : public skiagm::GM {
Brian Salomon3f363692017-02-02 21:05:19 -0500108 SkPoint fPts[kMeshVertexCnt];
109 SkPoint fTexs[kMeshVertexCnt];
110 SkColor fColors[kMeshVertexCnt];
reedd053ce92016-03-22 10:17:23 -0700111 sk_sp<SkShader> fShader1;
112 sk_sp<SkShader> fShader2;
113 sk_sp<SkColorFilter> fColorFilter;
Florin Malitaf614ba22017-02-16 22:12:41 -0500114 SkScalar fShaderScale;
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000115
116public:
Mike Reed887cdf12017-04-03 11:11:09 -0400117 VerticesGM(SkScalar shaderScale) : fShaderScale(shaderScale) {}
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000118
119protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000120
mtklein36352bf2015-03-25 18:17:31 -0700121 void onOnceBeforeDraw() override {
Florin Malitaf614ba22017-02-16 22:12:41 -0500122 fill_mesh(fPts, fTexs, fColors, fShaderScale);
123 fShader1 = make_shader1(fShaderScale);
reed1a9b9642016-03-13 14:13:58 -0700124 fShader2 = make_shader2();
reedd053ce92016-03-22 10:17:23 -0700125 fColorFilter = make_color_filter();
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000126 }
127
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000128 SkString getName() const override {
reed@google.com60da8f32014-05-05 20:41:21 +0000129 SkString name("vertices");
Florin Malitaf614ba22017-02-16 22:12:41 -0500130 if (fShaderScale != 1) {
131 name.append("_scaled_shader");
132 }
reed@google.com60da8f32014-05-05 20:41:21 +0000133 return name;
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000134 }
135
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000136 SkISize getISize() override { return SkISize::Make(975, 1175); }
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000137
mtklein36352bf2015-03-25 18:17:31 -0700138 void onDraw(SkCanvas* canvas) override {
Mike Reed7d954ad2016-10-28 15:42:34 -0400139 const SkBlendMode modes[] = {
140 SkBlendMode::kClear,
141 SkBlendMode::kSrc,
142 SkBlendMode::kDst,
143 SkBlendMode::kSrcOver,
144 SkBlendMode::kDstOver,
145 SkBlendMode::kSrcIn,
146 SkBlendMode::kDstIn,
147 SkBlendMode::kSrcOut,
148 SkBlendMode::kDstOut,
149 SkBlendMode::kSrcATop,
150 SkBlendMode::kDstATop,
151 SkBlendMode::kXor,
152 SkBlendMode::kPlus,
153 SkBlendMode::kModulate,
154 SkBlendMode::kScreen,
155 SkBlendMode::kOverlay,
156 SkBlendMode::kDarken,
157 SkBlendMode::kLighten,
158 SkBlendMode::kColorDodge,
159 SkBlendMode::kColorBurn,
160 SkBlendMode::kHardLight,
161 SkBlendMode::kSoftLight,
162 SkBlendMode::kDifference,
163 SkBlendMode::kExclusion,
164 SkBlendMode::kMultiply,
165 SkBlendMode::kHue,
166 SkBlendMode::kSaturation,
167 SkBlendMode::kColor,
168 SkBlendMode::kLuminosity,
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000169 };
skia.committer@gmail.com4c912862013-12-30 07:01:37 +0000170
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000171 SkPaint paint;
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000172
bsalomon093779c2016-03-08 11:53:31 -0800173 canvas->translate(4, 4);
Brian Salomon199fb872017-02-06 09:41:10 -0500174 for (auto mode : modes) {
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000175 canvas->save();
Mike Reed9407e242019-02-15 16:13:57 -0500176 for (float alpha : {1.0f, 0.5f}) {
Brian Salomon199fb872017-02-06 09:41:10 -0500177 for (const auto& cf : {sk_sp<SkColorFilter>(nullptr), fColorFilter}) {
178 for (const auto& shader : {fShader1, fShader2}) {
179 static constexpr struct {
180 bool fHasColors;
181 bool fHasTexs;
182 } kAttrs[] = {{true, false}, {false, true}, {true, true}};
183 for (auto attrs : kAttrs) {
184 paint.setShader(shader);
185 paint.setColorFilter(cf);
Mike Reed9407e242019-02-15 16:13:57 -0500186 paint.setAlphaf(alpha);
Mike Reed5fa66452017-03-16 09:06:34 -0400187
188 const SkColor* colors = attrs.fHasColors ? fColors : nullptr;
189 const SkPoint* texs = attrs.fHasTexs ? fTexs : nullptr;
Mike Reed887cdf12017-04-03 11:11:09 -0400190 auto v = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode,
191 kMeshVertexCnt, fPts, texs, colors,
192 kMeshIndexCnt, kMeshFan);
193 canvas->drawVertices(v, mode, paint);
Brian Salomon199fb872017-02-06 09:41:10 -0500194 canvas->translate(40, 0);
Brian Salomon199fb872017-02-06 09:41:10 -0500195 }
196 }
197 }
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000198 }
199 canvas->restore();
bsalomon093779c2016-03-08 11:53:31 -0800200 canvas->translate(0, 40);
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000201 }
202 }
203
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000204private:
John Stiles7571f9e2020-09-02 22:42:33 -0400205 using INHERITED = skiagm::GM;
mike@reedtribe.org0c87ea82013-12-30 04:07:34 +0000206};
207
reed@google.com60da8f32014-05-05 20:41:21 +0000208/////////////////////////////////////////////////////////////////////////////////////
209
Mike Reed887cdf12017-04-03 11:11:09 -0400210DEF_GM(return new VerticesGM(1);)
211DEF_GM(return new VerticesGM(1 / kShaderSize);)
Brian Salomon3f363692017-02-02 21:05:19 -0500212
Mike Reed887cdf12017-04-03 11:11:09 -0400213static void draw_batching(SkCanvas* canvas) {
Mike Reed97eb4fe2017-03-14 12:04:16 -0400214 // Triangle fans can't batch so we convert to regular triangles,
215 static constexpr int kNumTris = kMeshIndexCnt - 2;
Mike Reed887cdf12017-04-03 11:11:09 -0400216 SkVertices::Builder builder(SkVertices::kTriangles_VertexMode, kMeshVertexCnt, 3 * kNumTris,
Mike Reedaa9e3322017-03-16 14:38:48 -0400217 SkVertices::kHasColors_BuilderFlag |
218 SkVertices::kHasTexCoords_BuilderFlag);
Mike Reed97eb4fe2017-03-14 12:04:16 -0400219
220 SkPoint* pts = builder.positions();
221 SkPoint* texs = builder.texCoords();
222 SkColor* colors = builder.colors();
223 fill_mesh(pts, texs, colors, 1);
Brian Salomon199fb872017-02-06 09:41:10 -0500224
Brian Salomon3f363692017-02-02 21:05:19 -0500225 SkTDArray<SkMatrix> matrices;
Herb Derby161a80f2022-09-22 15:50:42 -0400226 matrices.append()->reset();
227 matrices.append()->setTranslate(0, 40);
228 matrices.append()
John Stilesa212b952021-08-02 13:26:38 -0400229 ->setRotate(45, kMeshSize / 2, kMeshSize / 2)
230 .postScale(1.2f, .8f, kMeshSize / 2, kMeshSize / 2)
231 .postTranslate(0, 80);
Brian Salomon3f363692017-02-02 21:05:19 -0500232
Florin Malitaf614ba22017-02-16 22:12:41 -0500233 auto shader = make_shader1(1);
Brian Salomon3f363692017-02-02 21:05:19 -0500234
Mike Reed97eb4fe2017-03-14 12:04:16 -0400235 uint16_t* indices = builder.indices();
Brian Salomon3f363692017-02-02 21:05:19 -0500236 for (size_t i = 0; i < kNumTris; ++i) {
237 indices[3 * i] = kMeshFan[0];
238 indices[3 * i + 1] = kMeshFan[i + 1];
239 indices[3 * i + 2] = kMeshFan[i + 2];
Mike Reed97eb4fe2017-03-14 12:04:16 -0400240
Brian Salomon3f363692017-02-02 21:05:19 -0500241 }
Brian Salomon199fb872017-02-06 09:41:10 -0500242
Brian Salomon199fb872017-02-06 09:41:10 -0500243 canvas->save();
Brian Salomon3f363692017-02-02 21:05:19 -0500244 canvas->translate(10, 10);
245 for (bool useShader : {false, true}) {
246 for (bool useTex : {false, true}) {
247 for (const auto& m : matrices) {
248 canvas->save();
249 canvas->concat(m);
250 SkPaint paint;
Brian Salomon3f363692017-02-02 21:05:19 -0500251 paint.setShader(useShader ? shader : nullptr);
Brian Salomone00afb02021-11-22 12:22:16 -0500252 paint.setColor(SK_ColorWHITE);
Mike Reed5fa66452017-03-16 09:06:34 -0400253
254 const SkPoint* t = useTex ? texs : nullptr;
Mike Reed887cdf12017-04-03 11:11:09 -0400255 auto v = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, kMeshVertexCnt,
256 pts, t, colors, kNumTris * 3, indices);
257 canvas->drawVertices(v, SkBlendMode::kModulate, paint);
Brian Salomon3f363692017-02-02 21:05:19 -0500258 canvas->restore();
259 }
260 canvas->translate(0, 120);
261 }
262 }
Brian Salomon199fb872017-02-06 09:41:10 -0500263 canvas->restore();
264}
265
266// This test exists to exercise batching in the gpu backend.
267DEF_SIMPLE_GM(vertices_batching, canvas, 100, 500) {
Mike Reed887cdf12017-04-03 11:11:09 -0400268 draw_batching(canvas);
Brian Salomon199fb872017-02-06 09:41:10 -0500269 canvas->translate(50, 0);
Mike Reed887cdf12017-04-03 11:11:09 -0400270 draw_batching(canvas);
Brian Salomon3f363692017-02-02 21:05:19 -0500271}
Mike Reedd32bdaf2020-03-06 12:52:52 -0500272
Brian Osmane41fa2d2020-03-20 15:45:49 -0400273// Test case for skbug.com/10069. We need to draw the vertices twice (with different matrices) to
274// trigger the bug.
275DEF_SIMPLE_GM(vertices_perspective, canvas, 256, 256) {
276 SkPaint paint;
277 paint.setShader(ToolUtils::create_checkerboard_shader(SK_ColorBLACK, SK_ColorWHITE, 32));
278
279 SkRect r = SkRect::MakeWH(128, 128);
280
281 SkPoint pos[4];
282 r.toQuad(pos);
283 auto verts = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4, pos, pos, nullptr);
284
285 SkMatrix persp;
286 persp.setPerspY(SK_Scalar1 / 100);
287
288 canvas->save();
289 canvas->concat(persp);
290 canvas->drawRect(r, paint);
291 canvas->restore();
292
293 canvas->save();
294 canvas->translate(r.width(), 0);
295 canvas->concat(persp);
296 canvas->drawRect(r, paint);
297 canvas->restore();
298
299 canvas->save();
300 canvas->translate(0, r.height());
301 canvas->concat(persp);
Brian Salomon90ef83a2021-11-18 10:14:06 -0500302 canvas->drawVertices(verts, SkBlendMode::kModulate, paint);
Brian Osmane41fa2d2020-03-20 15:45:49 -0400303 canvas->restore();
304
305 canvas->save();
306 canvas->translate(r.width(), r.height());
307 canvas->concat(persp);
Brian Salomon90ef83a2021-11-18 10:14:06 -0500308 canvas->drawVertices(verts, SkBlendMode::kModulate, paint);
Brian Osmane41fa2d2020-03-20 15:45:49 -0400309 canvas->restore();
310}
Brian Osman4b3403e2022-03-10 10:05:16 -0500311
312DEF_SIMPLE_GM(skbug_13047, canvas, 200, 200) {
Kevin Lubick8b741882023-10-06 11:41:38 -0400313 auto image = ToolUtils::GetResourceAsImage("images/mandrill_128.png");
Brian Osman4b3403e2022-03-10 10:05:16 -0500314
315 const float w = image->width();
316 const float h = image->height();
317
318 SkPoint verts[] = {{0, 0}, {200, 0}, {200, 200}, {0, 200}};
319 SkPoint texs[] = {{0, 0}, {w, 0}, {w, h}, {0, h}};
320 uint16_t indices[] = {0, 1, 2, 2, 3, 0};
321
322 auto v = SkVertices::MakeCopy(
323 SkVertices::kTriangles_VertexMode, 4, verts, texs, nullptr, 6, indices);
324
325 auto m = SkMatrix::Scale(2, 2); // ignored in CPU ???
326 auto s = image->makeShader(SkSamplingOptions(SkFilterMode::kLinear), &m);
327
328 SkPaint p;
329 p.setShader(s);
330
331 canvas->drawVertices(v, SkBlendMode::kModulate, p);
332}
Brian Osmanfc0892a2024-02-14 14:53:42 -0500333
334// Makes sure that drawVertices allows for triangles with "collapsed" UVs, where all three vertices
335// have the same texture coordinate. b/40044794
336DEF_SIMPLE_GM_BG(vertices_collapsed, canvas, 50, 50, SK_ColorWHITE) {
337 SkPoint verts[] = {{5, 5}, {45, 5}, {45, 45}, {5, 45}};
338 SkPoint texs[] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
339 uint16_t indices[] = {0, 1, 2, 2, 3, 0};
340
341 sk_sp<SkVertices> v = SkVertices::MakeCopy(
342 SkVertices::kTriangles_VertexMode, 4, verts, texs, nullptr, 6, indices);
343
344 sk_sp<SkSurface> surf = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(1, 1));
345 surf->getCanvas()->clear(SK_ColorGREEN);
346 sk_sp<SkShader> shader = surf->makeImageSnapshot()->makeShader(SkSamplingOptions{});
347 SkPaint paint;
348 paint.setShader(shader);
349
350 canvas->drawVertices(v, SkBlendMode::kDst, paint);
351}