beziereffects.cpp revision 8059eb9f6e24ed609393fbda4ad71edea03ac258
1bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
2bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt/*
3bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt * Copyright 2013 Google Inc.
4bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt *
5bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt * Use of this source code is governed by a BSD-style license that can be
6bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt * found in the LICENSE file.
7bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt */
8bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
9bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt// This test only works with the GPU backend.
10bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
11bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt#include "gm.h"
12bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
13bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt#if SK_SUPPORT_GPU
14bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
15bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt#include "GrContext.h"
16bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt#include "GrPathUtils.h"
17bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt#include "GrTest.h"
18bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt#include "SkColorPriv.h"
19bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt#include "SkDevice.h"
20bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt#include "SkGeometry.h"
21bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
22bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt#include "effects/GrBezierEffect.h"
23bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
24bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtstatic inline SkScalar eval_line(const SkPoint& p, const SkScalar lineEq[3], SkScalar sign) {
25bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    return sign * (lineEq[0] * p.fX + lineEq[1] * p.fY + lineEq[2]);
26bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt}
27bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
28bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtnamespace skiagm {
29bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt/**
30bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt * This GM directly exercises effects that draw Bezier curves in the GPU backend.
31bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt */
32bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtclass BezierCubicEffects : public GM {
33bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtpublic:
34bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    BezierCubicEffects() {
35bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        this->setBGColor(0xFFFFFFFF);
36bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
37bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
38bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtprotected:
39bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    virtual SkString onShortName() SK_OVERRIDE {
40bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        return SkString("bezier_cubic_effects");
41bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
42bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
43bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    virtual SkISize onISize() SK_OVERRIDE {
44bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        return SkISize::Make(800, 800);
45bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
46bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
47bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    virtual uint32_t onGetFlags() const SK_OVERRIDE {
48bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        // This is a GPU-specific GM.
49bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        return kGPUOnly_Flag;
50bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
51bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
52bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
53bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
54bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
55bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        if (NULL == rt) {
56bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            return;
57bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        }
58bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        GrContext* context = rt->getContext();
59bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        if (NULL == context) {
60bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            return;
61bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        }
62bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
63bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        struct Vertex {
64bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            SkPoint fPosition;
65bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            float   fKLM[4]; // The last value is ignored. The effect expects a vec4f.
66bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        };
67bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
68bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        static const int kNumCubics = 15;
69bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        SkRandom rand;
70bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
71bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        // Mult by 3 for each edge effect type
72bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
73bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
74bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        SkScalar w = SkIntToScalar(rt->width()) / numCols;
75bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        SkScalar h = SkIntToScalar(rt->height()) / numRows;
76bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int row = 0;
77bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int col = 0;
78bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
79bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        for (int i = 0; i < kNumCubics; ++i) {
80bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            SkPoint baseControlPts[] = {
81bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
82bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
83bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
84bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
85bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            };
86bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
87bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkAutoTUnref<GrGeometryProcessor> gp;
88bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                {   // scope to contain GrTestTarget
89bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    GrTestTarget tt;
90bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    context->getTestTarget(&tt);
91bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    if (NULL == tt.target()) {
92bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                        continue;
93bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    }
94bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
95bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    gp.reset(GrCubicEffect::Create(0xff000000, SkMatrix::I(), et,
96bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                                                   *tt.target()->caps()));
97bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    if (!gp) {
98bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                        continue;
99bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    }
100bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                }
101bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
102bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkScalar x = SkScalarMul(col, w);
103bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkScalar y = SkScalarMul(row, h);
104bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkPoint controlPts[] = {
105bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
106bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
107bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
108bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
109bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                };
110bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkPoint chopped[10];
111bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkScalar klmEqs[9];
112bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkScalar klmSigns[3];
113bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
114bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                                                                   chopped,
115bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                                                                   klmEqs,
116bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                                                                   klmSigns);
117bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
118bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkPaint ctrlPtPaint;
119bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
120bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                for (int i = 0; i < 4; ++i) {
121bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
122bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                }
123bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
124bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkPaint polyPaint;
125bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                polyPaint.setColor(0xffA0A0A0);
126bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                polyPaint.setStrokeWidth(0);
127bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                polyPaint.setStyle(SkPaint::kStroke_Style);
128bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
129bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
130bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkPaint choppedPtPaint;
131bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
132bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
133bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                for (int c = 0; c < cnt; ++c) {
134bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    SkPoint* pts = chopped + 3 * c;
135bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
136bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    for (int i = 0; i < 4; ++i) {
137bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                        canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
138bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    }
139bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
140bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    SkRect bounds;
141bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    bounds.set(pts, 4);
142bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
143bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    SkPaint boundsPaint;
144bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    boundsPaint.setColor(0xff808080);
145bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    boundsPaint.setStrokeWidth(0);
146bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    boundsPaint.setStyle(SkPaint::kStroke_Style);
147bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    canvas->drawRect(bounds, boundsPaint);
148bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
149bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    GrTestTarget tt;
150bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    context->getTestTarget(&tt);
151bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    SkASSERT(tt.target());
152bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
153bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    GrDrawState ds;
154bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
155bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    GrDrawTarget::AutoReleaseGeometry geo(tt.target(), 4, gp->getVertexStride(), 0);
156bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    SkASSERT(gp->getVertexStride() == sizeof(Vertex));
157bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    Vertex* verts = reinterpret_cast<Vertex*>(geo.vertices());
158bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
159bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop,
160bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                                                  bounds.fRight, bounds.fBottom,
161bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                                                  sizeof(Vertex));
162bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    for (int v = 0; v < 4; ++v) {
163bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                        verts[v].fKLM[0] = eval_line(verts[v].fPosition, klmEqs + 0, klmSigns[c]);
164bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                        verts[v].fKLM[1] = eval_line(verts[v].fPosition, klmEqs + 3, klmSigns[c]);
165bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                        verts[v].fKLM[2] = eval_line(verts[v].fPosition, klmEqs + 6, 1.f);
166bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    }
167bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
168bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    ds.setRenderTarget(rt);
169bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
170bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
171bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    tt.target()->drawIndexed(&ds, gp, kTriangleFan_GrPrimitiveType, 0, 0,4,6);
172bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                }
173bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                ++col;
174bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                if (numCols == col) {
175bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    col = 0;
176bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    ++row;
177bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                }
178bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            }
179bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        }
180bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
181bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
182bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtprivate:
183bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    typedef GM INHERITED;
184bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt};
185bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
186bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt//////////////////////////////////////////////////////////////////////////////
187bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
188bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt/**
189bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt * This GM directly exercises effects that draw Bezier curves in the GPU backend.
190bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt */
191bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtclass BezierConicEffects : public GM {
192bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtpublic:
193bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    BezierConicEffects() {
194bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        this->setBGColor(0xFFFFFFFF);
195bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
196bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
197bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtprotected:
198bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    virtual SkString onShortName() SK_OVERRIDE {
199bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        return SkString("bezier_conic_effects");
200bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
201bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
202bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    virtual SkISize onISize() SK_OVERRIDE {
203bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        return SkISize::Make(800, 800);
204bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
205bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
206bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    virtual uint32_t onGetFlags() const SK_OVERRIDE {
207bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        // This is a GPU-specific GM.
208bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        return kGPUOnly_Flag;
209bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
210bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
211bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
212bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
213bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
214bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        if (NULL == rt) {
215bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            return;
216bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        }
217bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        GrContext* context = rt->getContext();
218bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        if (NULL == context) {
219bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            return;
220bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        }
221bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
222bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        struct Vertex {
223bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            SkPoint fPosition;
224bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            float   fKLM[4]; // The last value is ignored. The effect expects a vec4f.
225bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        };
226bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
227bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        static const int kNumConics = 10;
228bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        SkRandom rand;
229bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
230bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        // Mult by 3 for each edge effect type
231bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
232bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
233bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        SkScalar w = SkIntToScalar(rt->width()) / numCols;
234bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        SkScalar h = SkIntToScalar(rt->height()) / numRows;
235bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int row = 0;
236bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int col = 0;
237bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
238bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        for (int i = 0; i < kNumConics; ++i) {
239bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            SkPoint baseControlPts[] = {
240bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
241bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
242bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
243bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            };
244bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            SkScalar weight = rand.nextRangeF(0.f, 2.f);
245bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
246bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkAutoTUnref<GrGeometryProcessor> gp;
247bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                {   // scope to contain GrTestTarget
248bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    GrTestTarget tt;
249bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    context->getTestTarget(&tt);
250bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    if (NULL == tt.target()) {
251bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                        continue;
252bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    }
253bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
254bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    gp.reset(GrConicEffect::Create(0xff000000, SkMatrix::I(), et,
255bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                                                   *tt.target()->caps(), SkMatrix::I()));
256bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    if (!gp) {
257bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                        continue;
258bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    }
259bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                }
260bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
261bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkScalar x = SkScalarMul(col, w);
262bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkScalar y = SkScalarMul(row, h);
263bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkPoint controlPts[] = {
264bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
265bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
266bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
267bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                };
268bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkConic dst[4];
269bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkScalar klmEqs[9];
270bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                int cnt = chop_conic(controlPts, dst, weight);
271bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
272bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
273bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkPaint ctrlPtPaint;
274bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
275bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                for (int i = 0; i < 3; ++i) {
276bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
277bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                }
278bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
279bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkPaint polyPaint;
280bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                polyPaint.setColor(0xffA0A0A0);
281bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                polyPaint.setStrokeWidth(0);
282bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                polyPaint.setStyle(SkPaint::kStroke_Style);
283bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
284bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
285bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkPaint choppedPtPaint;
286bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
287bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
288bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                for (int c = 0; c < cnt; ++c) {
289bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    SkPoint* pts = dst[c].fPts;
290bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    for (int i = 0; i < 3; ++i) {
291bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                        canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
292bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    }
293bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
294bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    SkRect bounds;
295bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
296bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    //bounds.set(bPts, 2);
297bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    bounds.set(pts, 3);
298bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
299bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    SkPaint boundsPaint;
300bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    boundsPaint.setColor(0xff808080);
301bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    boundsPaint.setStrokeWidth(0);
302bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    boundsPaint.setStyle(SkPaint::kStroke_Style);
303bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    canvas->drawRect(bounds, boundsPaint);
304bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
305bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    GrTestTarget tt;
306bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    context->getTestTarget(&tt);
307bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    SkASSERT(tt.target());
308bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
309bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    GrDrawState ds;
310bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
311bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    GrDrawTarget::AutoReleaseGeometry geo(tt.target(), 4, gp->getVertexStride(), 0);
312bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    SkASSERT(gp->getVertexStride() == sizeof(Vertex));
313bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    Vertex* verts = reinterpret_cast<Vertex*>(geo.vertices());
314bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
315bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop,
316bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                                                  bounds.fRight, bounds.fBottom,
317bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                                                  sizeof(Vertex));
318bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    for (int v = 0; v < 4; ++v) {
319bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                        verts[v].fKLM[0] = eval_line(verts[v].fPosition, klmEqs + 0, 1.f);
320bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                        verts[v].fKLM[1] = eval_line(verts[v].fPosition, klmEqs + 3, 1.f);
321bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                        verts[v].fKLM[2] = eval_line(verts[v].fPosition, klmEqs + 6, 1.f);
322bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    }
323bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
324bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    ds.setRenderTarget(rt);
325bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
326bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
327bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    tt.target()->drawIndexed(&ds, gp, kTriangleFan_GrPrimitiveType, 0, 0,4,6);
328bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                }
329bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                ++col;
330bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                if (numCols == col) {
331bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    col = 0;
332bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                    ++row;
333bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                }
334bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            }
335bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        }
336bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
337bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
338bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtprivate:
339bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    // Uses the max curvature function for quads to estimate
340bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    // where to chop the conic. If the max curvature is not
341bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    // found along the curve segment it will return 1 and
342bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    // dst[0] is the original conic. If it returns 2 the dst[0]
343bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    // and dst[1] are the two new conics.
344bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
345bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        SkScalar t = SkFindQuadMaxCurvature(src);
346bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        if (t == 0) {
347bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            if (dst) {
348bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                dst[0].set(src, weight);
349bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            }
350bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            return 1;
351bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        } else {
352bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            if (dst) {
353bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                SkConic conic;
354bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                conic.set(src, weight);
355bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                conic.chopAt(t, dst);
356bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            }
357bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            return 2;
358bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        }
359bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
360bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
361bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    // Calls split_conic on the entire conic and then once more on each subsection.
362bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    // Most cases will result in either 1 conic (chop point is not within t range)
363bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    // or 3 points (split once and then one subsection is split again).
364bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
365bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        SkConic dstTemp[2];
366bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int conicCnt = split_conic(src, dstTemp, weight);
367bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        if (2 == conicCnt) {
368bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
369bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
370bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        } else {
371bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            dst[0] = dstTemp[0];
372bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        }
373bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        return conicCnt;
374bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
375bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
376bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    typedef GM INHERITED;
377bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt};
378bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
379bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt//////////////////////////////////////////////////////////////////////////////
380bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt/**
381bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
382bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt */
383bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtclass BezierQuadEffects : public GM {
384bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtpublic:
385bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    BezierQuadEffects() {
386bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        this->setBGColor(0xFFFFFFFF);
387bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
388bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
389bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholtprotected:
390bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    virtual SkString onShortName() SK_OVERRIDE {
391bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        return SkString("bezier_quad_effects");
392bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
393bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
394bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    virtual SkISize onISize() SK_OVERRIDE {
395bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        return SkISize::Make(800, 800);
396bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
397bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
398bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    virtual uint32_t onGetFlags() const SK_OVERRIDE {
399bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        // This is a GPU-specific GM.
400bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        return kGPUOnly_Flag;
401bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    }
402bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
403bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
404bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
405bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
406bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        if (NULL == rt) {
407bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            return;
408bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        }
409bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        GrContext* context = rt->getContext();
410bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        if (NULL == context) {
411bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            return;
412bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        }
413bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
414bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        struct Vertex {
415bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            SkPoint fPosition;
416bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            float   fUV[4]; // The last two values are ignored. The effect expects a vec4f.
417bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        };
418bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
419bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        static const int kNumQuads = 5;
420bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        SkRandom rand;
421bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
422bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
423bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
424bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        SkScalar w = SkIntToScalar(rt->width()) / numCols;
425bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        SkScalar h = SkIntToScalar(rt->height()) / numRows;
426bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int row = 0;
427bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        int col = 0;
428bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt
429bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt        for (int i = 0; i < kNumQuads; ++i) {
430bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt            SkPoint baseControlPts[] = {
431bf3c50fba221f216e38d3f60f89161ced4c684c0Eric Anholt                {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
432                {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
433                {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
434            };
435            for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
436                SkAutoTUnref<GrGeometryProcessor> gp;
437                {   // scope to contain GrTestTarget
438                    GrTestTarget tt;
439                    context->getTestTarget(&tt);
440                    if (NULL == tt.target()) {
441                        continue;
442                    }
443                    GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
444                    gp.reset(GrQuadEffect::Create(0xff000000, SkMatrix::I(), et,
445                                                  *tt.target()->caps(), SkMatrix::I()));
446                    if (!gp) {
447                        continue;
448                    }
449                }
450
451                SkScalar x = SkScalarMul(col, w);
452                SkScalar y = SkScalarMul(row, h);
453                SkPoint controlPts[] = {
454                    {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
455                    {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
456                    {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
457                };
458                SkPoint chopped[5];
459                int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
460
461                SkPaint ctrlPtPaint;
462                ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
463                for (int i = 0; i < 3; ++i) {
464                    canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
465                }
466
467                SkPaint polyPaint;
468                polyPaint.setColor(0xffA0A0A0);
469                polyPaint.setStrokeWidth(0);
470                polyPaint.setStyle(SkPaint::kStroke_Style);
471                canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
472
473                SkPaint choppedPtPaint;
474                choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
475
476                for (int c = 0; c < cnt; ++c) {
477                    SkPoint* pts = chopped + 2 * c;
478
479                    for (int i = 0; i < 3; ++i) {
480                        canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
481                    }
482
483                    SkRect bounds;
484                    bounds.set(pts, 3);
485
486                    SkPaint boundsPaint;
487                    boundsPaint.setColor(0xff808080);
488                    boundsPaint.setStrokeWidth(0);
489                    boundsPaint.setStyle(SkPaint::kStroke_Style);
490                    canvas->drawRect(bounds, boundsPaint);
491
492                    GrTestTarget tt;
493                    context->getTestTarget(&tt);
494                    SkASSERT(tt.target());
495
496                    GrDrawState ds;
497
498                    GrDrawTarget::AutoReleaseGeometry geo(tt.target(), 4, gp->getVertexStride(), 0);
499                    SkASSERT(gp->getVertexStride() == sizeof(Vertex));
500                    Vertex* verts = reinterpret_cast<Vertex*>(geo.vertices());
501
502                    verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop,
503                                                  bounds.fRight, bounds.fBottom,
504                                                  sizeof(Vertex));
505
506                    GrPathUtils::QuadUVMatrix DevToUV(pts);
507                    DevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
508
509                    ds.setRenderTarget(rt);
510
511                    tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
512                    tt.target()->drawIndexed(&ds, gp, kTriangles_GrPrimitiveType, 0, 0, 4, 6);
513                }
514                ++col;
515                if (numCols == col) {
516                    col = 0;
517                    ++row;
518                }
519            }
520        }
521    }
522
523private:
524    typedef GM INHERITED;
525};
526
527DEF_GM( return SkNEW(BezierCubicEffects); )
528DEF_GM( return SkNEW(BezierConicEffects); )
529DEF_GM( return SkNEW(BezierQuadEffects); )
530
531}
532
533#endif
534