blob: 61fad24bcd0db773227c2841daa3385a3ff2baf1 [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
Brian Salomona6aa5902016-12-16 09:32:00 -05008#include "GrDashOp.h"
Brian Salomon98222ac2017-07-12 15:27:54 -04009#include "GrAppliedClip.h"
bsalomoneb1cb5c2015-05-22 08:01:09 -070010#include "GrCaps.h"
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000011#include "GrContext.h"
Robert Phillips7c525e62018-06-12 10:11:12 -040012#include "GrContextPriv.h"
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000013#include "GrCoordTransform.h"
joshualitt5478d422014-11-14 16:00:38 -080014#include "GrDefaultGeoProcFactory.h"
Brian Salomon5ec9def2016-12-20 15:34:05 -050015#include "GrDrawOpTest.h"
Brian Salomondad29232016-12-01 16:40:24 -050016#include "GrGeometryProcessor.h"
Robert Phillips7c525e62018-06-12 10:11:12 -040017#include "GrMemoryPool.h"
Brian Salomon742e31d2016-12-07 17:06:19 -050018#include "GrOpFlushState.h"
joshualittb0a8a372014-09-23 09:50:21 -070019#include "GrProcessor.h"
bsalomon6663acf2016-05-10 09:14:17 -070020#include "GrStyle.h"
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000021#include "SkGr.h"
Brian Salomonfa3783f2018-01-05 13:49:07 -050022#include "SkMatrixPriv.h"
Cary Clarkdf429f32017-11-08 11:44:31 -050023#include "SkPointPriv.h"
egdaniel2d721d32015-11-11 13:06:05 -080024#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniele659a582015-11-13 09:55:43 -080025#include "glsl/GrGLSLGeometryProcessor.h"
egdaniel018fb622015-10-28 07:26:40 -070026#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080027#include "glsl/GrGLSLUniformHandler.h"
egdaniel0eafe792015-11-20 14:01:22 -080028#include "glsl/GrGLSLVarying.h"
Chris Daltonc17bf322017-10-24 10:59:03 -060029#include "glsl/GrGLSLVertexGeoBuilder.h"
Brian Salomon89527432016-12-16 09:52:16 -050030#include "ops/GrMeshDrawOp.h"
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000031
Brian Salomona6aa5902016-12-16 09:32:00 -050032using AAMode = GrDashOp::AAMode;
bsalomonaf18fb42016-06-07 08:10:46 -070033
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000034///////////////////////////////////////////////////////////////////////////////
35
egdaniele61c4112014-06-12 10:24:21 -070036// Returns whether or not the gpu can fast path the dash line effect.
Brian Salomona6aa5902016-12-16 09:32:00 -050037bool GrDashOp::CanDrawDashLine(const SkPoint pts[2], const GrStyle& style,
38 const SkMatrix& viewMatrix) {
egdaniele61c4112014-06-12 10:24:21 -070039 // Pts must be either horizontal or vertical in src space
40 if (pts[0].fX != pts[1].fX && pts[0].fY != pts[1].fY) {
41 return false;
42 }
43
44 // May be able to relax this to include skew. As of now cannot do perspective
45 // because of the non uniform scaling of bloating a rect
46 if (!viewMatrix.preservesRightAngles()) {
47 return false;
48 }
49
bsalomon6663acf2016-05-10 09:14:17 -070050 if (!style.isDashed() || 2 != style.dashIntervalCnt()) {
egdaniele61c4112014-06-12 10:24:21 -070051 return false;
52 }
53
bsalomon6663acf2016-05-10 09:14:17 -070054 const SkScalar* intervals = style.dashIntervals();
kkinnunen261694c2015-05-05 08:00:10 -070055 if (0 == intervals[0] && 0 == intervals[1]) {
egdaniele61c4112014-06-12 10:24:21 -070056 return false;
57 }
58
bsalomon6663acf2016-05-10 09:14:17 -070059 SkPaint::Cap cap = style.strokeRec().getCap();
Greg Daniel5fb30562017-06-29 12:27:48 -040060 if (SkPaint::kRound_Cap == cap) {
61 // Current we don't support round caps unless the on interval is zero
62 if (intervals[0] != 0.f) {
63 return false;
64 }
65 // If the width of the circle caps in greater than the off interval we will pick up unwanted
66 // segments of circles at the start and end of the dash line.
67 if (style.strokeRec().getWidth() > intervals[1]) {
68 return false;
69 }
egdaniele61c4112014-06-12 10:24:21 -070070 }
71
72 return true;
73}
74
75namespace {
egdaniele61c4112014-06-12 10:24:21 -070076struct DashLineVertex {
77 SkPoint fPos;
78 SkPoint fDashPos;
joshualitt5224ba72015-02-03 15:07:51 -080079 SkScalar fIntervalLength;
80 SkRect fRect;
81};
82struct DashCircleVertex {
83 SkPoint fPos;
84 SkPoint fDashPos;
85 SkScalar fIntervalLength;
86 SkScalar fRadius;
87 SkScalar fCenterX;
egdaniele61c4112014-06-12 10:24:21 -070088};
egdaniele61c4112014-06-12 10:24:21 -070089};
90
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000091static void calc_dash_scaling(SkScalar* parallelScale, SkScalar* perpScale,
92 const SkMatrix& viewMatrix, const SkPoint pts[2]) {
93 SkVector vecSrc = pts[1] - pts[0];
Greg Danielc96f9b52017-12-07 15:00:06 -050094 if (pts[1] == pts[0]) {
95 vecSrc.set(1.0, 0.0);
96 }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000097 SkScalar magSrc = vecSrc.length();
98 SkScalar invSrc = magSrc ? SkScalarInvert(magSrc) : 0;
99 vecSrc.scale(invSrc);
100
101 SkVector vecSrcPerp;
Cary Clarkdf429f32017-11-08 11:44:31 -0500102 SkPointPriv::RotateCW(vecSrc, &vecSrcPerp);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000103 viewMatrix.mapVectors(&vecSrc, 1);
104 viewMatrix.mapVectors(&vecSrcPerp, 1);
105
106 // parallelScale tells how much to scale along the line parallel to the dash line
107 // perpScale tells how much to scale in the direction perpendicular to the dash line
108 *parallelScale = vecSrc.length();
109 *perpScale = vecSrcPerp.length();
110}
111
112// calculates the rotation needed to aligned pts to the x axis with pts[0] < pts[1]
113// Stores the rotation matrix in rotMatrix, and the mapped points in ptsRot
halcanary96fcdcc2015-08-27 07:41:13 -0700114static void align_to_x_axis(const SkPoint pts[2], SkMatrix* rotMatrix, SkPoint ptsRot[2] = nullptr) {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000115 SkVector vec = pts[1] - pts[0];
Greg Danielc96f9b52017-12-07 15:00:06 -0500116 if (pts[1] == pts[0]) {
117 vec.set(1.0, 0.0);
118 }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000119 SkScalar mag = vec.length();
120 SkScalar inv = mag ? SkScalarInvert(mag) : 0;
121
122 vec.scale(inv);
123 rotMatrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
124 if (ptsRot) {
125 rotMatrix->mapPoints(ptsRot, pts, 2);
126 // correction for numerical issues if map doesn't make ptsRot exactly horizontal
127 ptsRot[1].fY = pts[0].fY;
128 }
129}
130
131// Assumes phase < sum of all intervals
joshualitt4f569be2015-02-27 11:41:49 -0800132static SkScalar calc_start_adjustment(const SkScalar intervals[2], SkScalar phase) {
133 SkASSERT(phase < intervals[0] + intervals[1]);
134 if (phase >= intervals[0] && phase != 0) {
135 SkScalar srcIntervalLen = intervals[0] + intervals[1];
136 return srcIntervalLen - phase;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000137 }
138 return 0;
139}
140
joshualitt4f569be2015-02-27 11:41:49 -0800141static SkScalar calc_end_adjustment(const SkScalar intervals[2], const SkPoint pts[2],
egdaniele61c4112014-06-12 10:24:21 -0700142 SkScalar phase, SkScalar* endingInt) {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000143 if (pts[1].fX <= pts[0].fX) {
144 return 0;
145 }
joshualitt4f569be2015-02-27 11:41:49 -0800146 SkScalar srcIntervalLen = intervals[0] + intervals[1];
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000147 SkScalar totalLen = pts[1].fX - pts[0].fX;
reed80ea19c2015-05-12 10:37:34 -0700148 SkScalar temp = totalLen / srcIntervalLen;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000149 SkScalar numFullIntervals = SkScalarFloorToScalar(temp);
egdaniele61c4112014-06-12 10:24:21 -0700150 *endingInt = totalLen - numFullIntervals * srcIntervalLen + phase;
reed80ea19c2015-05-12 10:37:34 -0700151 temp = *endingInt / srcIntervalLen;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000152 *endingInt = *endingInt - SkScalarFloorToScalar(temp) * srcIntervalLen;
153 if (0 == *endingInt) {
154 *endingInt = srcIntervalLen;
155 }
joshualitt4f569be2015-02-27 11:41:49 -0800156 if (*endingInt > intervals[0]) {
joshualitt4f569be2015-02-27 11:41:49 -0800157 return *endingInt - intervals[0];
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000158 }
159 return 0;
160}
161
joshualitt5224ba72015-02-03 15:07:51 -0800162enum DashCap {
163 kRound_DashCap,
164 kNonRound_DashCap,
165};
166
167static int kDashVertices = 4;
168
169template <typename T>
170void setup_dashed_rect_common(const SkRect& rect, const SkMatrix& matrix, T* vertices, int idx,
senorblancof3c2c462015-04-20 14:44:26 -0700171 SkScalar offset, SkScalar bloatX, SkScalar bloatY, SkScalar len,
172 SkScalar stroke) {
173 SkScalar startDashX = offset - bloatX;
174 SkScalar endDashX = offset + len + bloatX;
175 SkScalar startDashY = -stroke - bloatY;
176 SkScalar endDashY = stroke + bloatY;
joshualitt5224ba72015-02-03 15:07:51 -0800177 vertices[idx].fDashPos = SkPoint::Make(startDashX , startDashY);
178 vertices[idx + 1].fDashPos = SkPoint::Make(startDashX, endDashY);
Brian Salomon57caa662017-10-18 12:21:05 +0000179 vertices[idx + 2].fDashPos = SkPoint::Make(endDashX, startDashY);
180 vertices[idx + 3].fDashPos = SkPoint::Make(endDashX, endDashY);
joshualitt5224ba72015-02-03 15:07:51 -0800181
182 vertices[idx].fPos = SkPoint::Make(rect.fLeft, rect.fTop);
183 vertices[idx + 1].fPos = SkPoint::Make(rect.fLeft, rect.fBottom);
Brian Salomon57caa662017-10-18 12:21:05 +0000184 vertices[idx + 2].fPos = SkPoint::Make(rect.fRight, rect.fTop);
185 vertices[idx + 3].fPos = SkPoint::Make(rect.fRight, rect.fBottom);
joshualitt5224ba72015-02-03 15:07:51 -0800186
Brian Salomonfa3783f2018-01-05 13:49:07 -0500187 SkMatrixPriv::MapPointsWithStride(matrix, &vertices[idx].fPos, sizeof(T), 4);
joshualitt5224ba72015-02-03 15:07:51 -0800188}
189
190static void setup_dashed_rect(const SkRect& rect, void* vertices, int idx,
senorblancof3c2c462015-04-20 14:44:26 -0700191 const SkMatrix& matrix, SkScalar offset, SkScalar bloatX,
192 SkScalar bloatY, SkScalar len, SkScalar stroke,
193 SkScalar startInterval, SkScalar endInterval, SkScalar strokeWidth,
194 DashCap cap, const size_t vertexStride) {
joshualitt5224ba72015-02-03 15:07:51 -0800195 SkScalar intervalLength = startInterval + endInterval;
196
197 if (kRound_DashCap == cap) {
198 SkASSERT(vertexStride == sizeof(DashCircleVertex));
199 DashCircleVertex* verts = reinterpret_cast<DashCircleVertex*>(vertices);
200
senorblancof3c2c462015-04-20 14:44:26 -0700201 setup_dashed_rect_common<DashCircleVertex>(rect, matrix, verts, idx, offset, bloatX,
202 bloatY, len, stroke);
joshualitt5224ba72015-02-03 15:07:51 -0800203
204 SkScalar radius = SkScalarHalf(strokeWidth) - 0.5f;
205 SkScalar centerX = SkScalarHalf(endInterval);
206
207 for (int i = 0; i < kDashVertices; i++) {
208 verts[idx + i].fIntervalLength = intervalLength;
209 verts[idx + i].fRadius = radius;
210 verts[idx + i].fCenterX = centerX;
211 }
joshualitt5224ba72015-02-03 15:07:51 -0800212 } else {
213 SkASSERT(kNonRound_DashCap == cap && vertexStride == sizeof(DashLineVertex));
214 DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(vertices);
215
senorblancof3c2c462015-04-20 14:44:26 -0700216 setup_dashed_rect_common<DashLineVertex>(rect, matrix, verts, idx, offset, bloatX,
217 bloatY, len, stroke);
joshualitt5224ba72015-02-03 15:07:51 -0800218
219 SkScalar halfOffLen = SkScalarHalf(endInterval);
220 SkScalar halfStroke = SkScalarHalf(strokeWidth);
221 SkRect rectParam;
222 rectParam.set(halfOffLen + 0.5f, -halfStroke + 0.5f,
223 halfOffLen + startInterval - 0.5f, halfStroke - 0.5f);
224 for (int i = 0; i < kDashVertices; i++) {
225 verts[idx + i].fIntervalLength = intervalLength;
226 verts[idx + i].fRect = rectParam;
227 }
228 }
egdaniele61c4112014-06-12 10:24:21 -0700229}
230
joshualitt5478d422014-11-14 16:00:38 -0800231static void setup_dashed_rect_pos(const SkRect& rect, int idx, const SkMatrix& matrix,
232 SkPoint* verts) {
233 verts[idx] = SkPoint::Make(rect.fLeft, rect.fTop);
234 verts[idx + 1] = SkPoint::Make(rect.fLeft, rect.fBottom);
Brian Salomon57caa662017-10-18 12:21:05 +0000235 verts[idx + 2] = SkPoint::Make(rect.fRight, rect.fTop);
236 verts[idx + 3] = SkPoint::Make(rect.fRight, rect.fBottom);
joshualitt5478d422014-11-14 16:00:38 -0800237 matrix.mapPoints(&verts[idx], 4);
238}
egdaniele61c4112014-06-12 10:24:21 -0700239
joshualitt5224ba72015-02-03 15:07:51 -0800240
241/**
242 * An GrGeometryProcessor that renders a dashed line.
243 * This GrGeometryProcessor is meant for dashed lines that only have a single on/off interval pair.
244 * Bounding geometry is rendered and the effect computes coverage based on the fragment's
245 * position relative to the dashed line.
246 */
bungeman06ca8ec2016-06-09 08:01:03 -0700247static sk_sp<GrGeometryProcessor> make_dash_gp(GrColor,
248 AAMode aaMode,
249 DashCap cap,
250 const SkMatrix& localMatrix,
251 bool usesLocalCoords);
joshualitt5224ba72015-02-03 15:07:51 -0800252
Brian Salomon98222ac2017-07-12 15:27:54 -0400253class DashOp final : public GrMeshDrawOp {
joshualitt4f569be2015-02-27 11:41:49 -0800254public:
Brian Salomon25a88092016-12-01 09:36:50 -0500255 DEFINE_OP_CLASS_ID
Robert Phillipsb493eeb2017-09-13 13:10:52 -0400256
Brian Salomona6aa5902016-12-16 09:32:00 -0500257 struct LineData {
joshualitt4f569be2015-02-27 11:41:49 -0800258 SkMatrix fViewMatrix;
259 SkMatrix fSrcRotInv;
260 SkPoint fPtsRot[2];
261 SkScalar fSrcStrokeWidth;
262 SkScalar fPhase;
263 SkScalar fIntervals[2];
264 SkScalar fParallelScale;
265 SkScalar fPerpendicularScale;
joshualitt4f569be2015-02-27 11:41:49 -0800266 };
267
Robert Phillips7c525e62018-06-12 10:11:12 -0400268 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
269 GrPaint&& paint,
270 const LineData& geometry,
271 SkPaint::Cap cap,
272 AAMode aaMode, bool fullDash,
Brian Salomon98222ac2017-07-12 15:27:54 -0400273 const GrUserStencilSettings* stencilSettings) {
Robert Phillipsc994a932018-06-19 13:09:54 -0400274 GrOpMemoryPool* pool = context->contextPriv().opMemoryPool();
275
276 return pool->allocate<DashOp>(std::move(paint), geometry, cap,
277 aaMode, fullDash, stencilSettings);
joshualitt4f569be2015-02-27 11:41:49 -0800278 }
279
Brian Salomona6aa5902016-12-16 09:32:00 -0500280 const char* name() const override { return "DashOp"; }
joshualitt4f569be2015-02-27 11:41:49 -0800281
Robert Phillipsf1748f52017-09-14 14:11:24 -0400282 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -0400283 fProcessorSet.visitProxies(func);
284 }
285
Brian Salomon7c3e7182016-12-01 09:35:30 -0500286 SkString dumpInfo() const override {
287 SkString string;
Brian Salomona6aa5902016-12-16 09:32:00 -0500288 for (const auto& geo : fLines) {
Brian Salomon7c3e7182016-12-01 09:35:30 -0500289 string.appendf("Pt0: [%.2f, %.2f], Pt1: [%.2f, %.2f], Width: %.2f, Ival0: %.2f, "
290 "Ival1 : %.2f, Phase: %.2f\n",
291 geo.fPtsRot[0].fX, geo.fPtsRot[0].fY,
292 geo.fPtsRot[1].fX, geo.fPtsRot[1].fY,
293 geo.fSrcStrokeWidth,
294 geo.fIntervals[0],
295 geo.fIntervals[1],
296 geo.fPhase);
297 }
Brian Salomon98222ac2017-07-12 15:27:54 -0400298 string += fProcessorSet.dumpProcessors();
299 string += INHERITED::dumpInfo();
Brian Salomon7c3e7182016-12-01 09:35:30 -0500300 return string;
301 }
302
Brian Salomon98222ac2017-07-12 15:27:54 -0400303 FixedFunctionFlags fixedFunctionFlags() const override {
304 FixedFunctionFlags flags = FixedFunctionFlags::kNone;
305 if (AAMode::kCoverageWithMSAA == fAAMode) {
306 flags |= FixedFunctionFlags::kUsesHWAA;
307 }
Brian Salomon89717fc2017-07-13 11:25:18 -0400308 if (fStencilSettings != &GrUserStencilSettings::kUnused) {
Brian Salomon98222ac2017-07-12 15:27:54 -0400309 flags |= FixedFunctionFlags::kUsesStencil;
310 }
311 return flags;
312 }
313
Brian Osman532b3f92018-07-11 10:02:07 -0400314 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
Brian Salomon98222ac2017-07-12 15:27:54 -0400315 GrProcessorAnalysisCoverage coverage;
Chris Dalton69824002017-10-31 00:37:52 -0600316 if (AAMode::kNone == fAAMode && !clip->numClipCoverageFragmentProcessors()) {
Brian Salomon98222ac2017-07-12 15:27:54 -0400317 coverage = GrProcessorAnalysisCoverage::kNone;
318 } else {
319 coverage = GrProcessorAnalysisCoverage::kSingleChannel;
320 }
Brian Osman532b3f92018-07-11 10:02:07 -0400321 auto analysis = fProcessorSet.finalize(fColor, coverage, clip, false, caps, &fColor);
Brian Salomon98222ac2017-07-12 15:27:54 -0400322 fDisallowCombineOnTouchOrOverlap = analysis.requiresDstTexture() ||
323 (fProcessorSet.xferProcessor() &&
324 fProcessorSet.xferProcessor()->xferBarrierType(caps));
325 fUsesLocalCoords = analysis.usesLocalCoords();
326 return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo;
327 }
328
bsalomone46f9fe2015-08-18 06:05:14 -0700329private:
Robert Phillips7c525e62018-06-12 10:11:12 -0400330 friend class GrOpMemoryPool; // for ctor
331
Brian Salomon98222ac2017-07-12 15:27:54 -0400332 DashOp(GrPaint&& paint, const LineData& geometry, SkPaint::Cap cap, AAMode aaMode,
333 bool fullDash, const GrUserStencilSettings* stencilSettings)
334 : INHERITED(ClassID())
335 , fColor(paint.getColor())
Brian Salomon98222ac2017-07-12 15:27:54 -0400336 , fFullDash(fullDash)
Brian Salomon89717fc2017-07-13 11:25:18 -0400337 , fCap(cap)
Brian Salomon98222ac2017-07-12 15:27:54 -0400338 , fAAMode(aaMode)
339 , fProcessorSet(std::move(paint))
340 , fStencilSettings(stencilSettings) {
Brian Salomona6aa5902016-12-16 09:32:00 -0500341 fLines.push_back(geometry);
bsalomone46f9fe2015-08-18 06:05:14 -0700342
343 // compute bounds
344 SkScalar halfStrokeWidth = 0.5f * geometry.fSrcStrokeWidth;
345 SkScalar xBloat = SkPaint::kButt_Cap == cap ? 0 : halfStrokeWidth;
bsalomon88cf17d2016-07-08 06:40:56 -0700346 SkRect bounds;
347 bounds.set(geometry.fPtsRot[0], geometry.fPtsRot[1]);
348 bounds.outset(xBloat, halfStrokeWidth);
bsalomone46f9fe2015-08-18 06:05:14 -0700349
350 // Note, we actually create the combined matrix here, and save the work
Brian Salomona6aa5902016-12-16 09:32:00 -0500351 SkMatrix& combinedMatrix = fLines[0].fSrcRotInv;
bsalomone46f9fe2015-08-18 06:05:14 -0700352 combinedMatrix.postConcat(geometry.fViewMatrix);
bsalomon88cf17d2016-07-08 06:40:56 -0700353
354 IsZeroArea zeroArea = geometry.fSrcStrokeWidth ? IsZeroArea::kNo : IsZeroArea::kYes;
355 HasAABloat aaBloat = (aaMode == AAMode::kNone) ? HasAABloat ::kNo : HasAABloat::kYes;
356 this->setTransformedBounds(bounds, combinedMatrix, aaBloat, zeroArea);
bsalomone46f9fe2015-08-18 06:05:14 -0700357 }
358
joshualitt4f569be2015-02-27 11:41:49 -0800359 struct DashDraw {
Brian Salomona6aa5902016-12-16 09:32:00 -0500360 DashDraw(const LineData& geo) {
joshualitt144c3c82015-11-30 12:30:13 -0800361 memcpy(fPtsRot, geo.fPtsRot, sizeof(geo.fPtsRot));
362 memcpy(fIntervals, geo.fIntervals, sizeof(geo.fIntervals));
363 fPhase = geo.fPhase;
364 }
365 SkPoint fPtsRot[2];
366 SkScalar fIntervals[2];
367 SkScalar fPhase;
joshualitt4f569be2015-02-27 11:41:49 -0800368 SkScalar fStartOffset;
369 SkScalar fStrokeWidth;
370 SkScalar fLineLength;
371 SkScalar fHalfDevStroke;
senorblancof3c2c462015-04-20 14:44:26 -0700372 SkScalar fDevBloatX;
373 SkScalar fDevBloatY;
joshualitt4f569be2015-02-27 11:41:49 -0800374 bool fLineDone;
375 bool fHasStartRect;
376 bool fHasEndRect;
377 };
378
Brian Salomon91326c32017-08-09 16:02:19 -0400379 void onPrepareDraws(Target* target) override {
Brian Salomona6aa5902016-12-16 09:32:00 -0500380 int instanceCount = fLines.count();
joshualitt4f569be2015-02-27 11:41:49 -0800381 SkPaint::Cap cap = this->cap();
joshualitte494a582015-08-03 09:32:36 -0700382 bool isRoundCap = SkPaint::kRound_Cap == cap;
383 DashCap capType = isRoundCap ? kRound_DashCap : kNonRound_DashCap;
joshualittdf0c5572015-08-03 11:35:28 -0700384
bungeman06ca8ec2016-06-09 08:01:03 -0700385 sk_sp<GrGeometryProcessor> gp;
joshualitt4f569be2015-02-27 11:41:49 -0800386 if (this->fullDash()) {
bungeman06ca8ec2016-06-09 08:01:03 -0700387 gp = make_dash_gp(this->color(), this->aaMode(), capType, this->viewMatrix(),
Brian Salomon98222ac2017-07-12 15:27:54 -0400388 fUsesLocalCoords);
joshualitt4f569be2015-02-27 11:41:49 -0800389 } else {
390 // Set up the vertex data for the line and start/end dashes
joshualittdf0c5572015-08-03 11:35:28 -0700391 using namespace GrDefaultGeoProcFactory;
392 Color color(this->color());
Brian Salomon98222ac2017-07-12 15:27:54 -0400393 LocalCoords::Type localCoordsType =
394 fUsesLocalCoords ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type;
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400395 gp = MakeForDeviceSpace(target->caps().shaderCaps(),
396 color,
397 Coverage::kSolid_Type,
398 localCoordsType,
Brian Salomon8c852be2017-01-04 10:44:42 -0500399 this->viewMatrix());
joshualittdf0c5572015-08-03 11:35:28 -0700400 }
401
402 if (!gp) {
403 SkDebugf("Could not create GrGeometryProcessor\n");
404 return;
joshualitt4f569be2015-02-27 11:41:49 -0800405 }
406
senorblancof3c2c462015-04-20 14:44:26 -0700407 // useAA here means Edge AA or MSAA
bsalomonaf18fb42016-06-07 08:10:46 -0700408 bool useAA = this->aaMode() != AAMode::kNone;
joshualitt4f569be2015-02-27 11:41:49 -0800409 bool fullDash = this->fullDash();
410
411 // We do two passes over all of the dashes. First we setup the start, end, and bounds,
412 // rectangles. We preserve all of this work in the rects / draws arrays below. Then we
413 // iterate again over these decomposed dashes to generate vertices
joshualitt144c3c82015-11-30 12:30:13 -0800414 static const int kNumStackDashes = 128;
415 SkSTArray<kNumStackDashes, SkRect, true> rects;
416 SkSTArray<kNumStackDashes, DashDraw, true> draws;
joshualitt4f569be2015-02-27 11:41:49 -0800417
418 int totalRectCount = 0;
joshualittd0f54572015-03-02 12:00:52 -0800419 int rectOffset = 0;
bsalomonb5238a72015-05-05 07:49:49 -0700420 rects.push_back_n(3 * instanceCount);
joshualitt4f569be2015-02-27 11:41:49 -0800421 for (int i = 0; i < instanceCount; i++) {
Brian Salomona6aa5902016-12-16 09:32:00 -0500422 const LineData& args = fLines[i];
joshualitt144c3c82015-11-30 12:30:13 -0800423
424 DashDraw& draw = draws.push_back(args);
joshualitt4f569be2015-02-27 11:41:49 -0800425
Greg Daniel95581bb2017-06-30 10:36:38 -0400426 bool hasCap = SkPaint::kButt_Cap != cap;
joshualitt4f569be2015-02-27 11:41:49 -0800427
428 // We always want to at least stroke out half a pixel on each side in device space
429 // so 0.5f / perpScale gives us this min in src space
430 SkScalar halfSrcStroke =
431 SkMaxScalar(args.fSrcStrokeWidth * 0.5f, 0.5f / args.fPerpendicularScale);
432
433 SkScalar strokeAdj;
434 if (!hasCap) {
435 strokeAdj = 0.f;
436 } else {
437 strokeAdj = halfSrcStroke;
438 }
439
440 SkScalar startAdj = 0;
441
joshualitt4f569be2015-02-27 11:41:49 -0800442 bool lineDone = false;
443
444 // Too simplify the algorithm, we always push back rects for start and end rect.
445 // Otherwise we'd have to track start / end rects for each individual geometry
joshualittd0f54572015-03-02 12:00:52 -0800446 SkRect& bounds = rects[rectOffset++];
447 SkRect& startRect = rects[rectOffset++];
448 SkRect& endRect = rects[rectOffset++];
joshualitt4f569be2015-02-27 11:41:49 -0800449
450 bool hasStartRect = false;
451 // If we are using AA, check to see if we are drawing a partial dash at the start. If so
452 // draw it separately here and adjust our start point accordingly
453 if (useAA) {
joshualitt144c3c82015-11-30 12:30:13 -0800454 if (draw.fPhase > 0 && draw.fPhase < draw.fIntervals[0]) {
joshualitt4f569be2015-02-27 11:41:49 -0800455 SkPoint startPts[2];
joshualitt144c3c82015-11-30 12:30:13 -0800456 startPts[0] = draw.fPtsRot[0];
joshualitt4f569be2015-02-27 11:41:49 -0800457 startPts[1].fY = startPts[0].fY;
joshualitt144c3c82015-11-30 12:30:13 -0800458 startPts[1].fX = SkMinScalar(startPts[0].fX + draw.fIntervals[0] - draw.fPhase,
459 draw.fPtsRot[1].fX);
joshualitt4f569be2015-02-27 11:41:49 -0800460 startRect.set(startPts, 2);
461 startRect.outset(strokeAdj, halfSrcStroke);
462
463 hasStartRect = true;
joshualitt144c3c82015-11-30 12:30:13 -0800464 startAdj = draw.fIntervals[0] + draw.fIntervals[1] - draw.fPhase;
joshualitt4f569be2015-02-27 11:41:49 -0800465 }
466 }
467
468 // adjustments for start and end of bounding rect so we only draw dash intervals
469 // contained in the original line segment.
joshualitt144c3c82015-11-30 12:30:13 -0800470 startAdj += calc_start_adjustment(draw.fIntervals, draw.fPhase);
joshualitt4f569be2015-02-27 11:41:49 -0800471 if (startAdj != 0) {
joshualitt144c3c82015-11-30 12:30:13 -0800472 draw.fPtsRot[0].fX += startAdj;
473 draw.fPhase = 0;
joshualitt4f569be2015-02-27 11:41:49 -0800474 }
475 SkScalar endingInterval = 0;
joshualitt144c3c82015-11-30 12:30:13 -0800476 SkScalar endAdj = calc_end_adjustment(draw.fIntervals, draw.fPtsRot, draw.fPhase,
joshualitt4f569be2015-02-27 11:41:49 -0800477 &endingInterval);
joshualitt144c3c82015-11-30 12:30:13 -0800478 draw.fPtsRot[1].fX -= endAdj;
479 if (draw.fPtsRot[0].fX >= draw.fPtsRot[1].fX) {
joshualitt4f569be2015-02-27 11:41:49 -0800480 lineDone = true;
481 }
482
483 bool hasEndRect = false;
484 // If we are using AA, check to see if we are drawing a partial dash at then end. If so
485 // draw it separately here and adjust our end point accordingly
486 if (useAA && !lineDone) {
487 // If we adjusted the end then we will not be drawing a partial dash at the end.
488 // If we didn't adjust the end point then we just need to make sure the ending
489 // dash isn't a full dash
joshualitt144c3c82015-11-30 12:30:13 -0800490 if (0 == endAdj && endingInterval != draw.fIntervals[0]) {
joshualitt4f569be2015-02-27 11:41:49 -0800491 SkPoint endPts[2];
joshualitt144c3c82015-11-30 12:30:13 -0800492 endPts[1] = draw.fPtsRot[1];
joshualitt4f569be2015-02-27 11:41:49 -0800493 endPts[0].fY = endPts[1].fY;
494 endPts[0].fX = endPts[1].fX - endingInterval;
495
496 endRect.set(endPts, 2);
497 endRect.outset(strokeAdj, halfSrcStroke);
498
499 hasEndRect = true;
joshualitt144c3c82015-11-30 12:30:13 -0800500 endAdj = endingInterval + draw.fIntervals[1];
joshualitt4f569be2015-02-27 11:41:49 -0800501
joshualitt144c3c82015-11-30 12:30:13 -0800502 draw.fPtsRot[1].fX -= endAdj;
503 if (draw.fPtsRot[0].fX >= draw.fPtsRot[1].fX) {
joshualitt4f569be2015-02-27 11:41:49 -0800504 lineDone = true;
505 }
506 }
507 }
508
Greg Danielc96f9b52017-12-07 15:00:06 -0500509 if (draw.fPtsRot[0].fX == draw.fPtsRot[1].fX &&
510 (0 != endAdj || 0 == startAdj) &&
511 hasCap) {
512 // At this point the fPtsRot[0]/[1] represent the start and end of the inner rect of
513 // dashes that we want to draw. The only way they can be equal is if the on interval
514 // is zero (or an edge case if the end of line ends at a full off interval, but this
515 // is handled as well). Thus if the on interval is zero then we need to draw a cap
516 // at this position if the stroke has caps. The spec says we only draw this point if
517 // point lies between [start of line, end of line). Thus we check if we are at the
518 // end (but not the start), and if so we don't draw the cap.
519 lineDone = false;
520 }
521
joshualitt4f569be2015-02-27 11:41:49 -0800522 if (startAdj != 0) {
joshualitt144c3c82015-11-30 12:30:13 -0800523 draw.fPhase = 0;
joshualitt4f569be2015-02-27 11:41:49 -0800524 }
525
526 // Change the dashing info from src space into device space
joshualitt144c3c82015-11-30 12:30:13 -0800527 SkScalar* devIntervals = draw.fIntervals;
528 devIntervals[0] = draw.fIntervals[0] * args.fParallelScale;
529 devIntervals[1] = draw.fIntervals[1] * args.fParallelScale;
530 SkScalar devPhase = draw.fPhase * args.fParallelScale;
joshualitt4f569be2015-02-27 11:41:49 -0800531 SkScalar strokeWidth = args.fSrcStrokeWidth * args.fPerpendicularScale;
532
senorblancof3c2c462015-04-20 14:44:26 -0700533 if ((strokeWidth < 1.f && useAA) || 0.f == strokeWidth) {
joshualitt4f569be2015-02-27 11:41:49 -0800534 strokeWidth = 1.f;
535 }
536
537 SkScalar halfDevStroke = strokeWidth * 0.5f;
538
Greg Daniel95581bb2017-06-30 10:36:38 -0400539 if (SkPaint::kSquare_Cap == cap) {
joshualitt4f569be2015-02-27 11:41:49 -0800540 // add cap to on interval and remove from off interval
541 devIntervals[0] += strokeWidth;
542 devIntervals[1] -= strokeWidth;
543 }
544 SkScalar startOffset = devIntervals[1] * 0.5f + devPhase;
545
senorblancof3c2c462015-04-20 14:44:26 -0700546 // For EdgeAA, we bloat in X & Y for both square and round caps.
547 // For MSAA, we don't bloat at all for square caps, and bloat in Y only for round caps.
bsalomonaf18fb42016-06-07 08:10:46 -0700548 SkScalar devBloatX = this->aaMode() == AAMode::kCoverage ? 0.5f : 0.0f;
549 SkScalar devBloatY;
550 if (SkPaint::kRound_Cap == cap && this->aaMode() == AAMode::kCoverageWithMSAA) {
551 devBloatY = 0.5f;
552 } else {
553 devBloatY = devBloatX;
554 }
joshualitt4f569be2015-02-27 11:41:49 -0800555
senorblancof3c2c462015-04-20 14:44:26 -0700556 SkScalar bloatX = devBloatX / args.fParallelScale;
557 SkScalar bloatY = devBloatY / args.fPerpendicularScale;
joshualitt4f569be2015-02-27 11:41:49 -0800558
559 if (devIntervals[1] <= 0.f && useAA) {
560 // Case when we end up drawing a solid AA rect
561 // Reset the start rect to draw this single solid rect
562 // but it requires to upload a new intervals uniform so we can mimic
563 // one giant dash
joshualitt144c3c82015-11-30 12:30:13 -0800564 draw.fPtsRot[0].fX -= hasStartRect ? startAdj : 0;
565 draw.fPtsRot[1].fX += hasEndRect ? endAdj : 0;
566 startRect.set(draw.fPtsRot, 2);
joshualitt4f569be2015-02-27 11:41:49 -0800567 startRect.outset(strokeAdj, halfSrcStroke);
568 hasStartRect = true;
569 hasEndRect = false;
570 lineDone = true;
571
572 SkPoint devicePts[2];
joshualitt144c3c82015-11-30 12:30:13 -0800573 args.fViewMatrix.mapPoints(devicePts, draw.fPtsRot, 2);
joshualitt4f569be2015-02-27 11:41:49 -0800574 SkScalar lineLength = SkPoint::Distance(devicePts[0], devicePts[1]);
575 if (hasCap) {
576 lineLength += 2.f * halfDevStroke;
577 }
578 devIntervals[0] = lineLength;
579 }
580
581 totalRectCount += !lineDone ? 1 : 0;
582 totalRectCount += hasStartRect ? 1 : 0;
583 totalRectCount += hasEndRect ? 1 : 0;
584
585 if (SkPaint::kRound_Cap == cap && 0 != args.fSrcStrokeWidth) {
586 // need to adjust this for round caps to correctly set the dashPos attrib on
587 // vertices
588 startOffset -= halfDevStroke;
589 }
590
joshualitt4f569be2015-02-27 11:41:49 -0800591 if (!lineDone) {
592 SkPoint devicePts[2];
joshualitt144c3c82015-11-30 12:30:13 -0800593 args.fViewMatrix.mapPoints(devicePts, draw.fPtsRot, 2);
joshualitt4f569be2015-02-27 11:41:49 -0800594 draw.fLineLength = SkPoint::Distance(devicePts[0], devicePts[1]);
595 if (hasCap) {
596 draw.fLineLength += 2.f * halfDevStroke;
597 }
598
joshualitt144c3c82015-11-30 12:30:13 -0800599 bounds.set(draw.fPtsRot[0].fX, draw.fPtsRot[0].fY,
600 draw.fPtsRot[1].fX, draw.fPtsRot[1].fY);
joshualitt4f569be2015-02-27 11:41:49 -0800601 bounds.outset(bloatX + strokeAdj, bloatY + halfSrcStroke);
602 }
603
604 if (hasStartRect) {
605 SkASSERT(useAA); // so that we know bloatX and bloatY have been set
606 startRect.outset(bloatX, bloatY);
607 }
608
609 if (hasEndRect) {
610 SkASSERT(useAA); // so that we know bloatX and bloatY have been set
611 endRect.outset(bloatX, bloatY);
612 }
613
614 draw.fStartOffset = startOffset;
senorblancof3c2c462015-04-20 14:44:26 -0700615 draw.fDevBloatX = devBloatX;
616 draw.fDevBloatY = devBloatY;
joshualitt4f569be2015-02-27 11:41:49 -0800617 draw.fHalfDevStroke = halfDevStroke;
618 draw.fStrokeWidth = strokeWidth;
619 draw.fHasStartRect = hasStartRect;
620 draw.fLineDone = lineDone;
621 draw.fHasEndRect = hasEndRect;
622 }
623
bsalomonb5238a72015-05-05 07:49:49 -0700624 if (!totalRectCount) {
625 return;
626 }
bsalomon8415abe2015-05-04 11:41:41 -0700627
bsalomonb5238a72015-05-05 07:49:49 -0700628 QuadHelper helper;
Brian Salomon92be2f72018-06-19 14:33:47 -0400629 size_t vertexStride;
630 if (fullDash) {
631 vertexStride =
632 SkPaint::kRound_Cap == fCap ? sizeof(DashCircleVertex) : sizeof(DashLineVertex);
633 } else {
634 vertexStride = sizeof(SkPoint);
635 }
636 SkASSERT(vertexStride == gp->debugOnly_vertexStride());
637 void* vertices = helper.init(target, vertexStride, totalRectCount);
bsalomonb5238a72015-05-05 07:49:49 -0700638 if (!vertices) {
joshualitt4b31de82015-03-05 14:33:41 -0800639 return;
640 }
641
joshualitt4f569be2015-02-27 11:41:49 -0800642 int curVIdx = 0;
643 int rectIndex = 0;
644 for (int i = 0; i < instanceCount; i++) {
Brian Salomona6aa5902016-12-16 09:32:00 -0500645 const LineData& geom = fLines[i];
joshualitt4f569be2015-02-27 11:41:49 -0800646
647 if (!draws[i].fLineDone) {
648 if (fullDash) {
Brian Salomon92be2f72018-06-19 14:33:47 -0400649 setup_dashed_rect(
650 rects[rectIndex], vertices, curVIdx, geom.fSrcRotInv,
651 draws[i].fStartOffset, draws[i].fDevBloatX, draws[i].fDevBloatY,
652 draws[i].fLineLength, draws[i].fHalfDevStroke, draws[i].fIntervals[0],
653 draws[i].fIntervals[1], draws[i].fStrokeWidth, capType, vertexStride);
joshualitt4f569be2015-02-27 11:41:49 -0800654 } else {
655 SkPoint* verts = reinterpret_cast<SkPoint*>(vertices);
bsalomonb5238a72015-05-05 07:49:49 -0700656 setup_dashed_rect_pos(rects[rectIndex], curVIdx, geom.fSrcRotInv, verts);
joshualitt4f569be2015-02-27 11:41:49 -0800657 }
658 curVIdx += 4;
659 }
660 rectIndex++;
661
662 if (draws[i].fHasStartRect) {
663 if (fullDash) {
Brian Salomon92be2f72018-06-19 14:33:47 -0400664 setup_dashed_rect(
665 rects[rectIndex], vertices, curVIdx, geom.fSrcRotInv,
666 draws[i].fStartOffset, draws[i].fDevBloatX, draws[i].fDevBloatY,
667 draws[i].fIntervals[0], draws[i].fHalfDevStroke, draws[i].fIntervals[0],
668 draws[i].fIntervals[1], draws[i].fStrokeWidth, capType, vertexStride);
joshualitt4f569be2015-02-27 11:41:49 -0800669 } else {
670 SkPoint* verts = reinterpret_cast<SkPoint*>(vertices);
bsalomonb5238a72015-05-05 07:49:49 -0700671 setup_dashed_rect_pos(rects[rectIndex], curVIdx, geom.fSrcRotInv, verts);
joshualitt4f569be2015-02-27 11:41:49 -0800672 }
joshualitt4f569be2015-02-27 11:41:49 -0800673 curVIdx += 4;
674 }
675 rectIndex++;
676
677 if (draws[i].fHasEndRect) {
678 if (fullDash) {
Brian Salomon92be2f72018-06-19 14:33:47 -0400679 setup_dashed_rect(
680 rects[rectIndex], vertices, curVIdx, geom.fSrcRotInv,
681 draws[i].fStartOffset, draws[i].fDevBloatX, draws[i].fDevBloatY,
682 draws[i].fIntervals[0], draws[i].fHalfDevStroke, draws[i].fIntervals[0],
683 draws[i].fIntervals[1], draws[i].fStrokeWidth, capType, vertexStride);
joshualitt4f569be2015-02-27 11:41:49 -0800684 } else {
685 SkPoint* verts = reinterpret_cast<SkPoint*>(vertices);
bsalomonb5238a72015-05-05 07:49:49 -0700686 setup_dashed_rect_pos(rects[rectIndex], curVIdx, geom.fSrcRotInv, verts);
joshualitt4f569be2015-02-27 11:41:49 -0800687 }
688 curVIdx += 4;
689 }
690 rectIndex++;
691 }
bsalomonb5238a72015-05-05 07:49:49 -0700692 SkASSERT(0 == (curVIdx % 4) && (curVIdx / 4) == totalRectCount);
Brian Salomon98222ac2017-07-12 15:27:54 -0400693 uint32_t pipelineFlags = 0;
694 if (AAMode::kCoverageWithMSAA == fAAMode) {
695 pipelineFlags |= GrPipeline::kHWAntialias_Flag;
696 }
Brian Salomon49348902018-06-26 09:12:38 -0400697 auto pipe = target->makePipeline(pipelineFlags, std::move(fProcessorSet),
698 target->detachAppliedClip());
699 helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
joshualitt4f569be2015-02-27 11:41:49 -0800700 }
701
Brian Salomon25a88092016-12-01 09:36:50 -0500702 bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
Brian Salomona6aa5902016-12-16 09:32:00 -0500703 DashOp* that = t->cast<DashOp>();
Brian Salomon98222ac2017-07-12 15:27:54 -0400704 if (fProcessorSet != that->fProcessorSet) {
705 return false;
706 }
707 if (fDisallowCombineOnTouchOrOverlap &&
708 GrRectsTouchOrOverlap(this->bounds(), that->bounds())) {
joshualitt8cab9a72015-07-16 09:13:50 -0700709 return false;
710 }
711
senorblancof3c2c462015-04-20 14:44:26 -0700712 if (this->aaMode() != that->aaMode()) {
joshualitt4f569be2015-02-27 11:41:49 -0800713 return false;
714 }
715
716 if (this->fullDash() != that->fullDash()) {
717 return false;
718 }
719
720 if (this->cap() != that->cap()) {
721 return false;
722 }
723
724 // TODO vertex color
725 if (this->color() != that->color()) {
726 return false;
727 }
728
Brian Salomon98222ac2017-07-12 15:27:54 -0400729 if (fUsesLocalCoords && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
joshualitt4f569be2015-02-27 11:41:49 -0800730 return false;
731 }
732
Brian Salomona6aa5902016-12-16 09:32:00 -0500733 fLines.push_back_n(that->fLines.count(), that->fLines.begin());
bsalomon88cf17d2016-07-08 06:40:56 -0700734 this->joinBounds(*that);
joshualitt4f569be2015-02-27 11:41:49 -0800735 return true;
736 }
737
Brian Salomona6aa5902016-12-16 09:32:00 -0500738 GrColor color() const { return fColor; }
Brian Salomona6aa5902016-12-16 09:32:00 -0500739 const SkMatrix& viewMatrix() const { return fLines[0].fViewMatrix; }
740 AAMode aaMode() const { return fAAMode; }
741 bool fullDash() const { return fFullDash; }
742 SkPaint::Cap cap() const { return fCap; }
joshualitt4f569be2015-02-27 11:41:49 -0800743
744 static const int kVertsPerDash = 4;
745 static const int kIndicesPerDash = 6;
746
Brian Salomonbeae8a92017-07-12 16:58:54 +0000747 SkSTArray<1, LineData, true> fLines;
Brian Salomon98222ac2017-07-12 15:27:54 -0400748 GrColor fColor;
Brian Salomon98222ac2017-07-12 15:27:54 -0400749 bool fDisallowCombineOnTouchOrOverlap : 1;
750 bool fUsesLocalCoords : 1;
Brian Salomon98222ac2017-07-12 15:27:54 -0400751 bool fFullDash : 1;
Brian Salomon89717fc2017-07-13 11:25:18 -0400752 // We use 3 bits for this 3-value enum because MSVS makes the underlying types signed.
753 SkPaint::Cap fCap : 3;
Brian Salomon98222ac2017-07-12 15:27:54 -0400754 AAMode fAAMode;
755 GrProcessorSet fProcessorSet;
756 const GrUserStencilSettings* fStencilSettings;
reed1b55a962015-09-17 20:16:13 -0700757
Brian Salomon98222ac2017-07-12 15:27:54 -0400758 typedef GrMeshDrawOp INHERITED;
joshualitt4f569be2015-02-27 11:41:49 -0800759};
760
Robert Phillips7c525e62018-06-12 10:11:12 -0400761std::unique_ptr<GrDrawOp> GrDashOp::MakeDashLineOp(GrContext* context,
762 GrPaint&& paint,
Brian Salomon98222ac2017-07-12 15:27:54 -0400763 const SkMatrix& viewMatrix,
764 const SkPoint pts[2],
765 AAMode aaMode,
766 const GrStyle& style,
767 const GrUserStencilSettings* stencilSettings) {
Brian Salomona6aa5902016-12-16 09:32:00 -0500768 SkASSERT(GrDashOp::CanDrawDashLine(pts, style, viewMatrix));
bsalomon6663acf2016-05-10 09:14:17 -0700769 const SkScalar* intervals = style.dashIntervals();
770 SkScalar phase = style.dashPhase();
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000771
bsalomon6663acf2016-05-10 09:14:17 -0700772 SkPaint::Cap cap = style.strokeRec().getCap();
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000773
Brian Salomona6aa5902016-12-16 09:32:00 -0500774 DashOp::LineData lineData;
775 lineData.fSrcStrokeWidth = style.strokeRec().getWidth();
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000776
777 // the phase should be normalized to be [0, sum of all intervals)
kkinnunen261694c2015-05-05 08:00:10 -0700778 SkASSERT(phase >= 0 && phase < intervals[0] + intervals[1]);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000779
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000780 // Rotate the src pts so they are aligned horizontally with pts[0].fX < pts[1].fX
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000781 if (pts[0].fY != pts[1].fY || pts[0].fX > pts[1].fX) {
egdaniele61c4112014-06-12 10:24:21 -0700782 SkMatrix rotMatrix;
Brian Salomona6aa5902016-12-16 09:32:00 -0500783 align_to_x_axis(pts, &rotMatrix, lineData.fPtsRot);
784 if (!rotMatrix.invert(&lineData.fSrcRotInv)) {
tfarina38406c82014-10-31 07:11:12 -0700785 SkDebugf("Failed to create invertible rotation matrix!\n");
halcanary96fcdcc2015-08-27 07:41:13 -0700786 return nullptr;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000787 }
788 } else {
Brian Salomona6aa5902016-12-16 09:32:00 -0500789 lineData.fSrcRotInv.reset();
790 memcpy(lineData.fPtsRot, pts, 2 * sizeof(SkPoint));
joshualitt4f569be2015-02-27 11:41:49 -0800791 }
792
793 // Scale corrections of intervals and stroke from view matrix
Brian Salomona6aa5902016-12-16 09:32:00 -0500794 calc_dash_scaling(&lineData.fParallelScale, &lineData.fPerpendicularScale, viewMatrix,
795 lineData.fPtsRot);
joshualitt4f569be2015-02-27 11:41:49 -0800796
Brian Salomona6aa5902016-12-16 09:32:00 -0500797 SkScalar offInterval = intervals[1] * lineData.fParallelScale;
798 SkScalar strokeWidth = lineData.fSrcStrokeWidth * lineData.fPerpendicularScale;
joshualitt4f569be2015-02-27 11:41:49 -0800799
Brian Salomona6aa5902016-12-16 09:32:00 -0500800 if (SkPaint::kSquare_Cap == cap && 0 != lineData.fSrcStrokeWidth) {
joshualitt4f569be2015-02-27 11:41:49 -0800801 // add cap to on interveal and remove from off interval
802 offInterval -= strokeWidth;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000803 }
804
joshualitt4f569be2015-02-27 11:41:49 -0800805 // TODO we can do a real rect call if not using fulldash(ie no off interval, not using AA)
bsalomonaf18fb42016-06-07 08:10:46 -0700806 bool fullDash = offInterval > 0.f || aaMode != AAMode::kNone;
skia.committer@gmail.com3b9e8be2014-05-20 03:05:34 +0000807
Brian Salomona6aa5902016-12-16 09:32:00 -0500808 lineData.fViewMatrix = viewMatrix;
809 lineData.fPhase = phase;
810 lineData.fIntervals[0] = intervals[0];
811 lineData.fIntervals[1] = intervals[1];
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000812
Robert Phillips7c525e62018-06-12 10:11:12 -0400813 return DashOp::Make(context, std::move(paint), lineData, cap, aaMode, fullDash,
814 stencilSettings);
joshualittfa2008f2015-04-29 11:32:05 -0700815}
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000816
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000817//////////////////////////////////////////////////////////////////////////////
818
egdanielf767e792014-07-02 06:21:32 -0700819class GLDashingCircleEffect;
joshualitt9b989322014-12-15 14:16:27 -0800820
egdanielf767e792014-07-02 06:21:32 -0700821/*
822 * This effect will draw a dotted line (defined as a dashed lined with round caps and no on
823 * interval). The radius of the dots is given by the strokeWidth and the spacing by the DashInfo.
824 * Both of the previous two parameters are in device space. This effect also requires the setting of
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400825 * a float2 vertex attribute for the the four corners of the bounding rect. This attribute is the
egdanielf767e792014-07-02 06:21:32 -0700826 * "dash position" of each vertex. In other words it is the vertex coords (in device space) if we
827 * transform the line to be horizontal, with the start of line at the origin then shifted to the
828 * right by half the off interval. The line then goes in the positive x direction.
829 */
joshualitt249af152014-09-15 11:41:13 -0700830class DashingCircleEffect : public GrGeometryProcessor {
egdanielf767e792014-07-02 06:21:32 -0700831public:
832 typedef SkPathEffect::DashInfo DashInfo;
833
bungeman06ca8ec2016-06-09 08:01:03 -0700834 static sk_sp<GrGeometryProcessor> Make(GrColor,
835 AAMode aaMode,
836 const SkMatrix& localMatrix,
837 bool usesLocalCoords);
egdanielf767e792014-07-02 06:21:32 -0700838
mtklein36352bf2015-03-25 18:17:31 -0700839 const char* name() const override { return "DashingCircleEffect"; }
egdanielf767e792014-07-02 06:21:32 -0700840
bsalomonaf18fb42016-06-07 08:10:46 -0700841 AAMode aaMode() const { return fAAMode; }
egdanielf767e792014-07-02 06:21:32 -0700842
joshualitt88c23fc2015-05-13 14:18:07 -0700843 GrColor color() const { return fColor; }
844
joshualitte3ababe2015-05-15 07:56:07 -0700845 const SkMatrix& localMatrix() const { return fLocalMatrix; }
846
joshualittb8c241a2015-05-19 08:23:30 -0700847 bool usesLocalCoords() const { return fUsesLocalCoords; }
848
Brian Salomon94efbf52016-11-29 13:43:05 -0500849 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override;
egdanielf767e792014-07-02 06:21:32 -0700850
Brian Salomon94efbf52016-11-29 13:43:05 -0500851 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
egdanielf767e792014-07-02 06:21:32 -0700852
853private:
bsalomonaf18fb42016-06-07 08:10:46 -0700854 DashingCircleEffect(GrColor, AAMode aaMode, const SkMatrix& localMatrix,
joshualittb8c241a2015-05-19 08:23:30 -0700855 bool usesLocalCoords);
egdanielf767e792014-07-02 06:21:32 -0700856
Brian Salomon92be2f72018-06-19 14:33:47 -0400857 const Attribute& onVertexAttribute(int i) const override {
858 return IthAttribute(i, kInPosition, kInDashParams, kInCircleParams);
859 }
860
joshualitt88c23fc2015-05-13 14:18:07 -0700861 GrColor fColor;
joshualitte3ababe2015-05-15 07:56:07 -0700862 SkMatrix fLocalMatrix;
joshualittb8c241a2015-05-19 08:23:30 -0700863 bool fUsesLocalCoords;
bsalomonaf18fb42016-06-07 08:10:46 -0700864 AAMode fAAMode;
Brian Salomon92be2f72018-06-19 14:33:47 -0400865
866 static constexpr Attribute kInPosition = {"inPosition", kFloat2_GrVertexAttribType};
867 static constexpr Attribute kInDashParams = {"inDashParams", kHalf3_GrVertexAttribType};
868 static constexpr Attribute kInCircleParams = {"inCircleParams", kHalf2_GrVertexAttribType};
egdanielf767e792014-07-02 06:21:32 -0700869
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400870 GR_DECLARE_GEOMETRY_PROCESSOR_TEST
egdanielf767e792014-07-02 06:21:32 -0700871
Brian Salomon92be2f72018-06-19 14:33:47 -0400872 friend class GLDashingCircleEffect;
joshualitt249af152014-09-15 11:41:13 -0700873 typedef GrGeometryProcessor INHERITED;
egdanielf767e792014-07-02 06:21:32 -0700874};
Brian Salomon92be2f72018-06-19 14:33:47 -0400875constexpr GrPrimitiveProcessor::Attribute DashingCircleEffect::kInPosition;
876constexpr GrPrimitiveProcessor::Attribute DashingCircleEffect::kInDashParams;
877constexpr GrPrimitiveProcessor::Attribute DashingCircleEffect::kInCircleParams;
egdanielf767e792014-07-02 06:21:32 -0700878
879//////////////////////////////////////////////////////////////////////////////
880
egdaniele659a582015-11-13 09:55:43 -0800881class GLDashingCircleEffect : public GrGLSLGeometryProcessor {
egdanielf767e792014-07-02 06:21:32 -0700882public:
joshualitt465283c2015-09-11 08:19:35 -0700883 GLDashingCircleEffect();
egdanielf767e792014-07-02 06:21:32 -0700884
mtklein36352bf2015-03-25 18:17:31 -0700885 void onEmitCode(EmitArgs&, GrGPArgs*) override;
egdanielf767e792014-07-02 06:21:32 -0700886
joshualitt87f48d92014-12-04 10:41:40 -0800887 static inline void GenKey(const GrGeometryProcessor&,
Brian Salomon94efbf52016-11-29 13:43:05 -0500888 const GrShaderCaps&,
joshualitt87f48d92014-12-04 10:41:40 -0800889 GrProcessorKeyBuilder*);
egdanielf767e792014-07-02 06:21:32 -0700890
bsalomona624bf32016-09-20 09:12:47 -0700891 void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&,
892 FPCoordTransformIter&& transformIter) override;
egdanielf767e792014-07-02 06:21:32 -0700893private:
joshualitt9b989322014-12-15 14:16:27 -0800894 UniformHandle fParamUniform;
895 UniformHandle fColorUniform;
896 GrColor fColor;
897 SkScalar fPrevRadius;
898 SkScalar fPrevCenterX;
899 SkScalar fPrevIntervalLength;
egdaniele659a582015-11-13 09:55:43 -0800900 typedef GrGLSLGeometryProcessor INHERITED;
egdanielf767e792014-07-02 06:21:32 -0700901};
902
joshualitt465283c2015-09-11 08:19:35 -0700903GLDashingCircleEffect::GLDashingCircleEffect() {
joshualitt9b989322014-12-15 14:16:27 -0800904 fColor = GrColor_ILLEGAL;
egdanielf767e792014-07-02 06:21:32 -0700905 fPrevRadius = SK_ScalarMin;
906 fPrevCenterX = SK_ScalarMin;
907 fPrevIntervalLength = SK_ScalarMax;
908}
909
robertphillips46d36f02015-01-18 08:14:14 -0800910void GLDashingCircleEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
joshualittc369e7c2014-10-22 10:56:26 -0700911 const DashingCircleEffect& dce = args.fGP.cast<DashingCircleEffect>();
egdaniel4ca2e602015-11-18 08:01:26 -0800912 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
egdaniel0eafe792015-11-20 14:01:22 -0800913 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
egdaniel7ea439b2015-12-03 09:20:44 -0800914 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
joshualitt2dd1ae02014-12-03 06:24:10 -0800915
joshualittabb52a12015-01-13 15:02:10 -0800916 // emit attributes
egdaniel0eafe792015-11-20 14:01:22 -0800917 varyingHandler->emitAttributes(dce);
joshualittabb52a12015-01-13 15:02:10 -0800918
joshualitt5224ba72015-02-03 15:07:51 -0800919 // XY are dashPos, Z is dashInterval
Chris Dalton27372882017-12-08 13:34:21 -0700920 GrGLSLVarying dashParams(kHalf3_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800921 varyingHandler->addVarying("DashParam", &dashParams);
Brian Salomon92be2f72018-06-19 14:33:47 -0400922 vertBuilder->codeAppendf("%s = %s;", dashParams.vsOut(), dce.kInDashParams.name());
joshualitt5224ba72015-02-03 15:07:51 -0800923
senorblancof3c2c462015-04-20 14:44:26 -0700924 // x refers to circle radius - 0.5, y refers to cicle's center x coord
Chris Dalton27372882017-12-08 13:34:21 -0700925 GrGLSLVarying circleParams(kHalf2_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800926 varyingHandler->addVarying("CircleParams", &circleParams);
Brian Salomon92be2f72018-06-19 14:33:47 -0400927 vertBuilder->codeAppendf("%s = %s;", circleParams.vsOut(), dce.kInCircleParams.name());
joshualitt30ba4362014-08-21 20:18:45 -0700928
Chris Dalton60283612018-02-14 13:38:14 -0700929 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
joshualitt9b989322014-12-15 14:16:27 -0800930 // Setup pass through color
Brian Salomonbfd51832017-01-04 13:22:08 -0500931 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform);
joshualitt9b989322014-12-15 14:16:27 -0800932
joshualittabb52a12015-01-13 15:02:10 -0800933 // Setup position
Brian Salomon92be2f72018-06-19 14:33:47 -0400934 this->writeOutputPosition(vertBuilder, gpArgs, dce.kInPosition.name());
joshualitt4973d9d2014-11-08 09:24:25 -0800935
joshualittabb52a12015-01-13 15:02:10 -0800936 // emit transforms
egdaniel7ea439b2015-12-03 09:20:44 -0800937 this->emitTransforms(vertBuilder,
egdaniel0eafe792015-11-20 14:01:22 -0800938 varyingHandler,
egdaniel7ea439b2015-12-03 09:20:44 -0800939 uniformHandler,
Brian Salomon92be2f72018-06-19 14:33:47 -0400940 dce.kInPosition.asShaderVar(),
egdaniel4ca2e602015-11-18 08:01:26 -0800941 dce.localMatrix(),
bsalomona624bf32016-09-20 09:12:47 -0700942 args.fFPCoordTransformHandler);
joshualittabb52a12015-01-13 15:02:10 -0800943
egdanielf767e792014-07-02 06:21:32 -0700944 // transforms all points so that we can compare them to our test circle
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400945 fragBuilder->codeAppendf("half xShifted = %s.x - floor(%s.x / %s.z) * %s.z;",
egdaniel4ca2e602015-11-18 08:01:26 -0800946 dashParams.fsIn(), dashParams.fsIn(), dashParams.fsIn(),
947 dashParams.fsIn());
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400948 fragBuilder->codeAppendf("half2 fragPosShifted = half2(xShifted, %s.y);", dashParams.fsIn());
949 fragBuilder->codeAppendf("half2 center = half2(%s.y, 0.0);", circleParams.fsIn());
950 fragBuilder->codeAppend("half dist = length(center - fragPosShifted);");
bsalomonaf18fb42016-06-07 08:10:46 -0700951 if (dce.aaMode() != AAMode::kNone) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400952 fragBuilder->codeAppendf("half diff = dist - %s.x;", circleParams.fsIn());
egdaniel4ca2e602015-11-18 08:01:26 -0800953 fragBuilder->codeAppend("diff = 1.0 - diff;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400954 fragBuilder->codeAppend("half alpha = clamp(diff, 0.0, 1.0);");
egdanielf767e792014-07-02 06:21:32 -0700955 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400956 fragBuilder->codeAppendf("half alpha = 1.0;");
egdaniel4ca2e602015-11-18 08:01:26 -0800957 fragBuilder->codeAppendf("alpha *= dist < %s.x + 0.5 ? 1.0 : 0.0;", circleParams.fsIn());
egdanielf767e792014-07-02 06:21:32 -0700958 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400959 fragBuilder->codeAppendf("%s = half4(alpha);", args.fOutputCoverage);
egdanielf767e792014-07-02 06:21:32 -0700960}
961
egdaniel018fb622015-10-28 07:26:40 -0700962void GLDashingCircleEffect::setData(const GrGLSLProgramDataManager& pdman,
bsalomona624bf32016-09-20 09:12:47 -0700963 const GrPrimitiveProcessor& processor,
964 FPCoordTransformIter&& transformIter) {
joshualittb8c241a2015-05-19 08:23:30 -0700965 const DashingCircleEffect& dce = processor.cast<DashingCircleEffect>();
966 if (dce.color() != fColor) {
egdaniel018fb622015-10-28 07:26:40 -0700967 float c[4];
joshualittb8c241a2015-05-19 08:23:30 -0700968 GrColorToRGBAFloat(dce.color(), c);
joshualitt9b989322014-12-15 14:16:27 -0800969 pdman.set4fv(fColorUniform, 1, c);
joshualittb8c241a2015-05-19 08:23:30 -0700970 fColor = dce.color();
joshualitt9b989322014-12-15 14:16:27 -0800971 }
bsalomona624bf32016-09-20 09:12:47 -0700972 this->setTransformDataHelper(dce.localMatrix(), pdman, &transformIter);
egdanielf767e792014-07-02 06:21:32 -0700973}
974
robertphillips46d36f02015-01-18 08:14:14 -0800975void GLDashingCircleEffect::GenKey(const GrGeometryProcessor& gp,
Brian Salomon94efbf52016-11-29 13:43:05 -0500976 const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700977 GrProcessorKeyBuilder* b) {
robertphillips46d36f02015-01-18 08:14:14 -0800978 const DashingCircleEffect& dce = gp.cast<DashingCircleEffect>();
979 uint32_t key = 0;
joshualittb8c241a2015-05-19 08:23:30 -0700980 key |= dce.usesLocalCoords() && dce.localMatrix().hasPerspective() ? 0x1 : 0x0;
Brian Salomonbfd51832017-01-04 13:22:08 -0500981 key |= static_cast<uint32_t>(dce.aaMode()) << 1;
joshualittb8c241a2015-05-19 08:23:30 -0700982 b->add32(key);
egdanielf767e792014-07-02 06:21:32 -0700983}
984
985//////////////////////////////////////////////////////////////////////////////
986
bungeman06ca8ec2016-06-09 08:01:03 -0700987sk_sp<GrGeometryProcessor> DashingCircleEffect::Make(GrColor color,
988 AAMode aaMode,
989 const SkMatrix& localMatrix,
990 bool usesLocalCoords) {
991 return sk_sp<GrGeometryProcessor>(
992 new DashingCircleEffect(color, aaMode, localMatrix, usesLocalCoords));
egdanielf767e792014-07-02 06:21:32 -0700993}
994
Brian Salomon94efbf52016-11-29 13:43:05 -0500995void DashingCircleEffect::getGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800996 GrProcessorKeyBuilder* b) const {
joshualitt465283c2015-09-11 08:19:35 -0700997 GLDashingCircleEffect::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800998}
999
Brian Salomon94efbf52016-11-29 13:43:05 -05001000GrGLSLPrimitiveProcessor* DashingCircleEffect::createGLSLInstance(const GrShaderCaps&) const {
joshualitt465283c2015-09-11 08:19:35 -07001001 return new GLDashingCircleEffect();
egdanielf767e792014-07-02 06:21:32 -07001002}
1003
joshualitt2e3b3e32014-12-09 13:31:14 -08001004DashingCircleEffect::DashingCircleEffect(GrColor color,
bsalomonaf18fb42016-06-07 08:10:46 -07001005 AAMode aaMode,
joshualittb8c241a2015-05-19 08:23:30 -07001006 const SkMatrix& localMatrix,
1007 bool usesLocalCoords)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001008 : INHERITED(kDashingCircleEffect_ClassID)
1009 , fColor(color)
joshualitte3ababe2015-05-15 07:56:07 -07001010 , fLocalMatrix(localMatrix)
joshualittb8c241a2015-05-19 08:23:30 -07001011 , fUsesLocalCoords(usesLocalCoords)
joshualitt88c23fc2015-05-13 14:18:07 -07001012 , fAAMode(aaMode) {
Brian Salomon92be2f72018-06-19 14:33:47 -04001013 this->setVertexAttributeCnt(3);
egdanielf767e792014-07-02 06:21:32 -07001014}
1015
joshualittb0a8a372014-09-23 09:50:21 -07001016GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingCircleEffect);
egdanielf767e792014-07-02 06:21:32 -07001017
Hal Canary6f6961e2017-01-31 13:50:44 -05001018#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -07001019sk_sp<GrGeometryProcessor> DashingCircleEffect::TestCreate(GrProcessorTestData* d) {
Brian Salomona6aa5902016-12-16 09:32:00 -05001020 AAMode aaMode = static_cast<AAMode>(d->fRandom->nextULessThan(GrDashOp::kAAModeCnt));
bungeman06ca8ec2016-06-09 08:01:03 -07001021 return DashingCircleEffect::Make(GrRandomColor(d->fRandom),
1022 aaMode, GrTest::TestMatrix(d->fRandom),
1023 d->fRandom->nextBool());
egdanielf767e792014-07-02 06:21:32 -07001024}
Hal Canary6f6961e2017-01-31 13:50:44 -05001025#endif
egdanielf767e792014-07-02 06:21:32 -07001026
1027//////////////////////////////////////////////////////////////////////////////
1028
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001029class GLDashingLineEffect;
1030
egdanielf767e792014-07-02 06:21:32 -07001031/*
1032 * This effect will draw a dashed line. The width of the dash is given by the strokeWidth and the
1033 * length and spacing by the DashInfo. Both of the previous two parameters are in device space.
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001034 * This effect also requires the setting of a float2 vertex attribute for the the four corners of the
egdanielf767e792014-07-02 06:21:32 -07001035 * bounding rect. This attribute is the "dash position" of each vertex. In other words it is the
1036 * vertex coords (in device space) if we transform the line to be horizontal, with the start of
1037 * line at the origin then shifted to the right by half the off interval. The line then goes in the
1038 * positive x direction.
1039 */
joshualitt249af152014-09-15 11:41:13 -07001040class DashingLineEffect : public GrGeometryProcessor {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001041public:
1042 typedef SkPathEffect::DashInfo DashInfo;
1043
bungeman06ca8ec2016-06-09 08:01:03 -07001044 static sk_sp<GrGeometryProcessor> Make(GrColor,
1045 AAMode aaMode,
1046 const SkMatrix& localMatrix,
1047 bool usesLocalCoords);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001048
mtklein36352bf2015-03-25 18:17:31 -07001049 const char* name() const override { return "DashingEffect"; }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001050
bsalomonaf18fb42016-06-07 08:10:46 -07001051 AAMode aaMode() const { return fAAMode; }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001052
joshualitt88c23fc2015-05-13 14:18:07 -07001053 GrColor color() const { return fColor; }
1054
Brian Salomonbfd51832017-01-04 13:22:08 -05001055 const SkMatrix& localMatrix() const { return fLocalMatrix; }
joshualitte3ababe2015-05-15 07:56:07 -07001056
joshualittb8c241a2015-05-19 08:23:30 -07001057 bool usesLocalCoords() const { return fUsesLocalCoords; }
1058
Brian Salomon94efbf52016-11-29 13:43:05 -05001059 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001060
Brian Salomon94efbf52016-11-29 13:43:05 -05001061 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001062
1063private:
bsalomonaf18fb42016-06-07 08:10:46 -07001064 DashingLineEffect(GrColor, AAMode aaMode, const SkMatrix& localMatrix,
joshualittb8c241a2015-05-19 08:23:30 -07001065 bool usesLocalCoords);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001066
Brian Salomon92be2f72018-06-19 14:33:47 -04001067 const Attribute& onVertexAttribute(int i) const override {
1068 return IthAttribute(i, kInPosition, kInDashParams, kInRectParams);
1069 }
1070
joshualitt88c23fc2015-05-13 14:18:07 -07001071 GrColor fColor;
joshualitte3ababe2015-05-15 07:56:07 -07001072 SkMatrix fLocalMatrix;
joshualittb8c241a2015-05-19 08:23:30 -07001073 bool fUsesLocalCoords;
bsalomonaf18fb42016-06-07 08:10:46 -07001074 AAMode fAAMode;
Brian Salomon92be2f72018-06-19 14:33:47 -04001075
1076 static constexpr Attribute kInPosition = {"inPosition", kFloat2_GrVertexAttribType};
1077 static constexpr Attribute kInDashParams = {"inDashParams", kHalf3_GrVertexAttribType};
1078 static constexpr Attribute kInRectParams = {"inRect", kHalf4_GrVertexAttribType};
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001079
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001080 GR_DECLARE_GEOMETRY_PROCESSOR_TEST
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001081
Brian Salomon92be2f72018-06-19 14:33:47 -04001082 friend class GLDashingLineEffect;
1083
joshualitt249af152014-09-15 11:41:13 -07001084 typedef GrGeometryProcessor INHERITED;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001085};
Brian Salomon92be2f72018-06-19 14:33:47 -04001086constexpr GrPrimitiveProcessor::Attribute DashingLineEffect::kInPosition;
1087constexpr GrPrimitiveProcessor::Attribute DashingLineEffect::kInDashParams;
1088constexpr GrPrimitiveProcessor::Attribute DashingLineEffect::kInRectParams;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001089
1090//////////////////////////////////////////////////////////////////////////////
1091
egdaniele659a582015-11-13 09:55:43 -08001092class GLDashingLineEffect : public GrGLSLGeometryProcessor {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001093public:
joshualitt465283c2015-09-11 08:19:35 -07001094 GLDashingLineEffect();
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001095
mtklein36352bf2015-03-25 18:17:31 -07001096 void onEmitCode(EmitArgs&, GrGPArgs*) override;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001097
joshualitt87f48d92014-12-04 10:41:40 -08001098 static inline void GenKey(const GrGeometryProcessor&,
Brian Salomon94efbf52016-11-29 13:43:05 -05001099 const GrShaderCaps&,
joshualitt87f48d92014-12-04 10:41:40 -08001100 GrProcessorKeyBuilder*);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001101
bsalomona624bf32016-09-20 09:12:47 -07001102 void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&,
1103 FPCoordTransformIter&& iter) override;
joshualitte3ababe2015-05-15 07:56:07 -07001104
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001105private:
joshualitt9b989322014-12-15 14:16:27 -08001106 GrColor fColor;
joshualitt9b989322014-12-15 14:16:27 -08001107 UniformHandle fColorUniform;
egdaniele659a582015-11-13 09:55:43 -08001108 typedef GrGLSLGeometryProcessor INHERITED;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001109};
1110
Brian Salomonbfd51832017-01-04 13:22:08 -05001111GLDashingLineEffect::GLDashingLineEffect() : fColor(GrColor_ILLEGAL) {}
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001112
robertphillips46d36f02015-01-18 08:14:14 -08001113void GLDashingLineEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
joshualittc369e7c2014-10-22 10:56:26 -07001114 const DashingLineEffect& de = args.fGP.cast<DashingLineEffect>();
joshualitt2dd1ae02014-12-03 06:24:10 -08001115
egdaniel4ca2e602015-11-18 08:01:26 -08001116 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
egdaniel0eafe792015-11-20 14:01:22 -08001117 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
egdaniel7ea439b2015-12-03 09:20:44 -08001118 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
joshualitt2dd1ae02014-12-03 06:24:10 -08001119
joshualittabb52a12015-01-13 15:02:10 -08001120 // emit attributes
egdaniel0eafe792015-11-20 14:01:22 -08001121 varyingHandler->emitAttributes(de);
joshualittabb52a12015-01-13 15:02:10 -08001122
joshualitt5224ba72015-02-03 15:07:51 -08001123 // XY refers to dashPos, Z is the dash interval length
Chris Dalton27372882017-12-08 13:34:21 -07001124 GrGLSLVarying inDashParams(kFloat3_GrSLType);
Chris Daltonfdde34e2017-10-16 14:15:26 -06001125 varyingHandler->addVarying("DashParams", &inDashParams);
Brian Salomon92be2f72018-06-19 14:33:47 -04001126 vertBuilder->codeAppendf("%s = %s;", inDashParams.vsOut(), de.kInDashParams.name());
joshualitt5224ba72015-02-03 15:07:51 -08001127
1128 // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5),
1129 // respectively.
Chris Dalton27372882017-12-08 13:34:21 -07001130 GrGLSLVarying inRectParams(kFloat4_GrSLType);
Chris Daltonfdde34e2017-10-16 14:15:26 -06001131 varyingHandler->addVarying("RectParams", &inRectParams);
Brian Salomon92be2f72018-06-19 14:33:47 -04001132 vertBuilder->codeAppendf("%s = %s;", inRectParams.vsOut(), de.kInRectParams.name());
joshualitt2dd1ae02014-12-03 06:24:10 -08001133
Chris Dalton60283612018-02-14 13:38:14 -07001134 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
joshualitt9b989322014-12-15 14:16:27 -08001135 // Setup pass through color
Brian Salomonbfd51832017-01-04 13:22:08 -05001136 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform);
joshualittb8c241a2015-05-19 08:23:30 -07001137
joshualittabb52a12015-01-13 15:02:10 -08001138 // Setup position
Brian Salomon92be2f72018-06-19 14:33:47 -04001139 this->writeOutputPosition(vertBuilder, gpArgs, de.kInPosition.name());
joshualitt4973d9d2014-11-08 09:24:25 -08001140
joshualittabb52a12015-01-13 15:02:10 -08001141 // emit transforms
egdaniel7ea439b2015-12-03 09:20:44 -08001142 this->emitTransforms(vertBuilder,
egdaniel0eafe792015-11-20 14:01:22 -08001143 varyingHandler,
egdaniel7ea439b2015-12-03 09:20:44 -08001144 uniformHandler,
Brian Salomon92be2f72018-06-19 14:33:47 -04001145 de.kInPosition.asShaderVar(),
egdaniel4ca2e602015-11-18 08:01:26 -08001146 de.localMatrix(),
bsalomona624bf32016-09-20 09:12:47 -07001147 args.fFPCoordTransformHandler);
joshualittabb52a12015-01-13 15:02:10 -08001148
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001149 // transforms all points so that we can compare them to our test rect
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001150 fragBuilder->codeAppendf("half xShifted = %s.x - floor(%s.x / %s.z) * %s.z;",
egdaniel4ca2e602015-11-18 08:01:26 -08001151 inDashParams.fsIn(), inDashParams.fsIn(), inDashParams.fsIn(),
1152 inDashParams.fsIn());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001153 fragBuilder->codeAppendf("half2 fragPosShifted = half2(xShifted, %s.y);", inDashParams.fsIn());
bsalomonaf18fb42016-06-07 08:10:46 -07001154 if (de.aaMode() == AAMode::kCoverage) {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001155 // The amount of coverage removed in x and y by the edges is computed as a pair of negative
1156 // numbers, xSub and ySub.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001157 fragBuilder->codeAppend("half xSub, ySub;");
egdaniel4ca2e602015-11-18 08:01:26 -08001158 fragBuilder->codeAppendf("xSub = min(fragPosShifted.x - %s.x, 0.0);", inRectParams.fsIn());
1159 fragBuilder->codeAppendf("xSub += min(%s.z - fragPosShifted.x, 0.0);", inRectParams.fsIn());
1160 fragBuilder->codeAppendf("ySub = min(fragPosShifted.y - %s.y, 0.0);", inRectParams.fsIn());
1161 fragBuilder->codeAppendf("ySub += min(%s.w - fragPosShifted.y, 0.0);", inRectParams.fsIn());
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001162 // Now compute coverage in x and y and multiply them to get the fraction of the pixel
1163 // covered.
egdaniel4ca2e602015-11-18 08:01:26 -08001164 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001165 "half alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));");
bsalomonaf18fb42016-06-07 08:10:46 -07001166 } else if (de.aaMode() == AAMode::kCoverageWithMSAA) {
senorblancof3c2c462015-04-20 14:44:26 -07001167 // For MSAA, we don't modulate the alpha by the Y distance, since MSAA coverage will handle
1168 // AA on the the top and bottom edges. The shader is only responsible for intra-dash alpha.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001169 fragBuilder->codeAppend("half xSub;");
egdaniel4ca2e602015-11-18 08:01:26 -08001170 fragBuilder->codeAppendf("xSub = min(fragPosShifted.x - %s.x, 0.0);", inRectParams.fsIn());
1171 fragBuilder->codeAppendf("xSub += min(%s.z - fragPosShifted.x, 0.0);", inRectParams.fsIn());
senorblancof3c2c462015-04-20 14:44:26 -07001172 // Now compute coverage in x to get the fraction of the pixel covered.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001173 fragBuilder->codeAppendf("half alpha = (1.0 + max(xSub, -1.0));");
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001174 } else {
1175 // Assuming the bounding geometry is tight so no need to check y values
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001176 fragBuilder->codeAppendf("half alpha = 1.0;");
egdaniel4ca2e602015-11-18 08:01:26 -08001177 fragBuilder->codeAppendf("alpha *= (fragPosShifted.x - %s.x) > -0.5 ? 1.0 : 0.0;",
1178 inRectParams.fsIn());
1179 fragBuilder->codeAppendf("alpha *= (%s.z - fragPosShifted.x) >= -0.5 ? 1.0 : 0.0;",
1180 inRectParams.fsIn());
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001181 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001182 fragBuilder->codeAppendf("%s = half4(alpha);", args.fOutputCoverage);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001183}
1184
egdaniel018fb622015-10-28 07:26:40 -07001185void GLDashingLineEffect::setData(const GrGLSLProgramDataManager& pdman,
bsalomona624bf32016-09-20 09:12:47 -07001186 const GrPrimitiveProcessor& processor,
1187 FPCoordTransformIter&& transformIter) {
joshualittb8c241a2015-05-19 08:23:30 -07001188 const DashingLineEffect& de = processor.cast<DashingLineEffect>();
1189 if (de.color() != fColor) {
egdaniel018fb622015-10-28 07:26:40 -07001190 float c[4];
joshualittb8c241a2015-05-19 08:23:30 -07001191 GrColorToRGBAFloat(de.color(), c);
joshualitt9b989322014-12-15 14:16:27 -08001192 pdman.set4fv(fColorUniform, 1, c);
joshualittb8c241a2015-05-19 08:23:30 -07001193 fColor = de.color();
joshualitt9b989322014-12-15 14:16:27 -08001194 }
bsalomona624bf32016-09-20 09:12:47 -07001195 this->setTransformDataHelper(de.localMatrix(), pdman, &transformIter);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001196}
1197
robertphillips46d36f02015-01-18 08:14:14 -08001198void GLDashingLineEffect::GenKey(const GrGeometryProcessor& gp,
Brian Salomon94efbf52016-11-29 13:43:05 -05001199 const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001200 GrProcessorKeyBuilder* b) {
robertphillips46d36f02015-01-18 08:14:14 -08001201 const DashingLineEffect& de = gp.cast<DashingLineEffect>();
1202 uint32_t key = 0;
joshualittb8c241a2015-05-19 08:23:30 -07001203 key |= de.usesLocalCoords() && de.localMatrix().hasPerspective() ? 0x1 : 0x0;
bsalomonaf18fb42016-06-07 08:10:46 -07001204 key |= static_cast<int>(de.aaMode()) << 8;
joshualittb8c241a2015-05-19 08:23:30 -07001205 b->add32(key);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001206}
1207
1208//////////////////////////////////////////////////////////////////////////////
skia.committer@gmail.com3b9e8be2014-05-20 03:05:34 +00001209
bungeman06ca8ec2016-06-09 08:01:03 -07001210sk_sp<GrGeometryProcessor> DashingLineEffect::Make(GrColor color,
1211 AAMode aaMode,
1212 const SkMatrix& localMatrix,
1213 bool usesLocalCoords) {
1214 return sk_sp<GrGeometryProcessor>(
1215 new DashingLineEffect(color, aaMode, localMatrix, usesLocalCoords));
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001216}
1217
Brian Salomon94efbf52016-11-29 13:43:05 -05001218void DashingLineEffect::getGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -08001219 GrProcessorKeyBuilder* b) const {
joshualitt465283c2015-09-11 08:19:35 -07001220 GLDashingLineEffect::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -08001221}
1222
Brian Salomon94efbf52016-11-29 13:43:05 -05001223GrGLSLPrimitiveProcessor* DashingLineEffect::createGLSLInstance(const GrShaderCaps&) const {
joshualitt465283c2015-09-11 08:19:35 -07001224 return new GLDashingLineEffect();
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001225}
1226
joshualitt2e3b3e32014-12-09 13:31:14 -08001227DashingLineEffect::DashingLineEffect(GrColor color,
bsalomonaf18fb42016-06-07 08:10:46 -07001228 AAMode aaMode,
joshualittb8c241a2015-05-19 08:23:30 -07001229 const SkMatrix& localMatrix,
1230 bool usesLocalCoords)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001231 : INHERITED(kDashingLineEffect_ClassID)
1232 , fColor(color)
joshualitte3ababe2015-05-15 07:56:07 -07001233 , fLocalMatrix(localMatrix)
joshualittb8c241a2015-05-19 08:23:30 -07001234 , fUsesLocalCoords(usesLocalCoords)
joshualitt88c23fc2015-05-13 14:18:07 -07001235 , fAAMode(aaMode) {
Brian Salomon92be2f72018-06-19 14:33:47 -04001236 this->setVertexAttributeCnt(3);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001237}
1238
joshualittb0a8a372014-09-23 09:50:21 -07001239GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingLineEffect);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001240
Hal Canary6f6961e2017-01-31 13:50:44 -05001241#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -07001242sk_sp<GrGeometryProcessor> DashingLineEffect::TestCreate(GrProcessorTestData* d) {
Brian Salomona6aa5902016-12-16 09:32:00 -05001243 AAMode aaMode = static_cast<AAMode>(d->fRandom->nextULessThan(GrDashOp::kAAModeCnt));
bungeman06ca8ec2016-06-09 08:01:03 -07001244 return DashingLineEffect::Make(GrRandomColor(d->fRandom),
1245 aaMode, GrTest::TestMatrix(d->fRandom),
1246 d->fRandom->nextBool());
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001247}
Mike Klein5045e502018-06-19 01:40:57 +00001248
Brian Salomon92be2f72018-06-19 14:33:47 -04001249#endif
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001250//////////////////////////////////////////////////////////////////////////////
1251
bungeman06ca8ec2016-06-09 08:01:03 -07001252static sk_sp<GrGeometryProcessor> make_dash_gp(GrColor color,
1253 AAMode aaMode,
1254 DashCap cap,
1255 const SkMatrix& viewMatrix,
1256 bool usesLocalCoords) {
joshualittdf0c5572015-08-03 11:35:28 -07001257 SkMatrix invert;
1258 if (usesLocalCoords && !viewMatrix.invert(&invert)) {
1259 SkDebugf("Failed to invert\n");
halcanary96fcdcc2015-08-27 07:41:13 -07001260 return nullptr;
joshualittdf0c5572015-08-03 11:35:28 -07001261 }
1262
egdanielf767e792014-07-02 06:21:32 -07001263 switch (cap) {
joshualitt5224ba72015-02-03 15:07:51 -08001264 case kRound_DashCap:
bungeman06ca8ec2016-06-09 08:01:03 -07001265 return DashingCircleEffect::Make(color, aaMode, invert, usesLocalCoords);
joshualitt5224ba72015-02-03 15:07:51 -08001266 case kNonRound_DashCap:
bungeman06ca8ec2016-06-09 08:01:03 -07001267 return DashingLineEffect::Make(color, aaMode, invert, usesLocalCoords);
egdanielf767e792014-07-02 06:21:32 -07001268 }
halcanary96fcdcc2015-08-27 07:41:13 -07001269 return nullptr;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +00001270}
joshualittfa2008f2015-04-29 11:32:05 -07001271
1272/////////////////////////////////////////////////////////////////////////////////////////////////
1273
Hal Canary6f6961e2017-01-31 13:50:44 -05001274#if GR_TEST_UTILS
joshualittfa2008f2015-04-29 11:32:05 -07001275
Brian Salomon98222ac2017-07-12 15:27:54 -04001276GR_DRAW_OP_TEST_DEFINE(DashOp) {
joshualittfa2008f2015-04-29 11:32:05 -07001277 SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random);
Brian Salomon98222ac2017-07-12 15:27:54 -04001278 AAMode aaMode;
1279 do {
1280 aaMode = static_cast<AAMode>(random->nextULessThan(GrDashOp::kAAModeCnt));
1281 } while (AAMode::kCoverageWithMSAA == aaMode && GrFSAAType::kUnifiedMSAA != fsaaType);
joshualittfa2008f2015-04-29 11:32:05 -07001282
1283 // We can only dash either horizontal or vertical lines
1284 SkPoint pts[2];
1285 if (random->nextBool()) {
1286 // vertical
1287 pts[0].fX = 1.f;
1288 pts[0].fY = random->nextF() * 10.f;
1289 pts[1].fX = 1.f;
1290 pts[1].fY = random->nextF() * 10.f;
1291 } else {
1292 // horizontal
1293 pts[0].fX = random->nextF() * 10.f;
1294 pts[0].fY = 1.f;
1295 pts[1].fX = random->nextF() * 10.f;
1296 pts[1].fY = 1.f;
1297 }
1298
1299 // pick random cap
bsalomona7d85ba2016-07-06 11:54:59 -07001300 SkPaint::Cap cap = SkPaint::Cap(random->nextULessThan(SkPaint::kCapCount));
joshualittfa2008f2015-04-29 11:32:05 -07001301
1302 SkScalar intervals[2];
1303
1304 // We can only dash with the following intervals
1305 enum Intervals {
1306 kOpenOpen_Intervals ,
1307 kOpenClose_Intervals,
1308 kCloseOpen_Intervals,
1309 };
1310
Greg Daniel5d00f002017-06-29 13:44:51 -04001311 Intervals intervalType = SkPaint::kRound_Cap == cap ?
joshualittfa2008f2015-04-29 11:32:05 -07001312 kOpenClose_Intervals :
1313 Intervals(random->nextULessThan(kCloseOpen_Intervals + 1));
1314 static const SkScalar kIntervalMin = 0.1f;
Greg Daniel5d00f002017-06-29 13:44:51 -04001315 static const SkScalar kIntervalMinCircles = 1.f; // Must be >= to stroke width
joshualittfa2008f2015-04-29 11:32:05 -07001316 static const SkScalar kIntervalMax = 10.f;
1317 switch (intervalType) {
1318 case kOpenOpen_Intervals:
1319 intervals[0] = random->nextRangeScalar(kIntervalMin, kIntervalMax);
1320 intervals[1] = random->nextRangeScalar(kIntervalMin, kIntervalMax);
1321 break;
Greg Daniel5d00f002017-06-29 13:44:51 -04001322 case kOpenClose_Intervals: {
joshualittfa2008f2015-04-29 11:32:05 -07001323 intervals[0] = 0.f;
Greg Daniel5d00f002017-06-29 13:44:51 -04001324 SkScalar min = SkPaint::kRound_Cap == cap ? kIntervalMinCircles : kIntervalMin;
1325 intervals[1] = random->nextRangeScalar(min, kIntervalMax);
joshualittfa2008f2015-04-29 11:32:05 -07001326 break;
Greg Daniel5d00f002017-06-29 13:44:51 -04001327 }
joshualittfa2008f2015-04-29 11:32:05 -07001328 case kCloseOpen_Intervals:
1329 intervals[0] = random->nextRangeScalar(kIntervalMin, kIntervalMax);
1330 intervals[1] = 0.f;
1331 break;
1332
1333 }
1334
1335 // phase is 0 < sum (i0, i1)
1336 SkScalar phase = random->nextRangeScalar(0, intervals[0] + intervals[1]);
1337
1338 SkPaint p;
1339 p.setStyle(SkPaint::kStroke_Style);
1340 p.setStrokeWidth(SkIntToScalar(1));
1341 p.setStrokeCap(cap);
bsalomon6663acf2016-05-10 09:14:17 -07001342 p.setPathEffect(GrTest::TestDashPathEffect::Make(intervals, 2, phase));
joshualittfa2008f2015-04-29 11:32:05 -07001343
bsalomon6663acf2016-05-10 09:14:17 -07001344 GrStyle style(p);
joshualittfa2008f2015-04-29 11:32:05 -07001345
Robert Phillips7c525e62018-06-12 10:11:12 -04001346 return GrDashOp::MakeDashLineOp(context, std::move(paint), viewMatrix, pts, aaMode, style,
Brian Salomon98222ac2017-07-12 15:27:54 -04001347 GrGetRandomStencil(random, context));
joshualittfa2008f2015-04-29 11:32:05 -07001348}
1349
1350#endif