• 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 #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