Convert shape-clipping FPs to GrSkSLFP

Change-Id: Ic574939fd37dd9ded9868d3ffa9ac962140fb66c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/421537
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Brian Osman 2021-06-24 15:34:08 -04:00 committed by Skia Commit-Bot
parent 65b4597d07
commit b384eb204c
22 changed files with 247 additions and 943 deletions

View File

@ -22,7 +22,6 @@
#include "src/gpu/GrFragmentProcessor.h"
#include "src/gpu/GrPaint.h"
#include "src/gpu/GrSurfaceDrawContext.h"
#include "src/gpu/effects/generated/GrAARectEffect.h"
#include "tools/gpu/TestOps.h"
#include <memory>
@ -74,7 +73,7 @@ protected:
for (int et = 0; et < kGrClipEdgeTypeCnt; ++et) {
SkRect rect = r.makeOffset(x, y);
GrClipEdgeType edgeType = static_cast<GrClipEdgeType>(et);
auto fp = GrAARectEffect::Make(/*inputFP=*/nullptr, edgeType, rect);
auto fp = GrFragmentProcessor::Rect(/*inputFP=*/nullptr, edgeType, rect);
SkASSERT(fp);
GrPaint grPaint;

View File

@ -308,20 +308,14 @@ skia_gpu_sources = [
"$_src/gpu/effects/GrTextureEffect.h",
"$_src/gpu/effects/GrYUVtoRGBEffect.cpp",
"$_src/gpu/effects/GrYUVtoRGBEffect.h",
"$_src/gpu/effects/generated/GrAARectEffect.cpp",
"$_src/gpu/effects/generated/GrAARectEffect.h",
"$_src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.cpp",
"$_src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h",
"$_src/gpu/effects/generated/GrCircleBlurFragmentProcessor.cpp",
"$_src/gpu/effects/generated/GrCircleBlurFragmentProcessor.h",
"$_src/gpu/effects/generated/GrCircleEffect.cpp",
"$_src/gpu/effects/generated/GrCircleEffect.h",
"$_src/gpu/effects/generated/GrConfigConversionEffect.cpp",
"$_src/gpu/effects/generated/GrConfigConversionEffect.h",
"$_src/gpu/effects/generated/GrDitherEffect.cpp",
"$_src/gpu/effects/generated/GrDitherEffect.h",
"$_src/gpu/effects/generated/GrEllipseEffect.cpp",
"$_src/gpu/effects/generated/GrEllipseEffect.h",
"$_src/gpu/effects/generated/GrRRectBlurEffect.cpp",
"$_src/gpu/effects/generated/GrRRectBlurEffect.h",
"$_src/gpu/effects/generated/GrRectBlurEffect.cpp",

View File

@ -207,13 +207,10 @@ skia_sksl_gpu_sources = [
]
skia_gpu_processor_sources = [
"$_src/gpu/effects/GrAARectEffect.fp",
"$_src/gpu/effects/GrAlphaThresholdFragmentProcessor.fp",
"$_src/gpu/effects/GrCircleBlurFragmentProcessor.fp",
"$_src/gpu/effects/GrCircleEffect.fp",
"$_src/gpu/effects/GrConfigConversionEffect.fp",
"$_src/gpu/effects/GrDitherEffect.fp",
"$_src/gpu/effects/GrEllipseEffect.fp",
"$_src/gpu/effects/GrRRectBlurEffect.fp",
"$_src/gpu/effects/GrRectBlurEffect.fp",
"$_src/gpu/gradients/GrClampedGradientEffect.fp",

View File

@ -15,6 +15,7 @@
#include "src/gpu/GrClip.h"
#include "src/gpu/GrDeferredProxyUploader.h"
#include "src/gpu/GrDirectContextPriv.h"
#include "src/gpu/GrFragmentProcessor.h"
#include "src/gpu/GrProxyProvider.h"
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrSWMaskHelper.h"
@ -23,7 +24,6 @@
#include "src/gpu/effects/GrConvexPolyEffect.h"
#include "src/gpu/effects/GrRRectEffect.h"
#include "src/gpu/effects/GrTextureEffect.h"
#include "src/gpu/effects/generated/GrAARectEffect.h"
#include "src/gpu/geometry/GrQuadUtils.h"
#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
@ -213,7 +213,7 @@ static GrFPResult analytic_clip_fp(const GrClipStack::Element& e,
GrClipEdgeType edgeType = get_clip_edge_type(e.fOp, e.fAA);
if (e.fLocalToDevice.isIdentity()) {
if (e.fShape.isRect()) {
return GrFPSuccess(GrAARectEffect::Make(std::move(fp), edgeType, e.fShape.rect()));
return GrFPSuccess(GrFragmentProcessor::Rect(std::move(fp), edgeType, e.fShape.rect()));
} else if (e.fShape.isRRect()) {
return GrRRectEffect::Make(std::move(fp), edgeType, e.fShape.rrect(), caps);
}

View File

@ -627,6 +627,205 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::DeviceSpace(
//////////////////////////////////////////////////////////////////////////////
#define CLIP_EDGE_SKSL \
"const int kFillBW = 0;" \
"const int kFillAA = 1;" \
"const int kInverseFillBW = 2;" \
"const int kInverseFillAA = 3;"
static_assert(static_cast<int>(GrClipEdgeType::kFillBW) == 0);
static_assert(static_cast<int>(GrClipEdgeType::kFillAA) == 1);
static_assert(static_cast<int>(GrClipEdgeType::kInverseFillBW) == 2);
static_assert(static_cast<int>(GrClipEdgeType::kInverseFillAA) == 3);
std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::Rect(
std::unique_ptr<GrFragmentProcessor> inputFP, GrClipEdgeType edgeType, SkRect rect) {
static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
uniform int edgeType; // GrClipEdgeType, specialized
uniform float4 rectUniform;
half4 main(float2 xy, half4 inColor) {
half coverage;
if (edgeType == kFillBW || edgeType == kInverseFillBW) {
// non-AA
coverage = all(greaterThan(float4(sk_FragCoord.xy, rectUniform.zw),
float4(rectUniform.xy, sk_FragCoord.xy))) ? 1 : 0;
} else {
// compute coverage relative to left and right edges, add, then subtract 1 to
// account for double counting. And similar for top/bottom.
half4 dists4 = clamp(half4(1, 1, -1, -1) *
half4(sk_FragCoord.xyxy - rectUniform), 0, 1);
half2 dists2 = dists4.xy + dists4.zw - 1;
coverage = dists2.x * dists2.y;
}
if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
coverage = 1.0 - coverage;
}
return inColor * coverage;
}
)");
SkASSERT(rect.isSorted());
// The AA math in the shader evaluates to 0 at the uploaded coordinates, so outset by 0.5
// to interpolate from 0 at a half pixel inset and 1 at a half pixel outset of rect.
SkRect rectUniform = GrProcessorEdgeTypeIsAA(edgeType) ? rect.makeOutset(.5f, .5f) : rect;
return GrSkSLFP::Make(effect, "Rect", std::move(inputFP),
GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
"edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
"rectUniform", rectUniform);
}
GrFPResult GrFragmentProcessor::Circle(std::unique_ptr<GrFragmentProcessor> inputFP,
GrClipEdgeType edgeType,
SkPoint center,
float radius) {
// A radius below half causes the implicit insetting done by this processor to become
// inverted. We could handle this case by making the processor code more complicated.
if (radius < .5f && GrProcessorEdgeTypeIsInverseFill(edgeType)) {
return GrFPFailure(std::move(inputFP));
}
static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
uniform int edgeType; // GrClipEdgeType, specialized
// The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular
// fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills.
uniform float4 circle;
half4 main(float2 xy, half4 inColor) {
// TODO: Right now the distance to circle calculation is performed in a space normalized
// to the radius and then denormalized. This is to mitigate overflow on devices that
// don't have full float.
half d;
if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
d = half((length((circle.xy - sk_FragCoord.xy) * circle.w) - 1.0) * circle.z);
} else {
d = half((1.0 - length((circle.xy - sk_FragCoord.xy) * circle.w)) * circle.z);
}
if (edgeType == kFillAA || edgeType == kInverseFillAA) {
return inColor * saturate(d);
} else {
return d > 0.5 ? inColor : half4(0);
}
}
)");
SkScalar effectiveRadius = radius;
if (GrProcessorEdgeTypeIsInverseFill(edgeType)) {
effectiveRadius -= 0.5f;
// When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the shader.
effectiveRadius = std::max(0.001f, effectiveRadius);
} else {
effectiveRadius += 0.5f;
}
SkV4 circle = {center.fX, center.fY, effectiveRadius, SkScalarInvert(effectiveRadius)};
return GrFPSuccess(GrSkSLFP::Make(effect, "Circle", std::move(inputFP),
GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
"edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
"circle", circle));
}
GrFPResult GrFragmentProcessor::Ellipse(std::unique_ptr<GrFragmentProcessor> inputFP,
GrClipEdgeType edgeType,
SkPoint center,
SkPoint radii,
const GrShaderCaps& caps) {
const bool medPrecision = !caps.floatIs32Bits();
// Small radii produce bad results on devices without full float.
if (medPrecision && (radii.fX < 0.5f || radii.fY < 0.5f)) {
return GrFPFailure(std::move(inputFP));
}
// Very narrow ellipses produce bad results on devices without full float
if (medPrecision && (radii.fX > 255*radii.fY || radii.fY > 255*radii.fX)) {
return GrFPFailure(std::move(inputFP));
}
// Very large ellipses produce bad results on devices without full float
if (medPrecision && (radii.fX > 16384 || radii.fY > 16384)) {
return GrFPFailure(std::move(inputFP));
}
static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
uniform int edgeType; // GrClipEdgeType, specialized
uniform int medPrecision; // !sk_Caps.floatIs32Bits, specialized
uniform float4 ellipse;
uniform float2 scale; // only for medPrecision
half4 main(float2 xy, half4 inColor) {
// d is the offset to the ellipse center
float2 d = sk_FragCoord.xy - ellipse.xy;
// If we're on a device with a "real" mediump then we'll do the distance computation in
// a space that is normalized by the larger radius or 128, whichever is smaller. The
// scale uniform will be scale, 1/scale. The inverse squared radii uniform values are
// already in this normalized space. The center is not.
if (bool(medPrecision)) {
d *= scale.y;
}
float2 Z = d * ellipse.zw;
// implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
float implicit = dot(Z, d) - 1;
// grad_dot is the squared length of the gradient of the implicit.
float grad_dot = 4 * dot(Z, Z);
// Avoid calling inversesqrt on zero.
if (bool(medPrecision)) {
grad_dot = max(grad_dot, 6.1036e-5);
} else {
grad_dot = max(grad_dot, 1.1755e-38);
}
float approx_dist = implicit * inversesqrt(grad_dot);
if (bool(medPrecision)) {
approx_dist *= scale.x;
}
half alpha;
if (edgeType == kFillBW) {
alpha = approx_dist > 0.0 ? 0.0 : 1.0;
} else if (edgeType == kFillAA) {
alpha = saturate(0.5 - half(approx_dist));
} else if (edgeType == kInverseFillBW) {
alpha = approx_dist > 0.0 ? 1.0 : 0.0;
} else { // edgeType == kInverseFillAA
alpha = saturate(0.5 + half(approx_dist));
}
return inColor * alpha;
}
)");
float invRXSqd;
float invRYSqd;
SkV2 scale = {1, 1};
// If we're using a scale factor to work around precision issues, choose the larger radius as
// the scale factor. The inv radii need to be pre-adjusted by the scale factor.
if (medPrecision) {
if (radii.fX > radii.fY) {
invRXSqd = 1.f;
invRYSqd = (radii.fX * radii.fX) / (radii.fY * radii.fY);
scale = {radii.fX, 1.f / radii.fX};
} else {
invRXSqd = (radii.fY * radii.fY) / (radii.fX * radii.fX);
invRYSqd = 1.f;
scale = {radii.fY, 1.f / radii.fY};
}
} else {
invRXSqd = 1.f / (radii.fX * radii.fX);
invRYSqd = 1.f / (radii.fY * radii.fY);
}
SkV4 ellipse = {center.fX, center.fY, invRXSqd, invRYSqd};
return GrFPSuccess(GrSkSLFP::Make(effect, "Ellipse", std::move(inputFP),
GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
"edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
"medPrecision", GrSkSLFP::Specialize<int>(medPrecision),
"ellipse", ellipse,
"scale", scale));
}
//////////////////////////////////////////////////////////////////////////////
GrFragmentProcessor::CIter::CIter(const GrPaint& paint) {
if (paint.hasCoverageFragmentProcessor()) {
fFPStack.push_back(paint.getCoverageFragmentProcessor());

View File

@ -21,6 +21,15 @@ class GrShaderCaps;
class GrSwizzle;
class GrTextureEffect;
/**
* Some fragment-processor creation methods have preconditions that might not be satisfied by the
* calling code. Those methods can return a `GrFPResult` from their factory methods. If creation
* succeeds, the new fragment processor is created and `success` is true. If a precondition is not
* met, `success` is set to false and the input FP is returned unchanged.
*/
class GrFragmentProcessor;
using GrFPResult = std::tuple<bool /*success*/, std::unique_ptr<GrFragmentProcessor>>;
/** Provides custom fragment shader code. Fragment processors receive an input position and
produce an output color. They may contain uniforms and may have children fragment processors
that are sampled.
@ -133,6 +142,26 @@ public:
*/
static std::unique_ptr<GrFragmentProcessor> DeviceSpace(std::unique_ptr<GrFragmentProcessor>);
/**
* "Shape" FPs, often used for clipping. Each one evaluates a particular kind of shape (rect,
* circle, ellipse), and modulates the coverage of that shape against the results of the input
* FP. GrClipEdgeType is used to select inverse/normal fill, and AA or non-AA edges.
*/
static std::unique_ptr<GrFragmentProcessor> Rect(std::unique_ptr<GrFragmentProcessor>,
GrClipEdgeType,
SkRect);
static GrFPResult Circle(std::unique_ptr<GrFragmentProcessor>,
GrClipEdgeType,
SkPoint center,
float radius);
static GrFPResult Ellipse(std::unique_ptr<GrFragmentProcessor>,
GrClipEdgeType,
SkPoint center,
SkPoint radii,
const GrShaderCaps&);
/**
* Makes a copy of this fragment processor that draws equivalently to the original.
* If the processor has child processors they are cloned as well.
@ -516,13 +545,6 @@ private:
const Src& fT;
};
/**
* Some fragment-processor creation methods have preconditions that might not be satisfied by the
* calling code. Those methods can return a `GrFPResult` from their factory methods. If creation
* succeeds, the new fragment processor is created and `success` is true. If a precondition is not
* met, `success` is set to false and the input FP is returned unchanged.
*/
using GrFPResult = std::tuple<bool /*success*/, std::unique_ptr<GrFragmentProcessor>>;
static inline GrFPResult GrFPFailure(std::unique_ptr<GrFragmentProcessor> fp) {
return {false, std::move(fp)};
}

View File

@ -54,12 +54,10 @@ public:
kEllipticalRRectEffect_ClassID,
kGP_ClassID,
kVertexColorSpaceBenchGP_ClassID,
kGrAARectEffect_ClassID,
kGrAlphaThresholdFragmentProcessor_ClassID,
kGrBicubicEffect_ClassID,
kGrBitmapTextGeoProc_ClassID,
kGrCircleBlurFragmentProcessor_ClassID,
kGrCircleEffect_ClassID,
kGrClampedGradientEffect_ClassID,
kGrColorSpaceXformEffect_ClassID,
kGrConfigConversionEffect_ClassID,
@ -78,7 +76,6 @@ public:
kGrDSLFPTest_Swizzle_ClassID,
kGrDSLFPTest_Ternary_ClassID,
kGrDSLFPTest_WhileStatement_ClassID,
kGrEllipseEffect_ClassID,
kGrFillRRectOp_Processor_ClassID,
kGrGaussianConvolutionFragmentProcessor_ClassID,
kGrHighContrastFilterEffect_ClassID,

View File

@ -146,7 +146,7 @@ SkTArray<GrXPFactoryTestFactory*, true>* GrXPFactoryTestFactory::GetFactories()
* we verify the count is as expected. If a new factory is added, then these numbers must be
* manually adjusted.
*/
static constexpr int kFPFactoryCount = 25;
static constexpr int kFPFactoryCount = 22;
static constexpr int kGPFactoryCount = 14;
static constexpr int kXPFactoryCount = 4;

View File

@ -11,6 +11,7 @@
#include "src/gpu/GrColor.h"
#include "src/gpu/GrDrawingManager.h"
#include "src/gpu/GrFixedClip.h"
#include "src/gpu/GrFragmentProcessor.h"
#include "src/gpu/GrPathRenderer.h"
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrReducedClip.h"
@ -22,7 +23,6 @@
#include "src/gpu/GrUserStencilSettings.h"
#include "src/gpu/effects/GrConvexPolyEffect.h"
#include "src/gpu/effects/GrRRectEffect.h"
#include "src/gpu/effects/generated/GrAARectEffect.h"
#include "src/gpu/geometry/GrStyledShape.h"
#include "src/shaders/SkShaderBase.h"
@ -644,8 +644,8 @@ GrReducedClip::ClipResult GrReducedClip::addAnalyticRect(const SkRect& deviceSpa
return ClipResult::kNotClipped;
}
fAnalyticFP = GrAARectEffect::Make(std::move(fAnalyticFP), GetClipEdgeType(invert, aa),
deviceSpaceRect);
fAnalyticFP = GrFragmentProcessor::Rect(
std::move(fAnalyticFP), GetClipEdgeType(invert, aa), deviceSpaceRect);
SkASSERT(fAnalyticFP != nullptr);
++fNumAnalyticElements;

View File

@ -1,60 +0,0 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
in fragmentProcessor inputFP;
layout(key) in GrClipEdgeType edgeType;
in float4 rect;
uniform float4 rectUniform;
@optimizationFlags {
ProcessorOptimizationFlags(inputFP.get()) & kCompatibleWithCoverageAsAlpha_OptimizationFlag
}
half4 main() {
half coverage;
@switch (edgeType) {
case GrClipEdgeType::kFillBW: // fall through
case GrClipEdgeType::kInverseFillBW:
// non-AA
coverage = all(greaterThan(float4(sk_FragCoord.xy, rectUniform.zw),
float4(rectUniform.xy, sk_FragCoord.xy))) ? 1 : 0;
break;
default:
// compute coverage relative to left and right edges, add, then subtract 1 to account
// for double counting. And similar for top/bottom.
half4 dists4 = clamp(half4(1, 1, -1, -1) *
half4(sk_FragCoord.xyxy - rectUniform), 0, 1);
half2 dists2 = dists4.xy + dists4.zw - 1;
coverage = dists2.x * dists2.y;
}
@if (edgeType == GrClipEdgeType::kInverseFillBW || edgeType == GrClipEdgeType::kInverseFillAA) {
coverage = 1.0 - coverage;
}
return sample(inputFP) * coverage;
}
@setData(pdman) {
SkASSERT(rect.isSorted());
// The AA math in the shader evaluates to 0 at the uploaded coordinates, so outset by 0.5
// to interpolate from 0 at a half pixel inset and 1 at a half pixel outset of rect.
const SkRect& newRect = GrProcessorEdgeTypeIsAA(edgeType) ? rect.makeOutset(.5f, .5f) : rect;
pdman.set4f(rectUniform, newRect.fLeft, newRect.fTop, newRect.fRight, newRect.fBottom);
}
@test(d) {
SkScalar l = d->fRandom->nextSScalar1();
SkScalar t = d->fRandom->nextSScalar1();
SkScalar r = d->fRandom->nextSScalar1();
SkScalar b = d->fRandom->nextSScalar1();
SkRect rect = SkRect::MakeLTRB(l, t, r, b);
rect.sort();
GrClipEdgeType edgeType = static_cast<GrClipEdgeType>(
d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
return GrAARectEffect::Make(d->inputFP(), edgeType, rect);
}

View File

@ -1,78 +0,0 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
in fragmentProcessor inputFP;
layout(key) in GrClipEdgeType edgeType;
in float2 center;
in float radius;
// The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular
// fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills.
uniform float4 circle;
@make {
static GrFPResult Make(std::unique_ptr<GrFragmentProcessor> inputFP,
GrClipEdgeType edgeType, SkPoint center, float radius) {
// A radius below half causes the implicit insetting done by this processor to become
// inverted. We could handle this case by making the processor code more complicated.
if (radius < .5f && GrProcessorEdgeTypeIsInverseFill(edgeType)) {
return GrFPFailure(std::move(inputFP));
}
return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>(
new GrCircleEffect(std::move(inputFP), edgeType, center, radius)));
}
}
@optimizationFlags {
ProcessorOptimizationFlags(inputFP.get()) & kCompatibleWithCoverageAsAlpha_OptimizationFlag
}
@setData(pdman) {
SkScalar effectiveRadius = radius;
if (GrProcessorEdgeTypeIsInverseFill(edgeType)) {
effectiveRadius -= 0.5f;
// When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the shader.
effectiveRadius = std::max(0.001f, effectiveRadius);
} else {
effectiveRadius += 0.5f;
}
pdman.set4f(circle, center.fX, center.fY, effectiveRadius, SkScalarInvert(effectiveRadius));
}
half4 main() {
// TODO: Right now the distance to circle calculation is performed in a space normalized to the
// radius and then denormalized. This is to mitigate overflow on devices that don't have full
// float.
half d;
@if (edgeType == GrClipEdgeType::kInverseFillBW ||
edgeType == GrClipEdgeType::kInverseFillAA) {
d = half((length((circle.xy - sk_FragCoord.xy) * circle.w) - 1.0) * circle.z);
} else {
d = half((1.0 - length((circle.xy - sk_FragCoord.xy) * circle.w)) * circle.z);
}
half4 inputColor = sample(inputFP);
@if (edgeType == GrClipEdgeType::kFillAA ||
edgeType == GrClipEdgeType::kInverseFillAA) {
return inputColor * saturate(d);
} else {
return d > 0.5 ? inputColor : half4(0);
}
}
@test(testData) {
SkPoint center;
center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f);
center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f);
SkScalar radius = testData->fRandom->nextRangeF(1.f, 1000.f);
bool success;
std::unique_ptr<GrFragmentProcessor> fp = testData->inputFP();
do {
GrClipEdgeType et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt);
std::tie(success, fp) = GrCircleEffect::Make(std::move(fp), et, center, radius);
} while (!success);
return fp;
}

