| 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 "src/gpu/ccpr/GrVSCoverageProcessor.h" |
| 9 | |
| 10 | #include "src/gpu/GrOpsRenderPass.h" |
| 11 | #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
| 12 | #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" |
| 13 | |
| 14 | // This class implements the coverage processor with vertex shaders. |
| 15 | class GrVSCoverageProcessor::Impl : public GrGLSLGeometryProcessor { |
| 16 | public: |
| 17 | Impl(std::unique_ptr<Shader> shader, int numSides) |
| 18 | : fShader(std::move(shader)), fNumSides(numSides) {} |
| 19 | |
| 20 | private: |
| 21 | void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&, |
| 22 | const CoordTransformRange& transformRange) final { |
| 23 | this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); |
| 24 | } |
| 25 | |
| 26 | void onEmitCode(EmitArgs&, GrGPArgs*) override; |
| 27 | |
| 28 | const std::unique_ptr<Shader> fShader; |
| 29 | const int fNumSides; |
| 30 | }; |
| 31 | |
| 32 | static constexpr int kInstanceAttribIdx_X = 0; // Transposed X values of all input points. |
| 33 | static constexpr int kInstanceAttribIdx_Y = 1; // Transposed Y values of all input points. |
| 34 | |
| 35 | // Vertex data tells the shader how to offset vertices for conservative raster, as well as how to |
| 36 | // calculate coverage values for corners and edges. |
| 37 | static constexpr int kVertexData_LeftNeighborIdShift = 10; |
| 38 | static constexpr int kVertexData_RightNeighborIdShift = 8; |
| 39 | static constexpr int kVertexData_BloatIdxShift = 6; |
| 40 | static constexpr int kVertexData_InvertNegativeCoverageBit = 1 << 5; |
| 41 | static constexpr int kVertexData_IsCornerBit = 1 << 4; |
| 42 | static constexpr int kVertexData_IsEdgeBit = 1 << 3; |
| 43 | static constexpr int kVertexData_IsHullBit = 1 << 2; |
| 44 | |
| 45 | static constexpr int32_t pack_vertex_data(int32_t leftNeighborID, int32_t rightNeighborID, |
| 46 | int32_t bloatIdx, int32_t cornerID, |
| 47 | int32_t = 0) { |
| 48 | return (leftNeighborID << kVertexData_LeftNeighborIdShift) | |
| 49 | (rightNeighborID << kVertexData_RightNeighborIdShift) | |
| 50 | (bloatIdx << kVertexData_BloatIdxShift) | |
| 51 | cornerID | extraData; |
| 52 | } |
| 53 | |
| 54 | static constexpr int32_t hull_vertex_data(int32_t cornerID, int32_t bloatIdx, int n) { |
| 55 | return pack_vertex_data((cornerID + n - 1) % n, (cornerID + 1) % n, bloatIdx, cornerID, |
| 56 | kVertexData_IsHullBit); |
| 57 | } |
| 58 | |
| 59 | static constexpr int32_t edge_vertex_data(int32_t edgeID, int32_t endptIdx, int32_t bloatIdx, |
| 60 | int n) { |
| 61 | return pack_vertex_data(0 == endptIdx ? (edgeID + 1) % n : edgeID, |
| 62 | 0 == endptIdx ? (edgeID + 1) % n : edgeID, |
| 63 | bloatIdx, 0 == endptIdx ? edgeID : (edgeID + 1) % n, |
| 64 | kVertexData_IsEdgeBit | |
| 65 | (!endptIdx ? kVertexData_InvertNegativeCoverageBit : 0)); |
| 66 | } |
| 67 | |
| 68 | static constexpr int32_t corner_vertex_data(int32_t leftID, int32_t cornerID, int32_t rightID, |
| 69 | int32_t bloatIdx) { |
| 70 | return pack_vertex_data(leftID, rightID, bloatIdx, cornerID, kVertexData_IsCornerBit); |
| 71 | } |
| 72 | |
| 73 | static constexpr int32_t kTriangleVertices[] = { |
| 74 | hull_vertex_data(0, 0, 3), |
| 75 | hull_vertex_data(0, 1, 3), |
| 76 | hull_vertex_data(0, 2, 3), |
| 77 | hull_vertex_data(1, 0, 3), |
| 78 | hull_vertex_data(1, 1, 3), |
| 79 | hull_vertex_data(1, 2, 3), |
| 80 | hull_vertex_data(2, 0, 3), |
| 81 | hull_vertex_data(2, 1, 3), |
| 82 | hull_vertex_data(2, 2, 3), |
| 83 | |
| 84 | edge_vertex_data(0, 0, 0, 3), |
| 85 | edge_vertex_data(0, 0, 1, 3), |
| 86 | edge_vertex_data(0, 0, 2, 3), |
| 87 | edge_vertex_data(0, 1, 0, 3), |
| 88 | edge_vertex_data(0, 1, 1, 3), |
| 89 | edge_vertex_data(0, 1, 2, 3), |
| 90 | |
| 91 | edge_vertex_data(1, 0, 0, 3), |
| 92 | edge_vertex_data(1, 0, 1, 3), |
| 93 | edge_vertex_data(1, 0, 2, 3), |
| 94 | edge_vertex_data(1, 1, 0, 3), |
| 95 | edge_vertex_data(1, 1, 1, 3), |
| 96 | edge_vertex_data(1, 1, 2, 3), |
| 97 | |
| 98 | edge_vertex_data(2, 0, 0, 3), |
| 99 | edge_vertex_data(2, 0, 1, 3), |
| 100 | edge_vertex_data(2, 0, 2, 3), |
| 101 | edge_vertex_data(2, 1, 0, 3), |
| 102 | edge_vertex_data(2, 1, 1, 3), |
| 103 | edge_vertex_data(2, 1, 2, 3), |
| 104 | |
| 105 | corner_vertex_data(2, 0, 1, 0), |
| 106 | corner_vertex_data(2, 0, 1, 1), |
| 107 | corner_vertex_data(2, 0, 1, 2), |
| 108 | corner_vertex_data(2, 0, 1, 3), |
| 109 | |
| 110 | corner_vertex_data(0, 1, 2, 0), |
| 111 | corner_vertex_data(0, 1, 2, 1), |
| 112 | corner_vertex_data(0, 1, 2, 2), |
| 113 | corner_vertex_data(0, 1, 2, 3), |
| 114 | |
| 115 | corner_vertex_data(1, 2, 0, 0), |
| 116 | corner_vertex_data(1, 2, 0, 1), |
| 117 | corner_vertex_data(1, 2, 0, 2), |
| 118 | corner_vertex_data(1, 2, 0, 3), |
| 119 | }; |
| 120 | |
| 121 | GR_DECLARE_STATIC_UNIQUE_KEY(gTriangleVertexBufferKey); |
| 122 | |
| 123 | static constexpr uint16_t kRestartStrip = 0xffff; |
| 124 | |
| 125 | static constexpr uint16_t kTriangleIndicesAsStrips[] = { |
| 126 | 1, 2, 0, 3, 8, kRestartStrip, // First corner and main body of the hull. |
| 127 | 4, 5, 3, 6, 8, 7, kRestartStrip, // Opposite side and corners of the hull. |
| 128 | 10, 9, 11, 14, 12, 13, kRestartStrip, // First edge. |
| 129 | 16, 15, 17, 20, 18, 19, kRestartStrip, // Second edge. |
| 130 | 22, 21, 23, 26, 24, 25, kRestartStrip, // Third edge. |
| 131 | 28, 27, 29, 30, kRestartStrip, // First corner. |
| 132 | 32, 31, 33, 34, kRestartStrip, // Second corner. |
| 133 | 36, 35, 37, 38 // Third corner. |
| 134 | }; |
| 135 | |
| 136 | static constexpr uint16_t kTriangleIndicesAsTris[] = { |
| 137 | // First corner and main body of the hull. |
| 138 | 1, 2, 0, |
| 139 | 2, 3, 0, |
| 140 | 0, 3, 8, // Main body. |
| 141 | |
| 142 | // Opposite side and corners of the hull. |
| 143 | 4, 5, 3, |
| 144 | 5, 6, 3, |
| 145 | 3, 6, 8, |
| 146 | 6, 7, 8, |
| 147 | |
| 148 | // First edge. |
| 149 | 10, 9, 11, |
| 150 | 9, 14, 11, |
| 151 | 11, 14, 12, |
| 152 | 14, 13, 12, |
| 153 | |
| 154 | // Second edge. |
| 155 | 16, 15, 17, |
| 156 | 15, 20, 17, |
| 157 | 17, 20, 18, |
| 158 | 20, 19, 18, |
| 159 | |
| 160 | // Third edge. |
| 161 | 22, 21, 23, |
| 162 | 21, 26, 23, |
| 163 | 23, 26, 24, |
| 164 | 26, 25, 24, |
| 165 | |
| 166 | // First corner. |
| 167 | 28, 27, 29, |
| 168 | 27, 30, 29, |
| 169 | |
| 170 | // Second corner. |
| 171 | 32, 31, 33, |
| 172 | 31, 34, 33, |
| 173 | |
| 174 | // Third corner. |
| 175 | 36, 35, 37, |
| 176 | 35, 38, 37, |
| 177 | }; |
| 178 | |
| 179 | GR_DECLARE_STATIC_UNIQUE_KEY(gTriangleIndexBufferKey); |
| 180 | |
| 181 | // Curves, including quadratics, are drawn with a four-sided hull. |
| 182 | static constexpr int32_t kCurveVertices[] = { |
| 183 | hull_vertex_data(0, 0, 4), |
| 184 | hull_vertex_data(0, 1, 4), |
| 185 | hull_vertex_data(0, 2, 4), |
| 186 | hull_vertex_data(1, 0, 4), |
| 187 | hull_vertex_data(1, 1, 4), |
| 188 | hull_vertex_data(1, 2, 4), |
| 189 | hull_vertex_data(2, 0, 4), |
| 190 | hull_vertex_data(2, 1, 4), |
| 191 | hull_vertex_data(2, 2, 4), |
| 192 | hull_vertex_data(3, 0, 4), |
| 193 | hull_vertex_data(3, 1, 4), |
| 194 | hull_vertex_data(3, 2, 4), |
| 195 | |
| 196 | corner_vertex_data(3, 0, 1, 0), |
| 197 | corner_vertex_data(3, 0, 1, 1), |
| 198 | corner_vertex_data(3, 0, 1, 2), |
| 199 | corner_vertex_data(3, 0, 1, 3), |
| 200 | |
| 201 | corner_vertex_data(2, 3, 0, 0), |
| 202 | corner_vertex_data(2, 3, 0, 1), |
| 203 | corner_vertex_data(2, 3, 0, 2), |
| 204 | corner_vertex_data(2, 3, 0, 3), |
| 205 | }; |
| 206 | |
| 207 | GR_DECLARE_STATIC_UNIQUE_KEY(gCurveVertexBufferKey); |
| 208 | |
| 209 | static constexpr uint16_t kCurveIndicesAsStrips[] = { |
| 210 | 1, 0, 2, 11, 3, 5, 4, kRestartStrip, // First half of the hull (split diagonally). |
| 211 | 7, 6, 8, 5, 9, 11, 10, kRestartStrip, // Second half of the hull. |
| 212 | 13, 12, 14, 15, kRestartStrip, // First corner. |
| 213 | 17, 16, 18, 19 // Final corner. |
| 214 | }; |
| 215 | |
| 216 | static constexpr uint16_t kCurveIndicesAsTris[] = { |
| 217 | // First half of the hull (split diagonally). |
| 218 | 1, 0, 2, |
| 219 | 0, 11, 2, |
| 220 | 2, 11, 3, |
| 221 | 11, 5, 3, |
| 222 | 3, 5, 4, |
| 223 | |
| 224 | // Second half of the hull. |
| 225 | 7, 6, 8, |
| 226 | 6, 5, 8, |
| 227 | 8, 5, 9, |
| 228 | 5, 11, 9, |
| 229 | 9, 11, 10, |
| 230 | |
| 231 | // First corner. |
| 232 | 13, 12, 14, |
| 233 | 12, 15, 14, |
| 234 | |
| 235 | // Final corner. |
| 236 | 17, 16, 18, |
| 237 | 16, 19, 18, |
| 238 | }; |
| 239 | |
| 240 | GR_DECLARE_STATIC_UNIQUE_KEY(gCurveIndexBufferKey); |
| 241 | |
| 242 | // Generates a conservative raster hull around a triangle or curve. For triangles we generate |
| 243 | // additional conservative rasters with coverage ramps around the edges and corners. |
| 244 | // |
| 245 | // Triangles are drawn in three steps: (1) Draw a conservative raster of the entire triangle, with a |
| 246 | // coverage of +1. (2) Draw conservative rasters around each edge, with a coverage ramp from -1 to |
| 247 | // 0. These edge coverage values convert jagged conservative raster edges into smooth, antialiased |
| 248 | // ones. (3) Draw conservative rasters (aka pixel-size boxes) around each corner, replacing the |
| 249 | // previous coverage values with ones that ramp to zero in the bloat vertices that fall outside the |
| 250 | // triangle. |
| 251 | // |
| 252 | // Curve shaders handle the opposite edge and corners on their own. For curves we just generate a |
| 253 | // conservative raster here and the shader does the rest. |
| 254 | void GrVSCoverageProcessor::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { |
| 255 | const GrVSCoverageProcessor& proc = args.fGP.cast<GrVSCoverageProcessor>(); |
| 256 | GrGLSLVertexBuilder* v = args.fVertBuilder; |
| 257 | int numInputPoints = proc.numInputPoints(); |
| 258 | |
| 259 | int inputWidth = (4 == numInputPoints || proc.hasInputWeight()) ? 4 : 3; |
| 260 | const char* swizzle = (4 == inputWidth) ? "xyzw" : "xyz" ; |
| 261 | v->codeAppendf("float%ix2 pts = transpose(float2x%i(%s.%s, %s.%s));" , inputWidth, inputWidth, |
| 262 | proc.fInputXAndYValues[kInstanceAttribIdx_X].name(), swizzle, |
| 263 | proc.fInputXAndYValues[kInstanceAttribIdx_Y].name(), swizzle); |
| 264 | |
| 265 | v->codeAppend ("half wind;" ); |
| 266 | Shader::CalcWind(proc, v, "pts" , "wind" ); |
| 267 | if (PrimitiveType::kWeightedTriangles == proc.fPrimitiveType) { |
| 268 | SkASSERT(3 == numInputPoints); |
| 269 | SkASSERT(kFloat4_GrVertexAttribType == |
| 270 | proc.fInputXAndYValues[kInstanceAttribIdx_X].cpuType()); |
| 271 | v->codeAppendf("wind *= half(%s.w);" , |
| 272 | proc.fInputXAndYValues[kInstanceAttribIdx_X].name()); |
| 273 | } |
| 274 | |
| 275 | float bloat = kAABloatRadius; |
| 276 | #ifdef SK_DEBUG |
| 277 | if (proc.debugBloatEnabled()) { |
| 278 | bloat *= proc.debugBloat(); |
| 279 | } |
| 280 | #endif |
| 281 | v->defineConstant("bloat" , bloat); |
| 282 | |
| 283 | const char* hullPts = "pts" ; |
| 284 | fShader->emitSetupCode(v, "pts" , (4 == fNumSides) ? &hullPts : nullptr); |
| 285 | |
| 286 | // Reverse all indices if the wind is counter-clockwise: [0, 1, 2] -> [2, 1, 0]. |
| 287 | v->codeAppendf("int clockwise_indices = wind > 0 ? %s : 0x%x - %s;" , |
| 288 | proc.fPerVertexData.name(), |
| 289 | ((fNumSides - 1) << kVertexData_LeftNeighborIdShift) | |
| 290 | ((fNumSides - 1) << kVertexData_RightNeighborIdShift) | |
| 291 | (((1 << kVertexData_RightNeighborIdShift) - 1) ^ 3) | |
| 292 | (fNumSides - 1), |
| 293 | proc.fPerVertexData.name()); |
| 294 | |
| 295 | // Here we generate conservative raster geometry for the input polygon. It is the convex |
| 296 | // hull of N pixel-size boxes, one centered on each the input points. Each corner has three |
| 297 | // vertices, where one or two may cause degenerate triangles. The vertex data tells us how |
| 298 | // to offset each vertex. Triangle edges and corners are also handled here using the same |
| 299 | // concept. For more details on conservative raster, see: |
| 300 | // https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter42.html |
| 301 | v->codeAppendf("float2 corner = %s[clockwise_indices & 3];" , hullPts); |
| 302 | v->codeAppendf("float2 left = %s[clockwise_indices >> %i];" , |
| 303 | hullPts, kVertexData_LeftNeighborIdShift); |
| 304 | v->codeAppendf("float2 right = %s[(clockwise_indices >> %i) & 3];" , |
| 305 | hullPts, kVertexData_RightNeighborIdShift); |
| 306 | |
| 307 | v->codeAppend ("float2 leftbloat = sign(corner - left);" ); |
| 308 | v->codeAppend ("leftbloat = float2(0 != leftbloat.y ? leftbloat.y : leftbloat.x, " |
| 309 | "0 != leftbloat.x ? -leftbloat.x : -leftbloat.y);" ); |
| 310 | |
| 311 | v->codeAppend ("float2 rightbloat = sign(right - corner);" ); |
| 312 | v->codeAppend ("rightbloat = float2(0 != rightbloat.y ? rightbloat.y : rightbloat.x, " |
| 313 | "0 != rightbloat.x ? -rightbloat.x : -rightbloat.y);" ); |
| 314 | |
| 315 | v->codeAppend ("bool2 left_right_notequal = notEqual(leftbloat, rightbloat);" ); |
| 316 | |
| 317 | v->codeAppend ("float2 bloatdir = leftbloat;" ); |
| 318 | |
| 319 | v->codeAppend ("float2 leftdir = corner - left;" ); |
| 320 | v->codeAppend ("leftdir = (float2(0) != leftdir) ? normalize(leftdir) : float2(1, 0);" ); |
| 321 | |
| 322 | v->codeAppend ("float2 rightdir = right - corner;" ); |
| 323 | v->codeAppend ("rightdir = (float2(0) != rightdir) ? normalize(rightdir) : float2(1, 0);" ); |
| 324 | |
| 325 | v->codeAppendf("if (0 != (%s & %i)) {" , // Are we a corner? |
| 326 | proc.fPerVertexData.name(), kVertexData_IsCornerBit); |
| 327 | |
| 328 | // In corner boxes, all 4 coverage values will not map linearly. |
| 329 | // Therefore it is important to align the box so its diagonal shared |
| 330 | // edge points out of the triangle, in the direction that ramps to 0. |
| 331 | v->codeAppend ( "bloatdir = float2(leftdir.x > rightdir.x ? +1 : -1, " |
| 332 | "leftdir.y > rightdir.y ? +1 : -1);" ); |
| 333 | |
| 334 | // For corner boxes, we hack left_right_notequal to always true. This |
| 335 | // in turn causes the upcoming code to always rotate, generating all |
| 336 | // 4 vertices of the corner box. |
| 337 | v->codeAppendf( "left_right_notequal = bool2(true);" ); |
| 338 | v->codeAppend ("}" ); |
| 339 | |
| 340 | // At each corner of the polygon, our hull will have either 1, 2, or 3 vertices (or 4 if |
| 341 | // it's a corner box). We begin with this corner's first raster vertex (leftbloat), then |
| 342 | // continue rotating 90 degrees clockwise until we reach the desired raster vertex for this |
| 343 | // invocation. Corners with less than 3 corresponding raster vertices will result in |
| 344 | // redundant vertices and degenerate triangles. |
| 345 | v->codeAppendf("int bloatidx = (%s >> %i) & 3;" , proc.fPerVertexData.name(), |
| 346 | kVertexData_BloatIdxShift); |
| 347 | v->codeAppend ("switch (bloatidx) {" ); |
| 348 | v->codeAppend ( "case 3:" ); |
| 349 | // Only corners will have bloatidx=3, and corners always rotate. |
| 350 | v->codeAppend ( "bloatdir = float2(-bloatdir.y, +bloatdir.x);" ); // 90 deg CW. |
| 351 | // fallthru. |
| 352 | v->codeAppend ( "case 2:" ); |
| 353 | v->codeAppendf( "if (all(left_right_notequal)) {" ); |
| 354 | v->codeAppend ( "bloatdir = float2(-bloatdir.y, +bloatdir.x);" ); // 90 deg CW. |
| 355 | v->codeAppend ( "}" ); |
| 356 | // fallthru. |
| 357 | v->codeAppend ( "case 1:" ); |
| 358 | v->codeAppendf( "if (any(left_right_notequal)) {" ); |
| 359 | v->codeAppend ( "bloatdir = float2(-bloatdir.y, +bloatdir.x);" ); // 90 deg CW. |
| 360 | v->codeAppend ( "}" ); |
| 361 | // fallthru. |
| 362 | v->codeAppend ("}" ); |
| 363 | |
| 364 | v->codeAppend ("float2 vertexpos = fma(bloatdir, float2(bloat), corner);" ); |
| 365 | gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos" ); |
| 366 | |
| 367 | // Hulls have a coverage of +1 all around. |
| 368 | v->codeAppend ("half coverage = +1;" ); |
| 369 | |
| 370 | if (3 == fNumSides) { |
| 371 | v->codeAppend ("half left_coverage; {" ); |
| 372 | Shader::CalcEdgeCoverageAtBloatVertex(v, "left" , "corner" , "bloatdir" , "left_coverage" ); |
| 373 | v->codeAppend ("}" ); |
| 374 | |
| 375 | v->codeAppend ("half right_coverage; {" ); |
| 376 | Shader::CalcEdgeCoverageAtBloatVertex(v, "corner" , "right" , "bloatdir" , "right_coverage" ); |
| 377 | v->codeAppend ("}" ); |
| 378 | |
| 379 | v->codeAppendf("if (0 != (%s & %i)) {" , // Are we an edge? |
| 380 | proc.fPerVertexData.name(), kVertexData_IsEdgeBit); |
| 381 | v->codeAppend ( "coverage = left_coverage;" ); |
| 382 | v->codeAppend ("}" ); |
| 383 | |
| 384 | v->codeAppendf("if (0 != (%s & %i)) {" , // Invert coverage? |
| 385 | proc.fPerVertexData.name(), |
| 386 | kVertexData_InvertNegativeCoverageBit); |
| 387 | v->codeAppend ( "coverage = -1 - coverage;" ); |
| 388 | v->codeAppend ("}" ); |
| 389 | } else if (!fShader->calculatesOwnEdgeCoverage()) { |
| 390 | // Determine the amount of coverage to subtract out for the flat edge of the curve. |
| 391 | v->codeAppendf("float2 p0 = pts[0], p1 = pts[%i];" , numInputPoints - 1); |
| 392 | v->codeAppendf("float2 n = float2(p0.y - p1.y, p1.x - p0.x);" ); |
| 393 | v->codeAppend ("float nwidth = bloat*2 * (abs(n.x) + abs(n.y));" ); |
| 394 | // When nwidth=0, wind must also be 0 (and coverage * wind = 0). So it doesn't matter |
| 395 | // what we come up with here as long as it isn't NaN or Inf. |
| 396 | v->codeAppend ("float d = dot(p0 - vertexpos, n);" ); |
| 397 | v->codeAppend ("d /= (0 != nwidth) ? nwidth : 1;" ); |
| 398 | v->codeAppend ("coverage = half(d) - .5*sign(wind);" ); |
| 399 | } |
| 400 | |
| 401 | // Non-corner geometry should have zero effect from corner coverage. |
| 402 | v->codeAppend ("half2 corner_coverage = half2(0);" ); |
| 403 | |
| 404 | v->codeAppendf("if (0 != (%s & %i)) {" , // Are we a corner? |
| 405 | proc.fPerVertexData.name(), kVertexData_IsCornerBit); |
| 406 | // Erase what the previous geometry wrote. |
| 407 | v->codeAppend ( "wind = -wind;" ); |
| 408 | if (3 == fNumSides) { |
| 409 | v->codeAppend ("coverage = 1 + left_coverage + right_coverage;" ); |
| 410 | } else if (!fShader->calculatesOwnEdgeCoverage()) { |
| 411 | v->codeAppend ("coverage = -coverage;" ); |
| 412 | } |
| 413 | |
| 414 | // Corner boxes require attenuated coverage. |
| 415 | v->codeAppend ( "half attenuation; {" ); |
| 416 | Shader::CalcCornerAttenuation(v, "leftdir" , "rightdir" , "attenuation" ); |
| 417 | v->codeAppend ( "}" ); |
| 418 | |
| 419 | // Attenuate corner coverage towards the outermost vertex (where bloatidx=0). |
| 420 | // This is all that curves need: At each vertex of the corner box, the curve |
| 421 | // Shader will calculate the curve's local coverage value, interpolate it |
| 422 | // alongside our attenuation parameter, and multiply the two together for a |
| 423 | // final coverage value. |
| 424 | v->codeAppend ( "corner_coverage = (0 == bloatidx) ? half2(0, attenuation) : half2(-1,+1);" ); |
| 425 | |
| 426 | if (3 == fNumSides) { |
| 427 | // For triangles we also provide the actual coverage values at each vertex of |
| 428 | // the corner box. |
| 429 | v->codeAppend ("if (1 == bloatidx || 2 == bloatidx) {" ); |
| 430 | v->codeAppend ( "corner_coverage.x -= right_coverage;" ); |
| 431 | v->codeAppend ("}" ); |
| 432 | v->codeAppend ("if (bloatidx >= 2) {" ); |
| 433 | v->codeAppend ( "corner_coverage.x -= left_coverage;" ); |
| 434 | v->codeAppend ("}" ); |
| 435 | } |
| 436 | v->codeAppend ("}" ); |
| 437 | |
| 438 | GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; |
| 439 | v->codeAppend ("coverage *= wind;" ); |
| 440 | v->codeAppend ("corner_coverage.x *= wind;" ); |
| 441 | fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag, &AccessCodeString(v), |
| 442 | "vertexpos" , "coverage" , "corner_coverage" , "wind" ); |
| 443 | |
| 444 | varyingHandler->emitAttributes(proc); |
| 445 | SkASSERT(!*args.fFPCoordTransformHandler); |
| 446 | |
| 447 | // Fragment shader. |
| 448 | GrGLSLFPFragmentBuilder* f = args.fFragBuilder; |
| 449 | f->codeAppendf("half coverage;" ); |
| 450 | fShader->emitFragmentCoverageCode(f, "coverage" ); |
| 451 | f->codeAppendf("%s = half4(coverage);" , args.fOutputColor); |
| 452 | f->codeAppendf("%s = half4(1);" , args.fOutputCoverage); |
| 453 | } |
| 454 | |
| 455 | void GrVSCoverageProcessor::reset(PrimitiveType primitiveType, int subpassIdx, |
| 456 | GrResourceProvider* rp) { |
| 457 | SkASSERT(subpassIdx == 0); |
| 458 | const GrCaps& caps = *rp->caps(); |
| 459 | |
| 460 | fPrimitiveType = primitiveType; |
| 461 | switch (fPrimitiveType) { |
| 462 | case PrimitiveType::kTriangles: |
| 463 | case PrimitiveType::kWeightedTriangles: { |
| 464 | GR_DEFINE_STATIC_UNIQUE_KEY(gTriangleVertexBufferKey); |
| 465 | fVertexBuffer = rp->findOrMakeStaticBuffer( |
| 466 | GrGpuBufferType::kVertex, sizeof(kTriangleVertices), kTriangleVertices, |
| 467 | gTriangleVertexBufferKey); |
| 468 | GR_DEFINE_STATIC_UNIQUE_KEY(gTriangleIndexBufferKey); |
| 469 | if (caps.usePrimitiveRestart()) { |
| 470 | fIndexBuffer = rp->findOrMakeStaticBuffer( |
| 471 | GrGpuBufferType::kIndex, sizeof(kTriangleIndicesAsStrips), |
| 472 | kTriangleIndicesAsStrips, gTriangleIndexBufferKey); |
| 473 | fNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsStrips); |
| 474 | } else { |
| 475 | fIndexBuffer = rp->findOrMakeStaticBuffer( |
| 476 | GrGpuBufferType::kIndex, sizeof(kTriangleIndicesAsTris), |
| 477 | kTriangleIndicesAsTris, gTriangleIndexBufferKey); |
| 478 | fNumIndicesPerInstance = SK_ARRAY_COUNT(kTriangleIndicesAsTris); |
| 479 | } |
| 480 | break; |
| 481 | } |
| 482 | |
| 483 | case PrimitiveType::kQuadratics: |
| 484 | case PrimitiveType::kCubics: |
| 485 | case PrimitiveType::kConics: { |
| 486 | GR_DEFINE_STATIC_UNIQUE_KEY(gCurveVertexBufferKey); |
| 487 | fVertexBuffer = rp->findOrMakeStaticBuffer( |
| 488 | GrGpuBufferType::kVertex, sizeof(kCurveVertices), kCurveVertices, |
| 489 | gCurveVertexBufferKey); |
| 490 | GR_DEFINE_STATIC_UNIQUE_KEY(gCurveIndexBufferKey); |
| 491 | if (caps.usePrimitiveRestart()) { |
| 492 | fIndexBuffer = rp->findOrMakeStaticBuffer( |
| 493 | GrGpuBufferType::kIndex, sizeof(kCurveIndicesAsStrips), |
| 494 | kCurveIndicesAsStrips, gCurveIndexBufferKey); |
| 495 | fNumIndicesPerInstance = SK_ARRAY_COUNT(kCurveIndicesAsStrips); |
| 496 | } else { |
| 497 | fIndexBuffer = rp->findOrMakeStaticBuffer( |
| 498 | GrGpuBufferType::kIndex, sizeof(kCurveIndicesAsTris), kCurveIndicesAsTris, |
| 499 | gCurveIndexBufferKey); |
| 500 | fNumIndicesPerInstance = SK_ARRAY_COUNT(kCurveIndicesAsTris); |
| 501 | } |
| 502 | break; |
| 503 | } |
| 504 | } |
| 505 | |
| 506 | GrVertexAttribType xyAttribType; |
| 507 | GrSLType xySLType; |
| 508 | if (4 == this->numInputPoints() || this->hasInputWeight()) { |
| 509 | static_assert(offsetof(QuadPointInstance, fX) == 0); |
| 510 | static_assert(sizeof(QuadPointInstance::fX) == |
| 511 | GrVertexAttribTypeSize(kFloat4_GrVertexAttribType)); |
| 512 | static_assert(sizeof(QuadPointInstance::fY) == |
| 513 | GrVertexAttribTypeSize(kFloat4_GrVertexAttribType)); |
| 514 | xyAttribType = kFloat4_GrVertexAttribType; |
| 515 | xySLType = kFloat4_GrSLType; |
| 516 | } else { |
| 517 | static_assert(sizeof(TriPointInstance) == |
| 518 | 2 * GrVertexAttribTypeSize(kFloat3_GrVertexAttribType)); |
| 519 | xyAttribType = kFloat3_GrVertexAttribType; |
| 520 | xySLType = kFloat3_GrSLType; |
| 521 | } |
| 522 | fInputXAndYValues[kInstanceAttribIdx_X] = {"X" , xyAttribType, xySLType}; |
| 523 | fInputXAndYValues[kInstanceAttribIdx_Y] = {"Y" , xyAttribType, xySLType}; |
| 524 | this->setInstanceAttributes(fInputXAndYValues, 2); |
| 525 | fPerVertexData = {"vertexdata" , kInt_GrVertexAttribType, kInt_GrSLType}; |
| 526 | this->setVertexAttributes(&fPerVertexData, 1); |
| 527 | |
| 528 | if (caps.usePrimitiveRestart()) { |
| 529 | fTriangleType = GrPrimitiveType::kTriangleStrip; |
| 530 | } else { |
| 531 | fTriangleType = GrPrimitiveType::kTriangles; |
| 532 | } |
| 533 | } |
| 534 | |
| 535 | void GrVSCoverageProcessor::bindBuffers(GrOpsRenderPass* renderPass, |
| 536 | const GrBuffer* instanceBuffer) const { |
| 537 | SkASSERT(fTriangleType == GrPrimitiveType::kTriangles || |
| 538 | fTriangleType == GrPrimitiveType::kTriangleStrip); |
| 539 | renderPass->bindBuffers(fIndexBuffer.get(), instanceBuffer, fVertexBuffer.get(), |
| 540 | GrPrimitiveRestart(GrPrimitiveType::kTriangleStrip == fTriangleType)); |
| 541 | } |
| 542 | |
| 543 | void GrVSCoverageProcessor::drawInstances(GrOpsRenderPass* renderPass, int instanceCount, |
| 544 | int baseInstance) const { |
| 545 | renderPass->drawIndexedInstanced(fNumIndicesPerInstance, 0, instanceCount, baseInstance, 0); |
| 546 | } |
| 547 | |
| 548 | GrGLSLPrimitiveProcessor* GrVSCoverageProcessor::onCreateGLSLInstance( |
| 549 | std::unique_ptr<Shader> shader) const { |
| 550 | switch (fPrimitiveType) { |
| 551 | case PrimitiveType::kTriangles: |
| 552 | case PrimitiveType::kWeightedTriangles: |
| 553 | return new Impl(std::move(shader), 3); |
| 554 | case PrimitiveType::kQuadratics: |
| 555 | case PrimitiveType::kCubics: |
| 556 | case PrimitiveType::kConics: |
| 557 | return new Impl(std::move(shader), 4); |
| 558 | } |
| 559 | SK_ABORT("Invalid PrimitiveType" ); |
| 560 | } |
| 561 | |