Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2017 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #include "GrCCPRCoverageProcessor.h" |
| 9 | |
Robert Phillips | 2890fbf | 2017-07-26 15:48:41 -0400 | [diff] [blame] | 10 | #include "GrRenderTargetProxy.h" |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 11 | #include "ccpr/GrCCPRTriangleProcessor.h" |
| 12 | #include "ccpr/GrCCPRQuadraticProcessor.h" |
| 13 | #include "ccpr/GrCCPRCubicProcessor.h" |
| 14 | #include "glsl/GrGLSLFragmentShaderBuilder.h" |
| 15 | #include "glsl/GrGLSLGeometryShaderBuilder.h" |
| 16 | #include "glsl/GrGLSLProgramBuilder.h" |
| 17 | #include "glsl/GrGLSLVertexShaderBuilder.h" |
| 18 | |
| 19 | const char* GrCCPRCoverageProcessor::GetProcessorName(Mode mode) { |
| 20 | switch (mode) { |
| 21 | case Mode::kTriangleHulls: |
| 22 | return "GrCCPRTriangleHullAndEdgeProcessor (hulls)"; |
| 23 | case Mode::kTriangleEdges: |
| 24 | return "GrCCPRTriangleHullAndEdgeProcessor (edges)"; |
| 25 | case Mode::kCombinedTriangleHullsAndEdges: |
| 26 | return "GrCCPRTriangleHullAndEdgeProcessor (combined hulls & edges)"; |
| 27 | case Mode::kTriangleCorners: |
| 28 | return "GrCCPRTriangleCornerProcessor"; |
| 29 | case Mode::kQuadraticHulls: |
| 30 | return "GrCCPRQuadraticHullProcessor"; |
Chris Dalton | b072bb6 | 2017-08-07 09:00:46 -0600 | [diff] [blame] | 31 | case Mode::kQuadraticCorners: |
| 32 | return "GrCCPRQuadraticCornerProcessor"; |
Chris Dalton | 7f578bf | 2017-09-05 16:46:48 -0600 | [diff] [blame] | 33 | case Mode::kSerpentineHulls: |
| 34 | return "GrCCPRCubicHullProcessor (serpentine)"; |
| 35 | case Mode::kLoopHulls: |
| 36 | return "GrCCPRCubicHullProcessor (loop)"; |
| 37 | case Mode::kSerpentineCorners: |
| 38 | return "GrCCPRCubicCornerProcessor (serpentine)"; |
| 39 | case Mode::kLoopCorners: |
| 40 | return "GrCCPRCubicCornerProcessor (loop)"; |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 41 | } |
Ben Wagner | b4aab9a | 2017-08-16 10:53:04 -0400 | [diff] [blame] | 42 | SK_ABORT("Unexpected ccpr coverage processor mode."); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 43 | return nullptr; |
| 44 | } |
| 45 | |
| 46 | GrCCPRCoverageProcessor::GrCCPRCoverageProcessor(Mode mode, GrBuffer* pointsBuffer) |
| 47 | : fMode(mode) |
Chris Dalton | c1e5963 | 2017-09-05 00:30:07 -0600 | [diff] [blame] | 48 | , fInstanceAttrib(this->addInstanceAttrib("instance", InstanceArrayFormat(mode), |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 49 | kHigh_GrSLPrecision)) { |
| 50 | fPointsBufferAccess.reset(kRG_float_GrPixelConfig, pointsBuffer, kVertex_GrShaderFlag); |
| 51 | this->addBufferAccess(&fPointsBufferAccess); |
| 52 | |
| 53 | this->setWillUseGeoShader(); |
| 54 | |
| 55 | this->initClassID<GrCCPRCoverageProcessor>(); |
| 56 | } |
| 57 | |
| 58 | void GrCCPRCoverageProcessor::getGLSLProcessorKey(const GrShaderCaps&, |
| 59 | GrProcessorKeyBuilder* b) const { |
| 60 | b->add32(int(fMode)); |
| 61 | } |
| 62 | |
| 63 | GrGLSLPrimitiveProcessor* GrCCPRCoverageProcessor::createGLSLInstance(const GrShaderCaps&) const { |
| 64 | switch (fMode) { |
| 65 | using GeometryType = GrCCPRTriangleHullAndEdgeProcessor::GeometryType; |
| 66 | |
| 67 | case Mode::kTriangleHulls: |
| 68 | return new GrCCPRTriangleHullAndEdgeProcessor(GeometryType::kHulls); |
| 69 | case Mode::kTriangleEdges: |
| 70 | return new GrCCPRTriangleHullAndEdgeProcessor(GeometryType::kEdges); |
| 71 | case Mode::kCombinedTriangleHullsAndEdges: |
| 72 | return new GrCCPRTriangleHullAndEdgeProcessor(GeometryType::kHullsAndEdges); |
| 73 | case Mode::kTriangleCorners: |
| 74 | return new GrCCPRTriangleCornerProcessor(); |
| 75 | case Mode::kQuadraticHulls: |
| 76 | return new GrCCPRQuadraticHullProcessor(); |
Chris Dalton | b072bb6 | 2017-08-07 09:00:46 -0600 | [diff] [blame] | 77 | case Mode::kQuadraticCorners: |
| 78 | return new GrCCPRQuadraticCornerProcessor(); |
Chris Dalton | 7f578bf | 2017-09-05 16:46:48 -0600 | [diff] [blame] | 79 | case Mode::kSerpentineHulls: |
| 80 | return new GrCCPRCubicHullProcessor(GrCCPRCubicProcessor::CubicType::kSerpentine); |
| 81 | case Mode::kLoopHulls: |
| 82 | return new GrCCPRCubicHullProcessor(GrCCPRCubicProcessor::CubicType::kLoop); |
| 83 | case Mode::kSerpentineCorners: |
| 84 | return new GrCCPRCubicCornerProcessor(GrCCPRCubicProcessor::CubicType::kSerpentine); |
| 85 | case Mode::kLoopCorners: |
| 86 | return new GrCCPRCubicCornerProcessor(GrCCPRCubicProcessor::CubicType::kLoop); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 87 | } |
Ben Wagner | b4aab9a | 2017-08-16 10:53:04 -0400 | [diff] [blame] | 88 | SK_ABORT("Unexpected ccpr coverage processor mode."); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 89 | return nullptr; |
| 90 | } |
| 91 | |
| 92 | using PrimitiveProcessor = GrCCPRCoverageProcessor::PrimitiveProcessor; |
| 93 | |
| 94 | void PrimitiveProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { |
| 95 | const GrCCPRCoverageProcessor& proc = args.fGP.cast<GrCCPRCoverageProcessor>(); |
| 96 | |
| 97 | GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; |
| 98 | switch (fCoverageType) { |
| 99 | case CoverageType::kOne: |
| 100 | case CoverageType::kShader: |
| 101 | varyingHandler->addFlatVarying("wind", &fFragWind, kLow_GrSLPrecision); |
| 102 | break; |
| 103 | case CoverageType::kInterpolated: |
| 104 | varyingHandler->addVarying("coverage_times_wind", &fFragCoverageTimesWind, |
| 105 | kMedium_GrSLPrecision); |
| 106 | break; |
| 107 | } |
| 108 | this->resetVaryings(varyingHandler); |
| 109 | |
| 110 | varyingHandler->emitAttributes(proc); |
| 111 | |
| 112 | this->emitVertexShader(proc, args.fVertBuilder, args.fTexelBuffers[0], args.fRTAdjustName, |
| 113 | gpArgs); |
| 114 | this->emitGeometryShader(proc, args.fGeomBuilder, args.fRTAdjustName); |
| 115 | this->emitCoverage(proc, args.fFragBuilder, args.fOutputColor, args.fOutputCoverage); |
| 116 | |
| 117 | SkASSERT(!args.fFPCoordTransformHandler->nextCoordTransform()); |
| 118 | } |
| 119 | |
| 120 | void PrimitiveProcessor::emitVertexShader(const GrCCPRCoverageProcessor& proc, |
| 121 | GrGLSLVertexBuilder* v, |
| 122 | const TexelBufferHandle& pointsBuffer, |
| 123 | const char* rtAdjust, GrGPArgs* gpArgs) const { |
Chris Dalton | c1e5963 | 2017-09-05 00:30:07 -0600 | [diff] [blame] | 124 | v->codeAppendf("int packedoffset = %s[%i];", proc.instanceAttrib(), proc.atlasOffsetIdx()); |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 125 | v->codeAppend ("highp float2 atlasoffset = float2((packedoffset<<16) >> 16, " |
| 126 | "packedoffset >> 16);"); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 127 | |
| 128 | this->onEmitVertexShader(proc, v, pointsBuffer, "atlasoffset", rtAdjust, gpArgs); |
| 129 | } |
| 130 | |
| 131 | void PrimitiveProcessor::emitGeometryShader(const GrCCPRCoverageProcessor& proc, |
| 132 | GrGLSLGeometryBuilder* g, const char* rtAdjust) const { |
| 133 | g->declareGlobal(fGeomWind); |
| 134 | this->emitWind(g, rtAdjust, fGeomWind.c_str()); |
| 135 | |
| 136 | SkString emitVertexFn; |
| 137 | SkSTArray<2, GrShaderVar> emitArgs; |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 138 | const char* position = emitArgs.emplace_back("position", kVec2f_GrSLType, |
| 139 | GrShaderVar::kNonArray, |
| 140 | kHigh_GrSLPrecision).c_str(); |
| 141 | const char* coverage = emitArgs.emplace_back("coverage", kFloat_GrSLType, |
| 142 | GrShaderVar::kNonArray, |
| 143 | kHigh_GrSLPrecision).c_str(); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 144 | g->emitFunction(kVoid_GrSLType, "emitVertex", emitArgs.count(), emitArgs.begin(), [&]() { |
| 145 | SkString fnBody; |
| 146 | this->emitPerVertexGeometryCode(&fnBody, position, coverage, fGeomWind.c_str()); |
| 147 | if (fFragWind.gsOut()) { |
| 148 | fnBody.appendf("%s = %s;", fFragWind.gsOut(), fGeomWind.c_str()); |
| 149 | } |
| 150 | if (fFragCoverageTimesWind.gsOut()) { |
| 151 | fnBody.appendf("%s = %s * %s;", |
| 152 | fFragCoverageTimesWind.gsOut(), coverage, fGeomWind.c_str()); |
| 153 | } |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 154 | fnBody.append ("gl_Position = float4(position, 0, 1);"); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 155 | fnBody.append ("EmitVertex();"); |
| 156 | return fnBody; |
| 157 | }().c_str(), &emitVertexFn); |
| 158 | |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 159 | g->codeAppendf("highp float2 bloat = %f * abs(%s.xz);", kAABloatRadius, rtAdjust); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 160 | |
| 161 | #ifdef SK_DEBUG |
| 162 | if (proc.debugVisualizations()) { |
| 163 | g->codeAppendf("bloat *= %f;", GrCCPRCoverageProcessor::kDebugBloat); |
| 164 | } |
| 165 | #endif |
| 166 | |
| 167 | return this->onEmitGeometryShader(g, emitVertexFn.c_str(), fGeomWind.c_str(), rtAdjust); |
| 168 | } |
| 169 | |
| 170 | int PrimitiveProcessor::emitHullGeometry(GrGLSLGeometryBuilder* g, const char* emitVertexFn, |
| 171 | const char* polygonPts, int numSides, |
Chris Dalton | 7f578bf | 2017-09-05 16:46:48 -0600 | [diff] [blame] | 172 | const char* wedgeIdx, const char* midpoint) const { |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 173 | SkASSERT(numSides >= 3); |
| 174 | |
Chris Dalton | 7f578bf | 2017-09-05 16:46:48 -0600 | [diff] [blame] | 175 | if (!midpoint) { |
| 176 | g->codeAppendf("highp float2 midpoint = %s * float%i(%f);", |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 177 | polygonPts, numSides, 1.0 / numSides); |
Chris Dalton | 7f578bf | 2017-09-05 16:46:48 -0600 | [diff] [blame] | 178 | midpoint = "midpoint"; |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 179 | } |
| 180 | |
| 181 | g->codeAppendf("int previdx = (%s + %i) %% %i, " |
| 182 | "nextidx = (%s + 1) %% %i;", |
| 183 | wedgeIdx, numSides - 1, numSides, wedgeIdx, numSides); |
| 184 | |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 185 | g->codeAppendf("highp float2 self = %s[%s];" |
| 186 | "highp int leftidx = %s > 0 ? previdx : nextidx;" |
| 187 | "highp int rightidx = %s > 0 ? nextidx : previdx;", |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 188 | polygonPts, wedgeIdx, fGeomWind.c_str(), fGeomWind.c_str()); |
| 189 | |
| 190 | // Which quadrant does the vector from self -> right fall into? |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 191 | g->codeAppendf("highp float2 right = %s[rightidx];", polygonPts); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 192 | if (3 == numSides) { |
| 193 | // TODO: evaluate perf gains. |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 194 | g->codeAppend ("highp float2 qsr = sign(right - self);"); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 195 | } else { |
| 196 | SkASSERT(4 == numSides); |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 197 | g->codeAppendf("highp float2 diag = %s[(%s + 2) %% 4];", polygonPts, wedgeIdx); |
| 198 | g->codeAppend ("highp float2 qsr = sign((right != self ? right : diag) - self);"); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 199 | } |
| 200 | |
| 201 | // Which quadrant does the vector from left -> self fall into? |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 202 | g->codeAppendf("highp float2 qls = sign(self - %s[leftidx]);", polygonPts); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 203 | |
| 204 | // d2 just helps us reduce triangle counts with orthogonal, axis-aligned lines. |
| 205 | // TODO: evaluate perf gains. |
| 206 | const char* dr2 = "dr"; |
| 207 | if (3 == numSides) { |
| 208 | // TODO: evaluate perf gains. |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 209 | g->codeAppend ("highp float2 dr = float2(qsr.y != 0 ? +qsr.y : +qsr.x, " |
| 210 | "qsr.x != 0 ? -qsr.x : +qsr.y);"); |
| 211 | g->codeAppend ("highp float2 dr2 = float2(qsr.y != 0 ? +qsr.y : -qsr.x, " |
| 212 | "qsr.x != 0 ? -qsr.x : -qsr.y);"); |
| 213 | g->codeAppend ("highp float2 dl = float2(qls.y != 0 ? +qls.y : +qls.x, " |
| 214 | "qls.x != 0 ? -qls.x : +qls.y);"); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 215 | dr2 = "dr2"; |
| 216 | } else { |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 217 | g->codeAppend ("highp float2 dr = float2(qsr.y != 0 ? +qsr.y : 1, " |
| 218 | "qsr.x != 0 ? -qsr.x : 1);"); |
| 219 | g->codeAppend ("highp float2 dl = (qls == float2(0)) ? dr : " |
| 220 | "float2(qls.y != 0 ? +qls.y : 1, qls.x != 0 ? -qls.x : 1);"); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 221 | } |
Ethan Nicholas | 5af9ea3 | 2017-07-28 15:19:46 -0400 | [diff] [blame] | 222 | g->codeAppendf("bool2 dnotequal = notEqual(%s, dl);", dr2); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 223 | |
| 224 | // Emit one third of what is the convex hull of pixel-size boxes centered on the vertices. |
| 225 | // Each invocation emits a different third. |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 226 | g->codeAppendf("%s(right + bloat * dr, 1);", emitVertexFn); |
Chris Dalton | 7f578bf | 2017-09-05 16:46:48 -0600 | [diff] [blame] | 227 | g->codeAppendf("%s(%s, 1);", emitVertexFn, midpoint); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 228 | g->codeAppendf("%s(self + bloat * %s, 1);", emitVertexFn, dr2); |
| 229 | g->codeAppend ("if (any(dnotequal)) {"); |
| 230 | g->codeAppendf( "%s(self + bloat * dl, 1);", emitVertexFn); |
| 231 | g->codeAppend ("}"); |
| 232 | g->codeAppend ("if (all(dnotequal)) {"); |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 233 | g->codeAppendf( "%s(self + bloat * float2(-dl.y, dl.x), 1);", emitVertexFn); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 234 | g->codeAppend ("}"); |
| 235 | g->codeAppend ("EndPrimitive();"); |
| 236 | |
Chris Dalton | 7f578bf | 2017-09-05 16:46:48 -0600 | [diff] [blame] | 237 | return 5; |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 238 | } |
| 239 | |
| 240 | int PrimitiveProcessor::emitEdgeGeometry(GrGLSLGeometryBuilder* g, const char* emitVertexFn, |
| 241 | const char* leftPt, const char* rightPt, |
| 242 | const char* distanceEquation) const { |
| 243 | if (!distanceEquation) { |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 244 | this->emitEdgeDistanceEquation(g, leftPt, rightPt, "highp float3 edge_distance_equation"); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 245 | distanceEquation = "edge_distance_equation"; |
| 246 | } |
| 247 | |
| 248 | // qlr is defined in emitEdgeDistanceEquation. |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 249 | g->codeAppendf("highp float2x2 endpts = float2x2(%s - bloat * qlr, %s + bloat * qlr);", |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 250 | leftPt, rightPt); |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 251 | g->codeAppendf("mediump float2 endpts_coverage = %s.xy * endpts + %s.z;", |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 252 | distanceEquation, distanceEquation); |
| 253 | |
| 254 | // d1 is defined in emitEdgeDistanceEquation. |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 255 | g->codeAppend ("highp float2 d2 = d1;"); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 256 | g->codeAppend ("bool aligned = qlr.x == 0 || qlr.y == 0;"); |
| 257 | g->codeAppend ("if (aligned) {"); |
| 258 | g->codeAppend ( "d1 -= qlr;"); |
| 259 | g->codeAppend ( "d2 += qlr;"); |
| 260 | g->codeAppend ("}"); |
| 261 | |
| 262 | // Emit the convex hull of 2 pixel-size boxes centered on the endpoints of the edge. Each |
| 263 | // invocation emits a different edge. Emit negative coverage that subtracts the appropiate |
| 264 | // amount back out from the hull we drew above. |
| 265 | g->codeAppend ("if (!aligned) {"); |
| 266 | g->codeAppendf( "%s(endpts[0], endpts_coverage[0]);", emitVertexFn); |
| 267 | g->codeAppend ("}"); |
| 268 | g->codeAppendf("%s(%s + bloat * d1, -1);", emitVertexFn, leftPt); |
| 269 | g->codeAppendf("%s(%s - bloat * d2, 0);", emitVertexFn, leftPt); |
| 270 | g->codeAppendf("%s(%s + bloat * d2, -1);", emitVertexFn, rightPt); |
| 271 | g->codeAppendf("%s(%s - bloat * d1, 0);", emitVertexFn, rightPt); |
| 272 | g->codeAppend ("if (!aligned) {"); |
| 273 | g->codeAppendf( "%s(endpts[1], endpts_coverage[1]);", emitVertexFn); |
| 274 | g->codeAppend ("}"); |
| 275 | g->codeAppend ("EndPrimitive();"); |
| 276 | |
| 277 | return 6; |
| 278 | } |
| 279 | |
| 280 | void PrimitiveProcessor::emitEdgeDistanceEquation(GrGLSLGeometryBuilder* g, |
| 281 | const char* leftPt, const char* rightPt, |
| 282 | const char* outputDistanceEquation) const { |
| 283 | // Which quadrant does the vector from left -> right fall into? |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 284 | g->codeAppendf("highp float2 qlr = sign(%s - %s);", rightPt, leftPt); |
| 285 | g->codeAppend ("highp float2 d1 = float2(qlr.y, -qlr.x);"); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 286 | |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 287 | g->codeAppendf("highp float2 n = float2(%s.y - %s.y, %s.x - %s.x);", |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 288 | rightPt, leftPt, leftPt, rightPt); |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 289 | g->codeAppendf("highp float2 kk = n * float2x2(%s + bloat * d1, %s - bloat * d1);", |
Ethan Nicholas | 5af9ea3 | 2017-07-28 15:19:46 -0400 | [diff] [blame] | 290 | leftPt, leftPt); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 291 | // Clamp for when n=0. wind=0 when n=0 so as long as we don't get Inf or NaN we are fine. |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 292 | g->codeAppendf("highp float scale = 1 / max(kk[0] - kk[1], 1e-30);"); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 293 | |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 294 | g->codeAppendf("%s = float3(-n, kk[1]) * scale;", outputDistanceEquation); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 295 | } |
| 296 | |
Chris Dalton | b072bb6 | 2017-08-07 09:00:46 -0600 | [diff] [blame] | 297 | int PrimitiveProcessor::emitCornerGeometry(GrGLSLGeometryBuilder* g, const char* emitVertexFn, |
| 298 | const char* pt) const { |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 299 | g->codeAppendf("%s(%s + float2(-bloat.x, -bloat.y), 1);", emitVertexFn, pt); |
| 300 | g->codeAppendf("%s(%s + float2(-bloat.x, +bloat.y), 1);", emitVertexFn, pt); |
| 301 | g->codeAppendf("%s(%s + float2(+bloat.x, -bloat.y), 1);", emitVertexFn, pt); |
| 302 | g->codeAppendf("%s(%s + float2(+bloat.x, +bloat.y), 1);", emitVertexFn, pt); |
Chris Dalton | b072bb6 | 2017-08-07 09:00:46 -0600 | [diff] [blame] | 303 | g->codeAppend ("EndPrimitive();"); |
| 304 | |
| 305 | return 4; |
| 306 | } |
| 307 | |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 308 | void PrimitiveProcessor::emitCoverage(const GrCCPRCoverageProcessor& proc, GrGLSLFragmentBuilder* f, |
| 309 | const char* outputColor, const char* outputCoverage) const { |
| 310 | switch (fCoverageType) { |
| 311 | case CoverageType::kOne: |
| 312 | f->codeAppendf("%s.a = %s;", outputColor, fFragWind.fsIn()); |
| 313 | break; |
| 314 | case CoverageType::kInterpolated: |
| 315 | f->codeAppendf("%s.a = %s;", outputColor, fFragCoverageTimesWind.fsIn()); |
| 316 | break; |
| 317 | case CoverageType::kShader: |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 318 | f->codeAppendf("mediump float coverage = 0;"); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 319 | this->emitShaderCoverage(f, "coverage"); |
| 320 | f->codeAppendf("%s.a = coverage * %s;", outputColor, fFragWind.fsIn()); |
| 321 | break; |
| 322 | } |
| 323 | |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 324 | f->codeAppendf("%s = float4(1);", outputCoverage); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 325 | |
| 326 | #ifdef SK_DEBUG |
| 327 | if (proc.debugVisualizations()) { |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 328 | f->codeAppendf("%s = float4(-%s.a, %s.a, 0, 1);", outputColor, outputColor, outputColor); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 329 | } |
| 330 | #endif |
| 331 | } |
| 332 | |
| 333 | int PrimitiveProcessor::defineSoftSampleLocations(GrGLSLFragmentBuilder* f, |
| 334 | const char* samplesName) const { |
| 335 | // Standard DX11 sample locations. |
| 336 | #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS) |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 337 | f->defineConstant("highp float2[8]", samplesName, "float2[8](" |
| 338 | "float2(+1, -3)/16, float2(-1, +3)/16, float2(+5, +1)/16, float2(-3, -5)/16, " |
| 339 | "float2(-5, +5)/16, float2(-7, -1)/16, float2(+3, +7)/16, float2(+7, -7)/16." |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 340 | ")"); |
| 341 | return 8; |
| 342 | #else |
Brian Salomon | 1d816b9 | 2017-08-17 11:07:59 -0400 | [diff] [blame] | 343 | f->defineConstant("highp float2[16]", samplesName, "float2[16](" |
| 344 | "float2(+1, +1)/16, float2(-1, -3)/16, float2(-3, +2)/16, float2(+4, -1)/16, " |
| 345 | "float2(-5, -2)/16, float2(+2, +5)/16, float2(+5, +3)/16, float2(+3, -5)/16, " |
| 346 | "float2(-2, +6)/16, float2( 0, -7)/16, float2(-4, -6)/16, float2(-6, +4)/16, " |
| 347 | "float2(-8, 0)/16, float2(+7, -4)/16, float2(+6, +7)/16, float2(-7, -8)/16." |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 348 | ")"); |
| 349 | return 16; |
| 350 | #endif |
| 351 | } |
| 352 | |
| 353 | #ifdef SK_DEBUG |
| 354 | |
| 355 | #include "GrRenderTarget.h" |
| 356 | |
Robert Phillips | 2890fbf | 2017-07-26 15:48:41 -0400 | [diff] [blame] | 357 | void GrCCPRCoverageProcessor::Validate(GrRenderTargetProxy* atlasProxy) { |
| 358 | SkASSERT(kAtlasOrigin == atlasProxy->origin()); |
| 359 | SkASSERT(GrPixelConfigIsAlphaOnly(atlasProxy->config())); |
| 360 | SkASSERT(GrPixelConfigIsFloatingPoint(atlasProxy->config())); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 361 | } |
| 362 | |
| 363 | #endif |