View File

@ -7,7 +7,6 @@
#include "src/core/SkPathPriv.h"
#include "src/gpu/effects/GrConvexPolyEffect.h"
#include "src/gpu/effects/generated/GrAARectEffect.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLProgramDataManager.h"

View File

@ -1,132 +0,0 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@header {
#include "src/gpu/GrShaderCaps.h"
}
in fragmentProcessor inputFP;
layout(key) in GrClipEdgeType edgeType;
in float2 center;
in float2 radii;
// The ellipse uniform is (center.x, center.y, 1 / rx^2, 1 / ry^2)
// The last two terms can underflow when float != fp32, so we also provide a workaround.
uniform float4 ellipse;
layout(when=!sk_Caps.floatIs32Bits) uniform float2 scale;
@make {
static GrFPResult Make(std::unique_ptr<GrFragmentProcessor> inputFP, GrClipEdgeType edgeType,
SkPoint center, SkPoint radii, const GrShaderCaps& caps) {
// Small radii produce bad results on devices without full float.
if (!caps.floatIs32Bits() && (radii.fX < 0.5f || radii.fY < 0.5f)) {
return GrFPFailure(std::move(inputFP));
}
// Very narrow ellipses produce bad results on devices without full float
if (!caps.floatIs32Bits() && (radii.fX > 255*radii.fY || radii.fY > 255*radii.fX)) {
return GrFPFailure(std::move(inputFP));
}
// Very large ellipses produce bad results on devices without full float
if (!caps.floatIs32Bits() && (radii.fX > 16384 || radii.fY > 16384)) {
return GrFPFailure(std::move(inputFP));
}
return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>(
new GrEllipseEffect(std::move(inputFP), edgeType, center, radii)));
}
}
@optimizationFlags {
ProcessorOptimizationFlags(inputFP.get()) & kCompatibleWithCoverageAsAlpha_OptimizationFlag
}
@setData(pdman) {
float invRXSqd;
float invRYSqd;
// If we're using a scale factor to work around precision issues, choose the larger radius as
// the scale factor. The inv radii need to be pre-adjusted by the scale factor.
if (scale.isValid()) {
if (radii.fX > radii.fY) {
invRXSqd = 1.f;
invRYSqd = (radii.fX * radii.fX) / (radii.fY * radii.fY);
pdman.set2f(scale, radii.fX, 1.f / radii.fX);
} else {
invRXSqd = (radii.fY * radii.fY) / (radii.fX * radii.fX);
invRYSqd = 1.f;
pdman.set2f(scale, radii.fY, 1.f / radii.fY);
}
} else {
invRXSqd = 1.f / (radii.fX * radii.fX);
invRYSqd = 1.f / (radii.fY * radii.fY);
}
pdman.set4f(ellipse, center.fX, center.fY, invRXSqd, invRYSqd);
}
half4 main() {
// d is the offset to the ellipse center
float2 d = sk_FragCoord.xy - ellipse.xy;
// If we're on a device with a "real" mediump then we'll do the distance computation in a space
// that is normalized by the larger radius or 128, whichever is smaller. The scale uniform will
// be scale, 1/scale. The inverse squared radii uniform values are already in this normalized space.
// The center is not.
const bool medPrecision = !sk_Caps.floatIs32Bits;
@if (medPrecision) {
d *= scale.y;
}
float2 Z = d * ellipse.zw;
// implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
float implicit = dot(Z, d) - 1;
// grad_dot is the squared length of the gradient of the implicit.
float grad_dot = 4 * dot(Z, Z);
// Avoid calling inversesqrt on zero.
@if (medPrecision) {
grad_dot = max(grad_dot, 6.1036e-5);
} else {
grad_dot = max(grad_dot, 1.1755e-38);
}
float approx_dist = implicit * inversesqrt(grad_dot);
@if (medPrecision) {
approx_dist *= scale.x;
}
half alpha;
@switch (edgeType) {
case GrClipEdgeType::kFillBW:
alpha = approx_dist > 0.0 ? 0.0 : 1.0;
break;
case GrClipEdgeType::kFillAA:
alpha = saturate(0.5 - half(approx_dist));
break;
case GrClipEdgeType::kInverseFillBW:
alpha = approx_dist > 0.0 ? 1.0 : 0.0;
break;
case GrClipEdgeType::kInverseFillAA:
alpha = saturate(0.5 + half(approx_dist));
break;
default:
// hairline not supported
discard;
}
return sample(inputFP) * alpha;
}
@test(testData) {
SkPoint center;
center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f);
center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f);
SkScalar rx = testData->fRandom->nextRangeF(0.f, 1000.f);
SkScalar ry = testData->fRandom->nextRangeF(0.f, 1000.f);
bool success;
std::unique_ptr<GrFragmentProcessor> fp = testData->inputFP();
do {
GrClipEdgeType et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt);
std::tie(success, fp) = GrEllipseEffect::Make(std::move(fp), et, center,
SkPoint::Make(rx, ry),
*testData->caps()->shaderCaps());
} while (!success);
return fp;
}

