1
2/*
3 * Copyright 2014 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9// This test only works with the GPU backend.
10
11#include "gm.h"
12
13#if SK_SUPPORT_GPU
14
15#include "GrBatchTarget.h"
16#include "GrContext.h"
17#include "GrDefaultGeoProcFactory.h"
18#include "GrPathUtils.h"
19#include "GrTest.h"
20#include "GrTestBatch.h"
21#include "SkColorPriv.h"
22#include "SkDevice.h"
23#include "SkGeometry.h"
24#include "SkTLList.h"
25
26#include "effects/GrConvexPolyEffect.h"
27
28namespace skiagm {
29
30class ConvexPolyTestBatch : public GrTestBatch {
31public:
32    struct Geometry : public GrTestBatch::Geometry {
33        SkRect fBounds;
34    };
35
36    const char* name() const override { return "ConvexPolyTestBatch"; }
37
38    static GrBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo) {
39        return SkNEW_ARGS(ConvexPolyTestBatch, (gp, geo));
40    }
41
42private:
43    ConvexPolyTestBatch(const GrGeometryProcessor* gp, const Geometry& geo)
44        : INHERITED(gp, geo.fBounds)
45        , fGeometry(geo) {
46    }
47
48    Geometry* geoData(int index) override {
49        SkASSERT(0 == index);
50        return &fGeometry;
51    }
52
53    const Geometry* geoData(int index) const override {
54        SkASSERT(0 == index);
55        return &fGeometry;
56    }
57
58    void onGenerateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
59        size_t vertexStride = this->geometryProcessor()->getVertexStride();
60        SkASSERT(vertexStride == sizeof(SkPoint));
61        QuadHelper helper;
62        SkPoint* verts = reinterpret_cast<SkPoint*>(helper.init(batchTarget, vertexStride, 1));
63        if (!verts) {
64            return;
65        }
66
67        // Make sure any artifacts around the exterior of path are visible by using overly
68        // conservative bounding geometry.
69        fGeometry.fBounds.outset(5.f, 5.f);
70        fGeometry.fBounds.toQuad(verts);
71
72        helper.issueDraw(batchTarget);
73    }
74
75    Geometry fGeometry;
76
77    typedef GrTestBatch INHERITED;
78};
79
80/**
81 * This GM directly exercises a GrProcessor that draws convex polygons.
82 */
83class ConvexPolyEffect : public GM {
84public:
85    ConvexPolyEffect() {
86        this->setBGColor(0xFFFFFFFF);
87    }
88
89protected:
90    SkString onShortName() override {
91        return SkString("convex_poly_effect");
92    }
93
94    SkISize onISize() override {
95        return SkISize::Make(720, 800);
96    }
97
98    void onOnceBeforeDraw() override {
99        SkPath tri;
100        tri.moveTo(5.f, 5.f);
101        tri.lineTo(100.f, 20.f);
102        tri.lineTo(15.f, 100.f);
103
104        fPaths.addToTail(tri);
105        fPaths.addToTail(SkPath())->reverseAddPath(tri);
106
107        tri.close();
108        fPaths.addToTail(tri);
109
110        SkPath ngon;
111        static const SkScalar kRadius = 50.f;
112        const SkPoint center = { kRadius, kRadius };
113        for (int i = 0; i < GrConvexPolyEffect::kMaxEdges; ++i) {
114            SkScalar angle = 2 * SK_ScalarPI * i / GrConvexPolyEffect::kMaxEdges;
115            SkPoint point;
116            point.fY = SkScalarSinCos(angle, &point.fX);
117            point.scale(kRadius);
118            point = center + point;
119            if (0 == i) {
120                ngon.moveTo(point);
121            } else {
122                ngon.lineTo(point);
123            }
124        }
125
126        fPaths.addToTail(ngon);
127        SkMatrix scaleM;
128        scaleM.setScale(1.1f, 0.4f);
129        ngon.transform(scaleM);
130        fPaths.addToTail(ngon);
131
132        // integer edges
133        fRects.addToTail(SkRect::MakeLTRB(5.f, 1.f, 30.f, 25.f));
134        // half-integer edges
135        fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 24.5f));
136        // vertically/horizontally thin rects that cover pixel centers
137        fRects.addToTail(SkRect::MakeLTRB(5.25f, 0.5f, 5.75f, 24.5f));
138        fRects.addToTail(SkRect::MakeLTRB(5.5f,  0.5f, 29.5f, 0.75f));
139        // vertically/horizontally thin rects that don't cover pixel centers
140        fRects.addToTail(SkRect::MakeLTRB(5.55f, 0.5f, 5.75f, 24.5f));
141        fRects.addToTail(SkRect::MakeLTRB(5.5f, .05f, 29.5f, .25f));
142        // small in x and y
143        fRects.addToTail(SkRect::MakeLTRB(5.05f, .55f, 5.45f, .85f));
144        // inverted in x and y
145        fRects.addToTail(SkRect::MakeLTRB(100.f, 50.5f, 5.f, 0.5f));
146    }
147
148    void onDraw(SkCanvas* canvas) override {
149        GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
150        if (NULL == rt) {
151            this->drawGpuOnlyMessage(canvas);
152            return;
153        }
154        GrContext* context = rt->getContext();
155        if (NULL == context) {
156            return;
157        }
158
159        static const GrColor color = 0xff000000;
160        SkAutoTUnref<const GrGeometryProcessor> gp(
161                GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType, color));
162
163        SkScalar y = 0;
164        for (SkTLList<SkPath>::Iter iter(fPaths, SkTLList<SkPath>::Iter::kHead_IterStart);
165             iter.get();
166             iter.next()) {
167            const SkPath* path = iter.get();
168            SkScalar x = 0;
169
170            for (int et = 0; et < kGrProcessorEdgeTypeCnt; ++et) {
171                GrTestTarget tt;
172                context->getTestTarget(&tt);
173                if (NULL == tt.target()) {
174                    SkDEBUGFAIL("Couldn't get Gr test target.");
175                    return;
176                }
177                const SkMatrix m = SkMatrix::MakeTrans(x, y);
178                SkPath p;
179                path->transform(m, &p);
180
181                GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et;
182                SkAutoTUnref<GrFragmentProcessor> fp(GrConvexPolyEffect::Create(edgeType, p));
183                if (!fp) {
184                    continue;
185                }
186
187                GrPipelineBuilder pipelineBuilder;
188                pipelineBuilder.addCoverageProcessor(fp);
189                pipelineBuilder.setRenderTarget(rt);
190
191                ConvexPolyTestBatch::Geometry geometry;
192                geometry.fColor = color;
193                geometry.fBounds = p.getBounds();
194
195                SkAutoTUnref<GrBatch> batch(ConvexPolyTestBatch::Create(gp, geometry));
196
197                tt.target()->drawBatch(&pipelineBuilder, batch);
198
199                x += SkScalarCeilToScalar(path->getBounds().width() + 10.f);
200            }
201
202            // Draw AA and non AA paths using normal API for reference.
203            canvas->save();
204            canvas->translate(x, y);
205            SkPaint paint;
206            canvas->drawPath(*path, paint);
207            canvas->translate(path->getBounds().width() + 10.f, 0);
208            paint.setAntiAlias(true);
209            canvas->drawPath(*path, paint);
210            canvas->restore();
211
212            y += SkScalarCeilToScalar(path->getBounds().height() + 20.f);
213        }
214
215        for (SkTLList<SkRect>::Iter iter(fRects, SkTLList<SkRect>::Iter::kHead_IterStart);
216             iter.get();
217             iter.next()) {
218
219            SkScalar x = 0;
220
221            for (int et = 0; et < kGrProcessorEdgeTypeCnt; ++et) {
222                GrTestTarget tt;
223                context->getTestTarget(&tt);
224                if (NULL == tt.target()) {
225                    SkDEBUGFAIL("Couldn't get Gr test target.");
226                    return;
227                }
228                SkRect rect = *iter.get();
229                rect.offset(x, y);
230                GrPrimitiveEdgeType edgeType = (GrPrimitiveEdgeType) et;
231                SkAutoTUnref<GrFragmentProcessor> fp(GrConvexPolyEffect::Create(edgeType, rect));
232                if (!fp) {
233                    continue;
234                }
235
236                GrPipelineBuilder pipelineBuilder;
237                pipelineBuilder.addCoverageProcessor(fp);
238                pipelineBuilder.setRenderTarget(rt);
239
240                ConvexPolyTestBatch::Geometry geometry;
241                geometry.fColor = color;
242                geometry.fBounds = rect;
243
244                SkAutoTUnref<GrBatch> batch(ConvexPolyTestBatch::Create(gp, geometry));
245
246                tt.target()->drawBatch(&pipelineBuilder, batch);
247
248                x += SkScalarCeilToScalar(rect.width() + 10.f);
249            }
250
251            // Draw rect without and with AA using normal API for reference
252            canvas->save();
253            canvas->translate(x, y);
254            SkPaint paint;
255            canvas->drawRect(*iter.get(), paint);
256            x += SkScalarCeilToScalar(iter.get()->width() + 10.f);
257            paint.setAntiAlias(true);
258            canvas->drawRect(*iter.get(), paint);
259            canvas->restore();
260
261            y += SkScalarCeilToScalar(iter.get()->height() + 20.f);
262        }
263    }
264
265private:
266    SkTLList<SkPath> fPaths;
267    SkTLList<SkRect> fRects;
268
269    typedef GM INHERITED;
270};
271
272DEF_GM( return SkNEW(ConvexPolyEffect); )
273}
274
275#endif
276