1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/gpu/ops/DashOp.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/gpu/GrRecordingContext.h" 11cb93a386Sopenharmony_ci#include "src/core/SkMatrixPriv.h" 12cb93a386Sopenharmony_ci#include "src/core/SkPointPriv.h" 13cb93a386Sopenharmony_ci#include "src/gpu/BufferWriter.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrAppliedClip.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrDefaultGeoProcFactory.h" 17cb93a386Sopenharmony_ci#include "src/gpu/GrGeometryProcessor.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrMemoryPool.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h" 20cb93a386Sopenharmony_ci#include "src/gpu/GrProcessor.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h" 22cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 23cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h" 24cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 25cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrQuad.h" 26cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 27cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLProgramDataManager.h" 28cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLUniformHandler.h" 29cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVarying.h" 30cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" 31cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h" 32cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h" 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ciusing AAMode = skgpu::v1::DashOp::AAMode; 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci#if GR_TEST_UTILS 37cb93a386Sopenharmony_cistatic const int kAAModeCnt = static_cast<int>(skgpu::v1::DashOp::AAMode::kCoverageWithMSAA) + 1; 38cb93a386Sopenharmony_ci#endif 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_cinamespace skgpu::v1::DashOp { 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_cinamespace { 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_civoid calc_dash_scaling(SkScalar* parallelScale, SkScalar* perpScale, 45cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, const SkPoint pts[2]) { 46cb93a386Sopenharmony_ci SkVector vecSrc = pts[1] - pts[0]; 47cb93a386Sopenharmony_ci if (pts[1] == pts[0]) { 48cb93a386Sopenharmony_ci vecSrc.set(1.0, 0.0); 49cb93a386Sopenharmony_ci } 50cb93a386Sopenharmony_ci SkScalar magSrc = vecSrc.length(); 51cb93a386Sopenharmony_ci SkScalar invSrc = magSrc ? SkScalarInvert(magSrc) : 0; 52cb93a386Sopenharmony_ci vecSrc.scale(invSrc); 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci SkVector vecSrcPerp; 55cb93a386Sopenharmony_ci SkPointPriv::RotateCW(vecSrc, &vecSrcPerp); 56cb93a386Sopenharmony_ci viewMatrix.mapVectors(&vecSrc, 1); 57cb93a386Sopenharmony_ci viewMatrix.mapVectors(&vecSrcPerp, 1); 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci // parallelScale tells how much to scale along the line parallel to the dash line 60cb93a386Sopenharmony_ci // perpScale tells how much to scale in the direction perpendicular to the dash line 61cb93a386Sopenharmony_ci *parallelScale = vecSrc.length(); 62cb93a386Sopenharmony_ci *perpScale = vecSrcPerp.length(); 63cb93a386Sopenharmony_ci} 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci// calculates the rotation needed to aligned pts to the x axis with pts[0] < pts[1] 66cb93a386Sopenharmony_ci// Stores the rotation matrix in rotMatrix, and the mapped points in ptsRot 67cb93a386Sopenharmony_civoid align_to_x_axis(const SkPoint pts[2], SkMatrix* rotMatrix, SkPoint ptsRot[2] = nullptr) { 68cb93a386Sopenharmony_ci SkVector vec = pts[1] - pts[0]; 69cb93a386Sopenharmony_ci if (pts[1] == pts[0]) { 70cb93a386Sopenharmony_ci vec.set(1.0, 0.0); 71cb93a386Sopenharmony_ci } 72cb93a386Sopenharmony_ci SkScalar mag = vec.length(); 73cb93a386Sopenharmony_ci SkScalar inv = mag ? SkScalarInvert(mag) : 0; 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci vec.scale(inv); 76cb93a386Sopenharmony_ci rotMatrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); 77cb93a386Sopenharmony_ci if (ptsRot) { 78cb93a386Sopenharmony_ci rotMatrix->mapPoints(ptsRot, pts, 2); 79cb93a386Sopenharmony_ci // correction for numerical issues if map doesn't make ptsRot exactly horizontal 80cb93a386Sopenharmony_ci ptsRot[1].fY = pts[0].fY; 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci} 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ci// Assumes phase < sum of all intervals 85cb93a386Sopenharmony_ciSkScalar calc_start_adjustment(const SkScalar intervals[2], SkScalar phase) { 86cb93a386Sopenharmony_ci SkASSERT(phase < intervals[0] + intervals[1]); 87cb93a386Sopenharmony_ci if (phase >= intervals[0] && phase != 0) { 88cb93a386Sopenharmony_ci SkScalar srcIntervalLen = intervals[0] + intervals[1]; 89cb93a386Sopenharmony_ci return srcIntervalLen - phase; 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci return 0; 92cb93a386Sopenharmony_ci} 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ciSkScalar calc_end_adjustment(const SkScalar intervals[2], const SkPoint pts[2], 95cb93a386Sopenharmony_ci SkScalar phase, SkScalar* endingInt) { 96cb93a386Sopenharmony_ci if (pts[1].fX <= pts[0].fX) { 97cb93a386Sopenharmony_ci return 0; 98cb93a386Sopenharmony_ci } 99cb93a386Sopenharmony_ci SkScalar srcIntervalLen = intervals[0] + intervals[1]; 100cb93a386Sopenharmony_ci SkScalar totalLen = pts[1].fX - pts[0].fX; 101cb93a386Sopenharmony_ci SkScalar temp = totalLen / srcIntervalLen; 102cb93a386Sopenharmony_ci SkScalar numFullIntervals = SkScalarFloorToScalar(temp); 103cb93a386Sopenharmony_ci *endingInt = totalLen - numFullIntervals * srcIntervalLen + phase; 104cb93a386Sopenharmony_ci temp = *endingInt / srcIntervalLen; 105cb93a386Sopenharmony_ci *endingInt = *endingInt - SkScalarFloorToScalar(temp) * srcIntervalLen; 106cb93a386Sopenharmony_ci if (0 == *endingInt) { 107cb93a386Sopenharmony_ci *endingInt = srcIntervalLen; 108cb93a386Sopenharmony_ci } 109cb93a386Sopenharmony_ci if (*endingInt > intervals[0]) { 110cb93a386Sopenharmony_ci return *endingInt - intervals[0]; 111cb93a386Sopenharmony_ci } 112cb93a386Sopenharmony_ci return 0; 113cb93a386Sopenharmony_ci} 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_cienum DashCap { 116cb93a386Sopenharmony_ci kRound_DashCap, 117cb93a386Sopenharmony_ci kNonRound_DashCap, 118cb93a386Sopenharmony_ci}; 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_civoid setup_dashed_rect(const SkRect& rect, 121cb93a386Sopenharmony_ci VertexWriter& vertices, 122cb93a386Sopenharmony_ci const SkMatrix& matrix, 123cb93a386Sopenharmony_ci SkScalar offset, 124cb93a386Sopenharmony_ci SkScalar bloatX, 125cb93a386Sopenharmony_ci SkScalar len, 126cb93a386Sopenharmony_ci SkScalar startInterval, 127cb93a386Sopenharmony_ci SkScalar endInterval, 128cb93a386Sopenharmony_ci SkScalar strokeWidth, 129cb93a386Sopenharmony_ci SkScalar perpScale, 130cb93a386Sopenharmony_ci DashCap cap) { 131cb93a386Sopenharmony_ci SkScalar intervalLength = startInterval + endInterval; 132cb93a386Sopenharmony_ci // 'dashRect' gets interpolated over the rendered 'rect'. For y we want the perpendicular signed 133cb93a386Sopenharmony_ci // distance from the stroke center line in device space. 'perpScale' is the scale factor applied 134cb93a386Sopenharmony_ci // to the y dimension of 'rect' isolated from 'matrix'. 135cb93a386Sopenharmony_ci SkScalar halfDevRectHeight = rect.height() * perpScale / 2.f; 136cb93a386Sopenharmony_ci SkRect dashRect = { offset - bloatX, -halfDevRectHeight, 137cb93a386Sopenharmony_ci offset + len + bloatX, halfDevRectHeight }; 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci if (kRound_DashCap == cap) { 140cb93a386Sopenharmony_ci SkScalar radius = SkScalarHalf(strokeWidth) - 0.5f; 141cb93a386Sopenharmony_ci SkScalar centerX = SkScalarHalf(endInterval); 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci vertices.writeQuad(GrQuad::MakeFromRect(rect, matrix), 144cb93a386Sopenharmony_ci VertexWriter::TriStripFromRect(dashRect), 145cb93a386Sopenharmony_ci intervalLength, 146cb93a386Sopenharmony_ci radius, 147cb93a386Sopenharmony_ci centerX); 148cb93a386Sopenharmony_ci } else { 149cb93a386Sopenharmony_ci SkASSERT(kNonRound_DashCap == cap); 150cb93a386Sopenharmony_ci SkScalar halfOffLen = SkScalarHalf(endInterval); 151cb93a386Sopenharmony_ci SkScalar halfStroke = SkScalarHalf(strokeWidth); 152cb93a386Sopenharmony_ci SkRect rectParam; 153cb93a386Sopenharmony_ci rectParam.setLTRB(halfOffLen + 0.5f, -halfStroke + 0.5f, 154cb93a386Sopenharmony_ci halfOffLen + startInterval - 0.5f, halfStroke - 0.5f); 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci vertices.writeQuad(GrQuad::MakeFromRect(rect, matrix), 157cb93a386Sopenharmony_ci VertexWriter::TriStripFromRect(dashRect), 158cb93a386Sopenharmony_ci intervalLength, 159cb93a386Sopenharmony_ci rectParam); 160cb93a386Sopenharmony_ci } 161cb93a386Sopenharmony_ci} 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ci/** 164cb93a386Sopenharmony_ci * An GrGeometryProcessor that renders a dashed line. 165cb93a386Sopenharmony_ci * This GrGeometryProcessor is meant for dashed lines that only have a single on/off interval pair. 166cb93a386Sopenharmony_ci * Bounding geometry is rendered and the effect computes coverage based on the fragment's 167cb93a386Sopenharmony_ci * position relative to the dashed line. 168cb93a386Sopenharmony_ci */ 169cb93a386Sopenharmony_ciGrGeometryProcessor* make_dash_gp(SkArenaAlloc* arena, 170cb93a386Sopenharmony_ci const SkPMColor4f&, 171cb93a386Sopenharmony_ci AAMode aaMode, 172cb93a386Sopenharmony_ci DashCap cap, 173cb93a386Sopenharmony_ci const SkMatrix& localMatrix, 174cb93a386Sopenharmony_ci bool usesLocalCoords); 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_ciclass DashOpImpl final : public GrMeshDrawOp { 177cb93a386Sopenharmony_cipublic: 178cb93a386Sopenharmony_ci DEFINE_OP_CLASS_ID 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ci struct LineData { 181cb93a386Sopenharmony_ci SkMatrix fViewMatrix; 182cb93a386Sopenharmony_ci SkMatrix fSrcRotInv; 183cb93a386Sopenharmony_ci SkPoint fPtsRot[2]; 184cb93a386Sopenharmony_ci SkScalar fSrcStrokeWidth; 185cb93a386Sopenharmony_ci SkScalar fPhase; 186cb93a386Sopenharmony_ci SkScalar fIntervals[2]; 187cb93a386Sopenharmony_ci SkScalar fParallelScale; 188cb93a386Sopenharmony_ci SkScalar fPerpendicularScale; 189cb93a386Sopenharmony_ci }; 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ci static GrOp::Owner Make(GrRecordingContext* context, 192cb93a386Sopenharmony_ci GrPaint&& paint, 193cb93a386Sopenharmony_ci const LineData& geometry, 194cb93a386Sopenharmony_ci SkPaint::Cap cap, 195cb93a386Sopenharmony_ci AAMode aaMode, bool fullDash, 196cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) { 197cb93a386Sopenharmony_ci return GrOp::Make<DashOpImpl>(context, std::move(paint), geometry, cap, 198cb93a386Sopenharmony_ci aaMode, fullDash, stencilSettings); 199cb93a386Sopenharmony_ci } 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ci const char* name() const override { return "DashOp"; } 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci void visitProxies(const GrVisitProxyFunc& func) const override { 204cb93a386Sopenharmony_ci if (fProgramInfo) { 205cb93a386Sopenharmony_ci fProgramInfo->visitFPProxies(func); 206cb93a386Sopenharmony_ci } else { 207cb93a386Sopenharmony_ci fProcessorSet.visitProxies(func); 208cb93a386Sopenharmony_ci } 209cb93a386Sopenharmony_ci } 210cb93a386Sopenharmony_ci 211cb93a386Sopenharmony_ci FixedFunctionFlags fixedFunctionFlags() const override { 212cb93a386Sopenharmony_ci FixedFunctionFlags flags = FixedFunctionFlags::kNone; 213cb93a386Sopenharmony_ci if (AAMode::kCoverageWithMSAA == fAAMode) { 214cb93a386Sopenharmony_ci flags |= FixedFunctionFlags::kUsesHWAA; 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci if (fStencilSettings != &GrUserStencilSettings::kUnused) { 217cb93a386Sopenharmony_ci flags |= FixedFunctionFlags::kUsesStencil; 218cb93a386Sopenharmony_ci } 219cb93a386Sopenharmony_ci return flags; 220cb93a386Sopenharmony_ci } 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip, 223cb93a386Sopenharmony_ci GrClampType clampType) override { 224cb93a386Sopenharmony_ci GrProcessorAnalysisCoverage coverage = GrProcessorAnalysisCoverage::kSingleChannel; 225cb93a386Sopenharmony_ci auto analysis = fProcessorSet.finalize(fColor, coverage, clip, fStencilSettings, caps, 226cb93a386Sopenharmony_ci clampType, &fColor); 227cb93a386Sopenharmony_ci fUsesLocalCoords = analysis.usesLocalCoords(); 228cb93a386Sopenharmony_ci return analysis; 229cb93a386Sopenharmony_ci } 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ciprivate: 232cb93a386Sopenharmony_ci friend class GrOp; // for ctor 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci DashOpImpl(GrPaint&& paint, const LineData& geometry, SkPaint::Cap cap, AAMode aaMode, 235cb93a386Sopenharmony_ci bool fullDash, const GrUserStencilSettings* stencilSettings) 236cb93a386Sopenharmony_ci : INHERITED(ClassID()) 237cb93a386Sopenharmony_ci , fColor(paint.getColor4f()) 238cb93a386Sopenharmony_ci , fFullDash(fullDash) 239cb93a386Sopenharmony_ci , fCap(cap) 240cb93a386Sopenharmony_ci , fAAMode(aaMode) 241cb93a386Sopenharmony_ci , fProcessorSet(std::move(paint)) 242cb93a386Sopenharmony_ci , fStencilSettings(stencilSettings) { 243cb93a386Sopenharmony_ci fLines.push_back(geometry); 244cb93a386Sopenharmony_ci 245cb93a386Sopenharmony_ci // compute bounds 246cb93a386Sopenharmony_ci SkScalar halfStrokeWidth = 0.5f * geometry.fSrcStrokeWidth; 247cb93a386Sopenharmony_ci SkScalar xBloat = SkPaint::kButt_Cap == cap ? 0 : halfStrokeWidth; 248cb93a386Sopenharmony_ci SkRect bounds; 249cb93a386Sopenharmony_ci bounds.set(geometry.fPtsRot[0], geometry.fPtsRot[1]); 250cb93a386Sopenharmony_ci bounds.outset(xBloat, halfStrokeWidth); 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci // Note, we actually create the combined matrix here, and save the work 253cb93a386Sopenharmony_ci SkMatrix& combinedMatrix = fLines[0].fSrcRotInv; 254cb93a386Sopenharmony_ci combinedMatrix.postConcat(geometry.fViewMatrix); 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci IsHairline zeroArea = geometry.fSrcStrokeWidth ? IsHairline::kNo : IsHairline::kYes; 257cb93a386Sopenharmony_ci HasAABloat aaBloat = (aaMode == AAMode::kNone) ? HasAABloat::kNo : HasAABloat::kYes; 258cb93a386Sopenharmony_ci this->setTransformedBounds(bounds, combinedMatrix, aaBloat, zeroArea); 259cb93a386Sopenharmony_ci } 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_ci struct DashDraw { 262cb93a386Sopenharmony_ci DashDraw(const LineData& geo) { 263cb93a386Sopenharmony_ci memcpy(fPtsRot, geo.fPtsRot, sizeof(geo.fPtsRot)); 264cb93a386Sopenharmony_ci memcpy(fIntervals, geo.fIntervals, sizeof(geo.fIntervals)); 265cb93a386Sopenharmony_ci fPhase = geo.fPhase; 266cb93a386Sopenharmony_ci } 267cb93a386Sopenharmony_ci SkPoint fPtsRot[2]; 268cb93a386Sopenharmony_ci SkScalar fIntervals[2]; 269cb93a386Sopenharmony_ci SkScalar fPhase; 270cb93a386Sopenharmony_ci SkScalar fStartOffset; 271cb93a386Sopenharmony_ci SkScalar fStrokeWidth; 272cb93a386Sopenharmony_ci SkScalar fLineLength; 273cb93a386Sopenharmony_ci SkScalar fDevBloatX; 274cb93a386Sopenharmony_ci SkScalar fPerpendicularScale; 275cb93a386Sopenharmony_ci bool fLineDone; 276cb93a386Sopenharmony_ci bool fHasStartRect; 277cb93a386Sopenharmony_ci bool fHasEndRect; 278cb93a386Sopenharmony_ci }; 279cb93a386Sopenharmony_ci 280cb93a386Sopenharmony_ci GrProgramInfo* programInfo() override { return fProgramInfo; } 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ci void onCreateProgramInfo(const GrCaps* caps, 283cb93a386Sopenharmony_ci SkArenaAlloc* arena, 284cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 285cb93a386Sopenharmony_ci bool usesMSAASurface, 286cb93a386Sopenharmony_ci GrAppliedClip&& appliedClip, 287cb93a386Sopenharmony_ci const GrDstProxyView& dstProxyView, 288cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 289cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override { 290cb93a386Sopenharmony_ci 291cb93a386Sopenharmony_ci DashCap capType = (this->cap() == SkPaint::kRound_Cap) ? kRound_DashCap : kNonRound_DashCap; 292cb93a386Sopenharmony_ci 293cb93a386Sopenharmony_ci GrGeometryProcessor* gp; 294cb93a386Sopenharmony_ci if (this->fullDash()) { 295cb93a386Sopenharmony_ci gp = make_dash_gp(arena, this->color(), this->aaMode(), capType, 296cb93a386Sopenharmony_ci this->viewMatrix(), fUsesLocalCoords); 297cb93a386Sopenharmony_ci } else { 298cb93a386Sopenharmony_ci // Set up the vertex data for the line and start/end dashes 299cb93a386Sopenharmony_ci using namespace GrDefaultGeoProcFactory; 300cb93a386Sopenharmony_ci Color color(this->color()); 301cb93a386Sopenharmony_ci LocalCoords::Type localCoordsType = 302cb93a386Sopenharmony_ci fUsesLocalCoords ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type; 303cb93a386Sopenharmony_ci gp = MakeForDeviceSpace(arena, 304cb93a386Sopenharmony_ci color, 305cb93a386Sopenharmony_ci Coverage::kSolid_Type, 306cb93a386Sopenharmony_ci localCoordsType, 307cb93a386Sopenharmony_ci this->viewMatrix()); 308cb93a386Sopenharmony_ci } 309cb93a386Sopenharmony_ci 310cb93a386Sopenharmony_ci if (!gp) { 311cb93a386Sopenharmony_ci SkDebugf("Could not create GrGeometryProcessor\n"); 312cb93a386Sopenharmony_ci return; 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci fProgramInfo = GrSimpleMeshDrawOpHelper::CreateProgramInfo(caps, 316cb93a386Sopenharmony_ci arena, 317cb93a386Sopenharmony_ci writeView, 318cb93a386Sopenharmony_ci usesMSAASurface, 319cb93a386Sopenharmony_ci std::move(appliedClip), 320cb93a386Sopenharmony_ci dstProxyView, 321cb93a386Sopenharmony_ci gp, 322cb93a386Sopenharmony_ci std::move(fProcessorSet), 323cb93a386Sopenharmony_ci GrPrimitiveType::kTriangles, 324cb93a386Sopenharmony_ci renderPassXferBarriers, 325cb93a386Sopenharmony_ci colorLoadOp, 326cb93a386Sopenharmony_ci GrPipeline::InputFlags::kNone, 327cb93a386Sopenharmony_ci fStencilSettings); 328cb93a386Sopenharmony_ci } 329cb93a386Sopenharmony_ci 330cb93a386Sopenharmony_ci void onPrepareDraws(GrMeshDrawTarget* target) override { 331cb93a386Sopenharmony_ci int instanceCount = fLines.count(); 332cb93a386Sopenharmony_ci SkPaint::Cap cap = this->cap(); 333cb93a386Sopenharmony_ci DashCap capType = (SkPaint::kRound_Cap == cap) ? kRound_DashCap : kNonRound_DashCap; 334cb93a386Sopenharmony_ci 335cb93a386Sopenharmony_ci if (!fProgramInfo) { 336cb93a386Sopenharmony_ci this->createProgramInfo(target); 337cb93a386Sopenharmony_ci if (!fProgramInfo) { 338cb93a386Sopenharmony_ci return; 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci } 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci // useAA here means Edge AA or MSAA 343cb93a386Sopenharmony_ci bool useAA = this->aaMode() != AAMode::kNone; 344cb93a386Sopenharmony_ci bool fullDash = this->fullDash(); 345cb93a386Sopenharmony_ci 346cb93a386Sopenharmony_ci // We do two passes over all of the dashes. First we setup the start, end, and bounds, 347cb93a386Sopenharmony_ci // rectangles. We preserve all of this work in the rects / draws arrays below. Then we 348cb93a386Sopenharmony_ci // iterate again over these decomposed dashes to generate vertices 349cb93a386Sopenharmony_ci static const int kNumStackDashes = 128; 350cb93a386Sopenharmony_ci SkSTArray<kNumStackDashes, SkRect, true> rects; 351cb93a386Sopenharmony_ci SkSTArray<kNumStackDashes, DashDraw, true> draws; 352cb93a386Sopenharmony_ci 353cb93a386Sopenharmony_ci int totalRectCount = 0; 354cb93a386Sopenharmony_ci int rectOffset = 0; 355cb93a386Sopenharmony_ci rects.push_back_n(3 * instanceCount); 356cb93a386Sopenharmony_ci for (int i = 0; i < instanceCount; i++) { 357cb93a386Sopenharmony_ci const LineData& args = fLines[i]; 358cb93a386Sopenharmony_ci 359cb93a386Sopenharmony_ci DashDraw& draw = draws.push_back(args); 360cb93a386Sopenharmony_ci 361cb93a386Sopenharmony_ci bool hasCap = SkPaint::kButt_Cap != cap; 362cb93a386Sopenharmony_ci 363cb93a386Sopenharmony_ci SkScalar halfSrcStroke = args.fSrcStrokeWidth * 0.5f; 364cb93a386Sopenharmony_ci if (halfSrcStroke == 0.0f || this->aaMode() != AAMode::kCoverageWithMSAA) { 365cb93a386Sopenharmony_ci // In the non-MSAA case, we always want to at least stroke out half a pixel on each 366cb93a386Sopenharmony_ci // side in device space. 0.5f / fPerpendicularScale gives us this min in src space. 367cb93a386Sopenharmony_ci // This is also necessary when the stroke width is zero, to allow hairlines to draw. 368cb93a386Sopenharmony_ci halfSrcStroke = std::max(halfSrcStroke, 0.5f / args.fPerpendicularScale); 369cb93a386Sopenharmony_ci } 370cb93a386Sopenharmony_ci 371cb93a386Sopenharmony_ci SkScalar strokeAdj = hasCap ? halfSrcStroke : 0.0f; 372cb93a386Sopenharmony_ci SkScalar startAdj = 0; 373cb93a386Sopenharmony_ci 374cb93a386Sopenharmony_ci bool lineDone = false; 375cb93a386Sopenharmony_ci 376cb93a386Sopenharmony_ci // Too simplify the algorithm, we always push back rects for start and end rect. 377cb93a386Sopenharmony_ci // Otherwise we'd have to track start / end rects for each individual geometry 378cb93a386Sopenharmony_ci SkRect& bounds = rects[rectOffset++]; 379cb93a386Sopenharmony_ci SkRect& startRect = rects[rectOffset++]; 380cb93a386Sopenharmony_ci SkRect& endRect = rects[rectOffset++]; 381cb93a386Sopenharmony_ci 382cb93a386Sopenharmony_ci bool hasStartRect = false; 383cb93a386Sopenharmony_ci // If we are using AA, check to see if we are drawing a partial dash at the start. If so 384cb93a386Sopenharmony_ci // draw it separately here and adjust our start point accordingly 385cb93a386Sopenharmony_ci if (useAA) { 386cb93a386Sopenharmony_ci if (draw.fPhase > 0 && draw.fPhase < draw.fIntervals[0]) { 387cb93a386Sopenharmony_ci SkPoint startPts[2]; 388cb93a386Sopenharmony_ci startPts[0] = draw.fPtsRot[0]; 389cb93a386Sopenharmony_ci startPts[1].fY = startPts[0].fY; 390cb93a386Sopenharmony_ci startPts[1].fX = std::min(startPts[0].fX + draw.fIntervals[0] - draw.fPhase, 391cb93a386Sopenharmony_ci draw.fPtsRot[1].fX); 392cb93a386Sopenharmony_ci startRect.setBounds(startPts, 2); 393cb93a386Sopenharmony_ci startRect.outset(strokeAdj, halfSrcStroke); 394cb93a386Sopenharmony_ci 395cb93a386Sopenharmony_ci hasStartRect = true; 396cb93a386Sopenharmony_ci startAdj = draw.fIntervals[0] + draw.fIntervals[1] - draw.fPhase; 397cb93a386Sopenharmony_ci } 398cb93a386Sopenharmony_ci } 399cb93a386Sopenharmony_ci 400cb93a386Sopenharmony_ci // adjustments for start and end of bounding rect so we only draw dash intervals 401cb93a386Sopenharmony_ci // contained in the original line segment. 402cb93a386Sopenharmony_ci startAdj += calc_start_adjustment(draw.fIntervals, draw.fPhase); 403cb93a386Sopenharmony_ci if (startAdj != 0) { 404cb93a386Sopenharmony_ci draw.fPtsRot[0].fX += startAdj; 405cb93a386Sopenharmony_ci draw.fPhase = 0; 406cb93a386Sopenharmony_ci } 407cb93a386Sopenharmony_ci SkScalar endingInterval = 0; 408cb93a386Sopenharmony_ci SkScalar endAdj = calc_end_adjustment(draw.fIntervals, draw.fPtsRot, draw.fPhase, 409cb93a386Sopenharmony_ci &endingInterval); 410cb93a386Sopenharmony_ci draw.fPtsRot[1].fX -= endAdj; 411cb93a386Sopenharmony_ci if (draw.fPtsRot[0].fX >= draw.fPtsRot[1].fX) { 412cb93a386Sopenharmony_ci lineDone = true; 413cb93a386Sopenharmony_ci } 414cb93a386Sopenharmony_ci 415cb93a386Sopenharmony_ci bool hasEndRect = false; 416cb93a386Sopenharmony_ci // If we are using AA, check to see if we are drawing a partial dash at then end. If so 417cb93a386Sopenharmony_ci // draw it separately here and adjust our end point accordingly 418cb93a386Sopenharmony_ci if (useAA && !lineDone) { 419cb93a386Sopenharmony_ci // If we adjusted the end then we will not be drawing a partial dash at the end. 420cb93a386Sopenharmony_ci // If we didn't adjust the end point then we just need to make sure the ending 421cb93a386Sopenharmony_ci // dash isn't a full dash 422cb93a386Sopenharmony_ci if (0 == endAdj && endingInterval != draw.fIntervals[0]) { 423cb93a386Sopenharmony_ci SkPoint endPts[2]; 424cb93a386Sopenharmony_ci endPts[1] = draw.fPtsRot[1]; 425cb93a386Sopenharmony_ci endPts[0].fY = endPts[1].fY; 426cb93a386Sopenharmony_ci endPts[0].fX = endPts[1].fX - endingInterval; 427cb93a386Sopenharmony_ci 428cb93a386Sopenharmony_ci endRect.setBounds(endPts, 2); 429cb93a386Sopenharmony_ci endRect.outset(strokeAdj, halfSrcStroke); 430cb93a386Sopenharmony_ci 431cb93a386Sopenharmony_ci hasEndRect = true; 432cb93a386Sopenharmony_ci endAdj = endingInterval + draw.fIntervals[1]; 433cb93a386Sopenharmony_ci 434cb93a386Sopenharmony_ci draw.fPtsRot[1].fX -= endAdj; 435cb93a386Sopenharmony_ci if (draw.fPtsRot[0].fX >= draw.fPtsRot[1].fX) { 436cb93a386Sopenharmony_ci lineDone = true; 437cb93a386Sopenharmony_ci } 438cb93a386Sopenharmony_ci } 439cb93a386Sopenharmony_ci } 440cb93a386Sopenharmony_ci 441cb93a386Sopenharmony_ci if (draw.fPtsRot[0].fX == draw.fPtsRot[1].fX && 442cb93a386Sopenharmony_ci (0 != endAdj || 0 == startAdj) && 443cb93a386Sopenharmony_ci hasCap) { 444cb93a386Sopenharmony_ci // At this point the fPtsRot[0]/[1] represent the start and end of the inner rect of 445cb93a386Sopenharmony_ci // dashes that we want to draw. The only way they can be equal is if the on interval 446cb93a386Sopenharmony_ci // is zero (or an edge case if the end of line ends at a full off interval, but this 447cb93a386Sopenharmony_ci // is handled as well). Thus if the on interval is zero then we need to draw a cap 448cb93a386Sopenharmony_ci // at this position if the stroke has caps. The spec says we only draw this point if 449cb93a386Sopenharmony_ci // point lies between [start of line, end of line). Thus we check if we are at the 450cb93a386Sopenharmony_ci // end (but not the start), and if so we don't draw the cap. 451cb93a386Sopenharmony_ci lineDone = false; 452cb93a386Sopenharmony_ci } 453cb93a386Sopenharmony_ci 454cb93a386Sopenharmony_ci if (startAdj != 0) { 455cb93a386Sopenharmony_ci draw.fPhase = 0; 456cb93a386Sopenharmony_ci } 457cb93a386Sopenharmony_ci 458cb93a386Sopenharmony_ci // Change the dashing info from src space into device space 459cb93a386Sopenharmony_ci SkScalar* devIntervals = draw.fIntervals; 460cb93a386Sopenharmony_ci devIntervals[0] = draw.fIntervals[0] * args.fParallelScale; 461cb93a386Sopenharmony_ci devIntervals[1] = draw.fIntervals[1] * args.fParallelScale; 462cb93a386Sopenharmony_ci SkScalar devPhase = draw.fPhase * args.fParallelScale; 463cb93a386Sopenharmony_ci SkScalar strokeWidth = args.fSrcStrokeWidth * args.fPerpendicularScale; 464cb93a386Sopenharmony_ci 465cb93a386Sopenharmony_ci if ((strokeWidth < 1.f && !useAA) || 0.f == strokeWidth) { 466cb93a386Sopenharmony_ci strokeWidth = 1.f; 467cb93a386Sopenharmony_ci } 468cb93a386Sopenharmony_ci 469cb93a386Sopenharmony_ci SkScalar halfDevStroke = strokeWidth * 0.5f; 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ci if (SkPaint::kSquare_Cap == cap) { 472cb93a386Sopenharmony_ci // add cap to on interval and remove from off interval 473cb93a386Sopenharmony_ci devIntervals[0] += strokeWidth; 474cb93a386Sopenharmony_ci devIntervals[1] -= strokeWidth; 475cb93a386Sopenharmony_ci } 476cb93a386Sopenharmony_ci SkScalar startOffset = devIntervals[1] * 0.5f + devPhase; 477cb93a386Sopenharmony_ci 478cb93a386Sopenharmony_ci SkScalar devBloatX = 0.0f; 479cb93a386Sopenharmony_ci SkScalar devBloatY = 0.0f; 480cb93a386Sopenharmony_ci switch (this->aaMode()) { 481cb93a386Sopenharmony_ci case AAMode::kNone: 482cb93a386Sopenharmony_ci break; 483cb93a386Sopenharmony_ci case AAMode::kCoverage: 484cb93a386Sopenharmony_ci // For EdgeAA, we bloat in X & Y for both square and round caps. 485cb93a386Sopenharmony_ci devBloatX = 0.5f; 486cb93a386Sopenharmony_ci devBloatY = 0.5f; 487cb93a386Sopenharmony_ci break; 488cb93a386Sopenharmony_ci case AAMode::kCoverageWithMSAA: 489cb93a386Sopenharmony_ci // For MSAA, we only bloat in Y for round caps. 490cb93a386Sopenharmony_ci devBloatY = (cap == SkPaint::kRound_Cap) ? 0.5f : 0.0f; 491cb93a386Sopenharmony_ci break; 492cb93a386Sopenharmony_ci } 493cb93a386Sopenharmony_ci 494cb93a386Sopenharmony_ci SkScalar bloatX = devBloatX / args.fParallelScale; 495cb93a386Sopenharmony_ci SkScalar bloatY = devBloatY / args.fPerpendicularScale; 496cb93a386Sopenharmony_ci 497cb93a386Sopenharmony_ci if (devIntervals[1] <= 0.f && useAA) { 498cb93a386Sopenharmony_ci // Case when we end up drawing a solid AA rect 499cb93a386Sopenharmony_ci // Reset the start rect to draw this single solid rect 500cb93a386Sopenharmony_ci // but it requires to upload a new intervals uniform so we can mimic 501cb93a386Sopenharmony_ci // one giant dash 502cb93a386Sopenharmony_ci draw.fPtsRot[0].fX -= hasStartRect ? startAdj : 0; 503cb93a386Sopenharmony_ci draw.fPtsRot[1].fX += hasEndRect ? endAdj : 0; 504cb93a386Sopenharmony_ci startRect.setBounds(draw.fPtsRot, 2); 505cb93a386Sopenharmony_ci startRect.outset(strokeAdj, halfSrcStroke); 506cb93a386Sopenharmony_ci hasStartRect = true; 507cb93a386Sopenharmony_ci hasEndRect = false; 508cb93a386Sopenharmony_ci lineDone = true; 509cb93a386Sopenharmony_ci 510cb93a386Sopenharmony_ci SkPoint devicePts[2]; 511cb93a386Sopenharmony_ci args.fSrcRotInv.mapPoints(devicePts, draw.fPtsRot, 2); 512cb93a386Sopenharmony_ci SkScalar lineLength = SkPoint::Distance(devicePts[0], devicePts[1]); 513cb93a386Sopenharmony_ci if (hasCap) { 514cb93a386Sopenharmony_ci lineLength += 2.f * halfDevStroke; 515cb93a386Sopenharmony_ci } 516cb93a386Sopenharmony_ci devIntervals[0] = lineLength; 517cb93a386Sopenharmony_ci } 518cb93a386Sopenharmony_ci 519cb93a386Sopenharmony_ci totalRectCount += !lineDone ? 1 : 0; 520cb93a386Sopenharmony_ci totalRectCount += hasStartRect ? 1 : 0; 521cb93a386Sopenharmony_ci totalRectCount += hasEndRect ? 1 : 0; 522cb93a386Sopenharmony_ci 523cb93a386Sopenharmony_ci if (SkPaint::kRound_Cap == cap && 0 != args.fSrcStrokeWidth) { 524cb93a386Sopenharmony_ci // need to adjust this for round caps to correctly set the dashPos attrib on 525cb93a386Sopenharmony_ci // vertices 526cb93a386Sopenharmony_ci startOffset -= halfDevStroke; 527cb93a386Sopenharmony_ci } 528cb93a386Sopenharmony_ci 529cb93a386Sopenharmony_ci if (!lineDone) { 530cb93a386Sopenharmony_ci SkPoint devicePts[2]; 531cb93a386Sopenharmony_ci args.fSrcRotInv.mapPoints(devicePts, draw.fPtsRot, 2); 532cb93a386Sopenharmony_ci draw.fLineLength = SkPoint::Distance(devicePts[0], devicePts[1]); 533cb93a386Sopenharmony_ci if (hasCap) { 534cb93a386Sopenharmony_ci draw.fLineLength += 2.f * halfDevStroke; 535cb93a386Sopenharmony_ci } 536cb93a386Sopenharmony_ci 537cb93a386Sopenharmony_ci bounds.setLTRB(draw.fPtsRot[0].fX, draw.fPtsRot[0].fY, 538cb93a386Sopenharmony_ci draw.fPtsRot[1].fX, draw.fPtsRot[1].fY); 539cb93a386Sopenharmony_ci bounds.outset(bloatX + strokeAdj, bloatY + halfSrcStroke); 540cb93a386Sopenharmony_ci } 541cb93a386Sopenharmony_ci 542cb93a386Sopenharmony_ci if (hasStartRect) { 543cb93a386Sopenharmony_ci SkASSERT(useAA); // so that we know bloatX and bloatY have been set 544cb93a386Sopenharmony_ci startRect.outset(bloatX, bloatY); 545cb93a386Sopenharmony_ci } 546cb93a386Sopenharmony_ci 547cb93a386Sopenharmony_ci if (hasEndRect) { 548cb93a386Sopenharmony_ci SkASSERT(useAA); // so that we know bloatX and bloatY have been set 549cb93a386Sopenharmony_ci endRect.outset(bloatX, bloatY); 550cb93a386Sopenharmony_ci } 551cb93a386Sopenharmony_ci 552cb93a386Sopenharmony_ci draw.fStartOffset = startOffset; 553cb93a386Sopenharmony_ci draw.fDevBloatX = devBloatX; 554cb93a386Sopenharmony_ci draw.fPerpendicularScale = args.fPerpendicularScale; 555cb93a386Sopenharmony_ci draw.fStrokeWidth = strokeWidth; 556cb93a386Sopenharmony_ci draw.fHasStartRect = hasStartRect; 557cb93a386Sopenharmony_ci draw.fLineDone = lineDone; 558cb93a386Sopenharmony_ci draw.fHasEndRect = hasEndRect; 559cb93a386Sopenharmony_ci } 560cb93a386Sopenharmony_ci 561cb93a386Sopenharmony_ci if (!totalRectCount) { 562cb93a386Sopenharmony_ci return; 563cb93a386Sopenharmony_ci } 564cb93a386Sopenharmony_ci 565cb93a386Sopenharmony_ci QuadHelper helper(target, fProgramInfo->geomProc().vertexStride(), totalRectCount); 566cb93a386Sopenharmony_ci VertexWriter vertices{ helper.vertices() }; 567cb93a386Sopenharmony_ci if (!vertices) { 568cb93a386Sopenharmony_ci return; 569cb93a386Sopenharmony_ci } 570cb93a386Sopenharmony_ci 571cb93a386Sopenharmony_ci int rectIndex = 0; 572cb93a386Sopenharmony_ci for (int i = 0; i < instanceCount; i++) { 573cb93a386Sopenharmony_ci const LineData& geom = fLines[i]; 574cb93a386Sopenharmony_ci 575cb93a386Sopenharmony_ci if (!draws[i].fLineDone) { 576cb93a386Sopenharmony_ci if (fullDash) { 577cb93a386Sopenharmony_ci setup_dashed_rect(rects[rectIndex], vertices, geom.fSrcRotInv, 578cb93a386Sopenharmony_ci draws[i].fStartOffset, draws[i].fDevBloatX, 579cb93a386Sopenharmony_ci draws[i].fLineLength, draws[i].fIntervals[0], 580cb93a386Sopenharmony_ci draws[i].fIntervals[1], draws[i].fStrokeWidth, 581cb93a386Sopenharmony_ci draws[i].fPerpendicularScale, 582cb93a386Sopenharmony_ci capType); 583cb93a386Sopenharmony_ci } else { 584cb93a386Sopenharmony_ci vertices.writeQuad(GrQuad::MakeFromRect(rects[rectIndex], geom.fSrcRotInv)); 585cb93a386Sopenharmony_ci } 586cb93a386Sopenharmony_ci } 587cb93a386Sopenharmony_ci rectIndex++; 588cb93a386Sopenharmony_ci 589cb93a386Sopenharmony_ci if (draws[i].fHasStartRect) { 590cb93a386Sopenharmony_ci if (fullDash) { 591cb93a386Sopenharmony_ci setup_dashed_rect(rects[rectIndex], vertices, geom.fSrcRotInv, 592cb93a386Sopenharmony_ci draws[i].fStartOffset, draws[i].fDevBloatX, 593cb93a386Sopenharmony_ci draws[i].fIntervals[0], draws[i].fIntervals[0], 594cb93a386Sopenharmony_ci draws[i].fIntervals[1], draws[i].fStrokeWidth, 595cb93a386Sopenharmony_ci draws[i].fPerpendicularScale, capType); 596cb93a386Sopenharmony_ci } else { 597cb93a386Sopenharmony_ci vertices.writeQuad(GrQuad::MakeFromRect(rects[rectIndex], geom.fSrcRotInv)); 598cb93a386Sopenharmony_ci } 599cb93a386Sopenharmony_ci } 600cb93a386Sopenharmony_ci rectIndex++; 601cb93a386Sopenharmony_ci 602cb93a386Sopenharmony_ci if (draws[i].fHasEndRect) { 603cb93a386Sopenharmony_ci if (fullDash) { 604cb93a386Sopenharmony_ci setup_dashed_rect(rects[rectIndex], vertices, geom.fSrcRotInv, 605cb93a386Sopenharmony_ci draws[i].fStartOffset, draws[i].fDevBloatX, 606cb93a386Sopenharmony_ci draws[i].fIntervals[0], draws[i].fIntervals[0], 607cb93a386Sopenharmony_ci draws[i].fIntervals[1], draws[i].fStrokeWidth, 608cb93a386Sopenharmony_ci draws[i].fPerpendicularScale, capType); 609cb93a386Sopenharmony_ci } else { 610cb93a386Sopenharmony_ci vertices.writeQuad(GrQuad::MakeFromRect(rects[rectIndex], geom.fSrcRotInv)); 611cb93a386Sopenharmony_ci } 612cb93a386Sopenharmony_ci } 613cb93a386Sopenharmony_ci rectIndex++; 614cb93a386Sopenharmony_ci } 615cb93a386Sopenharmony_ci 616cb93a386Sopenharmony_ci fMesh = helper.mesh(); 617cb93a386Sopenharmony_ci } 618cb93a386Sopenharmony_ci 619cb93a386Sopenharmony_ci void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override { 620cb93a386Sopenharmony_ci if (!fProgramInfo || !fMesh) { 621cb93a386Sopenharmony_ci return; 622cb93a386Sopenharmony_ci } 623cb93a386Sopenharmony_ci 624cb93a386Sopenharmony_ci flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds); 625cb93a386Sopenharmony_ci flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline()); 626cb93a386Sopenharmony_ci flushState->drawMesh(*fMesh); 627cb93a386Sopenharmony_ci } 628cb93a386Sopenharmony_ci 629cb93a386Sopenharmony_ci CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override { 630cb93a386Sopenharmony_ci auto that = t->cast<DashOpImpl>(); 631cb93a386Sopenharmony_ci if (fProcessorSet != that->fProcessorSet) { 632cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 633cb93a386Sopenharmony_ci } 634cb93a386Sopenharmony_ci 635cb93a386Sopenharmony_ci if (this->aaMode() != that->aaMode()) { 636cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 637cb93a386Sopenharmony_ci } 638cb93a386Sopenharmony_ci 639cb93a386Sopenharmony_ci if (this->fullDash() != that->fullDash()) { 640cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 641cb93a386Sopenharmony_ci } 642cb93a386Sopenharmony_ci 643cb93a386Sopenharmony_ci if (this->cap() != that->cap()) { 644cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 645cb93a386Sopenharmony_ci } 646cb93a386Sopenharmony_ci 647cb93a386Sopenharmony_ci // TODO vertex color 648cb93a386Sopenharmony_ci if (this->color() != that->color()) { 649cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 650cb93a386Sopenharmony_ci } 651cb93a386Sopenharmony_ci 652cb93a386Sopenharmony_ci if (fUsesLocalCoords && !SkMatrixPriv::CheapEqual(this->viewMatrix(), that->viewMatrix())) { 653cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 654cb93a386Sopenharmony_ci } 655cb93a386Sopenharmony_ci 656cb93a386Sopenharmony_ci fLines.push_back_n(that->fLines.count(), that->fLines.begin()); 657cb93a386Sopenharmony_ci return CombineResult::kMerged; 658cb93a386Sopenharmony_ci } 659cb93a386Sopenharmony_ci 660cb93a386Sopenharmony_ci#if GR_TEST_UTILS 661cb93a386Sopenharmony_ci SkString onDumpInfo() const override { 662cb93a386Sopenharmony_ci SkString string; 663cb93a386Sopenharmony_ci for (const auto& geo : fLines) { 664cb93a386Sopenharmony_ci string.appendf("Pt0: [%.2f, %.2f], Pt1: [%.2f, %.2f], Width: %.2f, Ival0: %.2f, " 665cb93a386Sopenharmony_ci "Ival1 : %.2f, Phase: %.2f\n", 666cb93a386Sopenharmony_ci geo.fPtsRot[0].fX, geo.fPtsRot[0].fY, 667cb93a386Sopenharmony_ci geo.fPtsRot[1].fX, geo.fPtsRot[1].fY, 668cb93a386Sopenharmony_ci geo.fSrcStrokeWidth, 669cb93a386Sopenharmony_ci geo.fIntervals[0], 670cb93a386Sopenharmony_ci geo.fIntervals[1], 671cb93a386Sopenharmony_ci geo.fPhase); 672cb93a386Sopenharmony_ci } 673cb93a386Sopenharmony_ci string += fProcessorSet.dumpProcessors(); 674cb93a386Sopenharmony_ci return string; 675cb93a386Sopenharmony_ci } 676cb93a386Sopenharmony_ci#endif 677cb93a386Sopenharmony_ci 678cb93a386Sopenharmony_ci const SkPMColor4f& color() const { return fColor; } 679cb93a386Sopenharmony_ci const SkMatrix& viewMatrix() const { return fLines[0].fViewMatrix; } 680cb93a386Sopenharmony_ci AAMode aaMode() const { return fAAMode; } 681cb93a386Sopenharmony_ci bool fullDash() const { return fFullDash; } 682cb93a386Sopenharmony_ci SkPaint::Cap cap() const { return fCap; } 683cb93a386Sopenharmony_ci 684cb93a386Sopenharmony_ci SkSTArray<1, LineData, true> fLines; 685cb93a386Sopenharmony_ci SkPMColor4f fColor; 686cb93a386Sopenharmony_ci bool fUsesLocalCoords : 1; 687cb93a386Sopenharmony_ci bool fFullDash : 1; 688cb93a386Sopenharmony_ci // We use 3 bits for this 3-value enum because MSVS makes the underlying types signed. 689cb93a386Sopenharmony_ci SkPaint::Cap fCap : 3; 690cb93a386Sopenharmony_ci AAMode fAAMode; 691cb93a386Sopenharmony_ci GrProcessorSet fProcessorSet; 692cb93a386Sopenharmony_ci const GrUserStencilSettings* fStencilSettings; 693cb93a386Sopenharmony_ci 694cb93a386Sopenharmony_ci GrSimpleMesh* fMesh = nullptr; 695cb93a386Sopenharmony_ci GrProgramInfo* fProgramInfo = nullptr; 696cb93a386Sopenharmony_ci 697cb93a386Sopenharmony_ci using INHERITED = GrMeshDrawOp; 698cb93a386Sopenharmony_ci}; 699cb93a386Sopenharmony_ci 700cb93a386Sopenharmony_ci/* 701cb93a386Sopenharmony_ci * This effect will draw a dotted line (defined as a dashed lined with round caps and no on 702cb93a386Sopenharmony_ci * interval). The radius of the dots is given by the strokeWidth and the spacing by the DashInfo. 703cb93a386Sopenharmony_ci * Both of the previous two parameters are in device space. This effect also requires the setting of 704cb93a386Sopenharmony_ci * a float2 vertex attribute for the the four corners of the bounding rect. This attribute is the 705cb93a386Sopenharmony_ci * "dash position" of each vertex. In other words it is the vertex coords (in device space) if we 706cb93a386Sopenharmony_ci * transform the line to be horizontal, with the start of line at the origin then shifted to the 707cb93a386Sopenharmony_ci * right by half the off interval. The line then goes in the positive x direction. 708cb93a386Sopenharmony_ci */ 709cb93a386Sopenharmony_ciclass DashingCircleEffect : public GrGeometryProcessor { 710cb93a386Sopenharmony_cipublic: 711cb93a386Sopenharmony_ci typedef SkPathEffect::DashInfo DashInfo; 712cb93a386Sopenharmony_ci 713cb93a386Sopenharmony_ci static GrGeometryProcessor* Make(SkArenaAlloc* arena, 714cb93a386Sopenharmony_ci const SkPMColor4f&, 715cb93a386Sopenharmony_ci AAMode aaMode, 716cb93a386Sopenharmony_ci const SkMatrix& localMatrix, 717cb93a386Sopenharmony_ci bool usesLocalCoords); 718cb93a386Sopenharmony_ci 719cb93a386Sopenharmony_ci const char* name() const override { return "DashingCircleEffect"; } 720cb93a386Sopenharmony_ci 721cb93a386Sopenharmony_ci SkString getShaderDfxInfo() const override; 722cb93a386Sopenharmony_ci 723cb93a386Sopenharmony_ci void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 724cb93a386Sopenharmony_ci 725cb93a386Sopenharmony_ci std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override; 726cb93a386Sopenharmony_ci 727cb93a386Sopenharmony_ciprivate: 728cb93a386Sopenharmony_ci class Impl; 729cb93a386Sopenharmony_ci 730cb93a386Sopenharmony_ci DashingCircleEffect(const SkPMColor4f&, AAMode aaMode, const SkMatrix& localMatrix, 731cb93a386Sopenharmony_ci bool usesLocalCoords); 732cb93a386Sopenharmony_ci 733cb93a386Sopenharmony_ci SkPMColor4f fColor; 734cb93a386Sopenharmony_ci SkMatrix fLocalMatrix; 735cb93a386Sopenharmony_ci bool fUsesLocalCoords; 736cb93a386Sopenharmony_ci AAMode fAAMode; 737cb93a386Sopenharmony_ci 738cb93a386Sopenharmony_ci Attribute fInPosition; 739cb93a386Sopenharmony_ci Attribute fInDashParams; 740cb93a386Sopenharmony_ci Attribute fInCircleParams; 741cb93a386Sopenharmony_ci 742cb93a386Sopenharmony_ci GR_DECLARE_GEOMETRY_PROCESSOR_TEST 743cb93a386Sopenharmony_ci 744cb93a386Sopenharmony_ci using INHERITED = GrGeometryProcessor; 745cb93a386Sopenharmony_ci}; 746cb93a386Sopenharmony_ci 747cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 748cb93a386Sopenharmony_ci 749cb93a386Sopenharmony_ciclass DashingCircleEffect::Impl : public ProgramImpl { 750cb93a386Sopenharmony_cipublic: 751cb93a386Sopenharmony_ci void setData(const GrGLSLProgramDataManager&, 752cb93a386Sopenharmony_ci const GrShaderCaps&, 753cb93a386Sopenharmony_ci const GrGeometryProcessor&) override; 754cb93a386Sopenharmony_ci 755cb93a386Sopenharmony_ciprivate: 756cb93a386Sopenharmony_ci void onEmitCode(EmitArgs&, GrGPArgs*) override; 757cb93a386Sopenharmony_ci 758cb93a386Sopenharmony_ci SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix(); 759cb93a386Sopenharmony_ci SkPMColor4f fColor = SK_PMColor4fILLEGAL; 760cb93a386Sopenharmony_ci float fPrevRadius = SK_FloatNaN; 761cb93a386Sopenharmony_ci float fPrevCenterX = SK_FloatNaN; 762cb93a386Sopenharmony_ci float fPrevIntervalLength = SK_FloatNaN; 763cb93a386Sopenharmony_ci 764cb93a386Sopenharmony_ci UniformHandle fParamUniform; 765cb93a386Sopenharmony_ci UniformHandle fColorUniform; 766cb93a386Sopenharmony_ci UniformHandle fLocalMatrixUniform; 767cb93a386Sopenharmony_ci}; 768cb93a386Sopenharmony_ci 769cb93a386Sopenharmony_civoid DashingCircleEffect::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { 770cb93a386Sopenharmony_ci const DashingCircleEffect& dce = args.fGeomProc.cast<DashingCircleEffect>(); 771cb93a386Sopenharmony_ci GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; 772cb93a386Sopenharmony_ci GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; 773cb93a386Sopenharmony_ci GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 774cb93a386Sopenharmony_ci 775cb93a386Sopenharmony_ci // emit attributes 776cb93a386Sopenharmony_ci varyingHandler->emitAttributes(dce); 777cb93a386Sopenharmony_ci 778cb93a386Sopenharmony_ci // XY are dashPos, Z is dashInterval 779cb93a386Sopenharmony_ci GrGLSLVarying dashParams(kHalf3_GrSLType); 780cb93a386Sopenharmony_ci varyingHandler->addVarying("DashParam", &dashParams); 781cb93a386Sopenharmony_ci vertBuilder->codeAppendf("%s = %s;", dashParams.vsOut(), dce.fInDashParams.name()); 782cb93a386Sopenharmony_ci 783cb93a386Sopenharmony_ci // x refers to circle radius - 0.5, y refers to cicle's center x coord 784cb93a386Sopenharmony_ci GrGLSLVarying circleParams(kHalf2_GrSLType); 785cb93a386Sopenharmony_ci varyingHandler->addVarying("CircleParams", &circleParams); 786cb93a386Sopenharmony_ci vertBuilder->codeAppendf("%s = %s;", circleParams.vsOut(), dce.fInCircleParams.name()); 787cb93a386Sopenharmony_ci 788cb93a386Sopenharmony_ci GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 789cb93a386Sopenharmony_ci // Setup pass through color 790cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 %s;", args.fOutputColor); 791cb93a386Sopenharmony_ci this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); 792cb93a386Sopenharmony_ci 793cb93a386Sopenharmony_ci // Setup position 794cb93a386Sopenharmony_ci WriteOutputPosition(vertBuilder, gpArgs, dce.fInPosition.name()); 795cb93a386Sopenharmony_ci if (dce.fUsesLocalCoords) { 796cb93a386Sopenharmony_ci WriteLocalCoord(vertBuilder, 797cb93a386Sopenharmony_ci uniformHandler, 798cb93a386Sopenharmony_ci *args.fShaderCaps, 799cb93a386Sopenharmony_ci gpArgs, 800cb93a386Sopenharmony_ci dce.fInPosition.asShaderVar(), 801cb93a386Sopenharmony_ci dce.fLocalMatrix, 802cb93a386Sopenharmony_ci &fLocalMatrixUniform); 803cb93a386Sopenharmony_ci } 804cb93a386Sopenharmony_ci 805cb93a386Sopenharmony_ci // transforms all points so that we can compare them to our test circle 806cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half xShifted = half(%s.x - floor(%s.x / %s.z) * %s.z);", 807cb93a386Sopenharmony_ci dashParams.fsIn(), dashParams.fsIn(), dashParams.fsIn(), 808cb93a386Sopenharmony_ci dashParams.fsIn()); 809cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 fragPosShifted = half2(xShifted, half(%s.y));", 810cb93a386Sopenharmony_ci dashParams.fsIn()); 811cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 center = half2(%s.y, 0.0);", circleParams.fsIn()); 812cb93a386Sopenharmony_ci fragBuilder->codeAppend("half dist = length(center - fragPosShifted);"); 813cb93a386Sopenharmony_ci if (dce.fAAMode != AAMode::kNone) { 814cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half diff = dist - %s.x;", circleParams.fsIn()); 815cb93a386Sopenharmony_ci fragBuilder->codeAppend("diff = 1.0 - diff;"); 816cb93a386Sopenharmony_ci fragBuilder->codeAppend("half alpha = saturate(diff);"); 817cb93a386Sopenharmony_ci } else { 818cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half alpha = 1.0;"); 819cb93a386Sopenharmony_ci fragBuilder->codeAppendf("alpha *= dist < %s.x + 0.5 ? 1.0 : 0.0;", circleParams.fsIn()); 820cb93a386Sopenharmony_ci } 821cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 %s = half4(alpha);", args.fOutputCoverage); 822cb93a386Sopenharmony_ci} 823cb93a386Sopenharmony_ci 824cb93a386Sopenharmony_civoid DashingCircleEffect::Impl::setData(const GrGLSLProgramDataManager& pdman, 825cb93a386Sopenharmony_ci const GrShaderCaps& shaderCaps, 826cb93a386Sopenharmony_ci const GrGeometryProcessor& geomProc) { 827cb93a386Sopenharmony_ci const DashingCircleEffect& dce = geomProc.cast<DashingCircleEffect>(); 828cb93a386Sopenharmony_ci if (dce.fColor != fColor) { 829cb93a386Sopenharmony_ci pdman.set4fv(fColorUniform, 1, dce.fColor.vec()); 830cb93a386Sopenharmony_ci fColor = dce.fColor; 831cb93a386Sopenharmony_ci } 832cb93a386Sopenharmony_ci SetTransform(pdman, shaderCaps, fLocalMatrixUniform, dce.fLocalMatrix, &fLocalMatrix); 833cb93a386Sopenharmony_ci} 834cb93a386Sopenharmony_ci 835cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 836cb93a386Sopenharmony_ci 837cb93a386Sopenharmony_ciGrGeometryProcessor* DashingCircleEffect::Make(SkArenaAlloc* arena, 838cb93a386Sopenharmony_ci const SkPMColor4f& color, 839cb93a386Sopenharmony_ci AAMode aaMode, 840cb93a386Sopenharmony_ci const SkMatrix& localMatrix, 841cb93a386Sopenharmony_ci bool usesLocalCoords) { 842cb93a386Sopenharmony_ci return arena->make([&](void* ptr) { 843cb93a386Sopenharmony_ci return new (ptr) DashingCircleEffect(color, aaMode, localMatrix, usesLocalCoords); 844cb93a386Sopenharmony_ci }); 845cb93a386Sopenharmony_ci} 846cb93a386Sopenharmony_ci 847cb93a386Sopenharmony_ciSkString DashingCircleEffect::getShaderDfxInfo() const 848cb93a386Sopenharmony_ci{ 849cb93a386Sopenharmony_ci SkString format; 850cb93a386Sopenharmony_ci format.printf("ShaderDfx_DashingCircleEffect_%d_%d_%d_%d_%d", fUsesLocalCoords, fAAMode, 851cb93a386Sopenharmony_ci fLocalMatrix.isIdentity(), fLocalMatrix.isScaleTranslate(), fLocalMatrix.hasPerspective()); 852cb93a386Sopenharmony_ci return format; 853cb93a386Sopenharmony_ci} 854cb93a386Sopenharmony_ci 855cb93a386Sopenharmony_civoid DashingCircleEffect::addToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { 856cb93a386Sopenharmony_ci uint32_t key = 0; 857cb93a386Sopenharmony_ci key |= fUsesLocalCoords ? 0x1 : 0x0; 858cb93a386Sopenharmony_ci key |= static_cast<uint32_t>(fAAMode) << 1; 859cb93a386Sopenharmony_ci key |= ProgramImpl::ComputeMatrixKey(caps, fLocalMatrix) << 3; 860cb93a386Sopenharmony_ci b->add32(key); 861cb93a386Sopenharmony_ci} 862cb93a386Sopenharmony_ci 863cb93a386Sopenharmony_cistd::unique_ptr<GrGeometryProcessor::ProgramImpl> DashingCircleEffect::makeProgramImpl( 864cb93a386Sopenharmony_ci const GrShaderCaps&) const { 865cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 866cb93a386Sopenharmony_ci} 867cb93a386Sopenharmony_ci 868cb93a386Sopenharmony_ciDashingCircleEffect::DashingCircleEffect(const SkPMColor4f& color, 869cb93a386Sopenharmony_ci AAMode aaMode, 870cb93a386Sopenharmony_ci const SkMatrix& localMatrix, 871cb93a386Sopenharmony_ci bool usesLocalCoords) 872cb93a386Sopenharmony_ci : INHERITED(kDashingCircleEffect_ClassID) 873cb93a386Sopenharmony_ci , fColor(color) 874cb93a386Sopenharmony_ci , fLocalMatrix(localMatrix) 875cb93a386Sopenharmony_ci , fUsesLocalCoords(usesLocalCoords) 876cb93a386Sopenharmony_ci , fAAMode(aaMode) { 877cb93a386Sopenharmony_ci fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; 878cb93a386Sopenharmony_ci fInDashParams = {"inDashParams", kFloat3_GrVertexAttribType, kHalf3_GrSLType}; 879cb93a386Sopenharmony_ci fInCircleParams = {"inCircleParams", kFloat2_GrVertexAttribType, kHalf2_GrSLType}; 880cb93a386Sopenharmony_ci this->setVertexAttributes(&fInPosition, 3); 881cb93a386Sopenharmony_ci} 882cb93a386Sopenharmony_ci 883cb93a386Sopenharmony_ciGR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingCircleEffect); 884cb93a386Sopenharmony_ci 885cb93a386Sopenharmony_ci#if GR_TEST_UTILS 886cb93a386Sopenharmony_ciGrGeometryProcessor* DashingCircleEffect::TestCreate(GrProcessorTestData* d) { 887cb93a386Sopenharmony_ci AAMode aaMode = static_cast<AAMode>(d->fRandom->nextULessThan(kAAModeCnt)); 888cb93a386Sopenharmony_ci GrColor color = GrTest::RandomColor(d->fRandom); 889cb93a386Sopenharmony_ci SkMatrix matrix = GrTest::TestMatrix(d->fRandom); 890cb93a386Sopenharmony_ci return DashingCircleEffect::Make(d->allocator(), 891cb93a386Sopenharmony_ci SkPMColor4f::FromBytes_RGBA(color), 892cb93a386Sopenharmony_ci aaMode, 893cb93a386Sopenharmony_ci matrix, 894cb93a386Sopenharmony_ci d->fRandom->nextBool()); 895cb93a386Sopenharmony_ci} 896cb93a386Sopenharmony_ci#endif 897cb93a386Sopenharmony_ci 898cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 899cb93a386Sopenharmony_ci 900cb93a386Sopenharmony_ci/* 901cb93a386Sopenharmony_ci * This effect will draw a dashed line. The width of the dash is given by the strokeWidth and the 902cb93a386Sopenharmony_ci * length and spacing by the DashInfo. Both of the previous two parameters are in device space. 903cb93a386Sopenharmony_ci * This effect also requires the setting of a float2 vertex attribute for the the four corners of the 904cb93a386Sopenharmony_ci * bounding rect. This attribute is the "dash position" of each vertex. In other words it is the 905cb93a386Sopenharmony_ci * vertex coords (in device space) if we transform the line to be horizontal, with the start of 906cb93a386Sopenharmony_ci * line at the origin then shifted to the right by half the off interval. The line then goes in the 907cb93a386Sopenharmony_ci * positive x direction. 908cb93a386Sopenharmony_ci */ 909cb93a386Sopenharmony_ciclass DashingLineEffect : public GrGeometryProcessor { 910cb93a386Sopenharmony_cipublic: 911cb93a386Sopenharmony_ci typedef SkPathEffect::DashInfo DashInfo; 912cb93a386Sopenharmony_ci 913cb93a386Sopenharmony_ci static GrGeometryProcessor* Make(SkArenaAlloc* arena, 914cb93a386Sopenharmony_ci const SkPMColor4f&, 915cb93a386Sopenharmony_ci AAMode aaMode, 916cb93a386Sopenharmony_ci const SkMatrix& localMatrix, 917cb93a386Sopenharmony_ci bool usesLocalCoords); 918cb93a386Sopenharmony_ci 919cb93a386Sopenharmony_ci const char* name() const override { return "DashingEffect"; } 920cb93a386Sopenharmony_ci 921cb93a386Sopenharmony_ci SkString getShaderDfxInfo() const override; 922cb93a386Sopenharmony_ci 923cb93a386Sopenharmony_ci bool usesLocalCoords() const { return fUsesLocalCoords; } 924cb93a386Sopenharmony_ci 925cb93a386Sopenharmony_ci void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 926cb93a386Sopenharmony_ci 927cb93a386Sopenharmony_ci std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override; 928cb93a386Sopenharmony_ci 929cb93a386Sopenharmony_ciprivate: 930cb93a386Sopenharmony_ci class Impl; 931cb93a386Sopenharmony_ci 932cb93a386Sopenharmony_ci DashingLineEffect(const SkPMColor4f&, AAMode aaMode, const SkMatrix& localMatrix, 933cb93a386Sopenharmony_ci bool usesLocalCoords); 934cb93a386Sopenharmony_ci 935cb93a386Sopenharmony_ci SkPMColor4f fColor; 936cb93a386Sopenharmony_ci SkMatrix fLocalMatrix; 937cb93a386Sopenharmony_ci bool fUsesLocalCoords; 938cb93a386Sopenharmony_ci AAMode fAAMode; 939cb93a386Sopenharmony_ci 940cb93a386Sopenharmony_ci Attribute fInPosition; 941cb93a386Sopenharmony_ci Attribute fInDashParams; 942cb93a386Sopenharmony_ci Attribute fInRect; 943cb93a386Sopenharmony_ci 944cb93a386Sopenharmony_ci GR_DECLARE_GEOMETRY_PROCESSOR_TEST 945cb93a386Sopenharmony_ci 946cb93a386Sopenharmony_ci using INHERITED = GrGeometryProcessor; 947cb93a386Sopenharmony_ci}; 948cb93a386Sopenharmony_ci 949cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 950cb93a386Sopenharmony_ci 951cb93a386Sopenharmony_ciclass DashingLineEffect::Impl : public ProgramImpl { 952cb93a386Sopenharmony_cipublic: 953cb93a386Sopenharmony_ci void setData(const GrGLSLProgramDataManager&, 954cb93a386Sopenharmony_ci const GrShaderCaps&, 955cb93a386Sopenharmony_ci const GrGeometryProcessor&) override; 956cb93a386Sopenharmony_ci 957cb93a386Sopenharmony_ciprivate: 958cb93a386Sopenharmony_ci void onEmitCode(EmitArgs&, GrGPArgs*) override; 959cb93a386Sopenharmony_ci 960cb93a386Sopenharmony_ci SkPMColor4f fColor = SK_PMColor4fILLEGAL; 961cb93a386Sopenharmony_ci SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix(); 962cb93a386Sopenharmony_ci 963cb93a386Sopenharmony_ci UniformHandle fLocalMatrixUniform; 964cb93a386Sopenharmony_ci UniformHandle fColorUniform; 965cb93a386Sopenharmony_ci}; 966cb93a386Sopenharmony_ci 967cb93a386Sopenharmony_civoid DashingLineEffect::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { 968cb93a386Sopenharmony_ci const DashingLineEffect& de = args.fGeomProc.cast<DashingLineEffect>(); 969cb93a386Sopenharmony_ci 970cb93a386Sopenharmony_ci GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; 971cb93a386Sopenharmony_ci GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; 972cb93a386Sopenharmony_ci GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 973cb93a386Sopenharmony_ci 974cb93a386Sopenharmony_ci // emit attributes 975cb93a386Sopenharmony_ci varyingHandler->emitAttributes(de); 976cb93a386Sopenharmony_ci 977cb93a386Sopenharmony_ci // XY refers to dashPos, Z is the dash interval length 978cb93a386Sopenharmony_ci GrGLSLVarying inDashParams(kFloat3_GrSLType); 979cb93a386Sopenharmony_ci varyingHandler->addVarying("DashParams", &inDashParams); 980cb93a386Sopenharmony_ci vertBuilder->codeAppendf("%s = %s;", inDashParams.vsOut(), de.fInDashParams.name()); 981cb93a386Sopenharmony_ci 982cb93a386Sopenharmony_ci // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5), 983cb93a386Sopenharmony_ci // respectively. 984cb93a386Sopenharmony_ci GrGLSLVarying inRectParams(kFloat4_GrSLType); 985cb93a386Sopenharmony_ci varyingHandler->addVarying("RectParams", &inRectParams); 986cb93a386Sopenharmony_ci vertBuilder->codeAppendf("%s = %s;", inRectParams.vsOut(), de.fInRect.name()); 987cb93a386Sopenharmony_ci 988cb93a386Sopenharmony_ci GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 989cb93a386Sopenharmony_ci // Setup pass through color 990cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 %s;", args.fOutputColor); 991cb93a386Sopenharmony_ci this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); 992cb93a386Sopenharmony_ci 993cb93a386Sopenharmony_ci // Setup position 994cb93a386Sopenharmony_ci WriteOutputPosition(vertBuilder, gpArgs, de.fInPosition.name()); 995cb93a386Sopenharmony_ci if (de.usesLocalCoords()) { 996cb93a386Sopenharmony_ci WriteLocalCoord(vertBuilder, 997cb93a386Sopenharmony_ci uniformHandler, 998cb93a386Sopenharmony_ci *args.fShaderCaps, 999cb93a386Sopenharmony_ci gpArgs, 1000cb93a386Sopenharmony_ci de.fInPosition.asShaderVar(), 1001cb93a386Sopenharmony_ci de.fLocalMatrix, 1002cb93a386Sopenharmony_ci &fLocalMatrixUniform); 1003cb93a386Sopenharmony_ci } 1004cb93a386Sopenharmony_ci 1005cb93a386Sopenharmony_ci // transforms all points so that we can compare them to our test rect 1006cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half xShifted = half(%s.x - floor(%s.x / %s.z) * %s.z);", 1007cb93a386Sopenharmony_ci inDashParams.fsIn(), inDashParams.fsIn(), inDashParams.fsIn(), 1008cb93a386Sopenharmony_ci inDashParams.fsIn()); 1009cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 fragPosShifted = half2(xShifted, half(%s.y));", 1010cb93a386Sopenharmony_ci inDashParams.fsIn()); 1011cb93a386Sopenharmony_ci if (de.fAAMode == AAMode::kCoverage) { 1012cb93a386Sopenharmony_ci // The amount of coverage removed in x and y by the edges is computed as a pair of negative 1013cb93a386Sopenharmony_ci // numbers, xSub and ySub. 1014cb93a386Sopenharmony_ci fragBuilder->codeAppend("half xSub, ySub;"); 1015cb93a386Sopenharmony_ci fragBuilder->codeAppendf("xSub = half(min(fragPosShifted.x - %s.x, 0.0));", 1016cb93a386Sopenharmony_ci inRectParams.fsIn()); 1017cb93a386Sopenharmony_ci fragBuilder->codeAppendf("xSub += half(min(%s.z - fragPosShifted.x, 0.0));", 1018cb93a386Sopenharmony_ci inRectParams.fsIn()); 1019cb93a386Sopenharmony_ci fragBuilder->codeAppendf("ySub = half(min(fragPosShifted.y - %s.y, 0.0));", 1020cb93a386Sopenharmony_ci inRectParams.fsIn()); 1021cb93a386Sopenharmony_ci fragBuilder->codeAppendf("ySub += half(min(%s.w - fragPosShifted.y, 0.0));", 1022cb93a386Sopenharmony_ci inRectParams.fsIn()); 1023cb93a386Sopenharmony_ci // Now compute coverage in x and y and multiply them to get the fraction of the pixel 1024cb93a386Sopenharmony_ci // covered. 1025cb93a386Sopenharmony_ci fragBuilder->codeAppendf( 1026cb93a386Sopenharmony_ci "half alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));"); 1027cb93a386Sopenharmony_ci } else if (de.fAAMode == AAMode::kCoverageWithMSAA) { 1028cb93a386Sopenharmony_ci // For MSAA, we don't modulate the alpha by the Y distance, since MSAA coverage will handle 1029cb93a386Sopenharmony_ci // AA on the the top and bottom edges. The shader is only responsible for intra-dash alpha. 1030cb93a386Sopenharmony_ci fragBuilder->codeAppend("half xSub;"); 1031cb93a386Sopenharmony_ci fragBuilder->codeAppendf("xSub = half(min(fragPosShifted.x - %s.x, 0.0));", 1032cb93a386Sopenharmony_ci inRectParams.fsIn()); 1033cb93a386Sopenharmony_ci fragBuilder->codeAppendf("xSub += half(min(%s.z - fragPosShifted.x, 0.0));", 1034cb93a386Sopenharmony_ci inRectParams.fsIn()); 1035cb93a386Sopenharmony_ci // Now compute coverage in x to get the fraction of the pixel covered. 1036cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half alpha = (1.0 + max(xSub, -1.0));"); 1037cb93a386Sopenharmony_ci } else { 1038cb93a386Sopenharmony_ci // Assuming the bounding geometry is tight so no need to check y values 1039cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half alpha = 1.0;"); 1040cb93a386Sopenharmony_ci fragBuilder->codeAppendf("alpha *= (fragPosShifted.x - %s.x) > -0.5 ? 1.0 : 0.0;", 1041cb93a386Sopenharmony_ci inRectParams.fsIn()); 1042cb93a386Sopenharmony_ci fragBuilder->codeAppendf("alpha *= (%s.z - fragPosShifted.x) >= -0.5 ? 1.0 : 0.0;", 1043cb93a386Sopenharmony_ci inRectParams.fsIn()); 1044cb93a386Sopenharmony_ci } 1045cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 %s = half4(alpha);", args.fOutputCoverage); 1046cb93a386Sopenharmony_ci} 1047cb93a386Sopenharmony_ci 1048cb93a386Sopenharmony_civoid DashingLineEffect::Impl::setData(const GrGLSLProgramDataManager& pdman, 1049cb93a386Sopenharmony_ci const GrShaderCaps& shaderCaps, 1050cb93a386Sopenharmony_ci const GrGeometryProcessor& geomProc) { 1051cb93a386Sopenharmony_ci const DashingLineEffect& de = geomProc.cast<DashingLineEffect>(); 1052cb93a386Sopenharmony_ci if (de.fColor != fColor) { 1053cb93a386Sopenharmony_ci pdman.set4fv(fColorUniform, 1, de.fColor.vec()); 1054cb93a386Sopenharmony_ci fColor = de.fColor; 1055cb93a386Sopenharmony_ci } 1056cb93a386Sopenharmony_ci SetTransform(pdman, shaderCaps, fLocalMatrixUniform, de.fLocalMatrix, &fLocalMatrix); 1057cb93a386Sopenharmony_ci} 1058cb93a386Sopenharmony_ci 1059cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 1060cb93a386Sopenharmony_ci 1061cb93a386Sopenharmony_ciGrGeometryProcessor* DashingLineEffect::Make(SkArenaAlloc* arena, 1062cb93a386Sopenharmony_ci const SkPMColor4f& color, 1063cb93a386Sopenharmony_ci AAMode aaMode, 1064cb93a386Sopenharmony_ci const SkMatrix& localMatrix, 1065cb93a386Sopenharmony_ci bool usesLocalCoords) { 1066cb93a386Sopenharmony_ci return arena->make([&](void* ptr) { 1067cb93a386Sopenharmony_ci return new (ptr) DashingLineEffect(color, aaMode, localMatrix, usesLocalCoords); 1068cb93a386Sopenharmony_ci }); 1069cb93a386Sopenharmony_ci} 1070cb93a386Sopenharmony_ci 1071cb93a386Sopenharmony_ciSkString DashingLineEffect::getShaderDfxInfo() const 1072cb93a386Sopenharmony_ci{ 1073cb93a386Sopenharmony_ci SkString format; 1074cb93a386Sopenharmony_ci format.printf("ShaderDfx_DashingLineEffect_%d_%d_%d_%d_%d", fUsesLocalCoords, fAAMode, 1075cb93a386Sopenharmony_ci fLocalMatrix.isIdentity(), fLocalMatrix.isScaleTranslate(), fLocalMatrix.hasPerspective()); 1076cb93a386Sopenharmony_ci return format; 1077cb93a386Sopenharmony_ci} 1078cb93a386Sopenharmony_ci 1079cb93a386Sopenharmony_civoid DashingLineEffect::addToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { 1080cb93a386Sopenharmony_ci uint32_t key = 0; 1081cb93a386Sopenharmony_ci key |= fUsesLocalCoords ? 0x1 : 0x0; 1082cb93a386Sopenharmony_ci key |= static_cast<int>(fAAMode) << 1; 1083cb93a386Sopenharmony_ci key |= ProgramImpl::ComputeMatrixKey(caps, fLocalMatrix) << 3; 1084cb93a386Sopenharmony_ci b->add32(key); 1085cb93a386Sopenharmony_ci} 1086cb93a386Sopenharmony_ci 1087cb93a386Sopenharmony_cistd::unique_ptr<GrGeometryProcessor::ProgramImpl> DashingLineEffect::makeProgramImpl( 1088cb93a386Sopenharmony_ci const GrShaderCaps&) const { 1089cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 1090cb93a386Sopenharmony_ci} 1091cb93a386Sopenharmony_ci 1092cb93a386Sopenharmony_ciDashingLineEffect::DashingLineEffect(const SkPMColor4f& color, 1093cb93a386Sopenharmony_ci AAMode aaMode, 1094cb93a386Sopenharmony_ci const SkMatrix& localMatrix, 1095cb93a386Sopenharmony_ci bool usesLocalCoords) 1096cb93a386Sopenharmony_ci : INHERITED(kDashingLineEffect_ClassID) 1097cb93a386Sopenharmony_ci , fColor(color) 1098cb93a386Sopenharmony_ci , fLocalMatrix(localMatrix) 1099cb93a386Sopenharmony_ci , fUsesLocalCoords(usesLocalCoords) 1100cb93a386Sopenharmony_ci , fAAMode(aaMode) { 1101cb93a386Sopenharmony_ci fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; 1102cb93a386Sopenharmony_ci fInDashParams = {"inDashParams", kFloat3_GrVertexAttribType, kHalf3_GrSLType}; 1103cb93a386Sopenharmony_ci fInRect = {"inRect", kFloat4_GrVertexAttribType, kHalf4_GrSLType}; 1104cb93a386Sopenharmony_ci this->setVertexAttributes(&fInPosition, 3); 1105cb93a386Sopenharmony_ci} 1106cb93a386Sopenharmony_ci 1107cb93a386Sopenharmony_ciGR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingLineEffect); 1108cb93a386Sopenharmony_ci 1109cb93a386Sopenharmony_ci#if GR_TEST_UTILS 1110cb93a386Sopenharmony_ciGrGeometryProcessor* DashingLineEffect::TestCreate(GrProcessorTestData* d) { 1111cb93a386Sopenharmony_ci AAMode aaMode = static_cast<AAMode>(d->fRandom->nextULessThan(kAAModeCnt)); 1112cb93a386Sopenharmony_ci GrColor color = GrTest::RandomColor(d->fRandom); 1113cb93a386Sopenharmony_ci SkMatrix matrix = GrTest::TestMatrix(d->fRandom); 1114cb93a386Sopenharmony_ci return DashingLineEffect::Make(d->allocator(), 1115cb93a386Sopenharmony_ci SkPMColor4f::FromBytes_RGBA(color), 1116cb93a386Sopenharmony_ci aaMode, 1117cb93a386Sopenharmony_ci matrix, 1118cb93a386Sopenharmony_ci d->fRandom->nextBool()); 1119cb93a386Sopenharmony_ci} 1120cb93a386Sopenharmony_ci 1121cb93a386Sopenharmony_ci#endif 1122cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 1123cb93a386Sopenharmony_ci 1124cb93a386Sopenharmony_ciGrGeometryProcessor* make_dash_gp(SkArenaAlloc* arena, 1125cb93a386Sopenharmony_ci const SkPMColor4f& color, 1126cb93a386Sopenharmony_ci AAMode aaMode, 1127cb93a386Sopenharmony_ci DashCap cap, 1128cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 1129cb93a386Sopenharmony_ci bool usesLocalCoords) { 1130cb93a386Sopenharmony_ci SkMatrix invert; 1131cb93a386Sopenharmony_ci if (usesLocalCoords && !viewMatrix.invert(&invert)) { 1132cb93a386Sopenharmony_ci SkDebugf("Failed to invert\n"); 1133cb93a386Sopenharmony_ci return nullptr; 1134cb93a386Sopenharmony_ci } 1135cb93a386Sopenharmony_ci 1136cb93a386Sopenharmony_ci switch (cap) { 1137cb93a386Sopenharmony_ci case kRound_DashCap: 1138cb93a386Sopenharmony_ci return DashingCircleEffect::Make(arena, color, aaMode, invert, usesLocalCoords); 1139cb93a386Sopenharmony_ci case kNonRound_DashCap: 1140cb93a386Sopenharmony_ci return DashingLineEffect::Make(arena, color, aaMode, invert, usesLocalCoords); 1141cb93a386Sopenharmony_ci } 1142cb93a386Sopenharmony_ci return nullptr; 1143cb93a386Sopenharmony_ci} 1144cb93a386Sopenharmony_ci 1145cb93a386Sopenharmony_ci} // anonymous namespace 1146cb93a386Sopenharmony_ci 1147cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////// 1148cb93a386Sopenharmony_ci 1149cb93a386Sopenharmony_ciGrOp::Owner MakeDashLineOp(GrRecordingContext* context, 1150cb93a386Sopenharmony_ci GrPaint&& paint, 1151cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 1152cb93a386Sopenharmony_ci const SkPoint pts[2], 1153cb93a386Sopenharmony_ci AAMode aaMode, 1154cb93a386Sopenharmony_ci const GrStyle& style, 1155cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) { 1156cb93a386Sopenharmony_ci SkASSERT(CanDrawDashLine(pts, style, viewMatrix)); 1157cb93a386Sopenharmony_ci const SkScalar* intervals = style.dashIntervals(); 1158cb93a386Sopenharmony_ci SkScalar phase = style.dashPhase(); 1159cb93a386Sopenharmony_ci 1160cb93a386Sopenharmony_ci SkPaint::Cap cap = style.strokeRec().getCap(); 1161cb93a386Sopenharmony_ci 1162cb93a386Sopenharmony_ci DashOpImpl::LineData lineData; 1163cb93a386Sopenharmony_ci lineData.fSrcStrokeWidth = style.strokeRec().getWidth(); 1164cb93a386Sopenharmony_ci 1165cb93a386Sopenharmony_ci // the phase should be normalized to be [0, sum of all intervals) 1166cb93a386Sopenharmony_ci SkASSERT(phase >= 0 && phase < intervals[0] + intervals[1]); 1167cb93a386Sopenharmony_ci 1168cb93a386Sopenharmony_ci // Rotate the src pts so they are aligned horizontally with pts[0].fX < pts[1].fX 1169cb93a386Sopenharmony_ci if (pts[0].fY != pts[1].fY || pts[0].fX > pts[1].fX) { 1170cb93a386Sopenharmony_ci SkMatrix rotMatrix; 1171cb93a386Sopenharmony_ci align_to_x_axis(pts, &rotMatrix, lineData.fPtsRot); 1172cb93a386Sopenharmony_ci if (!rotMatrix.invert(&lineData.fSrcRotInv)) { 1173cb93a386Sopenharmony_ci SkDebugf("Failed to create invertible rotation matrix!\n"); 1174cb93a386Sopenharmony_ci return nullptr; 1175cb93a386Sopenharmony_ci } 1176cb93a386Sopenharmony_ci } else { 1177cb93a386Sopenharmony_ci lineData.fSrcRotInv.reset(); 1178cb93a386Sopenharmony_ci memcpy(lineData.fPtsRot, pts, 2 * sizeof(SkPoint)); 1179cb93a386Sopenharmony_ci } 1180cb93a386Sopenharmony_ci 1181cb93a386Sopenharmony_ci // Scale corrections of intervals and stroke from view matrix 1182cb93a386Sopenharmony_ci calc_dash_scaling(&lineData.fParallelScale, &lineData.fPerpendicularScale, viewMatrix, pts); 1183cb93a386Sopenharmony_ci if (SkScalarNearlyZero(lineData.fParallelScale) || 1184cb93a386Sopenharmony_ci SkScalarNearlyZero(lineData.fPerpendicularScale)) { 1185cb93a386Sopenharmony_ci return nullptr; 1186cb93a386Sopenharmony_ci } 1187cb93a386Sopenharmony_ci 1188cb93a386Sopenharmony_ci SkScalar offInterval = intervals[1] * lineData.fParallelScale; 1189cb93a386Sopenharmony_ci SkScalar strokeWidth = lineData.fSrcStrokeWidth * lineData.fPerpendicularScale; 1190cb93a386Sopenharmony_ci 1191cb93a386Sopenharmony_ci if (SkPaint::kSquare_Cap == cap && 0 != lineData.fSrcStrokeWidth) { 1192cb93a386Sopenharmony_ci // add cap to on interval and remove from off interval 1193cb93a386Sopenharmony_ci offInterval -= strokeWidth; 1194cb93a386Sopenharmony_ci } 1195cb93a386Sopenharmony_ci 1196cb93a386Sopenharmony_ci // TODO we can do a real rect call if not using fulldash(ie no off interval, not using AA) 1197cb93a386Sopenharmony_ci bool fullDash = offInterval > 0.f || aaMode != AAMode::kNone; 1198cb93a386Sopenharmony_ci 1199cb93a386Sopenharmony_ci lineData.fViewMatrix = viewMatrix; 1200cb93a386Sopenharmony_ci lineData.fPhase = phase; 1201cb93a386Sopenharmony_ci lineData.fIntervals[0] = intervals[0]; 1202cb93a386Sopenharmony_ci lineData.fIntervals[1] = intervals[1]; 1203cb93a386Sopenharmony_ci 1204cb93a386Sopenharmony_ci return DashOpImpl::Make(context, std::move(paint), lineData, cap, aaMode, fullDash, 1205cb93a386Sopenharmony_ci stencilSettings); 1206cb93a386Sopenharmony_ci} 1207cb93a386Sopenharmony_ci 1208cb93a386Sopenharmony_ci// Returns whether or not the gpu can fast path the dash line effect. 1209cb93a386Sopenharmony_cibool CanDrawDashLine(const SkPoint pts[2], const GrStyle& style, const SkMatrix& viewMatrix) { 1210cb93a386Sopenharmony_ci // Pts must be either horizontal or vertical in src space 1211cb93a386Sopenharmony_ci if (pts[0].fX != pts[1].fX && pts[0].fY != pts[1].fY) { 1212cb93a386Sopenharmony_ci return false; 1213cb93a386Sopenharmony_ci } 1214cb93a386Sopenharmony_ci 1215cb93a386Sopenharmony_ci // May be able to relax this to include skew. As of now cannot do perspective 1216cb93a386Sopenharmony_ci // because of the non uniform scaling of bloating a rect 1217cb93a386Sopenharmony_ci if (!viewMatrix.preservesRightAngles()) { 1218cb93a386Sopenharmony_ci return false; 1219cb93a386Sopenharmony_ci } 1220cb93a386Sopenharmony_ci 1221cb93a386Sopenharmony_ci if (!style.isDashed() || 2 != style.dashIntervalCnt()) { 1222cb93a386Sopenharmony_ci return false; 1223cb93a386Sopenharmony_ci } 1224cb93a386Sopenharmony_ci 1225cb93a386Sopenharmony_ci const SkScalar* intervals = style.dashIntervals(); 1226cb93a386Sopenharmony_ci if (0 == intervals[0] && 0 == intervals[1]) { 1227cb93a386Sopenharmony_ci return false; 1228cb93a386Sopenharmony_ci } 1229cb93a386Sopenharmony_ci 1230cb93a386Sopenharmony_ci SkPaint::Cap cap = style.strokeRec().getCap(); 1231cb93a386Sopenharmony_ci if (SkPaint::kRound_Cap == cap) { 1232cb93a386Sopenharmony_ci // Current we don't support round caps unless the on interval is zero 1233cb93a386Sopenharmony_ci if (intervals[0] != 0.f) { 1234cb93a386Sopenharmony_ci return false; 1235cb93a386Sopenharmony_ci } 1236cb93a386Sopenharmony_ci // If the width of the circle caps in greater than the off interval we will pick up unwanted 1237cb93a386Sopenharmony_ci // segments of circles at the start and end of the dash line. 1238cb93a386Sopenharmony_ci if (style.strokeRec().getWidth() > intervals[1]) { 1239cb93a386Sopenharmony_ci return false; 1240cb93a386Sopenharmony_ci } 1241cb93a386Sopenharmony_ci } 1242cb93a386Sopenharmony_ci 1243cb93a386Sopenharmony_ci return true; 1244cb93a386Sopenharmony_ci} 1245cb93a386Sopenharmony_ci 1246cb93a386Sopenharmony_ci} // namespace skgpu::v1::DashOp 1247cb93a386Sopenharmony_ci 1248cb93a386Sopenharmony_ci#if GR_TEST_UTILS 1249cb93a386Sopenharmony_ci 1250cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h" 1251cb93a386Sopenharmony_ci 1252cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(DashOpImpl) { 1253cb93a386Sopenharmony_ci SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random); 1254cb93a386Sopenharmony_ci AAMode aaMode; 1255cb93a386Sopenharmony_ci do { 1256cb93a386Sopenharmony_ci aaMode = static_cast<AAMode>(random->nextULessThan(kAAModeCnt)); 1257cb93a386Sopenharmony_ci } while (AAMode::kCoverageWithMSAA == aaMode && numSamples <= 1); 1258cb93a386Sopenharmony_ci 1259cb93a386Sopenharmony_ci // We can only dash either horizontal or vertical lines 1260cb93a386Sopenharmony_ci SkPoint pts[2]; 1261cb93a386Sopenharmony_ci if (random->nextBool()) { 1262cb93a386Sopenharmony_ci // vertical 1263cb93a386Sopenharmony_ci pts[0].fX = 1.f; 1264cb93a386Sopenharmony_ci pts[0].fY = random->nextF() * 10.f; 1265cb93a386Sopenharmony_ci pts[1].fX = 1.f; 1266cb93a386Sopenharmony_ci pts[1].fY = random->nextF() * 10.f; 1267cb93a386Sopenharmony_ci } else { 1268cb93a386Sopenharmony_ci // horizontal 1269cb93a386Sopenharmony_ci pts[0].fX = random->nextF() * 10.f; 1270cb93a386Sopenharmony_ci pts[0].fY = 1.f; 1271cb93a386Sopenharmony_ci pts[1].fX = random->nextF() * 10.f; 1272cb93a386Sopenharmony_ci pts[1].fY = 1.f; 1273cb93a386Sopenharmony_ci } 1274cb93a386Sopenharmony_ci 1275cb93a386Sopenharmony_ci // pick random cap 1276cb93a386Sopenharmony_ci SkPaint::Cap cap = SkPaint::Cap(random->nextULessThan(SkPaint::kCapCount)); 1277cb93a386Sopenharmony_ci 1278cb93a386Sopenharmony_ci SkScalar intervals[2]; 1279cb93a386Sopenharmony_ci 1280cb93a386Sopenharmony_ci // We can only dash with the following intervals 1281cb93a386Sopenharmony_ci enum Intervals { 1282cb93a386Sopenharmony_ci kOpenOpen_Intervals , 1283cb93a386Sopenharmony_ci kOpenClose_Intervals, 1284cb93a386Sopenharmony_ci kCloseOpen_Intervals, 1285cb93a386Sopenharmony_ci }; 1286cb93a386Sopenharmony_ci 1287cb93a386Sopenharmony_ci Intervals intervalType = SkPaint::kRound_Cap == cap ? 1288cb93a386Sopenharmony_ci kOpenClose_Intervals : 1289cb93a386Sopenharmony_ci Intervals(random->nextULessThan(kCloseOpen_Intervals + 1)); 1290cb93a386Sopenharmony_ci static const SkScalar kIntervalMin = 0.1f; 1291cb93a386Sopenharmony_ci static const SkScalar kIntervalMinCircles = 1.f; // Must be >= to stroke width 1292cb93a386Sopenharmony_ci static const SkScalar kIntervalMax = 10.f; 1293cb93a386Sopenharmony_ci switch (intervalType) { 1294cb93a386Sopenharmony_ci case kOpenOpen_Intervals: 1295cb93a386Sopenharmony_ci intervals[0] = random->nextRangeScalar(kIntervalMin, kIntervalMax); 1296cb93a386Sopenharmony_ci intervals[1] = random->nextRangeScalar(kIntervalMin, kIntervalMax); 1297cb93a386Sopenharmony_ci break; 1298cb93a386Sopenharmony_ci case kOpenClose_Intervals: { 1299cb93a386Sopenharmony_ci intervals[0] = 0.f; 1300cb93a386Sopenharmony_ci SkScalar min = SkPaint::kRound_Cap == cap ? kIntervalMinCircles : kIntervalMin; 1301cb93a386Sopenharmony_ci intervals[1] = random->nextRangeScalar(min, kIntervalMax); 1302cb93a386Sopenharmony_ci break; 1303cb93a386Sopenharmony_ci } 1304cb93a386Sopenharmony_ci case kCloseOpen_Intervals: 1305cb93a386Sopenharmony_ci intervals[0] = random->nextRangeScalar(kIntervalMin, kIntervalMax); 1306cb93a386Sopenharmony_ci intervals[1] = 0.f; 1307cb93a386Sopenharmony_ci break; 1308cb93a386Sopenharmony_ci 1309cb93a386Sopenharmony_ci } 1310cb93a386Sopenharmony_ci 1311cb93a386Sopenharmony_ci // phase is 0 < sum (i0, i1) 1312cb93a386Sopenharmony_ci SkScalar phase = random->nextRangeScalar(0, intervals[0] + intervals[1]); 1313cb93a386Sopenharmony_ci 1314cb93a386Sopenharmony_ci SkPaint p; 1315cb93a386Sopenharmony_ci p.setStyle(SkPaint::kStroke_Style); 1316cb93a386Sopenharmony_ci p.setStrokeWidth(SkIntToScalar(1)); 1317cb93a386Sopenharmony_ci p.setStrokeCap(cap); 1318cb93a386Sopenharmony_ci p.setPathEffect(GrTest::TestDashPathEffect::Make(intervals, 2, phase)); 1319cb93a386Sopenharmony_ci 1320cb93a386Sopenharmony_ci GrStyle style(p); 1321cb93a386Sopenharmony_ci 1322cb93a386Sopenharmony_ci return skgpu::v1::DashOp::MakeDashLineOp(context, std::move(paint), viewMatrix, pts, aaMode, 1323cb93a386Sopenharmony_ci style, GrGetRandomStencil(random, context)); 1324cb93a386Sopenharmony_ci} 1325cb93a386Sopenharmony_ci 1326cb93a386Sopenharmony_ci#endif // GR_TEST_UTILS 1327