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