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 8layout(key) in GrClipEdgeType edgeType; 9in half2 center; 10in half radius; 11 12half2 prevCenter; 13half prevRadius = -1; 14// The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular 15// fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills. 16uniform half4 circle; 17 18@make { 19 static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkPoint center, 20 float radius) { 21 // A radius below half causes the implicit insetting done by this processor to become 22 // inverted. We could handle this case by making the processor code more complicated. 23 if (radius < .5f && GrProcessorEdgeTypeIsInverseFill(edgeType)) { 24 return nullptr; 25 } 26 return std::unique_ptr<GrFragmentProcessor>(new GrCircleEffect(edgeType, center, radius)); 27 } 28} 29 30@optimizationFlags { kCompatibleWithCoverageAsAlpha_OptimizationFlag } 31 32@setData(pdman) { 33 if (radius != prevRadius || center != prevCenter) { 34 SkScalar effectiveRadius = radius; 35 if (GrProcessorEdgeTypeIsInverseFill((GrClipEdgeType) edgeType)) { 36 effectiveRadius -= 0.5f; 37 // When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the shader. 38 effectiveRadius = SkTMax(0.001f, effectiveRadius); 39 } else { 40 effectiveRadius += 0.5f; 41 } 42 pdman.set4f(circle, center.fX, center.fY, effectiveRadius, 43 SkScalarInvert(effectiveRadius)); 44 prevCenter = center; 45 prevRadius = radius; 46 } 47} 48 49void main() { 50 // TODO: Right now the distance to circle caclulation is performed in a space normalized to the 51 // radius and then denormalized. This is to prevent overflow on devices that have a "real" 52 // mediump. It'd be nice to only do this on mediump devices. 53 half d; 54 @if (edgeType == GrClipEdgeType::kInverseFillBW || 55 edgeType == GrClipEdgeType::kInverseFillAA) { 56 d = (length((circle.xy - sk_FragCoord.xy) * circle.w) - 1.0) * circle.z; 57 } else { 58 d = (1.0 - length((circle.xy - sk_FragCoord.xy) * circle.w)) * circle.z; 59 } 60 @if (edgeType == GrClipEdgeType::kFillAA || 61 edgeType == GrClipEdgeType::kInverseFillAA || 62 edgeType == GrClipEdgeType::kHairlineAA) { 63 d = saturate(d); 64 } else { 65 d = d > 0.5 ? 1.0 : 0.0; 66 } 67 68 sk_OutColor = sk_InColor * d; 69} 70 71@test(testData) { 72 SkPoint center; 73 center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f); 74 center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f); 75 SkScalar radius = testData->fRandom->nextRangeF(1.f, 1000.f); 76 GrClipEdgeType et; 77 do { 78 et = (GrClipEdgeType) testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt); 79 } while (GrClipEdgeType::kHairlineAA == et); 80 return GrCircleEffect::Make(et, center, radius); 81}