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 "GrContext.h"
16#include "GrPathUtils.h"
17#include "GrTest.h"
18#include "SkColorPriv.h"
19#include "SkDevice.h"
20#include "SkGeometry.h"
21#include "SkTLList.h"
22
23#include "effects/GrConvexPolyEffect.h"
24
25namespace {
26extern const GrVertexAttrib kAttribs[] = {
27    {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
28};
29}
30
31namespace skiagm {
32/**
33 * This GM directly exercises a GrEffect that draws convex polygons.
34 */
35class ConvexPolyEffect : public GM {
36public:
37    ConvexPolyEffect() {
38        this->setBGColor(0xFFFFFFFF);
39    }
40
41protected:
42    virtual SkString onShortName() SK_OVERRIDE {
43        return SkString("convex_poly_effect");
44    }
45
46    virtual SkISize onISize() SK_OVERRIDE {
47        return SkISize::Make(720, 800);
48    }
49
50    virtual uint32_t onGetFlags() const SK_OVERRIDE {
51        // This is a GPU-specific GM.
52        return kGPUOnly_Flag;
53    }
54
55    virtual void onOnceBeforeDraw() SK_OVERRIDE {
56        SkPath tri;
57        tri.moveTo(5.f, 5.f);
58        tri.lineTo(100.f, 20.f);
59        tri.lineTo(15.f, 100.f);
60
61        fPaths.addToTail(tri);
62        fPaths.addToTail(SkPath())->reverseAddPath(tri);
63
64        tri.close();
65        fPaths.addToTail(tri);
66
67        SkPath ngon;
68        static const SkScalar kRadius = 50.f;
69        const SkPoint center = { kRadius, kRadius };
70        for (int i = 0; i < GrConvexPolyEffect::kMaxEdges; ++i) {
71            SkScalar angle = 2 * SK_ScalarPI * i / GrConvexPolyEffect::kMaxEdges;
72            SkPoint point;
73            point.fY = SkScalarSinCos(angle, &point.fX);
74            point.scale(kRadius);
75            point = center + point;
76            if (0 == i) {
77                ngon.moveTo(point);
78            } else {
79                ngon.lineTo(point);
80            }
81        }
82
83        fPaths.addToTail(ngon);
84        SkMatrix scaleM;
85        scaleM.setScale(1.1f, 0.4f);
86        ngon.transform(scaleM);
87        fPaths.addToTail(ngon);
88
89        // integer edges
90        fRects.addToTail(SkRect::MakeLTRB(5.f, 1.f, 30.f, 25.f));
91        // half-integer edges
92        fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 24.5f));
93        // vertically/horizontally thin rects that cover pixel centers
94        fRects.addToTail(SkRect::MakeLTRB(5.25f, 0.5f, 5.75f, 24.5f));
95        fRects.addToTail(SkRect::MakeLTRB(5.5f,  0.5f, 29.5f, 0.75f));
96        // vertically/horizontally thin rects that don't cover pixel centers
97        fRects.addToTail(SkRect::MakeLTRB(5.55f, 0.5f, 5.75f, 24.5f));
98        fRects.addToTail(SkRect::MakeLTRB(5.5f, .05f, 29.5f, .25f));
99        // small in x and y
100        fRects.addToTail(SkRect::MakeLTRB(5.05f, .55f, 5.45f, .85f));
101        // inverted in x and y
102        fRects.addToTail(SkRect::MakeLTRB(100.f, 50.5f, 5.f, 0.5f));
103    }
104
105    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
106        GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
107        if (NULL == rt) {
108            return;
109        }
110        GrContext* context = rt->getContext();
111        if (NULL == context) {
112            return;
113        }
114
115        SkScalar y = 0;
116        for (SkTLList<SkPath>::Iter iter(fPaths, SkTLList<SkPath>::Iter::kHead_IterStart);
117             NULL != iter.get();
118             iter.next()) {
119            const SkPath* path = iter.get();
120            SkScalar x = 0;
121
122            for (int et = 0; et < kGrEffectEdgeTypeCnt; ++et) {
123                GrTestTarget tt;
124                context->getTestTarget(&tt);
125                if (NULL == tt.target()) {
126                    SkDEBUGFAIL("Couldn't get Gr test target.");
127                    return;
128                }
129                GrDrawState* drawState = tt.target()->drawState();
130                drawState->setVertexAttribs<kAttribs>(SK_ARRAY_COUNT(kAttribs));
131
132                SkMatrix m;
133                SkPath p;
134                m.setTranslate(x, y);
135                path->transform(m, &p);
136
137                GrEffectEdgeType edgeType = (GrEffectEdgeType) et;
138                SkAutoTUnref<GrEffectRef> effect(GrConvexPolyEffect::Create(edgeType, p));
139                if (!effect) {
140                    continue;
141                }
142                drawState->addCoverageEffect(effect, 1);
143                drawState->setIdentityViewMatrix();
144                drawState->setRenderTarget(rt);
145                drawState->setColor(0xff000000);
146
147                SkPoint verts[4];
148                SkRect bounds = p.getBounds();
149                // Make sure any artifacts around the exterior of path are visible by using overly
150                // conservative bounding geometry.
151                bounds.outset(5.f, 5.f);
152                bounds.toQuad(verts);
153
154                tt.target()->setVertexSourceToArray(verts, 4);
155                tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
156                tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
157
158                x += SkScalarCeilToScalar(path->getBounds().width() + 10.f);
159            }
160
161            // Draw AA and non AA paths using normal API for reference.
162            canvas->save();
163            canvas->translate(x, y);
164            SkPaint paint;
165            canvas->drawPath(*path, paint);
166            canvas->translate(path->getBounds().width() + 10.f, 0);
167            paint.setAntiAlias(true);
168            canvas->drawPath(*path, paint);
169            canvas->restore();
170
171            y += SkScalarCeilToScalar(path->getBounds().height() + 20.f);
172        }
173
174        for (SkTLList<SkRect>::Iter iter(fRects, SkTLList<SkRect>::Iter::kHead_IterStart);
175             NULL != iter.get();
176             iter.next()) {
177
178            SkScalar x = 0;
179
180            for (int et = 0; et < kGrEffectEdgeTypeCnt; ++et) {
181                GrTestTarget tt;
182                context->getTestTarget(&tt);
183                if (NULL == tt.target()) {
184                    SkDEBUGFAIL("Couldn't get Gr test target.");
185                    return;
186                }
187                SkRect rect = *iter.get();
188                rect.offset(x, y);
189                GrEffectEdgeType edgeType = (GrEffectEdgeType) et;
190                SkAutoTUnref<GrEffectRef> effect(GrConvexPolyEffect::Create(edgeType, rect));
191                if (!effect) {
192                    continue;
193                }
194
195                GrDrawState* drawState = tt.target()->drawState();
196                drawState->setVertexAttribs<kAttribs>(SK_ARRAY_COUNT(kAttribs));
197                drawState->addCoverageEffect(effect, 1);
198                drawState->setIdentityViewMatrix();
199                drawState->setRenderTarget(rt);
200                drawState->setColor(0xff000000);
201
202                SkPoint verts[4];
203                SkRect bounds = rect;
204                bounds.outset(5.f, 5.f);
205                bounds.toQuad(verts);
206
207                tt.target()->setVertexSourceToArray(verts, 4);
208                tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
209                tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
210
211                x += SkScalarCeilToScalar(rect.width() + 10.f);
212            }
213
214            // Draw rect without and with AA using normal API for reference
215            canvas->save();
216            canvas->translate(x, y);
217            SkPaint paint;
218            canvas->drawRect(*iter.get(), paint);
219            x += SkScalarCeilToScalar(iter.get()->width() + 10.f);
220            paint.setAntiAlias(true);
221            canvas->drawRect(*iter.get(), paint);
222            canvas->restore();
223
224            y += SkScalarCeilToScalar(iter.get()->height() + 20.f);
225        }
226    }
227
228private:
229    SkTLList<SkPath> fPaths;
230    SkTLList<SkRect> fRects;
231
232    typedef GM INHERITED;
233};
234
235DEF_GM( return SkNEW(ConvexPolyEffect); )
236}
237
238#endif
239