View File

@ -5,11 +5,9 @@
* found in the LICENSE file.
*/
#include "src/gpu/effects/GrOvalEffect.h"
#include "include/core/SkRect.h"
#include "src/gpu/effects/generated/GrCircleEffect.h"
#include "src/gpu/effects/generated/GrEllipseEffect.h"
#include "src/gpu/GrFragmentProcessor.h"
#include "src/gpu/effects/GrOvalEffect.h"
GrFPResult GrOvalEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP, GrClipEdgeType edgeType,
const SkRect& oval, const GrShaderCaps& caps) {
@ -17,14 +15,14 @@ GrFPResult GrOvalEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP, GrCl
SkScalar h = oval.height();
if (SkScalarNearlyEqual(w, h)) {
w /= 2;
return GrCircleEffect::Make(std::move(inputFP), edgeType,
SkPoint::Make(oval.fLeft + w, oval.fTop + w), w);
return GrFragmentProcessor::Circle(std::move(inputFP), edgeType,
SkPoint::Make(oval.fLeft + w, oval.fTop + w), w);
} else {
w /= 2;
h /= 2;
return GrEllipseEffect::Make(std::move(inputFP), edgeType,
SkPoint::Make(oval.fLeft + w, oval.fTop + h),
SkPoint::Make(w, h), caps);
return GrFragmentProcessor::Ellipse(std::move(inputFP), edgeType,
SkPoint::Make(oval.fLeft + w, oval.fTop + h),
SkPoint::Make(w, h), caps);
}
SkUNREACHABLE;
}

