1/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8/**************************************************************************************************
9 *** This file was autogenerated from GrRRectBlurEffect.fp; do not modify.
10 **************************************************************************************************/
11#include "GrRRectBlurEffect.h"
12#if SK_SUPPORT_GPU
13
14std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::Make(GrContext* context, float sigma,
15                                                             float xformedSigma,
16                                                             const SkRRect& srcRRect,
17                                                             const SkRRect& devRRect) {
18    SkASSERT(!devRRect.isCircle() && !devRRect.isRect());  // Should've been caught up-stream
19
20    // TODO: loosen this up
21    if (!devRRect.isSimpleCircular()) {
22        return nullptr;
23    }
24
25    // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be
26    // sufficiently small relative to both the size of the corner radius and the
27    // width (and height) of the rrect.
28    SkRRect rrectToDraw;
29    SkISize size;
30    SkScalar ignored[SkBlurMaskFilter::kMaxDivisions];
31    int ignoredSize;
32    uint32_t ignored32;
33
34    bool ninePatchable = SkBlurMaskFilter::ComputeBlurredRRectParams(
35            srcRRect, devRRect, SkRect::MakeEmpty(), sigma, xformedSigma, &rrectToDraw, &size,
36            ignored, ignored, ignored, ignored, &ignoredSize, &ignoredSize, &ignored32);
37    if (!ninePatchable) {
38        return nullptr;
39    }
40
41    sk_sp<GrTextureProxy> mask(
42            find_or_create_rrect_blur_mask(context, rrectToDraw, size, xformedSigma));
43    if (!mask) {
44        return nullptr;
45    }
46
47    return std::unique_ptr<GrFragmentProcessor>(new GrRRectBlurEffect(
48            xformedSigma, devRRect.getBounds(), devRRect.getSimpleRadii().fX, std::move(mask)));
49}
50#include "glsl/GrGLSLFragmentProcessor.h"
51#include "glsl/GrGLSLFragmentShaderBuilder.h"
52#include "glsl/GrGLSLProgramBuilder.h"
53#include "GrTexture.h"
54#include "SkSLCPP.h"
55#include "SkSLUtil.h"
56class GrGLSLRRectBlurEffect : public GrGLSLFragmentProcessor {
57public:
58    GrGLSLRRectBlurEffect() {}
59    void emitCode(EmitArgs& args) override {
60        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
61        const GrRRectBlurEffect& _outer = args.fFp.cast<GrRRectBlurEffect>();
62        (void)_outer;
63        auto sigma = _outer.sigma();
64        (void)sigma;
65        auto rect = _outer.rect();
66        (void)rect;
67        auto cornerRadius = _outer.cornerRadius();
68        (void)cornerRadius;
69        fCornerRadiusVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
70                                                            kDefault_GrSLPrecision, "cornerRadius");
71        fProxyRectVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType,
72                                                         kDefault_GrSLPrecision, "proxyRect");
73        fBlurRadiusVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
74                                                          kDefault_GrSLPrecision, "blurRadius");
75        fragBuilder->codeAppendf(
76                "\nhalf2 translatedFragPos = half2(sk_FragCoord.xy - %s.xy);\nhalf threshold = "
77                "half(%s + 2.0 * float(%s));\nhalf2 middle = half2((%s.zw - %s.xy) - 2.0 * "
78                "float(threshold));\nif (translatedFragPos.x >= threshold && translatedFragPos.x < "
79                "middle.x + threshold) {\n    translatedFragPos.x = threshold;\n} else if "
80                "(translatedFragPos.x >= middle.x + threshold) {\n    translatedFragPos.x -= "
81                "float(middle.x) - 1.0;\n}\nif (translatedFragPos.y > threshold && "
82                "translatedFragPos.y < middle.y + threshold) {\n    translatedFr",
83                args.fUniformHandler->getUniformCStr(fProxyRectVar),
84                args.fUniformHandler->getUniformCStr(fCornerRadiusVar),
85                args.fUniformHandler->getUniformCStr(fBlurRadiusVar),
86                args.fUniformHandler->getUniformCStr(fProxyRectVar),
87                args.fUniformHandler->getUniformCStr(fProxyRectVar));
88        fragBuilder->codeAppendf(
89                "agPos.y = threshold;\n} else if (translatedFragPos.y >= middle.y + threshold) {\n "
90                "   translatedFragPos.y -= float(middle.y) - 1.0;\n}\nhalf2 proxyDims = "
91                "half2(half(2.0 * float(threshold) + 1.0));\nhalf2 texCoord = translatedFragPos / "
92                "proxyDims;\n%s = %s * texture(%s, float2(texCoord)).%s;\n",
93                args.fOutputColor, args.fInputColor ? args.fInputColor : "half4(1)",
94                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
95                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str());
96    }
97
98private:
99    void onSetData(const GrGLSLProgramDataManager& pdman,
100                   const GrFragmentProcessor& _proc) override {
101        const GrRRectBlurEffect& _outer = _proc.cast<GrRRectBlurEffect>();
102        { pdman.set1f(fCornerRadiusVar, _outer.cornerRadius()); }
103        auto sigma = _outer.sigma();
104        (void)sigma;
105        auto rect = _outer.rect();
106        (void)rect;
107        UniformHandle& cornerRadius = fCornerRadiusVar;
108        (void)cornerRadius;
109        GrSurfaceProxy& ninePatchSamplerProxy = *_outer.textureSampler(0).proxy();
110        GrTexture& ninePatchSampler = *ninePatchSamplerProxy.priv().peekTexture();
111        (void)ninePatchSampler;
112        UniformHandle& proxyRect = fProxyRectVar;
113        (void)proxyRect;
114        UniformHandle& blurRadius = fBlurRadiusVar;
115        (void)blurRadius;
116
117        float blurRadiusValue = 3.f * SkScalarCeilToScalar(sigma - 1 / 6.0f);
118        pdman.set1f(blurRadius, blurRadiusValue);
119
120        SkRect outset = rect;
121        outset.outset(blurRadiusValue, blurRadiusValue);
122        pdman.set4f(proxyRect, outset.fLeft, outset.fTop, outset.fRight, outset.fBottom);
123    }
124    UniformHandle fProxyRectVar;
125    UniformHandle fBlurRadiusVar;
126    UniformHandle fCornerRadiusVar;
127};
128GrGLSLFragmentProcessor* GrRRectBlurEffect::onCreateGLSLInstance() const {
129    return new GrGLSLRRectBlurEffect();
130}
131void GrRRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
132                                              GrProcessorKeyBuilder* b) const {}
133bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
134    const GrRRectBlurEffect& that = other.cast<GrRRectBlurEffect>();
135    (void)that;
136    if (fSigma != that.fSigma) return false;
137    if (fRect != that.fRect) return false;
138    if (fCornerRadius != that.fCornerRadius) return false;
139    if (fNinePatchSampler != that.fNinePatchSampler) return false;
140    return true;
141}
142GrRRectBlurEffect::GrRRectBlurEffect(const GrRRectBlurEffect& src)
143        : INHERITED(kGrRRectBlurEffect_ClassID, src.optimizationFlags())
144        , fSigma(src.fSigma)
145        , fRect(src.fRect)
146        , fCornerRadius(src.fCornerRadius)
147        , fNinePatchSampler(src.fNinePatchSampler) {
148    this->addTextureSampler(&fNinePatchSampler);
149}
150std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::clone() const {
151    return std::unique_ptr<GrFragmentProcessor>(new GrRRectBlurEffect(*this));
152}
153GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect);
154#if GR_TEST_UTILS
155std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) {
156    SkScalar w = d->fRandom->nextRangeScalar(100.f, 1000.f);
157    SkScalar h = d->fRandom->nextRangeScalar(100.f, 1000.f);
158    SkScalar r = d->fRandom->nextRangeF(1.f, 9.f);
159    SkScalar sigma = d->fRandom->nextRangeF(1.f, 10.f);
160    SkRRect rrect;
161    rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
162    return GrRRectBlurEffect::Make(d->context(), sigma, sigma, rrect, rrect);
163}
164#endif
165#endif
166