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:
parent
65b4597d07
commit
b384eb204c
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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)};
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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: {
|
||||
|
@ -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);
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
Loading…
Reference in New Issue
Block a user