blob: 0b84c2cffb33cd3959523a1c12373ce6369a0ba4 [file] [log] [blame]
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001/*
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#include "GrDashingEffect.h"
9
egdaniele61c4112014-06-12 10:24:21 -070010#include "../GrAARectRenderer.h"
11
joshualittb0a8a372014-09-23 09:50:21 -070012#include "GrGeometryProcessor.h"
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000013#include "GrContext.h"
14#include "GrCoordTransform.h"
joshualitt5478d422014-11-14 16:00:38 -080015#include "GrDefaultGeoProcFactory.h"
egdaniele61c4112014-06-12 10:24:21 -070016#include "GrDrawTarget.h"
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000017#include "GrDrawTargetCaps.h"
egdaniel605dd0f2014-11-12 08:35:25 -080018#include "GrInvariantOutput.h"
joshualittb0a8a372014-09-23 09:50:21 -070019#include "GrProcessor.h"
egdaniele61c4112014-06-12 10:24:21 -070020#include "GrStrokeInfo.h"
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000021#include "SkGr.h"
joshualitt5478d422014-11-14 16:00:38 -080022#include "gl/GrGLGeometryProcessor.h"
23#include "gl/GrGLProcessor.h"
24#include "gl/GrGLSL.h"
25#include "gl/builders/GrGLProgramBuilder.h"
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000026
27///////////////////////////////////////////////////////////////////////////////
28
egdaniele61c4112014-06-12 10:24:21 -070029// Returns whether or not the gpu can fast path the dash line effect.
30static bool can_fast_path_dash(const SkPoint pts[2], const GrStrokeInfo& strokeInfo,
egdaniel8dd688b2015-01-22 10:16:09 -080031 const GrDrawTarget& target, const GrPipelineBuilder& pipelineBuilder,
joshualitt9853cce2014-11-17 14:22:48 -080032 const SkMatrix& viewMatrix) {
egdaniel8dd688b2015-01-22 10:16:09 -080033 if (pipelineBuilder.getRenderTarget()->isMultisampled()) {
egdaniele61c4112014-06-12 10:24:21 -070034 return false;
35 }
36
37 // Pts must be either horizontal or vertical in src space
38 if (pts[0].fX != pts[1].fX && pts[0].fY != pts[1].fY) {
39 return false;
40 }
41
42 // May be able to relax this to include skew. As of now cannot do perspective
43 // because of the non uniform scaling of bloating a rect
44 if (!viewMatrix.preservesRightAngles()) {
45 return false;
46 }
47
48 if (!strokeInfo.isDashed() || 2 != strokeInfo.dashCount()) {
49 return false;
50 }
51
52 const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo();
53 if (0 == info.fIntervals[0] && 0 == info.fIntervals[1]) {
54 return false;
55 }
56
57 SkPaint::Cap cap = strokeInfo.getStrokeRec().getCap();
58 // Current we do don't handle Round or Square cap dashes
egdanielf767e792014-07-02 06:21:32 -070059 if (SkPaint::kRound_Cap == cap && info.fIntervals[0] != 0.f) {
egdaniele61c4112014-06-12 10:24:21 -070060 return false;
61 }
62
63 return true;
64}
65
66namespace {
egdaniele61c4112014-06-12 10:24:21 -070067struct DashLineVertex {
68 SkPoint fPos;
69 SkPoint fDashPos;
joshualitt5224ba72015-02-03 15:07:51 -080070 SkScalar fIntervalLength;
71 SkRect fRect;
72};
73struct DashCircleVertex {
74 SkPoint fPos;
75 SkPoint fDashPos;
76 SkScalar fIntervalLength;
77 SkScalar fRadius;
78 SkScalar fCenterX;
egdaniele61c4112014-06-12 10:24:21 -070079};
egdaniele61c4112014-06-12 10:24:21 -070080};
81
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000082static void calc_dash_scaling(SkScalar* parallelScale, SkScalar* perpScale,
83 const SkMatrix& viewMatrix, const SkPoint pts[2]) {
84 SkVector vecSrc = pts[1] - pts[0];
85 SkScalar magSrc = vecSrc.length();
86 SkScalar invSrc = magSrc ? SkScalarInvert(magSrc) : 0;
87 vecSrc.scale(invSrc);
88
89 SkVector vecSrcPerp;
90 vecSrc.rotateCW(&vecSrcPerp);
91 viewMatrix.mapVectors(&vecSrc, 1);
92 viewMatrix.mapVectors(&vecSrcPerp, 1);
93
94 // parallelScale tells how much to scale along the line parallel to the dash line
95 // perpScale tells how much to scale in the direction perpendicular to the dash line
96 *parallelScale = vecSrc.length();
97 *perpScale = vecSrcPerp.length();
98}
99
100// calculates the rotation needed to aligned pts to the x axis with pts[0] < pts[1]
101// Stores the rotation matrix in rotMatrix, and the mapped points in ptsRot
102static void align_to_x_axis(const SkPoint pts[2], SkMatrix* rotMatrix, SkPoint ptsRot[2] = NULL) {
103 SkVector vec = pts[1] - pts[0];
104 SkScalar mag = vec.length();
105 SkScalar inv = mag ? SkScalarInvert(mag) : 0;
106
107 vec.scale(inv);
108 rotMatrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
109 if (ptsRot) {
110 rotMatrix->mapPoints(ptsRot, pts, 2);
111 // correction for numerical issues if map doesn't make ptsRot exactly horizontal
112 ptsRot[1].fY = pts[0].fY;
113 }
114}
115
116// Assumes phase < sum of all intervals
117static SkScalar calc_start_adjustment(const SkPathEffect::DashInfo& info) {
118 SkASSERT(info.fPhase < info.fIntervals[0] + info.fIntervals[1]);
119 if (info.fPhase >= info.fIntervals[0] && info.fPhase != 0) {
120 SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1];
121 return srcIntervalLen - info.fPhase;
122 }
123 return 0;
124}
125
egdaniele61c4112014-06-12 10:24:21 -0700126static SkScalar calc_end_adjustment(const SkPathEffect::DashInfo& info, const SkPoint pts[2],
127 SkScalar phase, SkScalar* endingInt) {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000128 if (pts[1].fX <= pts[0].fX) {
129 return 0;
130 }
131 SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1];
132 SkScalar totalLen = pts[1].fX - pts[0].fX;
133 SkScalar temp = SkScalarDiv(totalLen, srcIntervalLen);
134 SkScalar numFullIntervals = SkScalarFloorToScalar(temp);
egdaniele61c4112014-06-12 10:24:21 -0700135 *endingInt = totalLen - numFullIntervals * srcIntervalLen + phase;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000136 temp = SkScalarDiv(*endingInt, srcIntervalLen);
137 *endingInt = *endingInt - SkScalarFloorToScalar(temp) * srcIntervalLen;
138 if (0 == *endingInt) {
139 *endingInt = srcIntervalLen;
140 }
141 if (*endingInt > info.fIntervals[0]) {
142 if (0 == info.fIntervals[0]) {
commit-bot@chromium.orgad883402014-05-19 14:43:45 +0000143 *endingInt -= 0.01f; // make sure we capture the last zero size pnt (used if has caps)
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000144 }
145 return *endingInt - info.fIntervals[0];
146 }
147 return 0;
148}
149
joshualitt5224ba72015-02-03 15:07:51 -0800150enum DashCap {
151 kRound_DashCap,
152 kNonRound_DashCap,
153};
154
155static int kDashVertices = 4;
156
157template <typename T>
158void setup_dashed_rect_common(const SkRect& rect, const SkMatrix& matrix, T* vertices, int idx,
159 SkScalar offset, SkScalar bloat, SkScalar len, SkScalar stroke) {
160 SkScalar startDashX = offset - bloat;
161 SkScalar endDashX = offset + len + bloat;
162 SkScalar startDashY = -stroke - bloat;
163 SkScalar endDashY = stroke + bloat;
164 vertices[idx].fDashPos = SkPoint::Make(startDashX , startDashY);
165 vertices[idx + 1].fDashPos = SkPoint::Make(startDashX, endDashY);
166 vertices[idx + 2].fDashPos = SkPoint::Make(endDashX, endDashY);
167 vertices[idx + 3].fDashPos = SkPoint::Make(endDashX, startDashY);
168
169 vertices[idx].fPos = SkPoint::Make(rect.fLeft, rect.fTop);
170 vertices[idx + 1].fPos = SkPoint::Make(rect.fLeft, rect.fBottom);
171 vertices[idx + 2].fPos = SkPoint::Make(rect.fRight, rect.fBottom);
172 vertices[idx + 3].fPos = SkPoint::Make(rect.fRight, rect.fTop);
173
174 matrix.mapPointsWithStride(&vertices[idx].fPos, sizeof(T), 4);
175}
176
177static void setup_dashed_rect(const SkRect& rect, void* vertices, int idx,
178 const SkMatrix& matrix, SkScalar offset, SkScalar bloat,
179 SkScalar len, SkScalar stroke, SkScalar startInterval,
180 SkScalar endInterval, SkScalar strokeWidth, DashCap cap,
181 const size_t vertexStride) {
182 SkScalar intervalLength = startInterval + endInterval;
183
184 if (kRound_DashCap == cap) {
185 SkASSERT(vertexStride == sizeof(DashCircleVertex));
186 DashCircleVertex* verts = reinterpret_cast<DashCircleVertex*>(vertices);
187
188 setup_dashed_rect_common<DashCircleVertex>(rect, matrix, verts, idx, offset, bloat, len,
189 stroke);
190
191 SkScalar radius = SkScalarHalf(strokeWidth) - 0.5f;
192 SkScalar centerX = SkScalarHalf(endInterval);
193
194 for (int i = 0; i < kDashVertices; i++) {
195 verts[idx + i].fIntervalLength = intervalLength;
196 verts[idx + i].fRadius = radius;
197 verts[idx + i].fCenterX = centerX;
198 }
199
200 } else {
201 SkASSERT(kNonRound_DashCap == cap && vertexStride == sizeof(DashLineVertex));
202 DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(vertices);
203
204 setup_dashed_rect_common<DashLineVertex>(rect, matrix, verts, idx, offset, bloat, len,
205 stroke);
206
207 SkScalar halfOffLen = SkScalarHalf(endInterval);
208 SkScalar halfStroke = SkScalarHalf(strokeWidth);
209 SkRect rectParam;
210 rectParam.set(halfOffLen + 0.5f, -halfStroke + 0.5f,
211 halfOffLen + startInterval - 0.5f, halfStroke - 0.5f);
212 for (int i = 0; i < kDashVertices; i++) {
213 verts[idx + i].fIntervalLength = intervalLength;
214 verts[idx + i].fRect = rectParam;
215 }
216 }
egdaniele61c4112014-06-12 10:24:21 -0700217}
218
joshualitt5478d422014-11-14 16:00:38 -0800219static void setup_dashed_rect_pos(const SkRect& rect, int idx, const SkMatrix& matrix,
220 SkPoint* verts) {
221 verts[idx] = SkPoint::Make(rect.fLeft, rect.fTop);
222 verts[idx + 1] = SkPoint::Make(rect.fLeft, rect.fBottom);
223 verts[idx + 2] = SkPoint::Make(rect.fRight, rect.fBottom);
224 verts[idx + 3] = SkPoint::Make(rect.fRight, rect.fTop);
225 matrix.mapPoints(&verts[idx], 4);
226}
egdaniele61c4112014-06-12 10:24:21 -0700227
joshualitt5224ba72015-02-03 15:07:51 -0800228
229/**
230 * An GrGeometryProcessor that renders a dashed line.
231 * This GrGeometryProcessor is meant for dashed lines that only have a single on/off interval pair.
232 * Bounding geometry is rendered and the effect computes coverage based on the fragment's
233 * position relative to the dashed line.
234 */
235static GrGeometryProcessor* create_dash_gp(GrColor,
236 GrPrimitiveEdgeType edgeType,
237 DashCap cap,
238 const SkMatrix& localMatrix);
239
egdaniel8dd688b2015-01-22 10:16:09 -0800240bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target,
241 GrPipelineBuilder* pipelineBuilder, GrColor color,
242 const SkMatrix& viewMatrix, const SkPoint pts[2],
joshualitt8059eb92014-12-29 15:10:07 -0800243 const GrPaint& paint, const GrStrokeInfo& strokeInfo) {
egdaniel8dd688b2015-01-22 10:16:09 -0800244 if (!can_fast_path_dash(pts, strokeInfo, *target, *pipelineBuilder, viewMatrix)) {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000245 return false;
246 }
247
egdaniele61c4112014-06-12 10:24:21 -0700248 const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo();
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000249
egdaniele61c4112014-06-12 10:24:21 -0700250 SkPaint::Cap cap = strokeInfo.getStrokeRec().getCap();
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000251
egdaniele61c4112014-06-12 10:24:21 -0700252 SkScalar srcStrokeWidth = strokeInfo.getStrokeRec().getWidth();
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000253
254 // the phase should be normalized to be [0, sum of all intervals)
255 SkASSERT(info.fPhase >= 0 && info.fPhase < info.fIntervals[0] + info.fIntervals[1]);
256
egdaniele61c4112014-06-12 10:24:21 -0700257 SkScalar srcPhase = info.fPhase;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000258
259 // Rotate the src pts so they are aligned horizontally with pts[0].fX < pts[1].fX
260 SkMatrix srcRotInv;
261 SkPoint ptsRot[2];
262 if (pts[0].fY != pts[1].fY || pts[0].fX > pts[1].fX) {
egdaniele61c4112014-06-12 10:24:21 -0700263 SkMatrix rotMatrix;
264 align_to_x_axis(pts, &rotMatrix, ptsRot);
265 if(!rotMatrix.invert(&srcRotInv)) {
tfarina38406c82014-10-31 07:11:12 -0700266 SkDebugf("Failed to create invertible rotation matrix!\n");
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000267 return false;
268 }
269 } else {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000270 srcRotInv.reset();
271 memcpy(ptsRot, pts, 2 * sizeof(SkPoint));
272 }
273
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000274 bool useAA = paint.isAntiAlias();
skia.committer@gmail.com3b9e8be2014-05-20 03:05:34 +0000275
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000276 // Scale corrections of intervals and stroke from view matrix
277 SkScalar parallelScale;
278 SkScalar perpScale;
joshualitt8059eb92014-12-29 15:10:07 -0800279 calc_dash_scaling(&parallelScale, &perpScale, viewMatrix, ptsRot);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000280
egdanielf767e792014-07-02 06:21:32 -0700281 bool hasCap = SkPaint::kButt_Cap != cap && 0 != srcStrokeWidth;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000282
283 // We always want to at least stroke out half a pixel on each side in device space
284 // so 0.5f / perpScale gives us this min in src space
egdaniele61c4112014-06-12 10:24:21 -0700285 SkScalar halfSrcStroke = SkMaxScalar(srcStrokeWidth * 0.5f, 0.5f / perpScale);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000286
egdaniele61c4112014-06-12 10:24:21 -0700287 SkScalar strokeAdj;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000288 if (!hasCap) {
egdaniele61c4112014-06-12 10:24:21 -0700289 strokeAdj = 0.f;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000290 } else {
egdaniele61c4112014-06-12 10:24:21 -0700291 strokeAdj = halfSrcStroke;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000292 }
293
egdaniele61c4112014-06-12 10:24:21 -0700294 SkScalar startAdj = 0;
295
296 SkMatrix combinedMatrix = srcRotInv;
joshualitt8059eb92014-12-29 15:10:07 -0800297 combinedMatrix.postConcat(viewMatrix);
egdaniele61c4112014-06-12 10:24:21 -0700298
299 bool lineDone = false;
300 SkRect startRect;
301 bool hasStartRect = false;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000302 // If we are using AA, check to see if we are drawing a partial dash at the start. If so
303 // draw it separately here and adjust our start point accordingly
304 if (useAA) {
egdaniele61c4112014-06-12 10:24:21 -0700305 if (srcPhase > 0 && srcPhase < info.fIntervals[0]) {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000306 SkPoint startPts[2];
307 startPts[0] = ptsRot[0];
308 startPts[1].fY = startPts[0].fY;
egdaniele61c4112014-06-12 10:24:21 -0700309 startPts[1].fX = SkMinScalar(startPts[0].fX + info.fIntervals[0] - srcPhase,
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000310 ptsRot[1].fX);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000311 startRect.set(startPts, 2);
egdaniele61c4112014-06-12 10:24:21 -0700312 startRect.outset(strokeAdj, halfSrcStroke);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000313
egdaniele61c4112014-06-12 10:24:21 -0700314 hasStartRect = true;
315 startAdj = info.fIntervals[0] + info.fIntervals[1] - srcPhase;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000316 }
317 }
318
319 // adjustments for start and end of bounding rect so we only draw dash intervals
320 // contained in the original line segment.
egdaniele61c4112014-06-12 10:24:21 -0700321 startAdj += calc_start_adjustment(info);
322 if (startAdj != 0) {
323 ptsRot[0].fX += startAdj;
324 srcPhase = 0;
325 }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000326 SkScalar endingInterval = 0;
egdaniele61c4112014-06-12 10:24:21 -0700327 SkScalar endAdj = calc_end_adjustment(info, ptsRot, srcPhase, &endingInterval);
328 ptsRot[1].fX -= endAdj;
329 if (ptsRot[0].fX >= ptsRot[1].fX) {
330 lineDone = true;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000331 }
332
egdaniele61c4112014-06-12 10:24:21 -0700333 SkRect endRect;
334 bool hasEndRect = false;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000335 // If we are using AA, check to see if we are drawing a partial dash at then end. If so
336 // draw it separately here and adjust our end point accordingly
egdaniele61c4112014-06-12 10:24:21 -0700337 if (useAA && !lineDone) {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000338 // If we adjusted the end then we will not be drawing a partial dash at the end.
339 // If we didn't adjust the end point then we just need to make sure the ending
340 // dash isn't a full dash
341 if (0 == endAdj && endingInterval != info.fIntervals[0]) {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000342 SkPoint endPts[2];
343 endPts[1] = ptsRot[1];
344 endPts[0].fY = endPts[1].fY;
skia.committer@gmail.com3b9e8be2014-05-20 03:05:34 +0000345 endPts[0].fX = endPts[1].fX - endingInterval;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000346
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000347 endRect.set(endPts, 2);
egdaniele61c4112014-06-12 10:24:21 -0700348 endRect.outset(strokeAdj, halfSrcStroke);
skia.committer@gmail.com3b9e8be2014-05-20 03:05:34 +0000349
egdaniele61c4112014-06-12 10:24:21 -0700350 hasEndRect = true;
351 endAdj = endingInterval + info.fIntervals[1];
352
353 ptsRot[1].fX -= endAdj;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000354 if (ptsRot[0].fX >= ptsRot[1].fX) {
egdaniele61c4112014-06-12 10:24:21 -0700355 lineDone = true;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000356 }
357 }
358 }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000359
egdaniele61c4112014-06-12 10:24:21 -0700360 if (startAdj != 0) {
361 srcPhase = 0;
362 }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000363
egdaniele61c4112014-06-12 10:24:21 -0700364 // Change the dashing info from src space into device space
365 SkScalar devIntervals[2];
366 devIntervals[0] = info.fIntervals[0] * parallelScale;
367 devIntervals[1] = info.fIntervals[1] * parallelScale;
368 SkScalar devPhase = srcPhase * parallelScale;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000369 SkScalar strokeWidth = srcStrokeWidth * perpScale;
370
371 if ((strokeWidth < 1.f && !useAA) || 0.f == strokeWidth) {
372 strokeWidth = 1.f;
373 }
374
egdaniele61c4112014-06-12 10:24:21 -0700375 SkScalar halfDevStroke = strokeWidth * 0.5f;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000376
377 if (SkPaint::kSquare_Cap == cap && 0 != srcStrokeWidth) {
378 // add cap to on interveal and remove from off interval
egdaniele61c4112014-06-12 10:24:21 -0700379 devIntervals[0] += strokeWidth;
380 devIntervals[1] -= strokeWidth;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000381 }
egdaniele61c4112014-06-12 10:24:21 -0700382 SkScalar startOffset = devIntervals[1] * 0.5f + devPhase;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000383
egdaniele61c4112014-06-12 10:24:21 -0700384 SkScalar bloatX = useAA ? 0.5f / parallelScale : 0.f;
385 SkScalar bloatY = useAA ? 0.5f / perpScale : 0.f;
386
387 SkScalar devBloat = useAA ? 0.5f : 0.f;
388
egdaniele61c4112014-06-12 10:24:21 -0700389 if (devIntervals[1] <= 0.f && useAA) {
390 // Case when we end up drawing a solid AA rect
391 // Reset the start rect to draw this single solid rect
392 // but it requires to upload a new intervals uniform so we can mimic
393 // one giant dash
394 ptsRot[0].fX -= hasStartRect ? startAdj : 0;
395 ptsRot[1].fX += hasEndRect ? endAdj : 0;
396 startRect.set(ptsRot, 2);
397 startRect.outset(strokeAdj, halfSrcStroke);
398 hasStartRect = true;
399 hasEndRect = false;
400 lineDone = true;
401
402 SkPoint devicePts[2];
joshualitt8059eb92014-12-29 15:10:07 -0800403 viewMatrix.mapPoints(devicePts, ptsRot, 2);
egdaniele61c4112014-06-12 10:24:21 -0700404 SkScalar lineLength = SkPoint::Distance(devicePts[0], devicePts[1]);
405 if (hasCap) {
406 lineLength += 2.f * halfDevStroke;
407 }
408 devIntervals[0] = lineLength;
409 }
joshualitt2dd1ae02014-12-03 06:24:10 -0800410
joshualittd27f73e2014-12-29 07:43:36 -0800411 // reset to device coordinates
412 SkMatrix invert;
joshualitt8059eb92014-12-29 15:10:07 -0800413 if (!viewMatrix.invert(&invert)) {
joshualittd27f73e2014-12-29 07:43:36 -0800414 SkDebugf("Failed to invert\n");
415 return false;
416 }
417
joshualitt5224ba72015-02-03 15:07:51 -0800418 bool isRoundCap = SkPaint::kRound_Cap == cap;
419 DashCap capType = isRoundCap ? kRound_DashCap : kNonRound_DashCap;
420
joshualitt56995b52014-12-11 15:44:02 -0800421 SkAutoTUnref<const GrGeometryProcessor> gp;
joshualitt5478d422014-11-14 16:00:38 -0800422 bool fullDash = devIntervals[1] > 0.f || useAA;
423 if (fullDash) {
egdaniele61c4112014-06-12 10:24:21 -0700424 SkPathEffect::DashInfo devInfo;
425 devInfo.fPhase = devPhase;
426 devInfo.fCount = 2;
427 devInfo.fIntervals = devIntervals;
joshualitt5224ba72015-02-03 15:07:51 -0800428 GrPrimitiveEdgeType edgeType = useAA ? kFillAA_GrProcessorEdgeType :
joshualittb0a8a372014-09-23 09:50:21 -0700429 kFillBW_GrProcessorEdgeType;
joshualitt5224ba72015-02-03 15:07:51 -0800430 gp.reset(create_dash_gp(color, edgeType, capType, invert));
joshualitt249af152014-09-15 11:41:13 -0700431 } else {
432 // Set up the vertex data for the line and start/end dashes
joshualitt8059eb92014-12-29 15:10:07 -0800433 gp.reset(GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType,
434 color,
435 SkMatrix::I(),
joshualittd27f73e2014-12-29 07:43:36 -0800436 invert));
joshualitt249af152014-09-15 11:41:13 -0700437 }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000438
egdaniele61c4112014-06-12 10:24:21 -0700439 int totalRectCnt = 0;
440
441 totalRectCnt += !lineDone ? 1 : 0;
442 totalRectCnt += hasStartRect ? 1 : 0;
443 totalRectCnt += hasEndRect ? 1 : 0;
444
joshualitt9853cce2014-11-17 14:22:48 -0800445 GrDrawTarget::AutoReleaseGeometry geo(target,
446 totalRectCnt * 4,
joshualitt2dd1ae02014-12-03 06:24:10 -0800447 gp->getVertexStride(), 0);
egdaniele61c4112014-06-12 10:24:21 -0700448 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700449 SkDebugf("Failed to get space for vertices!\n");
egdaniele61c4112014-06-12 10:24:21 -0700450 return false;
451 }
452
egdaniele61c4112014-06-12 10:24:21 -0700453 int curVIdx = 0;
454
egdanielf767e792014-07-02 06:21:32 -0700455 if (SkPaint::kRound_Cap == cap && 0 != srcStrokeWidth) {
456 // need to adjust this for round caps to correctly set the dashPos attrib on vertices
457 startOffset -= halfDevStroke;
458 }
459
egdaniele61c4112014-06-12 10:24:21 -0700460 // Draw interior part of dashed line
461 if (!lineDone) {
462 SkPoint devicePts[2];
joshualitt8059eb92014-12-29 15:10:07 -0800463 viewMatrix.mapPoints(devicePts, ptsRot, 2);
egdaniele61c4112014-06-12 10:24:21 -0700464 SkScalar lineLength = SkPoint::Distance(devicePts[0], devicePts[1]);
465 if (hasCap) {
466 lineLength += 2.f * halfDevStroke;
467 }
468
469 SkRect bounds;
470 bounds.set(ptsRot[0].fX, ptsRot[0].fY, ptsRot[1].fX, ptsRot[1].fY);
471 bounds.outset(bloatX + strokeAdj, bloatY + halfSrcStroke);
joshualitt5478d422014-11-14 16:00:38 -0800472 if (fullDash) {
joshualitt5224ba72015-02-03 15:07:51 -0800473 setup_dashed_rect(bounds, geo.vertices(), curVIdx, combinedMatrix, startOffset,
474 devBloat, lineLength, halfDevStroke, devIntervals[0], devIntervals[1],
475 strokeWidth, capType, gp->getVertexStride());
joshualitt5478d422014-11-14 16:00:38 -0800476 } else {
477 SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices());
joshualitt2dd1ae02014-12-03 06:24:10 -0800478 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
joshualitt5478d422014-11-14 16:00:38 -0800479 setup_dashed_rect_pos(bounds, curVIdx, combinedMatrix, verts);
480 }
egdaniele61c4112014-06-12 10:24:21 -0700481 curVIdx += 4;
482 }
483
484 if (hasStartRect) {
485 SkASSERT(useAA); // so that we know bloatX and bloatY have been set
486 startRect.outset(bloatX, bloatY);
joshualitt5478d422014-11-14 16:00:38 -0800487 if (fullDash) {
joshualitt5224ba72015-02-03 15:07:51 -0800488 setup_dashed_rect(startRect, geo.vertices(), curVIdx, combinedMatrix, startOffset,
489 devBloat, devIntervals[0], halfDevStroke, devIntervals[0],
490 devIntervals[1], strokeWidth, capType, gp->getVertexStride());
joshualitt5478d422014-11-14 16:00:38 -0800491 } else {
492 SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices());
joshualitt2dd1ae02014-12-03 06:24:10 -0800493 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
joshualitt5478d422014-11-14 16:00:38 -0800494 setup_dashed_rect_pos(startRect, curVIdx, combinedMatrix, verts);
495 }
496
egdaniele61c4112014-06-12 10:24:21 -0700497 curVIdx += 4;
498 }
499
500 if (hasEndRect) {
501 SkASSERT(useAA); // so that we know bloatX and bloatY have been set
502 endRect.outset(bloatX, bloatY);
joshualitt5478d422014-11-14 16:00:38 -0800503 if (fullDash) {
joshualitt5224ba72015-02-03 15:07:51 -0800504 setup_dashed_rect(endRect, geo.vertices(), curVIdx, combinedMatrix, startOffset,
505 devBloat, devIntervals[0], halfDevStroke, devIntervals[0],
506 devIntervals[1], strokeWidth, capType, gp->getVertexStride());
joshualitt5478d422014-11-14 16:00:38 -0800507 } else {
508 SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices());
joshualitt2dd1ae02014-12-03 06:24:10 -0800509 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
joshualitt5478d422014-11-14 16:00:38 -0800510 setup_dashed_rect_pos(endRect, curVIdx, combinedMatrix, verts);
511 }
512
egdaniele61c4112014-06-12 10:24:21 -0700513 }
514
515 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
egdaniel8dd688b2015-01-22 10:16:09 -0800516 target->drawIndexedInstances(pipelineBuilder, gp, kTriangles_GrPrimitiveType,
517 totalRectCnt, 4, 6);
egdaniele61c4112014-06-12 10:24:21 -0700518 target->resetIndexSource();
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000519 return true;
520}
521
522//////////////////////////////////////////////////////////////////////////////
523
egdanielf767e792014-07-02 06:21:32 -0700524class GLDashingCircleEffect;
joshualitt9b989322014-12-15 14:16:27 -0800525
526struct DashingCircleBatchTracker {
527 GrGPInput fInputColorType;
528 GrColor fColor;
joshualitt290c09b2014-12-19 13:45:20 -0800529 bool fUsesLocalCoords;
joshualitt9b989322014-12-15 14:16:27 -0800530};
531
egdanielf767e792014-07-02 06:21:32 -0700532/*
533 * This effect will draw a dotted line (defined as a dashed lined with round caps and no on
534 * interval). The radius of the dots is given by the strokeWidth and the spacing by the DashInfo.
535 * Both of the previous two parameters are in device space. This effect also requires the setting of
536 * a vec2 vertex attribute for the the four corners of the bounding rect. This attribute is the
537 * "dash position" of each vertex. In other words it is the vertex coords (in device space) if we
538 * transform the line to be horizontal, with the start of line at the origin then shifted to the
539 * right by half the off interval. The line then goes in the positive x direction.
540 */
joshualitt249af152014-09-15 11:41:13 -0700541class DashingCircleEffect : public GrGeometryProcessor {
egdanielf767e792014-07-02 06:21:32 -0700542public:
543 typedef SkPathEffect::DashInfo DashInfo;
544
joshualitt2e3b3e32014-12-09 13:31:14 -0800545 static GrGeometryProcessor* Create(GrColor,
546 GrPrimitiveEdgeType edgeType,
joshualittd27f73e2014-12-29 07:43:36 -0800547 const SkMatrix& localMatrix);
egdanielf767e792014-07-02 06:21:32 -0700548
549 virtual ~DashingCircleEffect();
550
mtklein72c9faa2015-01-09 10:06:39 -0800551 const char* name() const SK_OVERRIDE { return "DashingCircleEffect"; }
egdanielf767e792014-07-02 06:21:32 -0700552
joshualitt71c92602015-01-14 08:12:47 -0800553 const Attribute* inPosition() const { return fInPosition; }
joshualitt2dd1ae02014-12-03 06:24:10 -0800554
joshualitt5224ba72015-02-03 15:07:51 -0800555 const Attribute* inDashParams() const { return fInDashParams; }
556
557 const Attribute* inCircleParams() const { return fInCircleParams; }
joshualitt249af152014-09-15 11:41:13 -0700558
joshualittb0a8a372014-09-23 09:50:21 -0700559 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
egdanielf767e792014-07-02 06:21:32 -0700560
joshualitteb2a6762014-12-04 11:35:33 -0800561 virtual void getGLProcessorKey(const GrBatchTracker&,
562 const GrGLCaps&,
563 GrProcessorKeyBuilder* b) const SK_OVERRIDE;
egdanielf767e792014-07-02 06:21:32 -0700564
joshualittabb52a12015-01-13 15:02:10 -0800565 virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker&,
566 const GrGLCaps&) const SK_OVERRIDE;
egdanielf767e792014-07-02 06:21:32 -0700567
joshualitt4d8da812015-01-28 12:53:54 -0800568 void initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const SK_OVERRIDE;
joshualitt9b989322014-12-15 14:16:27 -0800569
joshualitt290c09b2014-12-19 13:45:20 -0800570 bool onCanMakeEqual(const GrBatchTracker&,
571 const GrGeometryProcessor&,
572 const GrBatchTracker&) const SK_OVERRIDE;
joshualitt9b989322014-12-15 14:16:27 -0800573
egdanielf767e792014-07-02 06:21:32 -0700574private:
joshualitt5224ba72015-02-03 15:07:51 -0800575 DashingCircleEffect(GrColor, GrPrimitiveEdgeType edgeType, const SkMatrix& localMatrix);
egdanielf767e792014-07-02 06:21:32 -0700576
mtklein72c9faa2015-01-09 10:06:39 -0800577 bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
egdanielf767e792014-07-02 06:21:32 -0700578
mtklein72c9faa2015-01-09 10:06:39 -0800579 void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const SK_OVERRIDE;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700580
joshualitt2dd1ae02014-12-03 06:24:10 -0800581 GrPrimitiveEdgeType fEdgeType;
joshualitt5224ba72015-02-03 15:07:51 -0800582 const Attribute* fInPosition;
583 const Attribute* fInDashParams;
584 const Attribute* fInCircleParams;
egdanielf767e792014-07-02 06:21:32 -0700585
joshualittb0a8a372014-09-23 09:50:21 -0700586 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
egdanielf767e792014-07-02 06:21:32 -0700587
joshualitt249af152014-09-15 11:41:13 -0700588 typedef GrGeometryProcessor INHERITED;
egdanielf767e792014-07-02 06:21:32 -0700589};
590
591//////////////////////////////////////////////////////////////////////////////
592
joshualitt249af152014-09-15 11:41:13 -0700593class GLDashingCircleEffect : public GrGLGeometryProcessor {
egdanielf767e792014-07-02 06:21:32 -0700594public:
joshualitteb2a6762014-12-04 11:35:33 -0800595 GLDashingCircleEffect(const GrGeometryProcessor&, const GrBatchTracker&);
egdanielf767e792014-07-02 06:21:32 -0700596
robertphillips46d36f02015-01-18 08:14:14 -0800597 void onEmitCode(EmitArgs&, GrGPArgs*) SK_OVERRIDE;
egdanielf767e792014-07-02 06:21:32 -0700598
joshualitt87f48d92014-12-04 10:41:40 -0800599 static inline void GenKey(const GrGeometryProcessor&,
600 const GrBatchTracker&,
601 const GrGLCaps&,
602 GrProcessorKeyBuilder*);
egdanielf767e792014-07-02 06:21:32 -0700603
joshualitt87f48d92014-12-04 10:41:40 -0800604 virtual void setData(const GrGLProgramDataManager&,
joshualitt9b989322014-12-15 14:16:27 -0800605 const GrPrimitiveProcessor&,
joshualitt87f48d92014-12-04 10:41:40 -0800606 const GrBatchTracker&) SK_OVERRIDE;
egdanielf767e792014-07-02 06:21:32 -0700607
608private:
joshualitt9b989322014-12-15 14:16:27 -0800609 UniformHandle fParamUniform;
610 UniformHandle fColorUniform;
611 GrColor fColor;
612 SkScalar fPrevRadius;
613 SkScalar fPrevCenterX;
614 SkScalar fPrevIntervalLength;
joshualitt249af152014-09-15 11:41:13 -0700615 typedef GrGLGeometryProcessor INHERITED;
egdanielf767e792014-07-02 06:21:32 -0700616};
617
joshualitteb2a6762014-12-04 11:35:33 -0800618GLDashingCircleEffect::GLDashingCircleEffect(const GrGeometryProcessor&,
619 const GrBatchTracker&) {
joshualitt9b989322014-12-15 14:16:27 -0800620 fColor = GrColor_ILLEGAL;
egdanielf767e792014-07-02 06:21:32 -0700621 fPrevRadius = SK_ScalarMin;
622 fPrevCenterX = SK_ScalarMin;
623 fPrevIntervalLength = SK_ScalarMax;
624}
625
robertphillips46d36f02015-01-18 08:14:14 -0800626void GLDashingCircleEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
joshualittc369e7c2014-10-22 10:56:26 -0700627 const DashingCircleEffect& dce = args.fGP.cast<DashingCircleEffect>();
joshualitt9b989322014-12-15 14:16:27 -0800628 const DashingCircleBatchTracker local = args.fBT.cast<DashingCircleBatchTracker>();
629 GrGLGPBuilder* pb = args.fPB;
joshualitt2dd1ae02014-12-03 06:24:10 -0800630 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
631
joshualittabb52a12015-01-13 15:02:10 -0800632 // emit attributes
633 vsBuilder->emitAttributes(dce);
634
joshualitt5224ba72015-02-03 15:07:51 -0800635 // XY are dashPos, Z is dashInterval
636 GrGLVertToFrag dashParams(kVec3f_GrSLType);
637 args.fPB->addVarying("DashParam", &dashParams);
638 vsBuilder->codeAppendf("%s = %s;", dashParams.vsOut(), dce.inDashParams()->fName);
639
640 // xy, refer to circle radius - 0.5, z refers to cicles center x coord
641 GrGLVertToFrag circleParams(kVec2f_GrSLType);
642 args.fPB->addVarying("CircleParams", &circleParams);
643 vsBuilder->codeAppendf("%s = %s;", circleParams.vsOut(), dce.inCircleParams()->fName);
joshualitt30ba4362014-08-21 20:18:45 -0700644
joshualitt9b989322014-12-15 14:16:27 -0800645 // Setup pass through color
646 this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL, &fColorUniform);
647
joshualittabb52a12015-01-13 15:02:10 -0800648 // Setup position
joshualittdd219872015-02-12 14:48:42 -0800649 this->setupPosition(pb, gpArgs, dce.inPosition()->fName, dce.viewMatrix());
joshualitt4973d9d2014-11-08 09:24:25 -0800650
joshualittabb52a12015-01-13 15:02:10 -0800651 // emit transforms
robertphillips46d36f02015-01-18 08:14:14 -0800652 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dce.inPosition()->fName, dce.localMatrix(),
joshualittabb52a12015-01-13 15:02:10 -0800653 args.fTransformsIn, args.fTransformsOut);
654
egdanielf767e792014-07-02 06:21:32 -0700655 // transforms all points so that we can compare them to our test circle
joshualittc369e7c2014-10-22 10:56:26 -0700656 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
joshualitt5224ba72015-02-03 15:07:51 -0800657 fsBuilder->codeAppendf("float xShifted = %s.x - floor(%s.x / %s.z) * %s.z;",
658 dashParams.fsIn(), dashParams.fsIn(), dashParams.fsIn(),
659 dashParams.fsIn());
660 fsBuilder->codeAppendf("vec2 fragPosShifted = vec2(xShifted, %s.y);", dashParams.fsIn());
661 fsBuilder->codeAppendf("vec2 center = vec2(%s.y, 0.0);", circleParams.fsIn());
662 fsBuilder->codeAppend("float dist = length(center - fragPosShifted);");
joshualittb0a8a372014-09-23 09:50:21 -0700663 if (GrProcessorEdgeTypeIsAA(dce.getEdgeType())) {
joshualitt5224ba72015-02-03 15:07:51 -0800664 fsBuilder->codeAppendf("float diff = dist - %s.x;", circleParams.fsIn());
665 fsBuilder->codeAppend("diff = 1.0 - diff;");
666 fsBuilder->codeAppend("float alpha = clamp(diff, 0.0, 1.0);");
egdanielf767e792014-07-02 06:21:32 -0700667 } else {
joshualitt5224ba72015-02-03 15:07:51 -0800668 fsBuilder->codeAppendf("float alpha = 1.0;");
669 fsBuilder->codeAppendf("alpha *= dist < %s.x + 0.5 ? 1.0 : 0.0;", circleParams.fsIn());
egdanielf767e792014-07-02 06:21:32 -0700670 }
joshualitt2dd1ae02014-12-03 06:24:10 -0800671 fsBuilder->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage);
egdanielf767e792014-07-02 06:21:32 -0700672}
673
joshualitt87f48d92014-12-04 10:41:40 -0800674void GLDashingCircleEffect::setData(const GrGLProgramDataManager& pdman,
joshualitt9b989322014-12-15 14:16:27 -0800675 const GrPrimitiveProcessor& processor,
676 const GrBatchTracker& bt) {
joshualittee2af952014-12-30 09:04:15 -0800677 this->setUniformViewMatrix(pdman, processor.viewMatrix());
678
joshualitt9b989322014-12-15 14:16:27 -0800679 const DashingCircleBatchTracker& local = bt.cast<DashingCircleBatchTracker>();
680 if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
681 GrGLfloat c[4];
682 GrColorToRGBAFloat(local.fColor, c);
683 pdman.set4fv(fColorUniform, 1, c);
684 fColor = local.fColor;
685 }
egdanielf767e792014-07-02 06:21:32 -0700686}
687
robertphillips46d36f02015-01-18 08:14:14 -0800688void GLDashingCircleEffect::GenKey(const GrGeometryProcessor& gp,
joshualitt9b989322014-12-15 14:16:27 -0800689 const GrBatchTracker& bt,
joshualitt87f48d92014-12-04 10:41:40 -0800690 const GrGLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700691 GrProcessorKeyBuilder* b) {
joshualitt9b989322014-12-15 14:16:27 -0800692 const DashingCircleBatchTracker& local = bt.cast<DashingCircleBatchTracker>();
robertphillips46d36f02015-01-18 08:14:14 -0800693 const DashingCircleEffect& dce = gp.cast<DashingCircleEffect>();
694 uint32_t key = 0;
695 key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 : 0x0;
696 key |= ComputePosKey(gp.viewMatrix()) << 1;
697 key |= dce.getEdgeType() << 8;
698 b->add32(key << 16 | local.fInputColorType);
egdanielf767e792014-07-02 06:21:32 -0700699}
700
701//////////////////////////////////////////////////////////////////////////////
702
joshualitt2e3b3e32014-12-09 13:31:14 -0800703GrGeometryProcessor* DashingCircleEffect::Create(GrColor color,
704 GrPrimitiveEdgeType edgeType,
joshualittd27f73e2014-12-29 07:43:36 -0800705 const SkMatrix& localMatrix) {
joshualitt5224ba72015-02-03 15:07:51 -0800706 return SkNEW_ARGS(DashingCircleEffect, (color, edgeType, localMatrix));
egdanielf767e792014-07-02 06:21:32 -0700707}
708
709DashingCircleEffect::~DashingCircleEffect() {}
710
joshualitt56995b52014-12-11 15:44:02 -0800711void DashingCircleEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const {
712 out->setUnknownSingleComponent();
egdanielf767e792014-07-02 06:21:32 -0700713}
714
joshualitteb2a6762014-12-04 11:35:33 -0800715void DashingCircleEffect::getGLProcessorKey(const GrBatchTracker& bt,
716 const GrGLCaps& caps,
717 GrProcessorKeyBuilder* b) const {
718 GLDashingCircleEffect::GenKey(*this, bt, caps, b);
719}
720
joshualittabb52a12015-01-13 15:02:10 -0800721GrGLPrimitiveProcessor* DashingCircleEffect::createGLInstance(const GrBatchTracker& bt,
722 const GrGLCaps&) const {
joshualitteb2a6762014-12-04 11:35:33 -0800723 return SkNEW_ARGS(GLDashingCircleEffect, (*this, bt));
egdanielf767e792014-07-02 06:21:32 -0700724}
725
joshualitt2e3b3e32014-12-09 13:31:14 -0800726DashingCircleEffect::DashingCircleEffect(GrColor color,
727 GrPrimitiveEdgeType edgeType,
joshualittd27f73e2014-12-29 07:43:36 -0800728 const SkMatrix& localMatrix)
joshualitt8059eb92014-12-29 15:10:07 -0800729 : INHERITED(color, SkMatrix::I(), localMatrix), fEdgeType(edgeType) {
joshualitteb2a6762014-12-04 11:35:33 -0800730 this->initClassID<DashingCircleEffect>();
joshualitt71c92602015-01-14 08:12:47 -0800731 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
joshualitt5224ba72015-02-03 15:07:51 -0800732 fInDashParams = &this->addVertexAttrib(Attribute("inDashParams", kVec3f_GrVertexAttribType));
733 fInCircleParams = &this->addVertexAttrib(Attribute("inCircleParams",
734 kVec2f_GrVertexAttribType));
egdanielf767e792014-07-02 06:21:32 -0700735}
736
bsalomon0e08fc12014-10-15 08:19:04 -0700737bool DashingCircleEffect::onIsEqual(const GrGeometryProcessor& other) const {
joshualitt49586be2014-09-16 08:21:41 -0700738 const DashingCircleEffect& dce = other.cast<DashingCircleEffect>();
joshualitt5224ba72015-02-03 15:07:51 -0800739 return fEdgeType == dce.fEdgeType;
egdanielf767e792014-07-02 06:21:32 -0700740}
741
joshualitt4d8da812015-01-28 12:53:54 -0800742void DashingCircleEffect::initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const {
joshualitt9b989322014-12-15 14:16:27 -0800743 DashingCircleBatchTracker* local = bt->cast<DashingCircleBatchTracker>();
744 local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
joshualitt290c09b2014-12-19 13:45:20 -0800745 local->fUsesLocalCoords = init.fUsesLocalCoords;
joshualitt9b989322014-12-15 14:16:27 -0800746}
747
joshualitt290c09b2014-12-19 13:45:20 -0800748bool DashingCircleEffect::onCanMakeEqual(const GrBatchTracker& m,
749 const GrGeometryProcessor& that,
750 const GrBatchTracker& t) const {
joshualitt9b989322014-12-15 14:16:27 -0800751 const DashingCircleBatchTracker& mine = m.cast<DashingCircleBatchTracker>();
752 const DashingCircleBatchTracker& theirs = t.cast<DashingCircleBatchTracker>();
joshualitt290c09b2014-12-19 13:45:20 -0800753 return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
754 that, theirs.fUsesLocalCoords) &&
755 CanCombineOutput(mine.fInputColorType, mine.fColor,
joshualitt9b989322014-12-15 14:16:27 -0800756 theirs.fInputColorType, theirs.fColor);
757}
758
joshualittb0a8a372014-09-23 09:50:21 -0700759GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingCircleEffect);
egdanielf767e792014-07-02 06:21:32 -0700760
joshualittb0a8a372014-09-23 09:50:21 -0700761GrGeometryProcessor* DashingCircleEffect::TestCreate(SkRandom* random,
762 GrContext*,
763 const GrDrawTargetCaps& caps,
764 GrTexture*[]) {
765 GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(random->nextULessThan(
766 kGrProcessorEdgeTypeCnt));
joshualitt8059eb92014-12-29 15:10:07 -0800767 return DashingCircleEffect::Create(GrRandomColor(random),
joshualitt5224ba72015-02-03 15:07:51 -0800768 edgeType, GrProcessorUnitTest::TestMatrix(random));
egdanielf767e792014-07-02 06:21:32 -0700769}
770
771//////////////////////////////////////////////////////////////////////////////
772
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000773class GLDashingLineEffect;
774
joshualitt9b989322014-12-15 14:16:27 -0800775struct DashingLineBatchTracker {
776 GrGPInput fInputColorType;
777 GrColor fColor;
joshualitt290c09b2014-12-19 13:45:20 -0800778 bool fUsesLocalCoords;
joshualitt9b989322014-12-15 14:16:27 -0800779};
780
egdanielf767e792014-07-02 06:21:32 -0700781/*
782 * This effect will draw a dashed line. The width of the dash is given by the strokeWidth and the
783 * length and spacing by the DashInfo. Both of the previous two parameters are in device space.
784 * This effect also requires the setting of a vec2 vertex attribute for the the four corners of the
785 * bounding rect. This attribute is the "dash position" of each vertex. In other words it is the
786 * vertex coords (in device space) if we transform the line to be horizontal, with the start of
787 * line at the origin then shifted to the right by half the off interval. The line then goes in the
788 * positive x direction.
789 */
joshualitt249af152014-09-15 11:41:13 -0700790class DashingLineEffect : public GrGeometryProcessor {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000791public:
792 typedef SkPathEffect::DashInfo DashInfo;
793
joshualitt2e3b3e32014-12-09 13:31:14 -0800794 static GrGeometryProcessor* Create(GrColor,
795 GrPrimitiveEdgeType edgeType,
joshualittd27f73e2014-12-29 07:43:36 -0800796 const SkMatrix& localMatrix);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000797
798 virtual ~DashingLineEffect();
799
mtklein72c9faa2015-01-09 10:06:39 -0800800 const char* name() const SK_OVERRIDE { return "DashingEffect"; }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000801
joshualitt71c92602015-01-14 08:12:47 -0800802 const Attribute* inPosition() const { return fInPosition; }
joshualitt2dd1ae02014-12-03 06:24:10 -0800803
joshualitt5224ba72015-02-03 15:07:51 -0800804 const Attribute* inDashParams() const { return fInDashParams; }
805
806 const Attribute* inRectParams() const { return fInRectParams; }
joshualitt249af152014-09-15 11:41:13 -0700807
joshualittb0a8a372014-09-23 09:50:21 -0700808 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000809
joshualitteb2a6762014-12-04 11:35:33 -0800810 virtual void getGLProcessorKey(const GrBatchTracker& bt,
811 const GrGLCaps& caps,
812 GrProcessorKeyBuilder* b) const SK_OVERRIDE;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000813
joshualittabb52a12015-01-13 15:02:10 -0800814 virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt,
815 const GrGLCaps&) const SK_OVERRIDE;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000816
joshualitt4d8da812015-01-28 12:53:54 -0800817 void initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const SK_OVERRIDE;
joshualitt9b989322014-12-15 14:16:27 -0800818
joshualitt290c09b2014-12-19 13:45:20 -0800819 bool onCanMakeEqual(const GrBatchTracker&,
820 const GrGeometryProcessor&,
821 const GrBatchTracker&) const SK_OVERRIDE;
joshualitt9b989322014-12-15 14:16:27 -0800822
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000823private:
joshualitt5224ba72015-02-03 15:07:51 -0800824 DashingLineEffect(GrColor, GrPrimitiveEdgeType edgeType, const SkMatrix& localMatrix);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000825
mtklein72c9faa2015-01-09 10:06:39 -0800826 bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000827
mtklein72c9faa2015-01-09 10:06:39 -0800828 void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const SK_OVERRIDE;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700829
joshualitt2dd1ae02014-12-03 06:24:10 -0800830 GrPrimitiveEdgeType fEdgeType;
joshualitt5224ba72015-02-03 15:07:51 -0800831 const Attribute* fInPosition;
832 const Attribute* fInDashParams;
833 const Attribute* fInRectParams;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000834
joshualittb0a8a372014-09-23 09:50:21 -0700835 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000836
joshualitt249af152014-09-15 11:41:13 -0700837 typedef GrGeometryProcessor INHERITED;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000838};
839
840//////////////////////////////////////////////////////////////////////////////
841
joshualitt249af152014-09-15 11:41:13 -0700842class GLDashingLineEffect : public GrGLGeometryProcessor {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000843public:
joshualitteb2a6762014-12-04 11:35:33 -0800844 GLDashingLineEffect(const GrGeometryProcessor&, const GrBatchTracker&);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000845
robertphillips46d36f02015-01-18 08:14:14 -0800846 void onEmitCode(EmitArgs&, GrGPArgs*) SK_OVERRIDE;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000847
joshualitt87f48d92014-12-04 10:41:40 -0800848 static inline void GenKey(const GrGeometryProcessor&,
849 const GrBatchTracker&,
850 const GrGLCaps&,
851 GrProcessorKeyBuilder*);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000852
joshualitt87f48d92014-12-04 10:41:40 -0800853 virtual void setData(const GrGLProgramDataManager&,
joshualitt9b989322014-12-15 14:16:27 -0800854 const GrPrimitiveProcessor&,
joshualitt87f48d92014-12-04 10:41:40 -0800855 const GrBatchTracker&) SK_OVERRIDE;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000856
857private:
joshualitt9b989322014-12-15 14:16:27 -0800858 GrColor fColor;
joshualitt9b989322014-12-15 14:16:27 -0800859 UniformHandle fColorUniform;
joshualitt249af152014-09-15 11:41:13 -0700860 typedef GrGLGeometryProcessor INHERITED;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000861};
862
joshualitteb2a6762014-12-04 11:35:33 -0800863GLDashingLineEffect::GLDashingLineEffect(const GrGeometryProcessor&,
864 const GrBatchTracker&) {
joshualitt9b989322014-12-15 14:16:27 -0800865 fColor = GrColor_ILLEGAL;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000866}
867
robertphillips46d36f02015-01-18 08:14:14 -0800868void GLDashingLineEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
joshualittc369e7c2014-10-22 10:56:26 -0700869 const DashingLineEffect& de = args.fGP.cast<DashingLineEffect>();
joshualitt9b989322014-12-15 14:16:27 -0800870 const DashingLineBatchTracker& local = args.fBT.cast<DashingLineBatchTracker>();
871 GrGLGPBuilder* pb = args.fPB;
joshualitt2dd1ae02014-12-03 06:24:10 -0800872
873 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
874
joshualittabb52a12015-01-13 15:02:10 -0800875 // emit attributes
876 vsBuilder->emitAttributes(de);
877
joshualitt5224ba72015-02-03 15:07:51 -0800878 // XY refers to dashPos, Z is the dash interval length
879 GrGLVertToFrag inDashParams(kVec3f_GrSLType);
880 args.fPB->addVarying("DashParams", &inDashParams);
881 vsBuilder->codeAppendf("%s = %s;", inDashParams.vsOut(), de.inDashParams()->fName);
882
883 // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5),
884 // respectively.
885 GrGLVertToFrag inRectParams(kVec4f_GrSLType);
886 args.fPB->addVarying("RectParams", &inRectParams);
887 vsBuilder->codeAppendf("%s = %s;", inRectParams.vsOut(), de.inRectParams()->fName);
joshualitt2dd1ae02014-12-03 06:24:10 -0800888
joshualitt9b989322014-12-15 14:16:27 -0800889 // Setup pass through color
890 this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL, &fColorUniform);
891
joshualittabb52a12015-01-13 15:02:10 -0800892 // Setup position
joshualittdd219872015-02-12 14:48:42 -0800893 this->setupPosition(pb, gpArgs, de.inPosition()->fName, de.viewMatrix());
joshualitt4973d9d2014-11-08 09:24:25 -0800894
joshualittabb52a12015-01-13 15:02:10 -0800895 // emit transforms
robertphillips46d36f02015-01-18 08:14:14 -0800896 this->emitTransforms(args.fPB, gpArgs->fPositionVar, de.inPosition()->fName, de.localMatrix(),
joshualittabb52a12015-01-13 15:02:10 -0800897 args.fTransformsIn, args.fTransformsOut);
898
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000899 // transforms all points so that we can compare them to our test rect
joshualittc369e7c2014-10-22 10:56:26 -0700900 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
joshualitt5224ba72015-02-03 15:07:51 -0800901 fsBuilder->codeAppendf("float xShifted = %s.x - floor(%s.x / %s.z) * %s.z;",
902 inDashParams.fsIn(), inDashParams.fsIn(), inDashParams.fsIn(),
903 inDashParams.fsIn());
904 fsBuilder->codeAppendf("vec2 fragPosShifted = vec2(xShifted, %s.y);", inDashParams.fsIn());
joshualittb0a8a372014-09-23 09:50:21 -0700905 if (GrProcessorEdgeTypeIsAA(de.getEdgeType())) {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000906 // The amount of coverage removed in x and y by the edges is computed as a pair of negative
907 // numbers, xSub and ySub.
joshualitt5224ba72015-02-03 15:07:51 -0800908 fsBuilder->codeAppend("float xSub, ySub;");
909 fsBuilder->codeAppendf("xSub = min(fragPosShifted.x - %s.x, 0.0);", inRectParams.fsIn());
910 fsBuilder->codeAppendf("xSub += min(%s.z - fragPosShifted.x, 0.0);", inRectParams.fsIn());
911 fsBuilder->codeAppendf("ySub = min(fragPosShifted.y - %s.y, 0.0);", inRectParams.fsIn());
912 fsBuilder->codeAppendf("ySub += min(%s.w - fragPosShifted.y, 0.0);", inRectParams.fsIn());
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000913 // Now compute coverage in x and y and multiply them to get the fraction of the pixel
914 // covered.
joshualitt5224ba72015-02-03 15:07:51 -0800915 fsBuilder->codeAppendf("float alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));");
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000916 } else {
917 // Assuming the bounding geometry is tight so no need to check y values
joshualitt5224ba72015-02-03 15:07:51 -0800918 fsBuilder->codeAppendf("float alpha = 1.0;");
919 fsBuilder->codeAppendf("alpha *= (fragPosShifted.x - %s.x) > -0.5 ? 1.0 : 0.0;",
920 inRectParams.fsIn());
921 fsBuilder->codeAppendf("alpha *= (%s.z - fragPosShifted.x) >= -0.5 ? 1.0 : 0.0;",
922 inRectParams.fsIn());
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000923 }
joshualitt2dd1ae02014-12-03 06:24:10 -0800924 fsBuilder->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000925}
926
joshualittb0a8a372014-09-23 09:50:21 -0700927void GLDashingLineEffect::setData(const GrGLProgramDataManager& pdman,
joshualitt9b989322014-12-15 14:16:27 -0800928 const GrPrimitiveProcessor& processor,
929 const GrBatchTracker& bt) {
joshualittee2af952014-12-30 09:04:15 -0800930 this->setUniformViewMatrix(pdman, processor.viewMatrix());
931
joshualitt9b989322014-12-15 14:16:27 -0800932 const DashingLineBatchTracker& local = bt.cast<DashingLineBatchTracker>();
933 if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
934 GrGLfloat c[4];
935 GrColorToRGBAFloat(local.fColor, c);
936 pdman.set4fv(fColorUniform, 1, c);
937 fColor = local.fColor;
938 }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000939}
940
robertphillips46d36f02015-01-18 08:14:14 -0800941void GLDashingLineEffect::GenKey(const GrGeometryProcessor& gp,
joshualitt9b989322014-12-15 14:16:27 -0800942 const GrBatchTracker& bt,
joshualitt87f48d92014-12-04 10:41:40 -0800943 const GrGLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700944 GrProcessorKeyBuilder* b) {
joshualitt9b989322014-12-15 14:16:27 -0800945 const DashingLineBatchTracker& local = bt.cast<DashingLineBatchTracker>();
robertphillips46d36f02015-01-18 08:14:14 -0800946 const DashingLineEffect& de = gp.cast<DashingLineEffect>();
947 uint32_t key = 0;
948 key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 : 0x0;
949 key |= ComputePosKey(gp.viewMatrix()) << 1;
950 key |= de.getEdgeType() << 8;
951 b->add32(key << 16 | local.fInputColorType);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000952}
953
954//////////////////////////////////////////////////////////////////////////////
skia.committer@gmail.com3b9e8be2014-05-20 03:05:34 +0000955
joshualitt2e3b3e32014-12-09 13:31:14 -0800956GrGeometryProcessor* DashingLineEffect::Create(GrColor color,
957 GrPrimitiveEdgeType edgeType,
joshualittd27f73e2014-12-29 07:43:36 -0800958 const SkMatrix& localMatrix) {
joshualitt5224ba72015-02-03 15:07:51 -0800959 return SkNEW_ARGS(DashingLineEffect, (color, edgeType, localMatrix));
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000960}
961
962DashingLineEffect::~DashingLineEffect() {}
963
joshualitt56995b52014-12-11 15:44:02 -0800964void DashingLineEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const {
965 out->setUnknownSingleComponent();
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000966}
967
joshualitteb2a6762014-12-04 11:35:33 -0800968void DashingLineEffect::getGLProcessorKey(const GrBatchTracker& bt,
969 const GrGLCaps& caps,
970 GrProcessorKeyBuilder* b) const {
971 GLDashingLineEffect::GenKey(*this, bt, caps, b);
972}
973
joshualittabb52a12015-01-13 15:02:10 -0800974GrGLPrimitiveProcessor* DashingLineEffect::createGLInstance(const GrBatchTracker& bt,
975 const GrGLCaps&) const {
joshualitteb2a6762014-12-04 11:35:33 -0800976 return SkNEW_ARGS(GLDashingLineEffect, (*this, bt));
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000977}
978
joshualitt2e3b3e32014-12-09 13:31:14 -0800979DashingLineEffect::DashingLineEffect(GrColor color,
980 GrPrimitiveEdgeType edgeType,
joshualittd27f73e2014-12-29 07:43:36 -0800981 const SkMatrix& localMatrix)
joshualitt8059eb92014-12-29 15:10:07 -0800982 : INHERITED(color, SkMatrix::I(), localMatrix), fEdgeType(edgeType) {
joshualitteb2a6762014-12-04 11:35:33 -0800983 this->initClassID<DashingLineEffect>();
joshualitt71c92602015-01-14 08:12:47 -0800984 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
joshualitt5224ba72015-02-03 15:07:51 -0800985 fInDashParams = &this->addVertexAttrib(Attribute("inDashParams", kVec3f_GrVertexAttribType));
986 fInRectParams = &this->addVertexAttrib(Attribute("inRect", kVec4f_GrVertexAttribType));
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000987}
988
bsalomon0e08fc12014-10-15 08:19:04 -0700989bool DashingLineEffect::onIsEqual(const GrGeometryProcessor& other) const {
joshualitt49586be2014-09-16 08:21:41 -0700990 const DashingLineEffect& de = other.cast<DashingLineEffect>();
joshualitt5224ba72015-02-03 15:07:51 -0800991 return fEdgeType == de.fEdgeType;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000992}
993
joshualitt4d8da812015-01-28 12:53:54 -0800994void DashingLineEffect::initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const {
joshualitt9b989322014-12-15 14:16:27 -0800995 DashingLineBatchTracker* local = bt->cast<DashingLineBatchTracker>();
996 local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
joshualitt290c09b2014-12-19 13:45:20 -0800997 local->fUsesLocalCoords = init.fUsesLocalCoords;
joshualitt9b989322014-12-15 14:16:27 -0800998}
999
joshualitt290c09b2014-12-19 13:45:20 -08001000bool DashingLineEffect::onCanMakeEqual(const GrBatchTracker& m,
1001 const GrGeometryProcessor& that,
1002 const GrBatchTracker& t) const {
joshualitt9b989322014-12-15 14:16:27 -08001003 const DashingLineBatchTracker& mine = m.cast<DashingLineBatchTracker>();
1004 const DashingLineBatchTracker& theirs = t.cast<DashingLineBatchTracker>();
joshualitt290c09b2014-12-19 13:45:20 -08001005 return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
1006 that, theirs.fUsesLocalCoords) &&
1007 CanCombineOutput(mine.fInputColorType, mine.fColor,
joshualitt9b989322014-12-15 14:16:27 -08001008 theirs.fInputColorType, theirs.fColor);
1009}
1010
joshualittb0a8a372014-09-23 09:50:21 -07001011GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingLineEffect);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001012
joshualittb0a8a372014-09-23 09:50:21 -07001013GrGeometryProcessor* DashingLineEffect::TestCreate(SkRandom* random,
1014 GrContext*,
1015 const GrDrawTargetCaps& caps,
1016 GrTexture*[]) {
1017 GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(random->nextULessThan(
1018 kGrProcessorEdgeTypeCnt));
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001019
joshualitt8059eb92014-12-29 15:10:07 -08001020 return DashingLineEffect::Create(GrRandomColor(random),
joshualitt5224ba72015-02-03 15:07:51 -08001021 edgeType, GrProcessorUnitTest::TestMatrix(random));
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001022}
1023
1024//////////////////////////////////////////////////////////////////////////////
1025
joshualitt5224ba72015-02-03 15:07:51 -08001026static GrGeometryProcessor* create_dash_gp(GrColor color,
1027 GrPrimitiveEdgeType edgeType,
1028 DashCap cap,
1029 const SkMatrix& localMatrix) {
egdanielf767e792014-07-02 06:21:32 -07001030 switch (cap) {
joshualitt5224ba72015-02-03 15:07:51 -08001031 case kRound_DashCap:
1032 return DashingCircleEffect::Create(color, edgeType, localMatrix);
1033 case kNonRound_DashCap:
1034 return DashingLineEffect::Create(color, edgeType, localMatrix);
egdanielf767e792014-07-02 06:21:32 -07001035 default:
1036 SkFAIL("Unexpected dashed cap.");
1037 }
1038 return NULL;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001039}