1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2019 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 // This test only works with the GPU backend.
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorFilter.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageFilter.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMaskFilter.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypeface.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkColorMatrix.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkImageFilters.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkShaderMaskFilter.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkLineClipper.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "tools/DecodeUtils.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "tools/Resources.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "tools/gpu/YUVUtils.h"
45*c8dee2aaSAndroid Build Coastguard Worker
46*c8dee2aaSAndroid Build Coastguard Worker #include <array>
47*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
48*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
51*c8dee2aaSAndroid Build Coastguard Worker
52*c8dee2aaSAndroid Build Coastguard Worker class ClipTileRenderer;
53*c8dee2aaSAndroid Build Coastguard Worker using ClipTileRendererArray = TArray<sk_sp<ClipTileRenderer>>;
54*c8dee2aaSAndroid Build Coastguard Worker
55*c8dee2aaSAndroid Build Coastguard Worker // This GM mimics the draw calls used by complex compositors that focus on drawing rectangles
56*c8dee2aaSAndroid Build Coastguard Worker // and quadrilaterals with per-edge AA, with complex images, effects, and seamless tiling.
57*c8dee2aaSAndroid Build Coastguard Worker // It will be updated to reflect the patterns seen in Chromium's SkiaRenderer. It is currently
58*c8dee2aaSAndroid Build Coastguard Worker // restricted to adding draw ops directly in Ganesh since there is no fully-specified public API.
59*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kTileWidth = 40;
60*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kTileHeight = 30;
61*c8dee2aaSAndroid Build Coastguard Worker
62*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kRowCount = 4;
63*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kColCount = 3;
64*c8dee2aaSAndroid Build Coastguard Worker
65*c8dee2aaSAndroid Build Coastguard Worker // To mimic Chromium's BSP clipping strategy, a set of three lines formed by triangle edges
66*c8dee2aaSAndroid Build Coastguard Worker // of the below points are used to clip against the regular tile grid. The tile grid occupies
67*c8dee2aaSAndroid Build Coastguard Worker // a 120 x 120 rectangle (40px * 3 cols by 30px * 4 rows).
68*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkPoint kClipP1 = {1.75f * kTileWidth, 0.8f * kTileHeight};
69*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkPoint kClipP2 = {0.6f * kTileWidth, 2.f * kTileHeight};
70*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkPoint kClipP3 = {2.9f * kTileWidth, 3.5f * kTileHeight};
71*c8dee2aaSAndroid Build Coastguard Worker
72*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////
73*c8dee2aaSAndroid Build Coastguard Worker // Utilities for operating on lines and tiles
74*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////
75*c8dee2aaSAndroid Build Coastguard Worker
76*c8dee2aaSAndroid Build Coastguard Worker // p0 and p1 form a segment contained the tile grid, so extends them by a large enough margin
77*c8dee2aaSAndroid Build Coastguard Worker // that the output points stored in 'line' are outside the tile grid (thus effectively infinite).
clipping_line_segment(const SkPoint & p0,const SkPoint & p1,SkPoint line[2])78*c8dee2aaSAndroid Build Coastguard Worker static void clipping_line_segment(const SkPoint& p0, const SkPoint& p1, SkPoint line[2]) {
79*c8dee2aaSAndroid Build Coastguard Worker SkVector v = p1 - p0;
80*c8dee2aaSAndroid Build Coastguard Worker // 10f was chosen as a balance between large enough to scale the currently set clip
81*c8dee2aaSAndroid Build Coastguard Worker // points outside of the tile grid, but small enough to preserve precision.
82*c8dee2aaSAndroid Build Coastguard Worker line[0] = p0 - v * 10.f;
83*c8dee2aaSAndroid Build Coastguard Worker line[1] = p1 + v * 10.f;
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker
86*c8dee2aaSAndroid Build Coastguard Worker // Returns true if line segment (p0-p1) intersects with line segment (l0-l1); if true is returned,
87*c8dee2aaSAndroid Build Coastguard Worker // the intersection point is stored in 'intersect'.
intersect_line_segments(const SkPoint & p0,const SkPoint & p1,const SkPoint & l0,const SkPoint & l1,SkPoint * intersect)88*c8dee2aaSAndroid Build Coastguard Worker static bool intersect_line_segments(const SkPoint& p0, const SkPoint& p1,
89*c8dee2aaSAndroid Build Coastguard Worker const SkPoint& l0, const SkPoint& l1, SkPoint* intersect) {
90*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kHorizontalTolerance = 0.01f; // Pretty conservative
91*c8dee2aaSAndroid Build Coastguard Worker
92*c8dee2aaSAndroid Build Coastguard Worker // Use doubles for accuracy, since the clipping strategy used below can create T
93*c8dee2aaSAndroid Build Coastguard Worker // junctions, and lower precision could artificially create gaps
94*c8dee2aaSAndroid Build Coastguard Worker double pY = (double) p1.fY - (double) p0.fY;
95*c8dee2aaSAndroid Build Coastguard Worker double pX = (double) p1.fX - (double) p0.fX;
96*c8dee2aaSAndroid Build Coastguard Worker double lY = (double) l1.fY - (double) l0.fY;
97*c8dee2aaSAndroid Build Coastguard Worker double lX = (double) l1.fX - (double) l0.fX;
98*c8dee2aaSAndroid Build Coastguard Worker double plY = (double) p0.fY - (double) l0.fY;
99*c8dee2aaSAndroid Build Coastguard Worker double plX = (double) p0.fX - (double) l0.fX;
100*c8dee2aaSAndroid Build Coastguard Worker if (SkScalarNearlyZero(pY, kHorizontalTolerance)) {
101*c8dee2aaSAndroid Build Coastguard Worker if (SkScalarNearlyZero(lY, kHorizontalTolerance)) {
102*c8dee2aaSAndroid Build Coastguard Worker // Two horizontal lines
103*c8dee2aaSAndroid Build Coastguard Worker return false;
104*c8dee2aaSAndroid Build Coastguard Worker } else {
105*c8dee2aaSAndroid Build Coastguard Worker // Recalculate but swap p and l
106*c8dee2aaSAndroid Build Coastguard Worker return intersect_line_segments(l0, l1, p0, p1, intersect);
107*c8dee2aaSAndroid Build Coastguard Worker }
108*c8dee2aaSAndroid Build Coastguard Worker }
109*c8dee2aaSAndroid Build Coastguard Worker
110*c8dee2aaSAndroid Build Coastguard Worker // Up to now, the line segments do not form an invalid intersection
111*c8dee2aaSAndroid Build Coastguard Worker double lNumerator = plX * pY - plY * pX;
112*c8dee2aaSAndroid Build Coastguard Worker double lDenom = lX * pY - lY * pX;
113*c8dee2aaSAndroid Build Coastguard Worker if (SkScalarNearlyZero(lDenom)) {
114*c8dee2aaSAndroid Build Coastguard Worker // Parallel or identical
115*c8dee2aaSAndroid Build Coastguard Worker return false;
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker
118*c8dee2aaSAndroid Build Coastguard Worker // Calculate alphaL that provides the intersection point along (l0-l1), e.g. l0+alphaL*(l1-l0)
119*c8dee2aaSAndroid Build Coastguard Worker double alphaL = lNumerator / lDenom;
120*c8dee2aaSAndroid Build Coastguard Worker if (alphaL < 0.0 || alphaL > 1.0) {
121*c8dee2aaSAndroid Build Coastguard Worker // Outside of the l segment
122*c8dee2aaSAndroid Build Coastguard Worker return false;
123*c8dee2aaSAndroid Build Coastguard Worker }
124*c8dee2aaSAndroid Build Coastguard Worker
125*c8dee2aaSAndroid Build Coastguard Worker // Calculate alphaP from the valid alphaL (since it could be outside p segment)
126*c8dee2aaSAndroid Build Coastguard Worker // double alphaP = (alphaL * l.fY - pl.fY) / p.fY;
127*c8dee2aaSAndroid Build Coastguard Worker double alphaP = (alphaL * lY - plY) / pY;
128*c8dee2aaSAndroid Build Coastguard Worker if (alphaP < 0.0 || alphaP > 1.0) {
129*c8dee2aaSAndroid Build Coastguard Worker // Outside of p segment
130*c8dee2aaSAndroid Build Coastguard Worker return false;
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker
133*c8dee2aaSAndroid Build Coastguard Worker // Is valid, so calculate the actual intersection point
134*c8dee2aaSAndroid Build Coastguard Worker *intersect = l1 * SkScalar(alphaL) + l0 * SkScalar(1.0 - alphaL);
135*c8dee2aaSAndroid Build Coastguard Worker return true;
136*c8dee2aaSAndroid Build Coastguard Worker }
137*c8dee2aaSAndroid Build Coastguard Worker
138*c8dee2aaSAndroid Build Coastguard Worker // Draw a line through the two points, outset by a fixed length in screen space
draw_outset_line(SkCanvas * canvas,const SkMatrix & local,const SkPoint pts[2],const SkPaint & paint)139*c8dee2aaSAndroid Build Coastguard Worker static void draw_outset_line(SkCanvas* canvas, const SkMatrix& local, const SkPoint pts[2],
140*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint) {
141*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kLineOutset = 10.f;
142*c8dee2aaSAndroid Build Coastguard Worker SkPoint mapped[2];
143*c8dee2aaSAndroid Build Coastguard Worker local.mapPoints(mapped, pts, 2);
144*c8dee2aaSAndroid Build Coastguard Worker SkVector v = mapped[1] - mapped[0];
145*c8dee2aaSAndroid Build Coastguard Worker v.setLength(v.length() + kLineOutset);
146*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(mapped[1] - v, mapped[0] + v, paint);
147*c8dee2aaSAndroid Build Coastguard Worker }
148*c8dee2aaSAndroid Build Coastguard Worker
149*c8dee2aaSAndroid Build Coastguard Worker // Draw grid of red lines at interior tile boundaries.
draw_tile_boundaries(SkCanvas * canvas,const SkMatrix & local)150*c8dee2aaSAndroid Build Coastguard Worker static void draw_tile_boundaries(SkCanvas* canvas, const SkMatrix& local) {
151*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
152*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
153*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorRED);
154*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
155*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(0.f);
156*c8dee2aaSAndroid Build Coastguard Worker for (int x = 1; x < kColCount; ++x) {
157*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[] = {{x * kTileWidth, 0}, {x * kTileWidth, kRowCount * kTileHeight}};
158*c8dee2aaSAndroid Build Coastguard Worker draw_outset_line(canvas, local, pts, paint);
159*c8dee2aaSAndroid Build Coastguard Worker }
160*c8dee2aaSAndroid Build Coastguard Worker for (int y = 1; y < kRowCount; ++y) {
161*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[] = {{0, y * kTileHeight}, {kTileWidth * kColCount, y * kTileHeight}};
162*c8dee2aaSAndroid Build Coastguard Worker draw_outset_line(canvas, local, pts, paint);
163*c8dee2aaSAndroid Build Coastguard Worker }
164*c8dee2aaSAndroid Build Coastguard Worker }
165*c8dee2aaSAndroid Build Coastguard Worker
166*c8dee2aaSAndroid Build Coastguard Worker // Draw the arbitrary clipping/split boundaries that intersect the tile grid as green lines
draw_clipping_boundaries(SkCanvas * canvas,const SkMatrix & local)167*c8dee2aaSAndroid Build Coastguard Worker static void draw_clipping_boundaries(SkCanvas* canvas, const SkMatrix& local) {
168*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
169*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
170*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorGREEN);
171*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
172*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(0.f);
173*c8dee2aaSAndroid Build Coastguard Worker
174*c8dee2aaSAndroid Build Coastguard Worker // Clip the "infinite" line segments to a rectangular region outside the tile grid
175*c8dee2aaSAndroid Build Coastguard Worker SkRect border = SkRect::MakeWH(kTileWidth * kColCount, kTileHeight * kRowCount);
176*c8dee2aaSAndroid Build Coastguard Worker
177*c8dee2aaSAndroid Build Coastguard Worker // Draw p1 to p2
178*c8dee2aaSAndroid Build Coastguard Worker SkPoint line[2];
179*c8dee2aaSAndroid Build Coastguard Worker SkPoint clippedLine[2];
180*c8dee2aaSAndroid Build Coastguard Worker clipping_line_segment(kClipP1, kClipP2, line);
181*c8dee2aaSAndroid Build Coastguard Worker SkAssertResult(SkLineClipper::IntersectLine(line, border, clippedLine));
182*c8dee2aaSAndroid Build Coastguard Worker draw_outset_line(canvas, local, clippedLine, paint);
183*c8dee2aaSAndroid Build Coastguard Worker
184*c8dee2aaSAndroid Build Coastguard Worker // Draw p2 to p3
185*c8dee2aaSAndroid Build Coastguard Worker clipping_line_segment(kClipP2, kClipP3, line);
186*c8dee2aaSAndroid Build Coastguard Worker SkAssertResult(SkLineClipper::IntersectLine(line, border, clippedLine));
187*c8dee2aaSAndroid Build Coastguard Worker draw_outset_line(canvas, local, clippedLine, paint);
188*c8dee2aaSAndroid Build Coastguard Worker
189*c8dee2aaSAndroid Build Coastguard Worker // Draw p3 to p1
190*c8dee2aaSAndroid Build Coastguard Worker clipping_line_segment(kClipP3, kClipP1, line);
191*c8dee2aaSAndroid Build Coastguard Worker SkAssertResult(SkLineClipper::IntersectLine(line, border, clippedLine));
192*c8dee2aaSAndroid Build Coastguard Worker draw_outset_line(canvas, local, clippedLine, paint);
193*c8dee2aaSAndroid Build Coastguard Worker }
194*c8dee2aaSAndroid Build Coastguard Worker
draw_text(SkCanvas * canvas,const char * text)195*c8dee2aaSAndroid Build Coastguard Worker static void draw_text(SkCanvas* canvas, const char* text) {
196*c8dee2aaSAndroid Build Coastguard Worker SkFont font(ToolUtils::DefaultPortableTypeface(), 12);
197*c8dee2aaSAndroid Build Coastguard Worker canvas->drawString(text, 0, 0, font, SkPaint());
198*c8dee2aaSAndroid Build Coastguard Worker }
199*c8dee2aaSAndroid Build Coastguard Worker
200*c8dee2aaSAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////////////////////////////
201*c8dee2aaSAndroid Build Coastguard Worker // Abstraction for rendering a possibly clipped tile, that can apply different effects to mimic
202*c8dee2aaSAndroid Build Coastguard Worker // the Chromium quad types, and a generic GM template to arrange renderers x transforms in a grid
203*c8dee2aaSAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////////////////////////////
204*c8dee2aaSAndroid Build Coastguard Worker
205*c8dee2aaSAndroid Build Coastguard Worker class ClipTileRenderer : public SkRefCntBase {
206*c8dee2aaSAndroid Build Coastguard Worker public:
207*c8dee2aaSAndroid Build Coastguard Worker // Draw the base rect, possibly clipped by 'clip' if that is not null. The edges to antialias
208*c8dee2aaSAndroid Build Coastguard Worker // are specified in 'edgeAA' (to make manipulation easier than an unsigned bitfield). 'tileID'
209*c8dee2aaSAndroid Build Coastguard Worker // represents the location of rect within the tile grid, 'quadID' is the unique ID of the clip
210*c8dee2aaSAndroid Build Coastguard Worker // region within the tile (reset for each tile).
211*c8dee2aaSAndroid Build Coastguard Worker //
212*c8dee2aaSAndroid Build Coastguard Worker // The edgeAA order matches that of clip, so it refers to top, right, bottom, left.
213*c8dee2aaSAndroid Build Coastguard Worker // Return draw count
214*c8dee2aaSAndroid Build Coastguard Worker virtual int drawTile(SkCanvas* canvas, const SkRect& rect, const SkPoint clip[4],
215*c8dee2aaSAndroid Build Coastguard Worker const bool edgeAA[4], int tileID, int quadID) = 0;
216*c8dee2aaSAndroid Build Coastguard Worker
217*c8dee2aaSAndroid Build Coastguard Worker virtual void drawBanner(SkCanvas* canvas) = 0;
218*c8dee2aaSAndroid Build Coastguard Worker
219*c8dee2aaSAndroid Build Coastguard Worker // Return draw count
drawTiles(SkCanvas * canvas)220*c8dee2aaSAndroid Build Coastguard Worker virtual int drawTiles(SkCanvas* canvas) {
221*c8dee2aaSAndroid Build Coastguard Worker // All three lines in a list
222*c8dee2aaSAndroid Build Coastguard Worker SkPoint lines[6];
223*c8dee2aaSAndroid Build Coastguard Worker clipping_line_segment(kClipP1, kClipP2, lines);
224*c8dee2aaSAndroid Build Coastguard Worker clipping_line_segment(kClipP2, kClipP3, lines + 2);
225*c8dee2aaSAndroid Build Coastguard Worker clipping_line_segment(kClipP3, kClipP1, lines + 4);
226*c8dee2aaSAndroid Build Coastguard Worker
227*c8dee2aaSAndroid Build Coastguard Worker bool edgeAA[4];
228*c8dee2aaSAndroid Build Coastguard Worker int tileID = 0;
229*c8dee2aaSAndroid Build Coastguard Worker int drawCount = 0;
230*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < kRowCount; ++i) {
231*c8dee2aaSAndroid Build Coastguard Worker for (int j = 0; j < kColCount; ++j) {
232*c8dee2aaSAndroid Build Coastguard Worker // The unclipped tile geometry
233*c8dee2aaSAndroid Build Coastguard Worker SkRect tile = SkRect::MakeXYWH(j * kTileWidth, i * kTileHeight,
234*c8dee2aaSAndroid Build Coastguard Worker kTileWidth, kTileHeight);
235*c8dee2aaSAndroid Build Coastguard Worker // Base edge AA flags if there are no clips; clipped lines will only turn off edges
236*c8dee2aaSAndroid Build Coastguard Worker edgeAA[0] = i == 0; // Top
237*c8dee2aaSAndroid Build Coastguard Worker edgeAA[1] = j == kColCount - 1; // Right
238*c8dee2aaSAndroid Build Coastguard Worker edgeAA[2] = i == kRowCount - 1; // Bottom
239*c8dee2aaSAndroid Build Coastguard Worker edgeAA[3] = j == 0; // Left
240*c8dee2aaSAndroid Build Coastguard Worker
241*c8dee2aaSAndroid Build Coastguard Worker // Now clip against the 3 lines formed by kClipPx and split into general purpose
242*c8dee2aaSAndroid Build Coastguard Worker // quads as needed.
243*c8dee2aaSAndroid Build Coastguard Worker int quadCount = 0;
244*c8dee2aaSAndroid Build Coastguard Worker drawCount += this->clipTile(canvas, tileID, tile, nullptr, edgeAA, lines, 3,
245*c8dee2aaSAndroid Build Coastguard Worker &quadCount);
246*c8dee2aaSAndroid Build Coastguard Worker tileID++;
247*c8dee2aaSAndroid Build Coastguard Worker }
248*c8dee2aaSAndroid Build Coastguard Worker }
249*c8dee2aaSAndroid Build Coastguard Worker
250*c8dee2aaSAndroid Build Coastguard Worker return drawCount;
251*c8dee2aaSAndroid Build Coastguard Worker }
252*c8dee2aaSAndroid Build Coastguard Worker
253*c8dee2aaSAndroid Build Coastguard Worker protected:
maskToFlags(const bool edgeAA[4]) const254*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::QuadAAFlags maskToFlags(const bool edgeAA[4]) const {
255*c8dee2aaSAndroid Build Coastguard Worker unsigned flags = (edgeAA[0] * SkCanvas::kTop_QuadAAFlag) |
256*c8dee2aaSAndroid Build Coastguard Worker (edgeAA[1] * SkCanvas::kRight_QuadAAFlag) |
257*c8dee2aaSAndroid Build Coastguard Worker (edgeAA[2] * SkCanvas::kBottom_QuadAAFlag) |
258*c8dee2aaSAndroid Build Coastguard Worker (edgeAA[3] * SkCanvas::kLeft_QuadAAFlag);
259*c8dee2aaSAndroid Build Coastguard Worker return static_cast<SkCanvas::QuadAAFlags>(flags);
260*c8dee2aaSAndroid Build Coastguard Worker }
261*c8dee2aaSAndroid Build Coastguard Worker
262*c8dee2aaSAndroid Build Coastguard Worker // Recursively splits the quadrilateral against the segments stored in 'lines', which must be
263*c8dee2aaSAndroid Build Coastguard Worker // 2 * lineCount long. Increments 'quadCount' for each split quadrilateral, and invokes the
264*c8dee2aaSAndroid Build Coastguard Worker // drawTile at leaves.
clipTile(SkCanvas * canvas,int tileID,const SkRect & baseRect,const SkPoint quad[4],const bool edgeAA[4],const SkPoint lines[],int lineCount,int * quadCount)265*c8dee2aaSAndroid Build Coastguard Worker int clipTile(SkCanvas* canvas, int tileID, const SkRect& baseRect, const SkPoint quad[4],
266*c8dee2aaSAndroid Build Coastguard Worker const bool edgeAA[4], const SkPoint lines[], int lineCount, int* quadCount) {
267*c8dee2aaSAndroid Build Coastguard Worker if (lineCount == 0) {
268*c8dee2aaSAndroid Build Coastguard Worker // No lines, so end recursion by drawing the tile. If the tile was never split then
269*c8dee2aaSAndroid Build Coastguard Worker // 'quad' remains null so that drawTile() can differentiate how it should draw.
270*c8dee2aaSAndroid Build Coastguard Worker int draws = this->drawTile(canvas, baseRect, quad, edgeAA, tileID, *quadCount);
271*c8dee2aaSAndroid Build Coastguard Worker *quadCount = *quadCount + 1;
272*c8dee2aaSAndroid Build Coastguard Worker return draws;
273*c8dee2aaSAndroid Build Coastguard Worker }
274*c8dee2aaSAndroid Build Coastguard Worker
275*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kTL = 0; // Top-left point index in points array
276*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kTR = 1; // Top-right point index in points array
277*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kBR = 2; // Bottom-right point index in points array
278*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kBL = 3; // Bottom-left point index in points array
279*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kS0 = 4; // First split point index in points array
280*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kS1 = 5; // Second split point index in points array
281*c8dee2aaSAndroid Build Coastguard Worker
282*c8dee2aaSAndroid Build Coastguard Worker SkPoint points[6];
283*c8dee2aaSAndroid Build Coastguard Worker if (quad) {
284*c8dee2aaSAndroid Build Coastguard Worker // Copy the original 4 points into set of points to consider
285*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) {
286*c8dee2aaSAndroid Build Coastguard Worker points[i] = quad[i];
287*c8dee2aaSAndroid Build Coastguard Worker }
288*c8dee2aaSAndroid Build Coastguard Worker } else {
289*c8dee2aaSAndroid Build Coastguard Worker // Haven't been split yet, so fill in based on the rect
290*c8dee2aaSAndroid Build Coastguard Worker baseRect.toQuad(points);
291*c8dee2aaSAndroid Build Coastguard Worker }
292*c8dee2aaSAndroid Build Coastguard Worker
293*c8dee2aaSAndroid Build Coastguard Worker // Consider the first line against the 4 quad edges in tile, which should have 0,1, or 2
294*c8dee2aaSAndroid Build Coastguard Worker // intersection points since the tile is convex.
295*c8dee2aaSAndroid Build Coastguard Worker int splitIndices[2]; // Edge that was intersected
296*c8dee2aaSAndroid Build Coastguard Worker int intersectionCount = 0;
297*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) {
298*c8dee2aaSAndroid Build Coastguard Worker SkPoint intersect;
299*c8dee2aaSAndroid Build Coastguard Worker if (intersect_line_segments(points[i], points[i == 3 ? 0 : i + 1],
300*c8dee2aaSAndroid Build Coastguard Worker lines[0], lines[1], &intersect)) {
301*c8dee2aaSAndroid Build Coastguard Worker // If the intersected point is the same as the last found intersection, the line
302*c8dee2aaSAndroid Build Coastguard Worker // runs through a vertex, so don't double count it
303*c8dee2aaSAndroid Build Coastguard Worker bool duplicate = false;
304*c8dee2aaSAndroid Build Coastguard Worker for (int j = 0; j < intersectionCount; ++j) {
305*c8dee2aaSAndroid Build Coastguard Worker if (SkScalarNearlyZero((intersect - points[kS0 + j]).length())) {
306*c8dee2aaSAndroid Build Coastguard Worker duplicate = true;
307*c8dee2aaSAndroid Build Coastguard Worker break;
308*c8dee2aaSAndroid Build Coastguard Worker }
309*c8dee2aaSAndroid Build Coastguard Worker }
310*c8dee2aaSAndroid Build Coastguard Worker if (!duplicate) {
311*c8dee2aaSAndroid Build Coastguard Worker points[kS0 + intersectionCount] = intersect;
312*c8dee2aaSAndroid Build Coastguard Worker splitIndices[intersectionCount] = i;
313*c8dee2aaSAndroid Build Coastguard Worker intersectionCount++;
314*c8dee2aaSAndroid Build Coastguard Worker }
315*c8dee2aaSAndroid Build Coastguard Worker }
316*c8dee2aaSAndroid Build Coastguard Worker }
317*c8dee2aaSAndroid Build Coastguard Worker
318*c8dee2aaSAndroid Build Coastguard Worker if (intersectionCount < 2) {
319*c8dee2aaSAndroid Build Coastguard Worker // Either the first line never intersected the quad (count == 0), or it intersected at a
320*c8dee2aaSAndroid Build Coastguard Worker // single vertex without going through quad area (count == 1), so check next line
321*c8dee2aaSAndroid Build Coastguard Worker return this->clipTile(
322*c8dee2aaSAndroid Build Coastguard Worker canvas, tileID, baseRect, quad, edgeAA, lines + 2, lineCount - 1, quadCount);
323*c8dee2aaSAndroid Build Coastguard Worker }
324*c8dee2aaSAndroid Build Coastguard Worker
325*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(intersectionCount == 2);
326*c8dee2aaSAndroid Build Coastguard Worker // Split the tile points into 2+ sub quads and recurse to the next lines, which may or may
327*c8dee2aaSAndroid Build Coastguard Worker // not further split the tile. Since the configurations are relatively simple, the possible
328*c8dee2aaSAndroid Build Coastguard Worker // splits are hardcoded below; subtile quad orderings are such that the sub tiles remain in
329*c8dee2aaSAndroid Build Coastguard Worker // clockwise order and match expected edges for QuadAAFlags. subtile indices refer to the
330*c8dee2aaSAndroid Build Coastguard Worker // 6-element 'points' array.
331*c8dee2aaSAndroid Build Coastguard Worker STArray<3, std::array<int, 4>> subtiles;
332*c8dee2aaSAndroid Build Coastguard Worker int s2 = -1; // Index of an original vertex chosen for a artificial split
333*c8dee2aaSAndroid Build Coastguard Worker if (splitIndices[1] - splitIndices[0] == 2) {
334*c8dee2aaSAndroid Build Coastguard Worker // Opposite edges, so the split trivially forms 2 sub quads
335*c8dee2aaSAndroid Build Coastguard Worker if (splitIndices[0] == 0) {
336*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kTL, kS0, kS1, kBL}});
337*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kS0, kTR, kBR, kS1}});
338*c8dee2aaSAndroid Build Coastguard Worker } else {
339*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kTL, kTR, kS0, kS1}});
340*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kS1, kS0, kBR, kBL}});
341*c8dee2aaSAndroid Build Coastguard Worker }
342*c8dee2aaSAndroid Build Coastguard Worker } else {
343*c8dee2aaSAndroid Build Coastguard Worker // Adjacent edges, which makes for a more complicated split, since it forms a degenerate
344*c8dee2aaSAndroid Build Coastguard Worker // quad (triangle) and a pentagon that must be artificially split. The pentagon is split
345*c8dee2aaSAndroid Build Coastguard Worker // using one of the original vertices (remembered in 's2'), which adds an additional
346*c8dee2aaSAndroid Build Coastguard Worker // degenerate quad, but ensures there are no T-junctions.
347*c8dee2aaSAndroid Build Coastguard Worker switch(splitIndices[0]) {
348*c8dee2aaSAndroid Build Coastguard Worker case 0:
349*c8dee2aaSAndroid Build Coastguard Worker // Could be connected to edge 1 or edge 3
350*c8dee2aaSAndroid Build Coastguard Worker if (splitIndices[1] == 1) {
351*c8dee2aaSAndroid Build Coastguard Worker s2 = kBL;
352*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kS0, kTR, kS1, kS0}}); // degenerate
353*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kTL, kS0, edgeAA[0] ? kS0 : kBL, kBL}}); // degenerate
354*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kS0, kS1, kBR, kBL}});
355*c8dee2aaSAndroid Build Coastguard Worker } else {
356*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(splitIndices[1] == 3);
357*c8dee2aaSAndroid Build Coastguard Worker s2 = kBR;
358*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kTL, kS0, kS1, kS1}}); // degenerate
359*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kS1, edgeAA[3] ? kS1 : kBR, kBR, kBL}}); // degenerate
360*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kS0, kTR, kBR, kS1}});
361*c8dee2aaSAndroid Build Coastguard Worker }
362*c8dee2aaSAndroid Build Coastguard Worker break;
363*c8dee2aaSAndroid Build Coastguard Worker case 1:
364*c8dee2aaSAndroid Build Coastguard Worker // Edge 0 handled above, should only be connected to edge 2
365*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(splitIndices[1] == 2);
366*c8dee2aaSAndroid Build Coastguard Worker s2 = kTL;
367*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kS0, kS0, kBR, kS1}}); // degenerate
368*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kTL, kTR, kS0, edgeAA[1] ? kS0 : kTL}}); // degenerate
369*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kTL, kS0, kS1, kBL}});
370*c8dee2aaSAndroid Build Coastguard Worker break;
371*c8dee2aaSAndroid Build Coastguard Worker case 2:
372*c8dee2aaSAndroid Build Coastguard Worker // Edge 1 handled above, should only be connected to edge 3
373*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(splitIndices[1] == 3);
374*c8dee2aaSAndroid Build Coastguard Worker s2 = kTR;
375*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kS1, kS0, kS0, kBL}}); // degenerate
376*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{edgeAA[2] ? kS0 : kTR, kTR, kBR, kS0}}); // degenerate
377*c8dee2aaSAndroid Build Coastguard Worker subtiles.push_back({{kTL, kTR, kS0, kS1}});
378*c8dee2aaSAndroid Build Coastguard Worker break;
379*c8dee2aaSAndroid Build Coastguard Worker case 3:
380*c8dee2aaSAndroid Build Coastguard Worker // Fall through, an adjacent edge split that hits edge 3 should have first found
381*c8dee2aaSAndroid Build Coastguard Worker // been found with edge 0 or edge 2 for the other end
382*c8dee2aaSAndroid Build Coastguard Worker default:
383*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(false);
384*c8dee2aaSAndroid Build Coastguard Worker return 0;
385*c8dee2aaSAndroid Build Coastguard Worker }
386*c8dee2aaSAndroid Build Coastguard Worker }
387*c8dee2aaSAndroid Build Coastguard Worker
388*c8dee2aaSAndroid Build Coastguard Worker SkPoint sub[4];
389*c8dee2aaSAndroid Build Coastguard Worker bool subAA[4];
390*c8dee2aaSAndroid Build Coastguard Worker int draws = 0;
391*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < subtiles.size(); ++i) {
392*c8dee2aaSAndroid Build Coastguard Worker // Fill in the quad points and update edge AA rules for new interior edges
393*c8dee2aaSAndroid Build Coastguard Worker for (int j = 0; j < 4; ++j) {
394*c8dee2aaSAndroid Build Coastguard Worker int p = subtiles[i][j];
395*c8dee2aaSAndroid Build Coastguard Worker sub[j] = points[p];
396*c8dee2aaSAndroid Build Coastguard Worker
397*c8dee2aaSAndroid Build Coastguard Worker int np = j == 3 ? subtiles[i][0] : subtiles[i][j + 1];
398*c8dee2aaSAndroid Build Coastguard Worker // The "new" edges are the edges that connect between the two split points or
399*c8dee2aaSAndroid Build Coastguard Worker // between a split point and the chosen s2 point. Otherwise the edge remains aligned
400*c8dee2aaSAndroid Build Coastguard Worker // with the original shape, so should preserve the AA setting.
401*c8dee2aaSAndroid Build Coastguard Worker if ((p >= kS0 && (np == s2 || np >= kS0)) ||
402*c8dee2aaSAndroid Build Coastguard Worker ((np >= kS0) && (p == s2 || p >= kS0))) {
403*c8dee2aaSAndroid Build Coastguard Worker // New edge
404*c8dee2aaSAndroid Build Coastguard Worker subAA[j] = false;
405*c8dee2aaSAndroid Build Coastguard Worker } else {
406*c8dee2aaSAndroid Build Coastguard Worker // The subtiles indices were arranged so that their edge ordering was still top,
407*c8dee2aaSAndroid Build Coastguard Worker // right, bottom, left so 'j' can be used to access edgeAA
408*c8dee2aaSAndroid Build Coastguard Worker subAA[j] = edgeAA[j];
409*c8dee2aaSAndroid Build Coastguard Worker }
410*c8dee2aaSAndroid Build Coastguard Worker }
411*c8dee2aaSAndroid Build Coastguard Worker
412*c8dee2aaSAndroid Build Coastguard Worker // Split the sub quad with the next line
413*c8dee2aaSAndroid Build Coastguard Worker draws += this->clipTile(canvas, tileID, baseRect, sub, subAA, lines + 2, lineCount - 1,
414*c8dee2aaSAndroid Build Coastguard Worker quadCount);
415*c8dee2aaSAndroid Build Coastguard Worker }
416*c8dee2aaSAndroid Build Coastguard Worker return draws;
417*c8dee2aaSAndroid Build Coastguard Worker }
418*c8dee2aaSAndroid Build Coastguard Worker };
419*c8dee2aaSAndroid Build Coastguard Worker
420*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kMatrixCount = 5;
421*c8dee2aaSAndroid Build Coastguard Worker
422*c8dee2aaSAndroid Build Coastguard Worker class CompositorGM : public skiagm::GM {
423*c8dee2aaSAndroid Build Coastguard Worker public:
CompositorGM(const char * name,std::function<ClipTileRendererArray ()> makeRendererFn)424*c8dee2aaSAndroid Build Coastguard Worker CompositorGM(const char* name, std::function<ClipTileRendererArray()> makeRendererFn)
425*c8dee2aaSAndroid Build Coastguard Worker : fMakeRendererFn(std::move(makeRendererFn))
426*c8dee2aaSAndroid Build Coastguard Worker , fName(name) {}
427*c8dee2aaSAndroid Build Coastguard Worker
428*c8dee2aaSAndroid Build Coastguard Worker protected:
getISize()429*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override {
430*c8dee2aaSAndroid Build Coastguard Worker // Initialize the array of renderers.
431*c8dee2aaSAndroid Build Coastguard Worker this->onceBeforeDraw();
432*c8dee2aaSAndroid Build Coastguard Worker
433*c8dee2aaSAndroid Build Coastguard Worker // The GM draws a grid of renderers (rows) x transforms (col). Within each cell, the
434*c8dee2aaSAndroid Build Coastguard Worker // renderer draws the transformed tile grid, which is approximately
435*c8dee2aaSAndroid Build Coastguard Worker // (kColCount*kTileWidth, kRowCount*kTileHeight), although it has additional line
436*c8dee2aaSAndroid Build Coastguard Worker // visualizations and can be transformed outside of those rectangular bounds (i.e. persp),
437*c8dee2aaSAndroid Build Coastguard Worker // so pad the cell dimensions to be conservative. Must also account for the banner text.
438*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kCellWidth = 1.3f * kColCount * kTileWidth;
439*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kCellHeight = 1.3f * kRowCount * kTileHeight;
440*c8dee2aaSAndroid Build Coastguard Worker return SkISize::Make(SkScalarRoundToInt(kCellWidth * kMatrixCount + 175.f),
441*c8dee2aaSAndroid Build Coastguard Worker SkScalarRoundToInt(kCellHeight * fRenderers.size() + 75.f));
442*c8dee2aaSAndroid Build Coastguard Worker }
443*c8dee2aaSAndroid Build Coastguard Worker
getName() const444*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override {
445*c8dee2aaSAndroid Build Coastguard Worker SkString fullName;
446*c8dee2aaSAndroid Build Coastguard Worker fullName.appendf("compositor_quads_%s", fName.c_str());
447*c8dee2aaSAndroid Build Coastguard Worker return fullName;
448*c8dee2aaSAndroid Build Coastguard Worker }
449*c8dee2aaSAndroid Build Coastguard Worker
onOnceBeforeDraw()450*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override {
451*c8dee2aaSAndroid Build Coastguard Worker fRenderers = fMakeRendererFn();
452*c8dee2aaSAndroid Build Coastguard Worker this->configureMatrices();
453*c8dee2aaSAndroid Build Coastguard Worker }
454*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)455*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
456*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kGap = 40.f;
457*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kBannerWidth = 120.f;
458*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kOffset = 15.f;
459*c8dee2aaSAndroid Build Coastguard Worker
460*c8dee2aaSAndroid Build Coastguard Worker TArray<int> drawCounts(fRenderers.size());
461*c8dee2aaSAndroid Build Coastguard Worker drawCounts.push_back_n(fRenderers.size(), 0);
462*c8dee2aaSAndroid Build Coastguard Worker
463*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
464*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kOffset + kBannerWidth, kOffset);
465*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fMatrices.size(); ++i) {
466*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
467*c8dee2aaSAndroid Build Coastguard Worker draw_text(canvas, fMatrixNames[i].c_str());
468*c8dee2aaSAndroid Build Coastguard Worker
469*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0.f, kGap);
470*c8dee2aaSAndroid Build Coastguard Worker for (int j = 0; j < fRenderers.size(); ++j) {
471*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
472*c8dee2aaSAndroid Build Coastguard Worker draw_tile_boundaries(canvas, fMatrices[i]);
473*c8dee2aaSAndroid Build Coastguard Worker draw_clipping_boundaries(canvas, fMatrices[i]);
474*c8dee2aaSAndroid Build Coastguard Worker
475*c8dee2aaSAndroid Build Coastguard Worker canvas->concat(fMatrices[i]);
476*c8dee2aaSAndroid Build Coastguard Worker drawCounts[j] += fRenderers[j]->drawTiles(canvas);
477*c8dee2aaSAndroid Build Coastguard Worker
478*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
479*c8dee2aaSAndroid Build Coastguard Worker // And advance to the next row
480*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0.f, kGap + kRowCount * kTileHeight);
481*c8dee2aaSAndroid Build Coastguard Worker }
482*c8dee2aaSAndroid Build Coastguard Worker // Reset back to the left edge
483*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
484*c8dee2aaSAndroid Build Coastguard Worker // And advance to the next column
485*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kGap + kColCount * kTileWidth, 0.f);
486*c8dee2aaSAndroid Build Coastguard Worker }
487*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
488*c8dee2aaSAndroid Build Coastguard Worker
489*c8dee2aaSAndroid Build Coastguard Worker // Print a row header, with total draw counts
490*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
491*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kOffset, kGap + 0.5f * kRowCount * kTileHeight);
492*c8dee2aaSAndroid Build Coastguard Worker for (int j = 0; j < fRenderers.size(); ++j) {
493*c8dee2aaSAndroid Build Coastguard Worker fRenderers[j]->drawBanner(canvas);
494*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0.f, 15.f);
495*c8dee2aaSAndroid Build Coastguard Worker draw_text(canvas, SkStringPrintf("Draws = %d", drawCounts[j]).c_str());
496*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0.f, kGap + kRowCount * kTileHeight);
497*c8dee2aaSAndroid Build Coastguard Worker }
498*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
499*c8dee2aaSAndroid Build Coastguard Worker }
500*c8dee2aaSAndroid Build Coastguard Worker
501*c8dee2aaSAndroid Build Coastguard Worker private:
502*c8dee2aaSAndroid Build Coastguard Worker std::function<ClipTileRendererArray()> fMakeRendererFn;
503*c8dee2aaSAndroid Build Coastguard Worker ClipTileRendererArray fRenderers;
504*c8dee2aaSAndroid Build Coastguard Worker TArray<SkMatrix> fMatrices;
505*c8dee2aaSAndroid Build Coastguard Worker TArray<SkString> fMatrixNames;
506*c8dee2aaSAndroid Build Coastguard Worker
507*c8dee2aaSAndroid Build Coastguard Worker SkString fName;
508*c8dee2aaSAndroid Build Coastguard Worker
configureMatrices()509*c8dee2aaSAndroid Build Coastguard Worker void configureMatrices() {
510*c8dee2aaSAndroid Build Coastguard Worker fMatrices.clear();
511*c8dee2aaSAndroid Build Coastguard Worker fMatrixNames.clear();
512*c8dee2aaSAndroid Build Coastguard Worker fMatrices.push_back_n(kMatrixCount);
513*c8dee2aaSAndroid Build Coastguard Worker
514*c8dee2aaSAndroid Build Coastguard Worker // Identity
515*c8dee2aaSAndroid Build Coastguard Worker fMatrices[0].setIdentity();
516*c8dee2aaSAndroid Build Coastguard Worker fMatrixNames.push_back(SkString("Identity"));
517*c8dee2aaSAndroid Build Coastguard Worker
518*c8dee2aaSAndroid Build Coastguard Worker // Translate/scale
519*c8dee2aaSAndroid Build Coastguard Worker fMatrices[1].setTranslate(5.5f, 20.25f);
520*c8dee2aaSAndroid Build Coastguard Worker fMatrices[1].postScale(.9f, .7f);
521*c8dee2aaSAndroid Build Coastguard Worker fMatrixNames.push_back(SkString("T+S"));
522*c8dee2aaSAndroid Build Coastguard Worker
523*c8dee2aaSAndroid Build Coastguard Worker // Rotation
524*c8dee2aaSAndroid Build Coastguard Worker fMatrices[2].setRotate(20.0f);
525*c8dee2aaSAndroid Build Coastguard Worker fMatrices[2].preTranslate(15.f, -20.f);
526*c8dee2aaSAndroid Build Coastguard Worker fMatrixNames.push_back(SkString("Rotate"));
527*c8dee2aaSAndroid Build Coastguard Worker
528*c8dee2aaSAndroid Build Coastguard Worker // Skew
529*c8dee2aaSAndroid Build Coastguard Worker fMatrices[3].setSkew(.5f, .25f);
530*c8dee2aaSAndroid Build Coastguard Worker fMatrices[3].preTranslate(-30.f, 0.f);
531*c8dee2aaSAndroid Build Coastguard Worker fMatrixNames.push_back(SkString("Skew"));
532*c8dee2aaSAndroid Build Coastguard Worker
533*c8dee2aaSAndroid Build Coastguard Worker // Perspective
534*c8dee2aaSAndroid Build Coastguard Worker SkPoint src[4];
535*c8dee2aaSAndroid Build Coastguard Worker SkRect::MakeWH(kColCount * kTileWidth, kRowCount * kTileHeight).toQuad(src);
536*c8dee2aaSAndroid Build Coastguard Worker SkPoint dst[4] = {{0, 0},
537*c8dee2aaSAndroid Build Coastguard Worker {kColCount * kTileWidth + 10.f, 15.f},
538*c8dee2aaSAndroid Build Coastguard Worker {kColCount * kTileWidth - 28.f, kRowCount * kTileHeight + 40.f},
539*c8dee2aaSAndroid Build Coastguard Worker {25.f, kRowCount * kTileHeight - 15.f}};
540*c8dee2aaSAndroid Build Coastguard Worker SkAssertResult(fMatrices[4].setPolyToPoly(src, dst, 4));
541*c8dee2aaSAndroid Build Coastguard Worker fMatrices[4].preTranslate(0.f, 10.f);
542*c8dee2aaSAndroid Build Coastguard Worker fMatrixNames.push_back(SkString("Perspective"));
543*c8dee2aaSAndroid Build Coastguard Worker
544*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fMatrices.size() == fMatrixNames.size());
545*c8dee2aaSAndroid Build Coastguard Worker }
546*c8dee2aaSAndroid Build Coastguard Worker
547*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = skiagm::GM;
548*c8dee2aaSAndroid Build Coastguard Worker };
549*c8dee2aaSAndroid Build Coastguard Worker
550*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////////////////
551*c8dee2aaSAndroid Build Coastguard Worker // Implementations of TileRenderer that color the clipped tiles in various ways
552*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////////////////////
553*c8dee2aaSAndroid Build Coastguard Worker
554*c8dee2aaSAndroid Build Coastguard Worker class DebugTileRenderer : public ClipTileRenderer {
555*c8dee2aaSAndroid Build Coastguard Worker public:
556*c8dee2aaSAndroid Build Coastguard Worker
Make()557*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> Make() {
558*c8dee2aaSAndroid Build Coastguard Worker // Since aa override is disabled, the quad flags arg doesn't matter.
559*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<ClipTileRenderer>(new DebugTileRenderer(SkCanvas::kAll_QuadAAFlags, false));
560*c8dee2aaSAndroid Build Coastguard Worker }
561*c8dee2aaSAndroid Build Coastguard Worker
MakeAA()562*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> MakeAA() {
563*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<ClipTileRenderer>(new DebugTileRenderer(SkCanvas::kAll_QuadAAFlags, true));
564*c8dee2aaSAndroid Build Coastguard Worker }
565*c8dee2aaSAndroid Build Coastguard Worker
MakeNonAA()566*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> MakeNonAA() {
567*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<ClipTileRenderer>(new DebugTileRenderer(SkCanvas::kNone_QuadAAFlags, true));
568*c8dee2aaSAndroid Build Coastguard Worker }
569*c8dee2aaSAndroid Build Coastguard Worker
drawTile(SkCanvas * canvas,const SkRect & rect,const SkPoint clip[4],const bool edgeAA[4],int tileID,int quadID)570*c8dee2aaSAndroid Build Coastguard Worker int drawTile(SkCanvas* canvas, const SkRect& rect, const SkPoint clip[4], const bool edgeAA[4],
571*c8dee2aaSAndroid Build Coastguard Worker int tileID, int quadID) override {
572*c8dee2aaSAndroid Build Coastguard Worker // Colorize the tile based on its grid position and quad ID
573*c8dee2aaSAndroid Build Coastguard Worker int i = tileID / kColCount;
574*c8dee2aaSAndroid Build Coastguard Worker int j = tileID % kColCount;
575*c8dee2aaSAndroid Build Coastguard Worker
576*c8dee2aaSAndroid Build Coastguard Worker SkColor4f c = {(i + 1.f) / kRowCount, (j + 1.f) / kColCount, .4f, 1.f};
577*c8dee2aaSAndroid Build Coastguard Worker float alpha = quadID / 10.f;
578*c8dee2aaSAndroid Build Coastguard Worker c.fR = c.fR * (1 - alpha) + alpha;
579*c8dee2aaSAndroid Build Coastguard Worker c.fG = c.fG * (1 - alpha) + alpha;
580*c8dee2aaSAndroid Build Coastguard Worker c.fB = c.fB * (1 - alpha) + alpha;
581*c8dee2aaSAndroid Build Coastguard Worker c.fA = c.fA * (1 - alpha) + alpha;
582*c8dee2aaSAndroid Build Coastguard Worker
583*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::QuadAAFlags aaFlags = fEnableAAOverride ? fAAOverride : this->maskToFlags(edgeAA);
584*c8dee2aaSAndroid Build Coastguard Worker canvas->experimental_DrawEdgeAAQuad(
585*c8dee2aaSAndroid Build Coastguard Worker rect, clip, aaFlags, c.toSkColor(), SkBlendMode::kSrcOver);
586*c8dee2aaSAndroid Build Coastguard Worker return 1;
587*c8dee2aaSAndroid Build Coastguard Worker }
588*c8dee2aaSAndroid Build Coastguard Worker
drawBanner(SkCanvas * canvas)589*c8dee2aaSAndroid Build Coastguard Worker void drawBanner(SkCanvas* canvas) override {
590*c8dee2aaSAndroid Build Coastguard Worker draw_text(canvas, "Edge AA");
591*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0.f, 15.f);
592*c8dee2aaSAndroid Build Coastguard Worker
593*c8dee2aaSAndroid Build Coastguard Worker SkString config;
594*c8dee2aaSAndroid Build Coastguard Worker constexpr char kFormat[] = "Ext(%s) - Int(%s)";
595*c8dee2aaSAndroid Build Coastguard Worker if (fEnableAAOverride) {
596*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fAAOverride == SkCanvas::kAll_QuadAAFlags ||
597*c8dee2aaSAndroid Build Coastguard Worker fAAOverride == SkCanvas::kNone_QuadAAFlags);
598*c8dee2aaSAndroid Build Coastguard Worker if (fAAOverride == SkCanvas::kAll_QuadAAFlags) {
599*c8dee2aaSAndroid Build Coastguard Worker config.appendf(kFormat, "yes", "yes");
600*c8dee2aaSAndroid Build Coastguard Worker } else {
601*c8dee2aaSAndroid Build Coastguard Worker config.appendf(kFormat, "no", "no");
602*c8dee2aaSAndroid Build Coastguard Worker }
603*c8dee2aaSAndroid Build Coastguard Worker } else {
604*c8dee2aaSAndroid Build Coastguard Worker config.appendf(kFormat, "yes", "no");
605*c8dee2aaSAndroid Build Coastguard Worker }
606*c8dee2aaSAndroid Build Coastguard Worker draw_text(canvas, config.c_str());
607*c8dee2aaSAndroid Build Coastguard Worker }
608*c8dee2aaSAndroid Build Coastguard Worker
609*c8dee2aaSAndroid Build Coastguard Worker private:
610*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::QuadAAFlags fAAOverride;
611*c8dee2aaSAndroid Build Coastguard Worker bool fEnableAAOverride;
612*c8dee2aaSAndroid Build Coastguard Worker
DebugTileRenderer(SkCanvas::QuadAAFlags aa,bool enableAAOverrde)613*c8dee2aaSAndroid Build Coastguard Worker DebugTileRenderer(SkCanvas::QuadAAFlags aa, bool enableAAOverrde)
614*c8dee2aaSAndroid Build Coastguard Worker : fAAOverride(aa)
615*c8dee2aaSAndroid Build Coastguard Worker , fEnableAAOverride(enableAAOverrde) {}
616*c8dee2aaSAndroid Build Coastguard Worker
617*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = ClipTileRenderer;
618*c8dee2aaSAndroid Build Coastguard Worker };
619*c8dee2aaSAndroid Build Coastguard Worker
620*c8dee2aaSAndroid Build Coastguard Worker // Tests tmp_drawEdgeAAQuad
621*c8dee2aaSAndroid Build Coastguard Worker class SolidColorRenderer : public ClipTileRenderer {
622*c8dee2aaSAndroid Build Coastguard Worker public:
623*c8dee2aaSAndroid Build Coastguard Worker
Make(const SkColor4f & color)624*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> Make(const SkColor4f& color) {
625*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<ClipTileRenderer>(new SolidColorRenderer(color));
626*c8dee2aaSAndroid Build Coastguard Worker }
627*c8dee2aaSAndroid Build Coastguard Worker
drawTile(SkCanvas * canvas,const SkRect & rect,const SkPoint clip[4],const bool edgeAA[4],int tileID,int quadID)628*c8dee2aaSAndroid Build Coastguard Worker int drawTile(SkCanvas* canvas, const SkRect& rect, const SkPoint clip[4], const bool edgeAA[4],
629*c8dee2aaSAndroid Build Coastguard Worker int tileID, int quadID) override {
630*c8dee2aaSAndroid Build Coastguard Worker canvas->experimental_DrawEdgeAAQuad(rect, clip, this->maskToFlags(edgeAA),
631*c8dee2aaSAndroid Build Coastguard Worker fColor.toSkColor(), SkBlendMode::kSrcOver);
632*c8dee2aaSAndroid Build Coastguard Worker return 1;
633*c8dee2aaSAndroid Build Coastguard Worker }
634*c8dee2aaSAndroid Build Coastguard Worker
drawBanner(SkCanvas * canvas)635*c8dee2aaSAndroid Build Coastguard Worker void drawBanner(SkCanvas* canvas) override {
636*c8dee2aaSAndroid Build Coastguard Worker draw_text(canvas, "Solid Color");
637*c8dee2aaSAndroid Build Coastguard Worker }
638*c8dee2aaSAndroid Build Coastguard Worker
639*c8dee2aaSAndroid Build Coastguard Worker private:
640*c8dee2aaSAndroid Build Coastguard Worker SkColor4f fColor;
641*c8dee2aaSAndroid Build Coastguard Worker
SolidColorRenderer(const SkColor4f & color)642*c8dee2aaSAndroid Build Coastguard Worker SolidColorRenderer(const SkColor4f& color) : fColor(color) {}
643*c8dee2aaSAndroid Build Coastguard Worker
644*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = ClipTileRenderer;
645*c8dee2aaSAndroid Build Coastguard Worker };
646*c8dee2aaSAndroid Build Coastguard Worker
647*c8dee2aaSAndroid Build Coastguard Worker // Tests drawEdgeAAImageSet(), but can batch the entries together in different ways
648*c8dee2aaSAndroid Build Coastguard Worker class TextureSetRenderer : public ClipTileRenderer {
649*c8dee2aaSAndroid Build Coastguard Worker public:
650*c8dee2aaSAndroid Build Coastguard Worker
MakeUnbatched(sk_sp<SkImage> image)651*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> MakeUnbatched(sk_sp<SkImage> image) {
652*c8dee2aaSAndroid Build Coastguard Worker return Make("Texture", "", std::move(image), nullptr, nullptr, nullptr, nullptr,
653*c8dee2aaSAndroid Build Coastguard Worker 1.f, true, 0);
654*c8dee2aaSAndroid Build Coastguard Worker }
655*c8dee2aaSAndroid Build Coastguard Worker
MakeBatched(sk_sp<SkImage> image,int transformCount)656*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> MakeBatched(sk_sp<SkImage> image, int transformCount) {
657*c8dee2aaSAndroid Build Coastguard Worker const char* subtitle = transformCount == 0 ? "" : "w/ xforms";
658*c8dee2aaSAndroid Build Coastguard Worker return Make("Texture Set", subtitle, std::move(image), nullptr, nullptr, nullptr, nullptr,
659*c8dee2aaSAndroid Build Coastguard Worker 1.f, false, transformCount);
660*c8dee2aaSAndroid Build Coastguard Worker }
661*c8dee2aaSAndroid Build Coastguard Worker
MakeShader(const char * name,sk_sp<SkImage> image,sk_sp<SkShader> shader,bool local)662*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> MakeShader(const char* name, sk_sp<SkImage> image,
663*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> shader, bool local) {
664*c8dee2aaSAndroid Build Coastguard Worker return Make("Shader", name, std::move(image), std::move(shader),
665*c8dee2aaSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, 1.f, local, 0);
666*c8dee2aaSAndroid Build Coastguard Worker }
667*c8dee2aaSAndroid Build Coastguard Worker
MakeColorFilter(const char * name,sk_sp<SkImage> image,sk_sp<SkColorFilter> filter)668*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> MakeColorFilter(const char* name, sk_sp<SkImage> image,
669*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorFilter> filter) {
670*c8dee2aaSAndroid Build Coastguard Worker return Make("Color Filter", name, std::move(image), nullptr, std::move(filter), nullptr,
671*c8dee2aaSAndroid Build Coastguard Worker nullptr, 1.f, false, 0);
672*c8dee2aaSAndroid Build Coastguard Worker }
673*c8dee2aaSAndroid Build Coastguard Worker
MakeImageFilter(const char * name,sk_sp<SkImage> image,sk_sp<SkImageFilter> filter)674*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> MakeImageFilter(const char* name, sk_sp<SkImage> image,
675*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImageFilter> filter) {
676*c8dee2aaSAndroid Build Coastguard Worker return Make("Image Filter", name, std::move(image), nullptr, nullptr, std::move(filter),
677*c8dee2aaSAndroid Build Coastguard Worker nullptr, 1.f, false, 0);
678*c8dee2aaSAndroid Build Coastguard Worker }
679*c8dee2aaSAndroid Build Coastguard Worker
MakeMaskFilter(const char * name,sk_sp<SkImage> image,sk_sp<SkMaskFilter> filter)680*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> MakeMaskFilter(const char* name, sk_sp<SkImage> image,
681*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkMaskFilter> filter) {
682*c8dee2aaSAndroid Build Coastguard Worker return Make("Mask Filter", name, std::move(image), nullptr, nullptr, nullptr,
683*c8dee2aaSAndroid Build Coastguard Worker std::move(filter), 1.f, false, 0);
684*c8dee2aaSAndroid Build Coastguard Worker }
685*c8dee2aaSAndroid Build Coastguard Worker
MakeAlpha(sk_sp<SkImage> image,SkScalar alpha)686*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> MakeAlpha(sk_sp<SkImage> image, SkScalar alpha) {
687*c8dee2aaSAndroid Build Coastguard Worker return Make("Alpha", SkStringPrintf("a = %.2f", alpha).c_str(), std::move(image), nullptr,
688*c8dee2aaSAndroid Build Coastguard Worker nullptr, nullptr, nullptr, alpha, false, 0);
689*c8dee2aaSAndroid Build Coastguard Worker }
690*c8dee2aaSAndroid Build Coastguard Worker
Make(const char * topBanner,const char * bottomBanner,sk_sp<SkImage> image,sk_sp<SkShader> shader,sk_sp<SkColorFilter> colorFilter,sk_sp<SkImageFilter> imageFilter,sk_sp<SkMaskFilter> maskFilter,SkScalar paintAlpha,bool resetAfterEachQuad,int transformCount)691*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> Make(const char* topBanner, const char* bottomBanner,
692*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> image, sk_sp<SkShader> shader,
693*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorFilter> colorFilter,
694*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImageFilter> imageFilter,
695*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkMaskFilter> maskFilter, SkScalar paintAlpha,
696*c8dee2aaSAndroid Build Coastguard Worker bool resetAfterEachQuad, int transformCount) {
697*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<ClipTileRenderer>(new TextureSetRenderer(topBanner, bottomBanner,
698*c8dee2aaSAndroid Build Coastguard Worker std::move(image), std::move(shader), std::move(colorFilter), std::move(imageFilter),
699*c8dee2aaSAndroid Build Coastguard Worker std::move(maskFilter), paintAlpha, resetAfterEachQuad, transformCount));
700*c8dee2aaSAndroid Build Coastguard Worker }
701*c8dee2aaSAndroid Build Coastguard Worker
drawTiles(SkCanvas * canvas)702*c8dee2aaSAndroid Build Coastguard Worker int drawTiles(SkCanvas* canvas) override {
703*c8dee2aaSAndroid Build Coastguard Worker int draws = this->INHERITED::drawTiles(canvas);
704*c8dee2aaSAndroid Build Coastguard Worker // Push the last tile set
705*c8dee2aaSAndroid Build Coastguard Worker draws += this->drawAndReset(canvas);
706*c8dee2aaSAndroid Build Coastguard Worker return draws;
707*c8dee2aaSAndroid Build Coastguard Worker }
708*c8dee2aaSAndroid Build Coastguard Worker
drawTile(SkCanvas * canvas,const SkRect & rect,const SkPoint clip[4],const bool edgeAA[4],int tileID,int quadID)709*c8dee2aaSAndroid Build Coastguard Worker int drawTile(SkCanvas* canvas, const SkRect& rect, const SkPoint clip[4], const bool edgeAA[4],
710*c8dee2aaSAndroid Build Coastguard Worker int tileID, int quadID) override {
711*c8dee2aaSAndroid Build Coastguard Worker // Now don't actually draw the tile, accumulate it in the growing entry set
712*c8dee2aaSAndroid Build Coastguard Worker bool hasClip = false;
713*c8dee2aaSAndroid Build Coastguard Worker if (clip) {
714*c8dee2aaSAndroid Build Coastguard Worker // Record the four points into fDstClips
715*c8dee2aaSAndroid Build Coastguard Worker fDstClips.push_back_n(4, clip);
716*c8dee2aaSAndroid Build Coastguard Worker hasClip = true;
717*c8dee2aaSAndroid Build Coastguard Worker }
718*c8dee2aaSAndroid Build Coastguard Worker
719*c8dee2aaSAndroid Build Coastguard Worker int matrixIdx = -1;
720*c8dee2aaSAndroid Build Coastguard Worker if (!fResetEachQuad && fTransformBatchCount > 0) {
721*c8dee2aaSAndroid Build Coastguard Worker // Handle transform batching. This works by capturing the CTM of the first tile draw,
722*c8dee2aaSAndroid Build Coastguard Worker // and then calculate the difference between that and future CTMs for later tiles.
723*c8dee2aaSAndroid Build Coastguard Worker if (fPreViewMatrices.size() == 0) {
724*c8dee2aaSAndroid Build Coastguard Worker fBaseCTM = canvas->getTotalMatrix();
725*c8dee2aaSAndroid Build Coastguard Worker fPreViewMatrices.push_back(SkMatrix::I());
726*c8dee2aaSAndroid Build Coastguard Worker matrixIdx = 0;
727*c8dee2aaSAndroid Build Coastguard Worker } else {
728*c8dee2aaSAndroid Build Coastguard Worker // Calculate matrix s.t. getTotalMatrix() = fBaseCTM * M
729*c8dee2aaSAndroid Build Coastguard Worker SkMatrix invBase;
730*c8dee2aaSAndroid Build Coastguard Worker if (!fBaseCTM.invert(&invBase)) {
731*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("Cannot invert CTM, transform batching will not be correct.\n");
732*c8dee2aaSAndroid Build Coastguard Worker } else {
733*c8dee2aaSAndroid Build Coastguard Worker SkMatrix preView = SkMatrix::Concat(invBase, canvas->getTotalMatrix());
734*c8dee2aaSAndroid Build Coastguard Worker if (preView != fPreViewMatrices[fPreViewMatrices.size() - 1]) {
735*c8dee2aaSAndroid Build Coastguard Worker // Add the new matrix
736*c8dee2aaSAndroid Build Coastguard Worker fPreViewMatrices.push_back(preView);
737*c8dee2aaSAndroid Build Coastguard Worker } // else re-use the last matrix
738*c8dee2aaSAndroid Build Coastguard Worker matrixIdx = fPreViewMatrices.size() - 1;
739*c8dee2aaSAndroid Build Coastguard Worker }
740*c8dee2aaSAndroid Build Coastguard Worker }
741*c8dee2aaSAndroid Build Coastguard Worker }
742*c8dee2aaSAndroid Build Coastguard Worker
743*c8dee2aaSAndroid Build Coastguard Worker // This acts like the whole image is rendered over the entire tile grid, so derive local
744*c8dee2aaSAndroid Build Coastguard Worker // coordinates from 'rect', based on the grid to image transform.
745*c8dee2aaSAndroid Build Coastguard Worker SkMatrix gridToImage = SkMatrix::RectToRect(SkRect::MakeWH(kColCount * kTileWidth,
746*c8dee2aaSAndroid Build Coastguard Worker kRowCount * kTileHeight),
747*c8dee2aaSAndroid Build Coastguard Worker SkRect::MakeWH(fImage->width(),
748*c8dee2aaSAndroid Build Coastguard Worker fImage->height()));
749*c8dee2aaSAndroid Build Coastguard Worker SkRect localRect = gridToImage.mapRect(rect);
750*c8dee2aaSAndroid Build Coastguard Worker
751*c8dee2aaSAndroid Build Coastguard Worker // drawTextureSet automatically derives appropriate local quad from localRect if clipPtr
752*c8dee2aaSAndroid Build Coastguard Worker // is not null.
753*c8dee2aaSAndroid Build Coastguard Worker fSetEntries.push_back(
754*c8dee2aaSAndroid Build Coastguard Worker {fImage, localRect, rect, matrixIdx, 1.f, this->maskToFlags(edgeAA), hasClip});
755*c8dee2aaSAndroid Build Coastguard Worker
756*c8dee2aaSAndroid Build Coastguard Worker if (fResetEachQuad) {
757*c8dee2aaSAndroid Build Coastguard Worker // Only ever draw one entry at a time
758*c8dee2aaSAndroid Build Coastguard Worker return this->drawAndReset(canvas);
759*c8dee2aaSAndroid Build Coastguard Worker } else {
760*c8dee2aaSAndroid Build Coastguard Worker return 0;
761*c8dee2aaSAndroid Build Coastguard Worker }
762*c8dee2aaSAndroid Build Coastguard Worker }
763*c8dee2aaSAndroid Build Coastguard Worker
drawBanner(SkCanvas * canvas)764*c8dee2aaSAndroid Build Coastguard Worker void drawBanner(SkCanvas* canvas) override {
765*c8dee2aaSAndroid Build Coastguard Worker if (fTopBanner.size() > 0) {
766*c8dee2aaSAndroid Build Coastguard Worker draw_text(canvas, fTopBanner.c_str());
767*c8dee2aaSAndroid Build Coastguard Worker }
768*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0.f, 15.f);
769*c8dee2aaSAndroid Build Coastguard Worker if (fBottomBanner.size() > 0) {
770*c8dee2aaSAndroid Build Coastguard Worker draw_text(canvas, fBottomBanner.c_str());
771*c8dee2aaSAndroid Build Coastguard Worker }
772*c8dee2aaSAndroid Build Coastguard Worker }
773*c8dee2aaSAndroid Build Coastguard Worker
774*c8dee2aaSAndroid Build Coastguard Worker private:
775*c8dee2aaSAndroid Build Coastguard Worker SkString fTopBanner;
776*c8dee2aaSAndroid Build Coastguard Worker SkString fBottomBanner;
777*c8dee2aaSAndroid Build Coastguard Worker
778*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> fImage;
779*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> fShader;
780*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorFilter> fColorFilter;
781*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImageFilter> fImageFilter;
782*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkMaskFilter> fMaskFilter;
783*c8dee2aaSAndroid Build Coastguard Worker SkScalar fPaintAlpha;
784*c8dee2aaSAndroid Build Coastguard Worker
785*c8dee2aaSAndroid Build Coastguard Worker // Batching rules
786*c8dee2aaSAndroid Build Coastguard Worker bool fResetEachQuad;
787*c8dee2aaSAndroid Build Coastguard Worker int fTransformBatchCount;
788*c8dee2aaSAndroid Build Coastguard Worker
789*c8dee2aaSAndroid Build Coastguard Worker TArray<SkPoint> fDstClips;
790*c8dee2aaSAndroid Build Coastguard Worker TArray<SkMatrix> fPreViewMatrices;
791*c8dee2aaSAndroid Build Coastguard Worker TArray<SkCanvas::ImageSetEntry> fSetEntries;
792*c8dee2aaSAndroid Build Coastguard Worker
793*c8dee2aaSAndroid Build Coastguard Worker SkMatrix fBaseCTM;
794*c8dee2aaSAndroid Build Coastguard Worker int fBatchCount;
795*c8dee2aaSAndroid Build Coastguard Worker
TextureSetRenderer(const char * topBanner,const char * bottomBanner,sk_sp<SkImage> image,sk_sp<SkShader> shader,sk_sp<SkColorFilter> colorFilter,sk_sp<SkImageFilter> imageFilter,sk_sp<SkMaskFilter> maskFilter,SkScalar paintAlpha,bool resetEachQuad,int transformBatchCount)796*c8dee2aaSAndroid Build Coastguard Worker TextureSetRenderer(const char* topBanner,
797*c8dee2aaSAndroid Build Coastguard Worker const char* bottomBanner,
798*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> image,
799*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> shader,
800*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorFilter> colorFilter,
801*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImageFilter> imageFilter,
802*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkMaskFilter> maskFilter,
803*c8dee2aaSAndroid Build Coastguard Worker SkScalar paintAlpha,
804*c8dee2aaSAndroid Build Coastguard Worker bool resetEachQuad,
805*c8dee2aaSAndroid Build Coastguard Worker int transformBatchCount)
806*c8dee2aaSAndroid Build Coastguard Worker : fTopBanner(topBanner)
807*c8dee2aaSAndroid Build Coastguard Worker , fBottomBanner(bottomBanner)
808*c8dee2aaSAndroid Build Coastguard Worker , fImage(std::move(image))
809*c8dee2aaSAndroid Build Coastguard Worker , fShader(std::move(shader))
810*c8dee2aaSAndroid Build Coastguard Worker , fColorFilter(std::move(colorFilter))
811*c8dee2aaSAndroid Build Coastguard Worker , fImageFilter(std::move(imageFilter))
812*c8dee2aaSAndroid Build Coastguard Worker , fMaskFilter(std::move(maskFilter))
813*c8dee2aaSAndroid Build Coastguard Worker , fPaintAlpha(paintAlpha)
814*c8dee2aaSAndroid Build Coastguard Worker , fResetEachQuad(resetEachQuad)
815*c8dee2aaSAndroid Build Coastguard Worker , fTransformBatchCount(transformBatchCount)
816*c8dee2aaSAndroid Build Coastguard Worker , fBatchCount(0) {
817*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(transformBatchCount >= 0 && (!resetEachQuad || transformBatchCount == 0));
818*c8dee2aaSAndroid Build Coastguard Worker }
819*c8dee2aaSAndroid Build Coastguard Worker
configureTilePaint(const SkRect & rect,SkPaint * paint) const820*c8dee2aaSAndroid Build Coastguard Worker void configureTilePaint(const SkRect& rect, SkPaint* paint) const {
821*c8dee2aaSAndroid Build Coastguard Worker paint->setAntiAlias(true);
822*c8dee2aaSAndroid Build Coastguard Worker paint->setBlendMode(SkBlendMode::kSrcOver);
823*c8dee2aaSAndroid Build Coastguard Worker
824*c8dee2aaSAndroid Build Coastguard Worker // Send non-white RGB, that should be ignored
825*c8dee2aaSAndroid Build Coastguard Worker paint->setColor4f({1.f, 0.4f, 0.25f, fPaintAlpha}, nullptr);
826*c8dee2aaSAndroid Build Coastguard Worker
827*c8dee2aaSAndroid Build Coastguard Worker
828*c8dee2aaSAndroid Build Coastguard Worker if (fShader) {
829*c8dee2aaSAndroid Build Coastguard Worker if (fResetEachQuad) {
830*c8dee2aaSAndroid Build Coastguard Worker // Apply a local transform in the shader to map from the tile rectangle to (0,0,w,h)
831*c8dee2aaSAndroid Build Coastguard Worker static const SkRect kTarget = SkRect::MakeWH(kTileWidth, kTileHeight);
832*c8dee2aaSAndroid Build Coastguard Worker SkMatrix local = SkMatrix::RectToRect(kTarget, rect);
833*c8dee2aaSAndroid Build Coastguard Worker paint->setShader(fShader->makeWithLocalMatrix(local));
834*c8dee2aaSAndroid Build Coastguard Worker } else {
835*c8dee2aaSAndroid Build Coastguard Worker paint->setShader(fShader);
836*c8dee2aaSAndroid Build Coastguard Worker }
837*c8dee2aaSAndroid Build Coastguard Worker }
838*c8dee2aaSAndroid Build Coastguard Worker
839*c8dee2aaSAndroid Build Coastguard Worker paint->setColorFilter(fColorFilter);
840*c8dee2aaSAndroid Build Coastguard Worker paint->setImageFilter(fImageFilter);
841*c8dee2aaSAndroid Build Coastguard Worker paint->setMaskFilter(fMaskFilter);
842*c8dee2aaSAndroid Build Coastguard Worker }
843*c8dee2aaSAndroid Build Coastguard Worker
drawAndReset(SkCanvas * canvas)844*c8dee2aaSAndroid Build Coastguard Worker int drawAndReset(SkCanvas* canvas) {
845*c8dee2aaSAndroid Build Coastguard Worker // Early out if there's nothing to draw
846*c8dee2aaSAndroid Build Coastguard Worker if (fSetEntries.size() == 0) {
847*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fDstClips.size() == 0 && fPreViewMatrices.size() == 0);
848*c8dee2aaSAndroid Build Coastguard Worker return 0;
849*c8dee2aaSAndroid Build Coastguard Worker }
850*c8dee2aaSAndroid Build Coastguard Worker
851*c8dee2aaSAndroid Build Coastguard Worker if (!fResetEachQuad && fTransformBatchCount > 0) {
852*c8dee2aaSAndroid Build Coastguard Worker // A batch is completed
853*c8dee2aaSAndroid Build Coastguard Worker fBatchCount++;
854*c8dee2aaSAndroid Build Coastguard Worker if (fBatchCount < fTransformBatchCount) {
855*c8dee2aaSAndroid Build Coastguard Worker // Haven't hit the point to submit yet, but end the current tile
856*c8dee2aaSAndroid Build Coastguard Worker return 0;
857*c8dee2aaSAndroid Build Coastguard Worker }
858*c8dee2aaSAndroid Build Coastguard Worker
859*c8dee2aaSAndroid Build Coastguard Worker // Submitting all tiles back to where fBaseCTM was the canvas' matrix, while the
860*c8dee2aaSAndroid Build Coastguard Worker // canvas currently has the CTM of the last tile batch, so reset it.
861*c8dee2aaSAndroid Build Coastguard Worker canvas->setMatrix(fBaseCTM);
862*c8dee2aaSAndroid Build Coastguard Worker }
863*c8dee2aaSAndroid Build Coastguard Worker
864*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
865*c8dee2aaSAndroid Build Coastguard Worker int expectedDstClipCount = 0;
866*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fSetEntries.size(); ++i) {
867*c8dee2aaSAndroid Build Coastguard Worker expectedDstClipCount += 4 * fSetEntries[i].fHasClip;
868*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fSetEntries[i].fMatrixIndex < 0 ||
869*c8dee2aaSAndroid Build Coastguard Worker fSetEntries[i].fMatrixIndex < fPreViewMatrices.size());
870*c8dee2aaSAndroid Build Coastguard Worker }
871*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(expectedDstClipCount == fDstClips.size());
872*c8dee2aaSAndroid Build Coastguard Worker #endif
873*c8dee2aaSAndroid Build Coastguard Worker
874*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
875*c8dee2aaSAndroid Build Coastguard Worker SkRect lastTileRect = fSetEntries[fSetEntries.size() - 1].fDstRect;
876*c8dee2aaSAndroid Build Coastguard Worker this->configureTilePaint(lastTileRect, &paint);
877*c8dee2aaSAndroid Build Coastguard Worker
878*c8dee2aaSAndroid Build Coastguard Worker canvas->experimental_DrawEdgeAAImageSet(
879*c8dee2aaSAndroid Build Coastguard Worker fSetEntries.begin(), fSetEntries.size(), fDstClips.begin(),
880*c8dee2aaSAndroid Build Coastguard Worker fPreViewMatrices.begin(), SkSamplingOptions(SkFilterMode::kLinear),
881*c8dee2aaSAndroid Build Coastguard Worker &paint, SkCanvas::kFast_SrcRectConstraint);
882*c8dee2aaSAndroid Build Coastguard Worker
883*c8dee2aaSAndroid Build Coastguard Worker // Reset for next tile
884*c8dee2aaSAndroid Build Coastguard Worker fDstClips.clear();
885*c8dee2aaSAndroid Build Coastguard Worker fPreViewMatrices.clear();
886*c8dee2aaSAndroid Build Coastguard Worker fSetEntries.clear();
887*c8dee2aaSAndroid Build Coastguard Worker fBatchCount = 0;
888*c8dee2aaSAndroid Build Coastguard Worker
889*c8dee2aaSAndroid Build Coastguard Worker return 1;
890*c8dee2aaSAndroid Build Coastguard Worker }
891*c8dee2aaSAndroid Build Coastguard Worker
892*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = ClipTileRenderer;
893*c8dee2aaSAndroid Build Coastguard Worker };
894*c8dee2aaSAndroid Build Coastguard Worker
895*c8dee2aaSAndroid Build Coastguard Worker class YUVTextureSetRenderer : public ClipTileRenderer {
896*c8dee2aaSAndroid Build Coastguard Worker public:
MakeFromJPEG(sk_sp<SkData> imageData)897*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<ClipTileRenderer> MakeFromJPEG(sk_sp<SkData> imageData) {
898*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<ClipTileRenderer>(new YUVTextureSetRenderer(std::move(imageData)));
899*c8dee2aaSAndroid Build Coastguard Worker }
900*c8dee2aaSAndroid Build Coastguard Worker
drawTiles(SkCanvas * canvas)901*c8dee2aaSAndroid Build Coastguard Worker int drawTiles(SkCanvas* canvas) override {
902*c8dee2aaSAndroid Build Coastguard Worker // Refresh the SkImage at the start, so that it's not attempted for every set entry
903*c8dee2aaSAndroid Build Coastguard Worker if (fYUVData) {
904*c8dee2aaSAndroid Build Coastguard Worker fImage = fYUVData->refImage(canvas->recordingContext(),
905*c8dee2aaSAndroid Build Coastguard Worker sk_gpu_test::LazyYUVImage::Type::kFromPixmaps);
906*c8dee2aaSAndroid Build Coastguard Worker if (!fImage) {
907*c8dee2aaSAndroid Build Coastguard Worker return 0;
908*c8dee2aaSAndroid Build Coastguard Worker }
909*c8dee2aaSAndroid Build Coastguard Worker }
910*c8dee2aaSAndroid Build Coastguard Worker
911*c8dee2aaSAndroid Build Coastguard Worker int draws = this->INHERITED::drawTiles(canvas);
912*c8dee2aaSAndroid Build Coastguard Worker // Push the last tile set
913*c8dee2aaSAndroid Build Coastguard Worker draws += this->drawAndReset(canvas);
914*c8dee2aaSAndroid Build Coastguard Worker return draws;
915*c8dee2aaSAndroid Build Coastguard Worker }
916*c8dee2aaSAndroid Build Coastguard Worker
drawTile(SkCanvas * canvas,const SkRect & rect,const SkPoint clip[4],const bool edgeAA[4],int tileID,int quadID)917*c8dee2aaSAndroid Build Coastguard Worker int drawTile(SkCanvas* canvas, const SkRect& rect, const SkPoint clip[4], const bool edgeAA[4],
918*c8dee2aaSAndroid Build Coastguard Worker int tileID, int quadID) override {
919*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fImage);
920*c8dee2aaSAndroid Build Coastguard Worker // Now don't actually draw the tile, accumulate it in the growing entry set
921*c8dee2aaSAndroid Build Coastguard Worker bool hasClip = false;
922*c8dee2aaSAndroid Build Coastguard Worker if (clip) {
923*c8dee2aaSAndroid Build Coastguard Worker // Record the four points into fDstClips
924*c8dee2aaSAndroid Build Coastguard Worker fDstClips.push_back_n(4, clip);
925*c8dee2aaSAndroid Build Coastguard Worker hasClip = true;
926*c8dee2aaSAndroid Build Coastguard Worker }
927*c8dee2aaSAndroid Build Coastguard Worker
928*c8dee2aaSAndroid Build Coastguard Worker // This acts like the whole image is rendered over the entire tile grid, so derive local
929*c8dee2aaSAndroid Build Coastguard Worker // coordinates from 'rect', based on the grid to image transform.
930*c8dee2aaSAndroid Build Coastguard Worker SkMatrix gridToImage = SkMatrix::RectToRect(SkRect::MakeWH(kColCount * kTileWidth,
931*c8dee2aaSAndroid Build Coastguard Worker kRowCount * kTileHeight),
932*c8dee2aaSAndroid Build Coastguard Worker SkRect::MakeWH(fImage->width(),
933*c8dee2aaSAndroid Build Coastguard Worker fImage->height()));
934*c8dee2aaSAndroid Build Coastguard Worker SkRect localRect = gridToImage.mapRect(rect);
935*c8dee2aaSAndroid Build Coastguard Worker
936*c8dee2aaSAndroid Build Coastguard Worker // drawTextureSet automatically derives appropriate local quad from localRect if clipPtr
937*c8dee2aaSAndroid Build Coastguard Worker // is not null. Also exercise per-entry alpha combined with YUVA images.
938*c8dee2aaSAndroid Build Coastguard Worker fSetEntries.push_back(
939*c8dee2aaSAndroid Build Coastguard Worker {fImage, localRect, rect, -1, .5f, this->maskToFlags(edgeAA), hasClip});
940*c8dee2aaSAndroid Build Coastguard Worker return 0;
941*c8dee2aaSAndroid Build Coastguard Worker }
942*c8dee2aaSAndroid Build Coastguard Worker
drawBanner(SkCanvas * canvas)943*c8dee2aaSAndroid Build Coastguard Worker void drawBanner(SkCanvas* canvas) override {
944*c8dee2aaSAndroid Build Coastguard Worker draw_text(canvas, "Texture");
945*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0.f, 15.f);
946*c8dee2aaSAndroid Build Coastguard Worker draw_text(canvas, "YUV + alpha - GPU Only");
947*c8dee2aaSAndroid Build Coastguard Worker }
948*c8dee2aaSAndroid Build Coastguard Worker
949*c8dee2aaSAndroid Build Coastguard Worker private:
950*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<sk_gpu_test::LazyYUVImage> fYUVData;
951*c8dee2aaSAndroid Build Coastguard Worker // The last accessed SkImage from fYUVData, held here for easy access by drawTile
952*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> fImage;
953*c8dee2aaSAndroid Build Coastguard Worker
954*c8dee2aaSAndroid Build Coastguard Worker TArray<SkPoint> fDstClips;
955*c8dee2aaSAndroid Build Coastguard Worker TArray<SkCanvas::ImageSetEntry> fSetEntries;
956*c8dee2aaSAndroid Build Coastguard Worker
YUVTextureSetRenderer(sk_sp<SkData> jpegData)957*c8dee2aaSAndroid Build Coastguard Worker YUVTextureSetRenderer(sk_sp<SkData> jpegData)
958*c8dee2aaSAndroid Build Coastguard Worker : fYUVData(sk_gpu_test::LazyYUVImage::Make(std::move(jpegData)))
959*c8dee2aaSAndroid Build Coastguard Worker , fImage(nullptr) {}
960*c8dee2aaSAndroid Build Coastguard Worker
drawAndReset(SkCanvas * canvas)961*c8dee2aaSAndroid Build Coastguard Worker int drawAndReset(SkCanvas* canvas) {
962*c8dee2aaSAndroid Build Coastguard Worker // Early out if there's nothing to draw
963*c8dee2aaSAndroid Build Coastguard Worker if (fSetEntries.size() == 0) {
964*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fDstClips.size() == 0);
965*c8dee2aaSAndroid Build Coastguard Worker return 0;
966*c8dee2aaSAndroid Build Coastguard Worker }
967*c8dee2aaSAndroid Build Coastguard Worker
968*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
969*c8dee2aaSAndroid Build Coastguard Worker int expectedDstClipCount = 0;
970*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fSetEntries.size(); ++i) {
971*c8dee2aaSAndroid Build Coastguard Worker expectedDstClipCount += 4 * fSetEntries[i].fHasClip;
972*c8dee2aaSAndroid Build Coastguard Worker }
973*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(expectedDstClipCount == fDstClips.size());
974*c8dee2aaSAndroid Build Coastguard Worker #endif
975*c8dee2aaSAndroid Build Coastguard Worker
976*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
977*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
978*c8dee2aaSAndroid Build Coastguard Worker paint.setBlendMode(SkBlendMode::kSrcOver);
979*c8dee2aaSAndroid Build Coastguard Worker
980*c8dee2aaSAndroid Build Coastguard Worker canvas->experimental_DrawEdgeAAImageSet(
981*c8dee2aaSAndroid Build Coastguard Worker fSetEntries.begin(), fSetEntries.size(), fDstClips.begin(), nullptr,
982*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions(SkFilterMode::kLinear), &paint,
983*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::kFast_SrcRectConstraint);
984*c8dee2aaSAndroid Build Coastguard Worker
985*c8dee2aaSAndroid Build Coastguard Worker // Reset for next tile
986*c8dee2aaSAndroid Build Coastguard Worker fDstClips.clear();
987*c8dee2aaSAndroid Build Coastguard Worker fSetEntries.clear();
988*c8dee2aaSAndroid Build Coastguard Worker
989*c8dee2aaSAndroid Build Coastguard Worker return 1;
990*c8dee2aaSAndroid Build Coastguard Worker }
991*c8dee2aaSAndroid Build Coastguard Worker
992*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = ClipTileRenderer;
993*c8dee2aaSAndroid Build Coastguard Worker };
994*c8dee2aaSAndroid Build Coastguard Worker
make_debug_renderers()995*c8dee2aaSAndroid Build Coastguard Worker static ClipTileRendererArray make_debug_renderers() {
996*c8dee2aaSAndroid Build Coastguard Worker return ClipTileRendererArray{DebugTileRenderer::Make(),
997*c8dee2aaSAndroid Build Coastguard Worker DebugTileRenderer::MakeAA(),
998*c8dee2aaSAndroid Build Coastguard Worker DebugTileRenderer::MakeNonAA()};
999*c8dee2aaSAndroid Build Coastguard Worker }
1000*c8dee2aaSAndroid Build Coastguard Worker
make_solid_color_renderers()1001*c8dee2aaSAndroid Build Coastguard Worker static ClipTileRendererArray make_solid_color_renderers() {
1002*c8dee2aaSAndroid Build Coastguard Worker return ClipTileRendererArray{SolidColorRenderer::Make({.2f, .8f, .3f, 1.f})};
1003*c8dee2aaSAndroid Build Coastguard Worker }
1004*c8dee2aaSAndroid Build Coastguard Worker
make_shader_renderers()1005*c8dee2aaSAndroid Build Coastguard Worker static ClipTileRendererArray make_shader_renderers() {
1006*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkPoint kPts[] = { {0.f, 0.f}, {0.25f * kTileWidth, 0.25f * kTileHeight} };
1007*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkColor kColors[] = { SK_ColorBLUE, SK_ColorWHITE };
1008*c8dee2aaSAndroid Build Coastguard Worker auto gradient = SkGradientShader::MakeLinear(kPts, kColors, nullptr, 2,
1009*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kMirror);
1010*c8dee2aaSAndroid Build Coastguard Worker
1011*c8dee2aaSAndroid Build Coastguard Worker auto info = SkImageInfo::Make(1, 1, kAlpha_8_SkColorType, kOpaque_SkAlphaType);
1012*c8dee2aaSAndroid Build Coastguard Worker SkBitmap bm;
1013*c8dee2aaSAndroid Build Coastguard Worker bm.allocPixels(info);
1014*c8dee2aaSAndroid Build Coastguard Worker bm.eraseColor(SK_ColorWHITE);
1015*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> image = bm.asImage();
1016*c8dee2aaSAndroid Build Coastguard Worker
1017*c8dee2aaSAndroid Build Coastguard Worker return ClipTileRendererArray{
1018*c8dee2aaSAndroid Build Coastguard Worker TextureSetRenderer::MakeShader("Gradient", image, gradient, false),
1019*c8dee2aaSAndroid Build Coastguard Worker TextureSetRenderer::MakeShader("Local Gradient", image, gradient, true)};
1020*c8dee2aaSAndroid Build Coastguard Worker }
1021*c8dee2aaSAndroid Build Coastguard Worker
make_image_renderers()1022*c8dee2aaSAndroid Build Coastguard Worker static ClipTileRendererArray make_image_renderers() {
1023*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> mandrill = ToolUtils::GetResourceAsImage("images/mandrill_512.png");
1024*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> mandrillJpeg = GetResourceAsData("images/mandrill_h1v1.jpg");
1025*c8dee2aaSAndroid Build Coastguard Worker return ClipTileRendererArray{TextureSetRenderer::MakeUnbatched(mandrill),
1026*c8dee2aaSAndroid Build Coastguard Worker TextureSetRenderer::MakeBatched(mandrill, 0),
1027*c8dee2aaSAndroid Build Coastguard Worker TextureSetRenderer::MakeBatched(mandrill, kMatrixCount),
1028*c8dee2aaSAndroid Build Coastguard Worker YUVTextureSetRenderer::MakeFromJPEG(mandrillJpeg)};
1029*c8dee2aaSAndroid Build Coastguard Worker }
1030*c8dee2aaSAndroid Build Coastguard Worker
make_filtered_renderers()1031*c8dee2aaSAndroid Build Coastguard Worker static ClipTileRendererArray make_filtered_renderers() {
1032*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> mandrill = ToolUtils::GetResourceAsImage("images/mandrill_512.png");
1033*c8dee2aaSAndroid Build Coastguard Worker
1034*c8dee2aaSAndroid Build Coastguard Worker SkColorMatrix cm;
1035*c8dee2aaSAndroid Build Coastguard Worker cm.setSaturation(10);
1036*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorFilter> colorFilter = SkColorFilters::Matrix(cm);
1037*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImageFilter> imageFilter = SkImageFilters::Dilate(8, 8, nullptr);
1038*c8dee2aaSAndroid Build Coastguard Worker
1039*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkColor kAlphas[] = { SK_ColorTRANSPARENT, SK_ColorBLACK };
1040*c8dee2aaSAndroid Build Coastguard Worker auto alphaGradient = SkGradientShader::MakeRadial(
1041*c8dee2aaSAndroid Build Coastguard Worker {0.5f * kTileWidth * kColCount, 0.5f * kTileHeight * kRowCount},
1042*c8dee2aaSAndroid Build Coastguard Worker 0.25f * kTileWidth * kColCount, kAlphas, nullptr, 2, SkTileMode::kClamp);
1043*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkMaskFilter> maskFilter = SkShaderMaskFilter::Make(std::move(alphaGradient));
1044*c8dee2aaSAndroid Build Coastguard Worker
1045*c8dee2aaSAndroid Build Coastguard Worker return ClipTileRendererArray{
1046*c8dee2aaSAndroid Build Coastguard Worker TextureSetRenderer::MakeAlpha(mandrill, 0.5f),
1047*c8dee2aaSAndroid Build Coastguard Worker TextureSetRenderer::MakeColorFilter("Saturation", mandrill, std::move(colorFilter)),
1048*c8dee2aaSAndroid Build Coastguard Worker
1049*c8dee2aaSAndroid Build Coastguard Worker // NOTE: won't draw correctly until SkCanvas' AutoLoopers are used to handle image filters
1050*c8dee2aaSAndroid Build Coastguard Worker TextureSetRenderer::MakeImageFilter("Dilate", mandrill, std::move(imageFilter)),
1051*c8dee2aaSAndroid Build Coastguard Worker
1052*c8dee2aaSAndroid Build Coastguard Worker // NOTE: blur mask filters do work (tested locally), but visually they don't make much
1053*c8dee2aaSAndroid Build Coastguard Worker // sense, since each quad is blurred independently
1054*c8dee2aaSAndroid Build Coastguard Worker TextureSetRenderer::MakeMaskFilter("Shader", mandrill, std::move(maskFilter))};
1055*c8dee2aaSAndroid Build Coastguard Worker }
1056*c8dee2aaSAndroid Build Coastguard Worker
1057*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new CompositorGM("debug", make_debug_renderers);)
1058*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new CompositorGM("color", make_solid_color_renderers);)
1059*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new CompositorGM("shader", make_shader_renderers);)
1060*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new CompositorGM("image", make_image_renderers);)
1061*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new CompositorGM("filter", make_filtered_renderers);)
1062