1 /*
2 * Copyright 2014 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
8 // This test only works with the GPU backend.
9
10 #include "gm.h"
11
12 #if SK_SUPPORT_GPU
13
14 #include "GrContext.h"
15 #include "GrDefaultGeoProcFactory.h"
16 #include "GrOpFlushState.h"
17 #include "GrPathUtils.h"
18 #include "GrRenderTargetContextPriv.h"
19 #include "GrTest.h"
20 #include "SkColorPriv.h"
21 #include "SkGeometry.h"
22 #include "SkTLList.h"
23 #include "effects/GrConvexPolyEffect.h"
24 #include "ops/GrMeshDrawOp.h"
25
26 /** outset rendered rect to visualize anti-aliased poly edges */
outset(const SkRect & unsorted)27 static SkRect outset(const SkRect& unsorted) {
28 SkRect r = unsorted;
29 r.outset(5.f, 5.f);
30 return r;
31 }
32
33 /** sorts a rect */
sorted_rect(const SkRect & unsorted)34 static SkRect sorted_rect(const SkRect& unsorted) {
35 SkRect r = unsorted;
36 r.sort();
37 return r;
38 }
39
40 namespace skiagm {
41 class PolyBoundsOp : public GrMeshDrawOp {
42 public:
43 DEFINE_OP_CLASS_ID
44
name() const45 const char* name() const override { return "PolyBoundsOp"; }
46
Make(GrPaint && paint,const SkRect & rect)47 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& rect) {
48 return std::unique_ptr<GrDrawOp>(new PolyBoundsOp(std::move(paint), rect));
49 }
50
fixedFunctionFlags() const51 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
52
finalize(const GrCaps & caps,const GrAppliedClip * clip)53 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
54 auto analysis = fProcessors.finalize(
55 fColor, GrProcessorAnalysisCoverage::kNone, clip, false, caps, &fColor);
56 return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo;
57 }
58
59 private:
PolyBoundsOp(GrPaint && paint,const SkRect & rect)60 PolyBoundsOp(GrPaint&& paint, const SkRect& rect)
61 : INHERITED(ClassID())
62 , fColor(paint.getColor())
63 , fProcessors(std::move(paint))
64 , fRect(outset(rect)) {
65 this->setBounds(sorted_rect(fRect), HasAABloat::kNo, IsZeroArea::kNo);
66 }
67
onPrepareDraws(Target * target) const68 void onPrepareDraws(Target* target) const override {
69 using namespace GrDefaultGeoProcFactory;
70
71 Color color(fColor);
72 sk_sp<GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Make(
73 color, Coverage::kSolid_Type, LocalCoords::kUnused_Type, SkMatrix::I()));
74
75 size_t vertexStride = gp->getVertexStride();
76 SkASSERT(vertexStride == sizeof(SkPoint));
77 QuadHelper helper;
78 SkPoint* verts = reinterpret_cast<SkPoint*>(helper.init(target, vertexStride, 1));
79 if (!verts) {
80 return;
81 }
82
83 fRect.toQuad(verts);
84
85 helper.recordDraw(target, gp.get(), target->makePipeline(0, &fProcessors));
86 }
87
onCombineIfPossible(GrOp * op,const GrCaps & caps)88 bool onCombineIfPossible(GrOp* op, const GrCaps& caps) override { return false; }
89
90 GrColor fColor;
91 GrProcessorSet fProcessors;
92 SkRect fRect;
93
94 typedef GrMeshDrawOp INHERITED;
95 };
96
97 /**
98 * This GM directly exercises a GrProcessor that draws convex polygons.
99 */
100 class ConvexPolyEffect : public GM {
101 public:
ConvexPolyEffect()102 ConvexPolyEffect() {
103 this->setBGColor(0xFFFFFFFF);
104 }
105
106 protected:
onShortName()107 SkString onShortName() override {
108 return SkString("convex_poly_effect");
109 }
110
onISize()111 SkISize onISize() override {
112 return SkISize::Make(720, 800);
113 }
114
onOnceBeforeDraw()115 void onOnceBeforeDraw() override {
116 SkPath tri;
117 tri.moveTo(5.f, 5.f);
118 tri.lineTo(100.f, 20.f);
119 tri.lineTo(15.f, 100.f);
120
121 fPaths.addToTail(tri);
122 fPaths.addToTail(SkPath())->reverseAddPath(tri);
123
124 tri.close();
125 fPaths.addToTail(tri);
126
127 SkPath ngon;
128 constexpr SkScalar kRadius = 50.f;
129 const SkPoint center = { kRadius, kRadius };
130 for (int i = 0; i < GrConvexPolyEffect::kMaxEdges; ++i) {
131 SkScalar angle = 2 * SK_ScalarPI * i / GrConvexPolyEffect::kMaxEdges;
132 SkPoint point;
133 point.fY = SkScalarSinCos(angle, &point.fX);
134 point.scale(kRadius);
135 point = center + point;
136 if (0 == i) {
137 ngon.moveTo(point);
138 } else {
139 ngon.lineTo(point);
140 }
141 }
142
143 fPaths.addToTail(ngon);
144 SkMatrix scaleM;
145 scaleM.setScale(1.1f, 0.4f);
146 ngon.transform(scaleM);
147 fPaths.addToTail(ngon);
148
149 SkPath linePath;
150 linePath.moveTo(5.f, 5.f);
151 linePath.lineTo(6.f, 6.f);
152 fPaths.addToTail(linePath);
153
154 // integer edges
155 fRects.addToTail(SkRect::MakeLTRB(5.f, 1.f, 30.f, 25.f));
156 // half-integer edges
157 fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 24.5f));
158 // vertically/horizontally thin rects that cover pixel centers
159 fRects.addToTail(SkRect::MakeLTRB(5.25f, 0.5f, 5.75f, 24.5f));
160 fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 0.75f));
161 // vertically/horizontally thin rects that don't cover pixel centers
162 fRects.addToTail(SkRect::MakeLTRB(5.55f, 0.5f, 5.75f, 24.5f));
163 fRects.addToTail(SkRect::MakeLTRB(5.5f, .05f, 29.5f, .25f));
164 // small in x and y
165 fRects.addToTail(SkRect::MakeLTRB(5.05f, .55f, 5.45f, .85f));
166 // inverted in x and y
167 fRects.addToTail(SkRect::MakeLTRB(100.f, 50.5f, 5.f, 0.5f));
168 }
169
onDraw(SkCanvas * canvas)170 void onDraw(SkCanvas* canvas) override {
171 GrRenderTargetContext* renderTargetContext =
172 canvas->internal_private_accessTopLayerRenderTargetContext();
173 if (!renderTargetContext) {
174 skiagm::GM::DrawGpuOnlyMessage(canvas);
175 return;
176 }
177
178 SkScalar y = 0;
179 constexpr SkScalar kDX = 12.f;
180 for (PathList::Iter iter(fPaths, PathList::Iter::kHead_IterStart);
181 iter.get();
182 iter.next()) {
183 const SkPath* path = iter.get();
184 SkScalar x = 0;
185
186 for (int et = 0; et < kGrProcessorEdgeTypeCnt; ++et) {
187 const SkMatrix m = SkMatrix::MakeTrans(x, y);
188 SkPath p;
189 path->transform(m, &p);
190
191 GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et;
192 sk_sp<GrFragmentProcessor> fp(GrConvexPolyEffect::Make(edgeType, p));
193 if (!fp) {
194 continue;
195 }
196
197 GrPaint grPaint;
198 grPaint.setColor4f(GrColor4f(0, 0, 0, 1.f));
199 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
200 grPaint.addCoverageFragmentProcessor(std::move(fp));
201
202 std::unique_ptr<GrDrawOp> op =
203 PolyBoundsOp::Make(std::move(grPaint), p.getBounds());
204 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
205
206 x += SkScalarCeilToScalar(path->getBounds().width() + kDX);
207 }
208
209 // Draw AA and non AA paths using normal API for reference.
210 canvas->save();
211 canvas->translate(x, y);
212 SkPaint paint;
213 canvas->drawPath(*path, paint);
214 canvas->translate(path->getBounds().width() + 10.f, 0);
215 paint.setAntiAlias(true);
216 canvas->drawPath(*path, paint);
217 canvas->restore();
218
219 y += SkScalarCeilToScalar(path->getBounds().height() + 20.f);
220 }
221
222 for (RectList::Iter iter(fRects, RectList::Iter::kHead_IterStart);
223 iter.get();
224 iter.next()) {
225
226 SkScalar x = 0;
227
228 for (int et = 0; et < kGrProcessorEdgeTypeCnt; ++et) {
229 SkRect rect = *iter.get();
230 rect.offset(x, y);
231 GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et;
232 sk_sp<GrFragmentProcessor> fp(GrConvexPolyEffect::Make(edgeType, rect));
233 if (!fp) {
234 continue;
235 }
236
237 GrPaint grPaint;
238 grPaint.setColor4f(GrColor4f(0, 0, 0, 1.f));
239 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
240 grPaint.addCoverageFragmentProcessor(std::move(fp));
241
242 std::unique_ptr<GrDrawOp> op = PolyBoundsOp::Make(std::move(grPaint), rect);
243 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
244
245 x += SkScalarCeilToScalar(rect.width() + kDX);
246 }
247
248 // Draw rect without and with AA using normal API for reference
249 canvas->save();
250 canvas->translate(x, y);
251 SkPaint paint;
252 canvas->drawRect(*iter.get(), paint);
253 x += SkScalarCeilToScalar(iter.get()->width() + kDX);
254 paint.setAntiAlias(true);
255 canvas->drawRect(*iter.get(), paint);
256 canvas->restore();
257
258 y += SkScalarCeilToScalar(iter.get()->height() + 20.f);
259 }
260 }
261
262 private:
263 typedef SkTLList<SkPath, 1> PathList;
264 typedef SkTLList<SkRect, 1> RectList;
265 PathList fPaths;
266 RectList fRects;
267
268 typedef GM INHERITED;
269 };
270
271 DEF_GM(return new ConvexPolyEffect;)
272 }
273
274 #endif
275