blob: d86a8b8163ace9eff83a5fd1df320ba361d719da [file] [log] [blame]
commit-bot@chromium.org78a10782013-08-21 19:27:48 +00001
2/*
3 * Copyright 2013 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
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000013#if SK_SUPPORT_GPU
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000014
joshualitt95964c62015-02-11 13:45:50 -080015#include "GrBatchTarget.h"
16#include "GrBufferAllocPool.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000017#include "GrContext.h"
18#include "GrPathUtils.h"
19#include "GrTest.h"
joshualitt95964c62015-02-11 13:45:50 -080020#include "GrTestBatch.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000021#include "SkColorPriv.h"
22#include "SkDevice.h"
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +000023#include "SkGeometry.h"
24
25#include "effects/GrBezierEffect.h"
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000026
commit-bot@chromium.org78a10782013-08-21 19:27:48 +000027static inline SkScalar eval_line(const SkPoint& p, const SkScalar lineEq[3], SkScalar sign) {
28 return sign * (lineEq[0] * p.fX + lineEq[1] * p.fY + lineEq[2]);
29}
30
31namespace skiagm {
joshualitt95964c62015-02-11 13:45:50 -080032
33class BezierCubicOrConicTestBatch : public GrTestBatch {
34public:
35 struct Geometry : public GrTestBatch::Geometry {
36 SkRect fBounds;
37 };
38
39 const char* name() const SK_OVERRIDE { return "BezierCubicOrConicTestBatch"; }
40
41 static GrBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo,
42 const SkScalar klmEqs[9], SkScalar sign) {
43 return SkNEW_ARGS(BezierCubicOrConicTestBatch, (gp, geo, klmEqs, sign));
44 }
45
46private:
47 BezierCubicOrConicTestBatch(const GrGeometryProcessor* gp, const Geometry& geo,
48 const SkScalar klmEqs[9], SkScalar sign)
49 : INHERITED(gp) {
50 for (int i = 0; i < 9; i++) {
51 fKlmEqs[i] = klmEqs[i];
52 }
53
54 fGeometry = geo;
55 fSign = sign;
56 }
57
58 struct Vertex {
59 SkPoint fPosition;
60 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
61 };
62
63 Geometry* geoData(int index) SK_OVERRIDE {
64 SkASSERT(0 == index);
65 return &fGeometry;
66 }
67
68 void onGenerateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
69 size_t vertexStride = this->geometryProcessor()->getVertexStride();
70
71 const GrVertexBuffer* vertexBuffer;
72 int firstVertex;
73
74 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
75 kVertsPerCubic,
76 &vertexBuffer,
77 &firstVertex);
78
joshualitt4b31de82015-03-05 14:33:41 -080079 if (!vertices || !batchTarget->quadIndexBuffer()) {
80 SkDebugf("Could not allocate buffers\n");
81 return;
82 }
83
joshualitt95964c62015-02-11 13:45:50 -080084 SkASSERT(vertexStride == sizeof(Vertex));
85 Vertex* verts = reinterpret_cast<Vertex*>(vertices);
86
87 verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop,
88 fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom,
89 sizeof(Vertex));
90 for (int v = 0; v < 4; ++v) {
91 verts[v].fKLM[0] = eval_line(verts[v].fPosition, fKlmEqs + 0, fSign);
92 verts[v].fKLM[1] = eval_line(verts[v].fPosition, fKlmEqs + 3, fSign);
93 verts[v].fKLM[2] = eval_line(verts[v].fPosition, fKlmEqs + 6, 1.f);
94 }
95
96 GrDrawTarget::DrawInfo drawInfo;
97 drawInfo.setPrimitiveType(kTriangleFan_GrPrimitiveType);
98 drawInfo.setVertexBuffer(vertexBuffer);
99 drawInfo.setStartVertex(firstVertex);
100 drawInfo.setVertexCount(kVertsPerCubic);
101 drawInfo.setStartIndex(0);
102 drawInfo.setIndexCount(kIndicesPerCubic);
103 drawInfo.setIndexBuffer(batchTarget->quadIndexBuffer());
104 batchTarget->draw(drawInfo);
105 }
106
107 Geometry fGeometry;
108 SkScalar fKlmEqs[9];
109 SkScalar fSign;
110
111 static const int kVertsPerCubic = 4;
112 static const int kIndicesPerCubic = 6;
113
114 typedef GrTestBatch INHERITED;
115};
116
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000117/**
118 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
119 */
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000120class BezierCubicEffects : public GM {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000121public:
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000122 BezierCubicEffects() {
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000123 this->setBGColor(0xFFFFFFFF);
124 }
125
126protected:
mtklein72c9faa2015-01-09 10:06:39 -0800127 SkString onShortName() SK_OVERRIDE {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000128 return SkString("bezier_cubic_effects");
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000129 }
130
mtklein72c9faa2015-01-09 10:06:39 -0800131 SkISize onISize() SK_OVERRIDE {
tfarinaf5393182014-06-09 23:59:03 -0700132 return SkISize::Make(800, 800);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000133 }
134
mtklein72c9faa2015-01-09 10:06:39 -0800135 void onDraw(SkCanvas* canvas) SK_OVERRIDE {
reed@google.com9c135db2014-03-12 18:28:35 +0000136 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000137 if (NULL == rt) {
bsalomonb62da802015-01-31 07:51:14 -0800138 this->drawGpuOnlyMessage(canvas);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000139 return;
140 }
141 GrContext* context = rt->getContext();
142 if (NULL == context) {
143 return;
144 }
145
146 struct Vertex {
147 SkPoint fPosition;
148 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
149 };
150
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000151 static const int kNumCubics = 15;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000152 SkRandom rand;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000153
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000154 // Mult by 3 for each edge effect type
155 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
156 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000157 SkScalar w = SkIntToScalar(rt->width()) / numCols;
158 SkScalar h = SkIntToScalar(rt->height()) / numRows;
159 int row = 0;
160 int col = 0;
161
162 for (int i = 0; i < kNumCubics; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000163 SkPoint baseControlPts[] = {
164 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
165 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
166 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
167 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000168 };
joshualittb0a8a372014-09-23 09:50:21 -0700169 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
170 SkAutoTUnref<GrGeometryProcessor> gp;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000171 { // scope to contain GrTestTarget
172 GrTestTarget tt;
173 context->getTestTarget(&tt);
174 if (NULL == tt.target()) {
175 continue;
176 }
joshualittb0a8a372014-09-23 09:50:21 -0700177 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
joshualitt8059eb92014-12-29 15:10:07 -0800178 gp.reset(GrCubicEffect::Create(0xff000000, SkMatrix::I(), et,
179 *tt.target()->caps()));
joshualittb0a8a372014-09-23 09:50:21 -0700180 if (!gp) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000181 continue;
182 }
183 }
184
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000185 SkScalar x = SkScalarMul(col, w);
186 SkScalar y = SkScalarMul(row, h);
187 SkPoint controlPts[] = {
188 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
189 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
190 {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
191 {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
192 };
193 SkPoint chopped[10];
194 SkScalar klmEqs[9];
195 SkScalar klmSigns[3];
196 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
197 chopped,
198 klmEqs,
199 klmSigns);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000200
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000201 SkPaint ctrlPtPaint;
202 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000203 for (int i = 0; i < 4; ++i) {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000204 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000205 }
206
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000207 SkPaint polyPaint;
208 polyPaint.setColor(0xffA0A0A0);
209 polyPaint.setStrokeWidth(0);
210 polyPaint.setStyle(SkPaint::kStroke_Style);
211 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000212
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000213 SkPaint choppedPtPaint;
214 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000215
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000216 for (int c = 0; c < cnt; ++c) {
217 SkPoint* pts = chopped + 3 * c;
218
219 for (int i = 0; i < 4; ++i) {
220 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
221 }
222
223 SkRect bounds;
224 bounds.set(pts, 4);
225
226 SkPaint boundsPaint;
227 boundsPaint.setColor(0xff808080);
228 boundsPaint.setStrokeWidth(0);
229 boundsPaint.setStyle(SkPaint::kStroke_Style);
230 canvas->drawRect(bounds, boundsPaint);
231
joshualitt50408ad2014-11-03 12:31:14 -0800232 GrTestTarget tt;
233 context->getTestTarget(&tt);
234 SkASSERT(tt.target());
235
egdaniel8dd688b2015-01-22 10:16:09 -0800236 GrPipelineBuilder pipelineBuilder;
egdaniel8dd688b2015-01-22 10:16:09 -0800237 pipelineBuilder.setRenderTarget(rt);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000238
joshualitt95964c62015-02-11 13:45:50 -0800239 BezierCubicOrConicTestBatch::Geometry geometry;
240 geometry.fColor = gp->color();
241 geometry.fBounds = bounds;
242
joshualitt44701df2015-02-23 14:44:57 -0800243 SkAutoTUnref<GrBatch> batch(
244 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, klmSigns[c]));
joshualitt95964c62015-02-11 13:45:50 -0800245
246 tt.target()->drawBatch(&pipelineBuilder, batch, NULL);
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000247 }
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000248 ++col;
249 if (numCols == col) {
250 col = 0;
251 ++row;
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000252 }
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000253 }
254 }
255 }
256
257private:
258 typedef GM INHERITED;
259};
260
261//////////////////////////////////////////////////////////////////////////////
262
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000263/**
264 * This GM directly exercises effects that draw Bezier curves in the GPU backend.
265 */
266class BezierConicEffects : public GM {
267public:
268 BezierConicEffects() {
269 this->setBGColor(0xFFFFFFFF);
270 }
271
272protected:
mtklein72c9faa2015-01-09 10:06:39 -0800273 SkString onShortName() SK_OVERRIDE {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000274 return SkString("bezier_conic_effects");
275 }
276
mtklein72c9faa2015-01-09 10:06:39 -0800277 SkISize onISize() SK_OVERRIDE {
tfarinaf5393182014-06-09 23:59:03 -0700278 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000279 }
280
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000281
mtklein72c9faa2015-01-09 10:06:39 -0800282 void onDraw(SkCanvas* canvas) SK_OVERRIDE {
reed@google.com9c135db2014-03-12 18:28:35 +0000283 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000284 if (NULL == rt) {
bsalomonb62da802015-01-31 07:51:14 -0800285 this->drawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000286 return;
287 }
288 GrContext* context = rt->getContext();
289 if (NULL == context) {
290 return;
291 }
292
293 struct Vertex {
294 SkPoint fPosition;
295 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
296 };
297
298 static const int kNumConics = 10;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000299 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000300
301 // Mult by 3 for each edge effect type
302 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
303 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
304 SkScalar w = SkIntToScalar(rt->width()) / numCols;
305 SkScalar h = SkIntToScalar(rt->height()) / numRows;
306 int row = 0;
307 int col = 0;
308
309 for (int i = 0; i < kNumConics; ++i) {
310 SkPoint baseControlPts[] = {
311 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
312 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
313 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
314 };
315 SkScalar weight = rand.nextRangeF(0.f, 2.f);
joshualittb0a8a372014-09-23 09:50:21 -0700316 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
317 SkAutoTUnref<GrGeometryProcessor> gp;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000318 { // scope to contain GrTestTarget
319 GrTestTarget tt;
320 context->getTestTarget(&tt);
321 if (NULL == tt.target()) {
322 continue;
323 }
joshualittb0a8a372014-09-23 09:50:21 -0700324 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
joshualitt8059eb92014-12-29 15:10:07 -0800325 gp.reset(GrConicEffect::Create(0xff000000, SkMatrix::I(), et,
326 *tt.target()->caps(), SkMatrix::I()));
joshualittb0a8a372014-09-23 09:50:21 -0700327 if (!gp) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000328 continue;
329 }
330 }
331
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000332 SkScalar x = SkScalarMul(col, w);
333 SkScalar y = SkScalarMul(row, h);
334 SkPoint controlPts[] = {
335 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
336 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
337 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
338 };
339 SkConic dst[4];
340 SkScalar klmEqs[9];
341 int cnt = chop_conic(controlPts, dst, weight);
342 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
343
344 SkPaint ctrlPtPaint;
345 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
346 for (int i = 0; i < 3; ++i) {
347 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
348 }
349
350 SkPaint polyPaint;
351 polyPaint.setColor(0xffA0A0A0);
352 polyPaint.setStrokeWidth(0);
353 polyPaint.setStyle(SkPaint::kStroke_Style);
354 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
355
356 SkPaint choppedPtPaint;
357 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
358
359 for (int c = 0; c < cnt; ++c) {
360 SkPoint* pts = dst[c].fPts;
361 for (int i = 0; i < 3; ++i) {
362 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
363 }
364
365 SkRect bounds;
366 //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
367 //bounds.set(bPts, 2);
368 bounds.set(pts, 3);
369
370 SkPaint boundsPaint;
371 boundsPaint.setColor(0xff808080);
372 boundsPaint.setStrokeWidth(0);
373 boundsPaint.setStyle(SkPaint::kStroke_Style);
374 canvas->drawRect(bounds, boundsPaint);
375
joshualitt50408ad2014-11-03 12:31:14 -0800376 GrTestTarget tt;
377 context->getTestTarget(&tt);
378 SkASSERT(tt.target());
379
egdaniel8dd688b2015-01-22 10:16:09 -0800380 GrPipelineBuilder pipelineBuilder;
egdaniel8dd688b2015-01-22 10:16:09 -0800381 pipelineBuilder.setRenderTarget(rt);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000382
joshualitt95964c62015-02-11 13:45:50 -0800383 BezierCubicOrConicTestBatch::Geometry geometry;
384 geometry.fColor = gp->color();
385 geometry.fBounds = bounds;
386
joshualitt44701df2015-02-23 14:44:57 -0800387 SkAutoTUnref<GrBatch> batch(
388 BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, 1.f));
joshualitt95964c62015-02-11 13:45:50 -0800389
390 tt.target()->drawBatch(&pipelineBuilder, batch, NULL);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000391 }
392 ++col;
393 if (numCols == col) {
394 col = 0;
395 ++row;
396 }
397 }
398 }
399 }
400
401private:
402 // Uses the max curvature function for quads to estimate
403 // where to chop the conic. If the max curvature is not
404 // found along the curve segment it will return 1 and
405 // dst[0] is the original conic. If it returns 2 the dst[0]
406 // and dst[1] are the two new conics.
407 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
408 SkScalar t = SkFindQuadMaxCurvature(src);
409 if (t == 0) {
410 if (dst) {
411 dst[0].set(src, weight);
412 }
413 return 1;
414 } else {
415 if (dst) {
416 SkConic conic;
417 conic.set(src, weight);
418 conic.chopAt(t, dst);
419 }
420 return 2;
421 }
422 }
423
424 // Calls split_conic on the entire conic and then once more on each subsection.
425 // Most cases will result in either 1 conic (chop point is not within t range)
426 // or 3 points (split once and then one subsection is split again).
427 int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
428 SkConic dstTemp[2];
429 int conicCnt = split_conic(src, dstTemp, weight);
430 if (2 == conicCnt) {
431 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
432 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
433 } else {
434 dst[0] = dstTemp[0];
435 }
436 return conicCnt;
437 }
438
439 typedef GM INHERITED;
440};
441
442//////////////////////////////////////////////////////////////////////////////
joshualitt95964c62015-02-11 13:45:50 -0800443
444class BezierQuadTestBatch : public GrTestBatch {
445public:
446 struct Geometry : public GrTestBatch::Geometry {
447 SkRect fBounds;
448 };
449
450 const char* name() const SK_OVERRIDE { return "BezierQuadTestBatch"; }
451
452 static GrBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo,
453 const GrPathUtils::QuadUVMatrix& devToUV) {
454 return SkNEW_ARGS(BezierQuadTestBatch, (gp, geo, devToUV));
455 }
456
457private:
458 BezierQuadTestBatch(const GrGeometryProcessor* gp, const Geometry& geo,
459 const GrPathUtils::QuadUVMatrix& devToUV)
460 : INHERITED(gp)
461 , fGeometry(geo)
462 , fDevToUV(devToUV) {
463 }
464
465 struct Vertex {
466 SkPoint fPosition;
467 float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
468 };
469
470 Geometry* geoData(int index) SK_OVERRIDE {
471 SkASSERT(0 == index);
472 return &fGeometry;
473 }
474
475 void onGenerateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
476 size_t vertexStride = this->geometryProcessor()->getVertexStride();
477
478 const GrVertexBuffer* vertexBuffer;
479 int firstVertex;
480
481 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
482 kVertsPerCubic,
483 &vertexBuffer,
484 &firstVertex);
485
joshualitt4b31de82015-03-05 14:33:41 -0800486 if (!vertices || !batchTarget->quadIndexBuffer()) {
487 SkDebugf("Could not allocate buffers\n");
488 return;
489 }
490
joshualitt95964c62015-02-11 13:45:50 -0800491 SkASSERT(vertexStride == sizeof(Vertex));
492 Vertex* verts = reinterpret_cast<Vertex*>(vertices);
493
494 verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop,
495 fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom,
496 sizeof(Vertex));
497
498 fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
499
500
501 GrDrawTarget::DrawInfo drawInfo;
502 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
503 drawInfo.setVertexBuffer(vertexBuffer);
504 drawInfo.setStartVertex(firstVertex);
505 drawInfo.setVertexCount(kVertsPerCubic);
506 drawInfo.setStartIndex(0);
507 drawInfo.setIndexCount(kIndicesPerCubic);
508 drawInfo.setIndexBuffer(batchTarget->quadIndexBuffer());
509 batchTarget->draw(drawInfo);
510 }
511
512 Geometry fGeometry;
513 GrPathUtils::QuadUVMatrix fDevToUV;
514
515 static const int kVertsPerCubic = 4;
516 static const int kIndicesPerCubic = 6;
517
518 typedef GrTestBatch INHERITED;
519};
520
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000521/**
522 * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
523 */
524class BezierQuadEffects : public GM {
525public:
526 BezierQuadEffects() {
527 this->setBGColor(0xFFFFFFFF);
528 }
529
530protected:
mtklein72c9faa2015-01-09 10:06:39 -0800531 SkString onShortName() SK_OVERRIDE {
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000532 return SkString("bezier_quad_effects");
533 }
534
mtklein72c9faa2015-01-09 10:06:39 -0800535 SkISize onISize() SK_OVERRIDE {
tfarinaf5393182014-06-09 23:59:03 -0700536 return SkISize::Make(800, 800);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000537 }
538
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000539
mtklein72c9faa2015-01-09 10:06:39 -0800540 void onDraw(SkCanvas* canvas) SK_OVERRIDE {
reed@google.com9c135db2014-03-12 18:28:35 +0000541 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000542 if (NULL == rt) {
bsalomonb62da802015-01-31 07:51:14 -0800543 this->drawGpuOnlyMessage(canvas);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000544 return;
545 }
546 GrContext* context = rt->getContext();
547 if (NULL == context) {
548 return;
549 }
550
551 struct Vertex {
552 SkPoint fPosition;
553 float fUV[4]; // The last two values are ignored. The effect expects a vec4f.
554 };
555
556 static const int kNumQuads = 5;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000557 SkRandom rand;
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000558
559 int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
560 int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
561 SkScalar w = SkIntToScalar(rt->width()) / numCols;
562 SkScalar h = SkIntToScalar(rt->height()) / numRows;
563 int row = 0;
564 int col = 0;
565
566 for (int i = 0; i < kNumQuads; ++i) {
567 SkPoint baseControlPts[] = {
568 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
569 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
570 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
571 };
joshualittb0a8a372014-09-23 09:50:21 -0700572 for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
573 SkAutoTUnref<GrGeometryProcessor> gp;
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000574 { // scope to contain GrTestTarget
575 GrTestTarget tt;
576 context->getTestTarget(&tt);
577 if (NULL == tt.target()) {
578 continue;
579 }
joshualittb0a8a372014-09-23 09:50:21 -0700580 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
joshualitt8059eb92014-12-29 15:10:07 -0800581 gp.reset(GrQuadEffect::Create(0xff000000, SkMatrix::I(), et,
582 *tt.target()->caps(), SkMatrix::I()));
joshualittb0a8a372014-09-23 09:50:21 -0700583 if (!gp) {
commit-bot@chromium.orgcabf4b22014-03-05 18:27:43 +0000584 continue;
585 }
586 }
587
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000588 SkScalar x = SkScalarMul(col, w);
589 SkScalar y = SkScalarMul(row, h);
590 SkPoint controlPts[] = {
591 {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
592 {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
593 {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
594 };
595 SkPoint chopped[5];
596 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
597
598 SkPaint ctrlPtPaint;
599 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
600 for (int i = 0; i < 3; ++i) {
601 canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
602 }
603
604 SkPaint polyPaint;
605 polyPaint.setColor(0xffA0A0A0);
606 polyPaint.setStrokeWidth(0);
607 polyPaint.setStyle(SkPaint::kStroke_Style);
608 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
609
610 SkPaint choppedPtPaint;
611 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
612
613 for (int c = 0; c < cnt; ++c) {
614 SkPoint* pts = chopped + 2 * c;
615
616 for (int i = 0; i < 3; ++i) {
617 canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
618 }
619
620 SkRect bounds;
621 bounds.set(pts, 3);
622
623 SkPaint boundsPaint;
624 boundsPaint.setColor(0xff808080);
625 boundsPaint.setStrokeWidth(0);
626 boundsPaint.setStyle(SkPaint::kStroke_Style);
627 canvas->drawRect(bounds, boundsPaint);
628
joshualitt50408ad2014-11-03 12:31:14 -0800629 GrTestTarget tt;
630 context->getTestTarget(&tt);
631 SkASSERT(tt.target());
632
egdaniel8dd688b2015-01-22 10:16:09 -0800633 GrPipelineBuilder pipelineBuilder;
joshualitt94dff152015-02-11 13:03:15 -0800634 pipelineBuilder.setRenderTarget(rt);
joshualitt3f284d72015-02-11 11:34:58 -0800635
joshualitt95964c62015-02-11 13:45:50 -0800636 GrPathUtils::QuadUVMatrix DevToUV(pts);
637
638 BezierQuadTestBatch::Geometry geometry;
639 geometry.fColor = gp->color();
640 geometry.fBounds = bounds;
641
642 SkAutoTUnref<GrBatch> batch(BezierQuadTestBatch::Create(gp, geometry, DevToUV));
643
644 tt.target()->drawBatch(&pipelineBuilder, batch, NULL);
commit-bot@chromium.org53a0b6c2013-08-23 18:05:01 +0000645 }
646 ++col;
647 if (numCols == col) {
648 col = 0;
649 ++row;
650 }
651 }
652 }
653 }
654
655private:
656 typedef GM INHERITED;
657};
658
659DEF_GM( return SkNEW(BezierCubicEffects); )
660DEF_GM( return SkNEW(BezierConicEffects); )
661DEF_GM( return SkNEW(BezierQuadEffects); )
commit-bot@chromium.org78a10782013-08-21 19:27:48 +0000662
663}
664
665#endif