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