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 GrRectBlurEffect.fp; do not modify.
10 **************************************************************************************************/
11#ifndef GrRectBlurEffect_DEFINED
12#define GrRectBlurEffect_DEFINED
13#include "include/core/SkTypes.h"
14#include "include/core/SkM44.h"
15
16#include <cmath>
17#include "include/core/SkRect.h"
18#include "include/core/SkScalar.h"
19#include "include/gpu/GrContext.h"
20#include "include/private/GrRecordingContext.h"
21#include "src/core/SkBlurMask.h"
22#include "src/core/SkMathPriv.h"
23#include "src/gpu/GrBitmapTextureMaker.h"
24#include "src/gpu/GrProxyProvider.h"
25#include "src/gpu/GrRecordingContextPriv.h"
26#include "src/gpu/GrShaderCaps.h"
27
28#include "src/gpu/GrCoordTransform.h"
29#include "src/gpu/GrFragmentProcessor.h"
30class GrRectBlurEffect : public GrFragmentProcessor {
31public:
32 static GrSurfaceProxyView CreateIntegralTexture(GrRecordingContext* context, float sixSigma) {
33 // The texture we're producing represents the integral of a normal distribution over a
34 // six-sigma range centered at zero. We want enough resolution so that the linear
35 // interpolation done in texture lookup doesn't introduce noticeable artifacts. We
36 // conservatively choose to have 2 texels for each dst pixel.
37 int minWidth = 2 * sk_float_ceil2int(sixSigma);
38 // Bin by powers of 2 with a minimum so we get good profile reuse.
39 int width = std::max(SkNextPow2(minWidth), 32);
40
41 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
42 GrUniqueKey key;
43 GrUniqueKey::Builder builder(&key, kDomain, 1, "Rect Blur Mask");
44 builder[0] = width;
45 builder.finish();
46
47 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
48 if (sk_sp<GrTextureProxy> proxy = proxyProvider->findOrCreateProxyByUniqueKey(key)) {
49 GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(proxy->backendFormat(),
50 GrColorType::kAlpha_8);
51 return {std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle};
52 }
53
54 SkBitmap bitmap;
55 if (!bitmap.tryAllocPixels(SkImageInfo::MakeA8(width, 1))) {
56 return {};
57 }
58 *bitmap.getAddr8(0, 0) = 255;
59 const float invWidth = 1.f / width;
60 for (int i = 1; i < width - 1; ++i) {
61 float x = (i + 0.5f) * invWidth;
62 x = (-6 * x + 3) * SK_ScalarRoot2Over2;
63 float integral = 0.5f * (std::erf(x) + 1.f);
64 *bitmap.getAddr8(i, 0) = SkToU8(sk_float_round2int(255.f * integral));
65 }
66 *bitmap.getAddr8(width - 1, 0) = 0;
67 bitmap.setImmutable();
68
69 GrBitmapTextureMaker maker(context, bitmap, GrImageTexGenPolicy::kNew_Uncached_Budgeted);
70 auto view = maker.view(GrMipMapped::kNo);
71 if (!view) {
72 return {};
73 }
74 SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin);
75 proxyProvider->assignUniqueKeyToProxy(key, view.asTextureProxy());
76 return view;
77 }
78
79 static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext* context,
80 const GrShaderCaps& caps,
81 const SkRect& rect,
82 float sigma) {
83 SkASSERT(rect.isSorted());
84 if (!caps.floatIs32Bits()) {
85 // We promote the math that gets us into the Gaussian space to full float when the rect
86 // coords are large. If we don't have full float then fail. We could probably clip the
87 // rect to an outset device bounds instead.
88 if (SkScalarAbs(rect.fLeft) > 16000.f || SkScalarAbs(rect.fTop) > 16000.f ||
89 SkScalarAbs(rect.fRight) > 16000.f || SkScalarAbs(rect.fBottom) > 16000.f) {
90 return nullptr;
91 }
92 }
93
94 const float sixSigma = 6 * sigma;
95 GrSurfaceProxyView integral = CreateIntegralTexture(context, sixSigma);
96 if (!integral) {
97 return nullptr;
98 }
99
100 // In the fast variant we think of the midpoint of the integral texture as aligning
101 // with the closest rect edge both in x and y. To simplify texture coord calculation we
102 // inset the rect so that the edge of the inset rect corresponds to t = 0 in the texture.
103 // It actually simplifies things a bit in the !isFast case, too.
104 float threeSigma = sixSigma / 2;
105 SkRect insetRect = {rect.fLeft + threeSigma, rect.fTop + threeSigma,
106 rect.fRight - threeSigma, rect.fBottom - threeSigma};
107
108 // In our fast variant we find the nearest horizontal and vertical edges and for each
109 // do a lookup in the integral texture for each and multiply them. When the rect is
110 // less than 6 sigma wide then things aren't so simple and we have to consider both the
111 // left and right edge of the rectangle (and similar in y).
112 bool isFast = insetRect.isSorted();
113 // 1 / (6 * sigma) is the domain of the integral texture. We use the inverse to produce
114 // normalized texture coords from frag coord distances.
115 float invSixSigma = 1.f / sixSigma;
116 return std::unique_ptr<GrFragmentProcessor>(
117 new GrRectBlurEffect(insetRect, std::move(integral), invSixSigma, isFast,
118 GrSamplerState::Filter::kBilerp));
119 }
120 GrRectBlurEffect(const GrRectBlurEffect& src);
121 std::unique_ptr<GrFragmentProcessor> clone() const override;
122 const char* name() const override { return "RectBlurEffect"; }
123 SkRect rect;
124 TextureSampler integral;
125 float invSixSigma;
126 bool isFast;
127
128private:
129 GrRectBlurEffect(SkRect rect,
130 GrSurfaceProxyView integral,
131 float invSixSigma,
132 bool isFast,
133 GrSamplerState samplerParams)
134 : INHERITED(kGrRectBlurEffect_ClassID,
135 (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag)
136 , rect(rect)
137 , integral(std::move(integral), samplerParams)
138 , invSixSigma(invSixSigma)
139 , isFast(isFast) {
140 this->setTextureSamplerCnt(1);
141 }
142 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
143 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
144 bool onIsEqual(const GrFragmentProcessor&) const override;
145 const TextureSampler& onTextureSampler(int) const override;
146 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
147 typedef GrFragmentProcessor INHERITED;
148};
149#endif
150