View File

@ -13,7 +13,6 @@
#include "src/gpu/GrShaderCaps.h"
#include "src/gpu/effects/GrConvexPolyEffect.h"
#include "src/gpu/effects/GrOvalEffect.h"
#include "src/gpu/effects/generated/GrAARectEffect.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
@ -712,7 +711,7 @@ GrFPResult GrRRectEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP,
GrClipEdgeType edgeType, const SkRRect& rrect,
const GrShaderCaps& caps) {
if (rrect.isRect()) {
auto fp = GrAARectEffect::Make(std::move(inputFP), edgeType, rrect.getBounds());
auto fp = GrFragmentProcessor::Rect(std::move(inputFP), edgeType, rrect.getBounds());
return GrFPSuccess(std::move(fp));
}
@ -725,7 +724,7 @@ GrFPResult GrRRectEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP,
SkRRectPriv::GetSimpleRadii(rrect).fY < kRadiusMin) {
// In this case the corners are extremely close to rectangular and we collapse the
// clip to a rectangular clip.
auto fp = GrAARectEffect::Make(std::move(inputFP), edgeType, rrect.getBounds());
auto fp = GrFragmentProcessor::Rect(std::move(inputFP), edgeType, rrect.getBounds());
return GrFPSuccess(std::move(fp));
}
if (SkRRectPriv::GetSimpleRadii(rrect).fX == SkRRectPriv::GetSimpleRadii(rrect).fY) {
@ -792,7 +791,8 @@ GrFPResult GrRRectEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP,
return CircularRRectEffect::Make(std::move(inputFP), edgeType, cornerFlags, *rr);
}
case CircularRRectEffect::kNone_CornerFlags: {
auto fp = GrAARectEffect::Make(std::move(inputFP), edgeType, rrect.getBounds());
auto fp =
GrFragmentProcessor::Rect(std::move(inputFP), edgeType, rrect.getBounds());
return GrFPSuccess(std::move(fp));
}
default: {

View File

@ -35,6 +35,7 @@ template <typename T> struct GrFPUniformType {
UNIFORM_TYPE(kFloat, float);
UNIFORM_TYPE(kFloat2, SkV2);
UNIFORM_TYPE(kFloat4, SkPMColor4f);
UNIFORM_TYPE(kFloat4, SkRect);
UNIFORM_TYPE(kFloat4, SkV4);
UNIFORM_TYPE(kFloat4, skvx::Vec<4, float>);
UNIFORM_TYPE(kFloat4x4, SkM44);

View File

@ -1,129 +0,0 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**************************************************************************************************
*** This file was autogenerated from GrAARectEffect.fp; do not modify.
**************************************************************************************************/
#include "GrAARectEffect.h"
#include "src/core/SkUtils.h"
#include "src/gpu/GrTexture.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
#include "src/sksl/SkSLCPP.h"
#include "src/sksl/SkSLUtil.h"
class GrGLSLAARectEffect : public GrGLSLFragmentProcessor {
public:
GrGLSLAARectEffect() {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
const GrAARectEffect& _outer = args.fFp.cast<GrAARectEffect>();
(void)_outer;
auto edgeType = _outer.edgeType;
(void)edgeType;
auto rect = _outer.rect;
(void)rect;
rectUniformVar = args.fUniformHandler->addUniform(
&_outer, kFragment_GrShaderFlag, kFloat4_GrSLType, "rectUniform");
fragBuilder->codeAppendf(
R"SkSL(half coverage;
@switch (%d) {
case 0:
case 2:
coverage = half(all(greaterThan(float4(sk_FragCoord.xy, %s.zw), float4(%s.xy, sk_FragCoord.xy))) ? 1 : 0);
break;
default:
half4 dists4 = clamp(half4(1.0, 1.0, -1.0, -1.0) * half4(sk_FragCoord.xyxy - %s), 0.0, 1.0);
half2 dists2 = (dists4.xy + dists4.zw) - 1.0;
coverage = dists2.x * dists2.y;
}
@if (%d == 2 || %d == 3) {
coverage = 1.0 - coverage;
})SkSL",
(int)_outer.edgeType,
args.fUniformHandler->getUniformCStr(rectUniformVar),
args.fUniformHandler->getUniformCStr(rectUniformVar),
args.fUniformHandler->getUniformCStr(rectUniformVar),
(int)_outer.edgeType,
(int)_outer.edgeType);
SkString _sample0 = this->invokeChild(0, args);
fragBuilder->codeAppendf(
R"SkSL(
return %s * coverage;
)SkSL",
_sample0.c_str());
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {
const GrAARectEffect& _outer = _proc.cast<GrAARectEffect>();
auto edgeType = _outer.edgeType;
(void)edgeType;
auto rect = _outer.rect;
(void)rect;
UniformHandle& rectUniform = rectUniformVar;
(void)rectUniform;
SkASSERT(rect.isSorted());
// The AA math in the shader evaluates to 0 at the uploaded coordinates, so outset by 0.5
// to interpolate from 0 at a half pixel inset and 1 at a half pixel outset of rect.
const SkRect& newRect =
GrProcessorEdgeTypeIsAA(edgeType) ? rect.makeOutset(.5f, .5f) : rect;
pdman.set4f(rectUniform, newRect.fLeft, newRect.fTop, newRect.fRight, newRect.fBottom);
}
UniformHandle rectUniformVar;
};
std::unique_ptr<GrGLSLFragmentProcessor> GrAARectEffect::onMakeProgramImpl() const {
return std::make_unique<GrGLSLAARectEffect>();
}
void GrAARectEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {
b->addBits(2, (uint32_t)edgeType, "edgeType");
}
bool GrAARectEffect::onIsEqual(const GrFragmentProcessor& other) const {
const GrAARectEffect& that = other.cast<GrAARectEffect>();
(void)that;
if (edgeType != that.edgeType) return false;
if (rect != that.rect) return false;
return true;
}
GrAARectEffect::GrAARectEffect(const GrAARectEffect& src)
: INHERITED(kGrAARectEffect_ClassID, src.optimizationFlags())
, edgeType(src.edgeType)
, rect(src.rect) {
this->cloneAndRegisterAllChildProcessors(src);
}
std::unique_ptr<GrFragmentProcessor> GrAARectEffect::clone() const {
return std::make_unique<GrAARectEffect>(*this);
}
#if GR_TEST_UTILS
SkString GrAARectEffect::onDumpInfo() const {
return SkStringPrintf("(edgeType=%d, rect=float4(%f, %f, %f, %f))",
(int)edgeType,
rect.left(),
rect.top(),
rect.right(),
rect.bottom());
}
#endif
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrAARectEffect);
#if GR_TEST_UTILS
std::unique_ptr<GrFragmentProcessor> GrAARectEffect::TestCreate(GrProcessorTestData* d) {
SkScalar l = d->fRandom->nextSScalar1();
SkScalar t = d->fRandom->nextSScalar1();
SkScalar r = d->fRandom->nextSScalar1();
SkScalar b = d->fRandom->nextSScalar1();
SkRect rect = SkRect::MakeLTRB(l, t, r, b);
rect.sort();
GrClipEdgeType edgeType =
static_cast<GrClipEdgeType>(d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
return GrAARectEffect::Make(d->inputFP(), edgeType, rect);
}
#endif

View File

@ -1,53 +0,0 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**************************************************************************************************
*** This file was autogenerated from GrAARectEffect.fp; do not modify.
**************************************************************************************************/
#ifndef GrAARectEffect_DEFINED
#define GrAARectEffect_DEFINED
#include "include/core/SkM44.h"
#include "include/core/SkTypes.h"
#include "src/gpu/GrFragmentProcessor.h"
class GrAARectEffect : public GrFragmentProcessor {
public:
static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP,
GrClipEdgeType edgeType,
SkRect rect) {
return std::unique_ptr<GrFragmentProcessor>(
new GrAARectEffect(std::move(inputFP), edgeType, rect));
}
GrAARectEffect(const GrAARectEffect& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "AARectEffect"; }
GrClipEdgeType edgeType;
SkRect rect;
private:
GrAARectEffect(std::unique_ptr<GrFragmentProcessor> inputFP,
GrClipEdgeType edgeType,
SkRect rect)
: INHERITED(kGrAARectEffect_ClassID,
(OptimizationFlags)ProcessorOptimizationFlags(inputFP.get()) &
kCompatibleWithCoverageAsAlpha_OptimizationFlag)
, edgeType(edgeType)
, rect(rect) {
this->registerChild(std::move(inputFP), SkSL::SampleUsage::PassThrough());
}
std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
#if GR_TEST_UTILS
SkString onDumpInfo() const override;
#endif
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
using INHERITED = GrFragmentProcessor;
};
#endif

