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