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 float2 center; 10in float radius; 11 12float2 prevCenter; 13float 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 float4 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 calculation is performed in a space normalized to the 51 // radius and then denormalized. This is to mitigate overflow on devices that don't have full 52 // float. 53 half d; 54 @if (edgeType == GrClipEdgeType::kInverseFillBW || 55 edgeType == GrClipEdgeType::kInverseFillAA) { 56 d = half((length((circle.xy - sk_FragCoord.xy) * circle.w) - 1.0) * circle.z); 57 } else { 58 d = half((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 sk_OutColor = sk_InColor * saturate(d); 64 } else { 65 sk_OutColor = d > 0.5 ? sk_InColor : half4(0); 66 } 67} 68 69@test(testData) { 70 SkPoint center; 71 center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f); 72 center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f); 73 SkScalar radius = testData->fRandom->nextRangeF(1.f, 1000.f); 74 GrClipEdgeType et; 75 do { 76 et = (GrClipEdgeType) testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt); 77 } while (GrClipEdgeType::kHairlineAA == et); 78 return GrCircleEffect::Make(et, center, radius); 79} 80