View File

@ -1,139 +0,0 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**************************************************************************************************
*** This file was autogenerated from GrCircleEffect.fp; do not modify.
**************************************************************************************************/
#include "GrCircleEffect.h"
#include "src/core/SkUtils.h"
#include "src/gpu/GrTexture.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
#include "src/sksl/SkSLCPP.h"
#include "src/sksl/SkSLUtil.h"
class GrGLSLCircleEffect : public GrGLSLFragmentProcessor {
public:
GrGLSLCircleEffect() {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
const GrCircleEffect& _outer = args.fFp.cast<GrCircleEffect>();
(void)_outer;
auto edgeType = _outer.edgeType;
(void)edgeType;
auto center = _outer.center;
(void)center;
auto radius = _outer.radius;
(void)radius;
circleVar = args.fUniformHandler->addUniform(
&_outer, kFragment_GrShaderFlag, kFloat4_GrSLType, "circle");
fragBuilder->codeAppendf(
R"SkSL(half d;
@if (%d == 2 || %d == 3) {
d = half((length((%s.xy - sk_FragCoord.xy) * %s.w) - 1.0) * %s.z);
} else {
d = half((1.0 - length((%s.xy - sk_FragCoord.xy) * %s.w)) * %s.z);
})SkSL",
(int)_outer.edgeType,
(int)_outer.edgeType,
args.fUniformHandler->getUniformCStr(circleVar),
args.fUniformHandler->getUniformCStr(circleVar),
args.fUniformHandler->getUniformCStr(circleVar),
args.fUniformHandler->getUniformCStr(circleVar),
args.fUniformHandler->getUniformCStr(circleVar),
args.fUniformHandler->getUniformCStr(circleVar));
SkString _sample0 = this->invokeChild(0, args);
fragBuilder->codeAppendf(
R"SkSL(
half4 inputColor = %s;
@if (%d == 1 || %d == 3) {
return inputColor * clamp(d, 0.0, 1.0);
} else {
return d > 0.5 ? inputColor : half4(0.0);
}
)SkSL",
_sample0.c_str(),
(int)_outer.edgeType,
(int)_outer.edgeType);
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {
const GrCircleEffect& _outer = _proc.cast<GrCircleEffect>();
auto edgeType = _outer.edgeType;
(void)edgeType;
auto center = _outer.center;
(void)center;
auto radius = _outer.radius;
(void)radius;
UniformHandle& circle = circleVar;
(void)circle;
SkScalar effectiveRadius = radius;
if (GrProcessorEdgeTypeIsInverseFill(edgeType)) {
effectiveRadius -= 0.5f;
// When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the shader.
effectiveRadius = std::max(0.001f, effectiveRadius);
} else {
effectiveRadius += 0.5f;
}
pdman.set4f(circle, center.fX, center.fY, effectiveRadius, SkScalarInvert(effectiveRadius));
}
UniformHandle circleVar;
};
std::unique_ptr<GrGLSLFragmentProcessor> GrCircleEffect::onMakeProgramImpl() const {
return std::make_unique<GrGLSLCircleEffect>();
}
void GrCircleEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {
b->addBits(2, (uint32_t)edgeType, "edgeType");
}
bool GrCircleEffect::onIsEqual(const GrFragmentProcessor& other) const {
const GrCircleEffect& that = other.cast<GrCircleEffect>();
(void)that;
if (edgeType != that.edgeType) return false;
if (center != that.center) return false;
if (radius != that.radius) return false;
return true;
}
GrCircleEffect::GrCircleEffect(const GrCircleEffect& src)
: INHERITED(kGrCircleEffect_ClassID, src.optimizationFlags())
, edgeType(src.edgeType)
, center(src.center)
, radius(src.radius) {
this->cloneAndRegisterAllChildProcessors(src);
}
std::unique_ptr<GrFragmentProcessor> GrCircleEffect::clone() const {
return std::make_unique<GrCircleEffect>(*this);
}
#if GR_TEST_UTILS
SkString GrCircleEffect::onDumpInfo() const {
return SkStringPrintf("(edgeType=%d, center=float2(%f, %f), radius=%f)",
(int)edgeType,
center.fX,
center.fY,
radius);
}
#endif
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCircleEffect);
#if GR_TEST_UTILS
std::unique_ptr<GrFragmentProcessor> GrCircleEffect::TestCreate(GrProcessorTestData* testData) {
SkPoint center;
center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f);
center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f);
SkScalar radius = testData->fRandom->nextRangeF(1.f, 1000.f);
bool success;
std::unique_ptr<GrFragmentProcessor> fp = testData->inputFP();
do {
GrClipEdgeType et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt);
std::tie(success, fp) = GrCircleEffect::Make(std::move(fp), et, center, radius);
} while (!success);
return fp;
}
#endif

View File

@ -1,62 +0,0 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**************************************************************************************************
*** This file was autogenerated from GrCircleEffect.fp; do not modify.
**************************************************************************************************/
#ifndef GrCircleEffect_DEFINED
#define GrCircleEffect_DEFINED
#include "include/core/SkM44.h"
#include "include/core/SkTypes.h"
#include "src/gpu/GrFragmentProcessor.h"
class GrCircleEffect : public GrFragmentProcessor {
public:
static GrFPResult Make(std::unique_ptr<GrFragmentProcessor> inputFP,
GrClipEdgeType edgeType,
SkPoint center,
float radius) {
// A radius below half causes the implicit insetting done by this processor to become
// inverted. We could handle this case by making the processor code more complicated.
if (radius < .5f && GrProcessorEdgeTypeIsInverseFill(edgeType)) {
return GrFPFailure(std::move(inputFP));
}
return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>(
new GrCircleEffect(std::move(inputFP), edgeType, center, radius)));
}
GrCircleEffect(const GrCircleEffect& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "CircleEffect"; }
GrClipEdgeType edgeType;
SkPoint center;
float radius;
private:
GrCircleEffect(std::unique_ptr<GrFragmentProcessor> inputFP,
GrClipEdgeType edgeType,
SkPoint center,
float radius)
: INHERITED(kGrCircleEffect_ClassID,
(OptimizationFlags)ProcessorOptimizationFlags(inputFP.get()) &
kCompatibleWithCoverageAsAlpha_OptimizationFlag)
, edgeType(edgeType)
, center(center)
, radius(radius) {
this->registerChild(std::move(inputFP), SkSL::SampleUsage::PassThrough());
}
std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
#if GR_TEST_UTILS
SkString onDumpInfo() const override;
#endif
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
using INHERITED = GrFragmentProcessor;
};
#endif

View File

@ -1,177 +0,0 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**************************************************************************************************
*** This file was autogenerated from GrEllipseEffect.fp; do not modify.
**************************************************************************************************/
#include "GrEllipseEffect.h"
#include "src/core/SkUtils.h"
#include "src/gpu/GrTexture.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
#include "src/sksl/SkSLCPP.h"
#include "src/sksl/SkSLUtil.h"
class GrGLSLEllipseEffect : public GrGLSLFragmentProcessor {
public:
GrGLSLEllipseEffect() {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
const GrEllipseEffect& _outer = args.fFp.cast<GrEllipseEffect>();
(void)_outer;
auto edgeType = _outer.edgeType;
(void)edgeType;
auto center = _outer.center;
(void)center;
auto radii = _outer.radii;
(void)radii;
ellipseVar = args.fUniformHandler->addUniform(
&_outer, kFragment_GrShaderFlag, kFloat4_GrSLType, "ellipse");
if (!sk_Caps.floatIs32Bits) {
scaleVar = args.fUniformHandler->addUniform(
&_outer, kFragment_GrShaderFlag, kFloat2_GrSLType, "scale");
}
fragBuilder->codeAppendf(
R"SkSL(float2 d = sk_FragCoord.xy - %s.xy;
const bool medPrecision = !sk_Caps.floatIs32Bits;
@if (medPrecision) {
d *= %s.y;
}
float2 Z = d * %s.zw;
float implicit = dot(Z, d) - 1.0;
float grad_dot = 4.0 * dot(Z, Z);
@if (medPrecision) {
grad_dot = max(grad_dot, 6.1036000261083245e-05);
} else {
grad_dot = max(grad_dot, 1.1754999560161448e-38);
}
float approx_dist = implicit * inversesqrt(grad_dot);
@if (medPrecision) {
approx_dist *= %s.x;
}
half alpha;
@switch (%d) {
case 0:
alpha = approx_dist > 0.0 ? 0.0 : 1.0;
break;
case 1:
alpha = clamp(0.5 - half(approx_dist), 0.0, 1.0);
break;
case 2:
alpha = approx_dist > 0.0 ? 1.0 : 0.0;
break;
case 3:
alpha = clamp(0.5 + half(approx_dist), 0.0, 1.0);
break;
default:
discard;
})SkSL",
args.fUniformHandler->getUniformCStr(ellipseVar),
scaleVar.isValid() ? args.fUniformHandler->getUniformCStr(scaleVar) : "float2(0)",
args.fUniformHandler->getUniformCStr(ellipseVar),
scaleVar.isValid() ? args.fUniformHandler->getUniformCStr(scaleVar) : "float2(0)",
(int)_outer.edgeType);
SkString _sample0 = this->invokeChild(0, args);
fragBuilder->codeAppendf(
R"SkSL(
return %s * alpha;
)SkSL",
_sample0.c_str());
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {
const GrEllipseEffect& _outer = _proc.cast<GrEllipseEffect>();
auto edgeType = _outer.edgeType;
(void)edgeType;
auto center = _outer.center;
(void)center;
auto radii = _outer.radii;
(void)radii;
UniformHandle& ellipse = ellipseVar;
(void)ellipse;
UniformHandle& scale = scaleVar;
(void)scale;
float invRXSqd;
float invRYSqd;
// If we're using a scale factor to work around precision issues, choose the larger radius
// as the scale factor. The inv radii need to be pre-adjusted by the scale factor.
if (scale.isValid()) {
if (radii.fX > radii.fY) {
invRXSqd = 1.f;
invRYSqd = (radii.fX * radii.fX) / (radii.fY * radii.fY);
pdman.set2f(scale, radii.fX, 1.f / radii.fX);
} else {
invRXSqd = (radii.fY * radii.fY) / (radii.fX * radii.fX);
invRYSqd = 1.f;
pdman.set2f(scale, radii.fY, 1.f / radii.fY);
}
} else {
invRXSqd = 1.f / (radii.fX * radii.fX);
invRYSqd = 1.f / (radii.fY * radii.fY);
}
pdman.set4f(ellipse, center.fX, center.fY, invRXSqd, invRYSqd);
}
UniformHandle ellipseVar;
UniformHandle scaleVar;
};
std::unique_ptr<GrGLSLFragmentProcessor> GrEllipseEffect::onMakeProgramImpl() const {
return std::make_unique<GrGLSLEllipseEffect>();
}
void GrEllipseEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {
b->addBits(2, (uint32_t)edgeType, "edgeType");
}
bool GrEllipseEffect::onIsEqual(const GrFragmentProcessor& other) const {
const GrEllipseEffect& that = other.cast<GrEllipseEffect>();
(void)that;
if (edgeType != that.edgeType) return false;
if (center != that.center) return false;
if (radii != that.radii) return false;
return true;
}
GrEllipseEffect::GrEllipseEffect(const GrEllipseEffect& src)
: INHERITED(kGrEllipseEffect_ClassID, src.optimizationFlags())
, edgeType(src.edgeType)
, center(src.center)
, radii(src.radii) {
this->cloneAndRegisterAllChildProcessors(src);
}
std::unique_ptr<GrFragmentProcessor> GrEllipseEffect::clone() const {
return std::make_unique<GrEllipseEffect>(*this);
}
#if GR_TEST_UTILS
SkString GrEllipseEffect::onDumpInfo() const {
return SkStringPrintf("(edgeType=%d, center=float2(%f, %f), radii=float2(%f, %f))",
(int)edgeType,
center.fX,
center.fY,
radii.fX,
radii.fY);
}
#endif
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrEllipseEffect);
#if GR_TEST_UTILS
std::unique_ptr<GrFragmentProcessor> GrEllipseEffect::TestCreate(GrProcessorTestData* testData) {
SkPoint center;
center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f);
center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f);
SkScalar rx = testData->fRandom->nextRangeF(0.f, 1000.f);
SkScalar ry = testData->fRandom->nextRangeF(0.f, 1000.f);
bool success;
std::unique_ptr<GrFragmentProcessor> fp = testData->inputFP();
do {
GrClipEdgeType et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt);
std::tie(success, fp) = GrEllipseEffect::Make(
std::move(fp), et, center, SkPoint::Make(rx, ry), *testData->caps()->shaderCaps());
} while (!success);
return fp;
}
#endif

View File

@ -1,72 +0,0 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**************************************************************************************************
*** This file was autogenerated from GrEllipseEffect.fp; do not modify.
**************************************************************************************************/
#ifndef GrEllipseEffect_DEFINED
#define GrEllipseEffect_DEFINED
#include "include/core/SkM44.h"
#include "include/core/SkTypes.h"
#include "src/gpu/GrShaderCaps.h"
#include "src/gpu/GrFragmentProcessor.h"
class GrEllipseEffect : public GrFragmentProcessor {
public:
static GrFPResult Make(std::unique_ptr<GrFragmentProcessor> inputFP,
GrClipEdgeType edgeType,
SkPoint center,
SkPoint radii,
const GrShaderCaps& caps) {
// Small radii produce bad results on devices without full float.
if (!caps.floatIs32Bits() && (radii.fX < 0.5f || radii.fY < 0.5f)) {
return GrFPFailure(std::move(inputFP));
}
// Very narrow ellipses produce bad results on devices without full float
if (!caps.floatIs32Bits() && (radii.fX > 255 * radii.fY || radii.fY > 255 * radii.fX)) {
return GrFPFailure(std::move(inputFP));
}
// Very large ellipses produce bad results on devices without full float
if (!caps.floatIs32Bits() && (radii.fX > 16384 || radii.fY > 16384)) {
return GrFPFailure(std::move(inputFP));
}
return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>(
new GrEllipseEffect(std::move(inputFP), edgeType, center, radii)));
}
GrEllipseEffect(const GrEllipseEffect& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "EllipseEffect"; }
GrClipEdgeType edgeType;
SkPoint center;
SkPoint radii;
private:
GrEllipseEffect(std::unique_ptr<GrFragmentProcessor> inputFP,
GrClipEdgeType edgeType,
SkPoint center,
SkPoint radii)
: INHERITED(kGrEllipseEffect_ClassID,
(OptimizationFlags)ProcessorOptimizationFlags(inputFP.get()) &
kCompatibleWithCoverageAsAlpha_OptimizationFlag)
, edgeType(edgeType)
, center(center)
, radii(radii) {
this->registerChild(std::move(inputFP), SkSL::SampleUsage::PassThrough());
}
std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
#if GR_TEST_UTILS
SkString onDumpInfo() const override;
#endif
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
using INHERITED = GrFragmentProcessor;
};
#endif