blob: 1b0e183ec9cb712998d80764df7238d1c4cb9e77 [file] [log] [blame]
Ethan Nicholas82399462017-10-16 12:35:44 -04001/*
Ethan Nicholas130fb3f2018-02-01 12:14:34 -05002 * Copyright 2018 Google Inc.
Ethan Nicholas82399462017-10-16 12:35:44 -04003 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Ethan Nicholas130fb3f2018-02-01 12:14:34 -05008/**************************************************************************************************
9 *** This file was autogenerated from GrRectBlurEffect.fp; do not modify.
10 **************************************************************************************************/
Ethan Nicholas82399462017-10-16 12:35:44 -040011#ifndef GrRectBlurEffect_DEFINED
12#define GrRectBlurEffect_DEFINED
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkTypes.h"
Ethan Nicholas82399462017-10-16 12:35:44 -040014
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "include/core/SkScalar.h"
16#include "src/core/SkBlurMask.h"
Brian Salomone7366842019-09-04 11:20:45 -040017#include "src/core/SkMathPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/gpu/GrProxyProvider.h"
19#include "src/gpu/GrShaderCaps.h"
20
21#include "src/gpu/GrCoordTransform.h"
22#include "src/gpu/GrFragmentProcessor.h"
Ethan Nicholas82399462017-10-16 12:35:44 -040023class GrRectBlurEffect : public GrFragmentProcessor {
24public:
Brian Salomone7366842019-09-04 11:20:45 -040025 static sk_sp<GrTextureProxy> CreateBlurProfileTexture(GrProxyProvider* proxyProvider,
26 float sigma) {
27 // The "profile" we are calculating is the integral of a Gaussian with 'sigma' and a half
28 // plane. All such profiles are just scales of each other. So all we really care about is
29 // having enough resolution so that the linear interpolation done in texture lookup doesn't
30 // introduce noticeable artifacts. SkBlurMask::ComputeBlurProfile() produces profiles with
31 // ceil(6 * sigma) entries. We conservatively choose to have 2 texels for each dst pixel.
32 int minProfileWidth = 2 * sk_float_ceil2int(6 * sigma);
33 // Bin by powers of 2 with a minimum so we get good profile reuse (remember we can just
34 // scale the texture coords to span the larger profile over a 6 sigma distance).
35 int profileWidth = SkTMax(SkNextPow2(minProfileWidth), 32);
36
37 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
38 GrUniqueKey key;
39 GrUniqueKey::Builder builder(&key, kDomain, 1, "Rect Blur Mask");
40 builder[0] = profileWidth;
41 builder.finish();
42
43 sk_sp<GrTextureProxy> blurProfile(proxyProvider->findOrCreateProxyByUniqueKey(
44 key, GrColorType::kAlpha_8, kTopLeft_GrSurfaceOrigin));
45 if (!blurProfile) {
46 SkBitmap bitmap;
47 if (!bitmap.tryAllocPixels(SkImageInfo::MakeA8(profileWidth, 1))) {
48 return nullptr;
49 }
50 SkBlurMask::ComputeBlurProfile(bitmap.getAddr8(0, 0), profileWidth, profileWidth / 6.f);
51 bitmap.setImmutable();
52 blurProfile = proxyProvider->createProxyFromBitmap(bitmap, GrMipMapped::kNo);
53 if (!blurProfile) {
54 return nullptr;
55 }
56 SkASSERT(blurProfile->origin() == kTopLeft_GrSurfaceOrigin);
57 proxyProvider->assignUniqueKeyToProxy(key, blurProfile.get());
58 }
59
60 return blurProfile;
61 }
62
Mike Kleind6ab77a2019-03-21 08:18:24 -050063 static std::unique_ptr<GrFragmentProcessor> Make(GrProxyProvider* proxyProvider,
64 const GrShaderCaps& caps, const SkRect& rect,
65 float sigma) {
Brian Salomon2c596592019-08-13 20:05:04 -040066 float doubleProfileSize = (12 * sigma);
Brian Salomonff6a7cd2018-05-10 09:42:27 -040067 if (!caps.floatIs32Bits()) {
Brian Salomon2c596592019-08-13 20:05:04 -040068 // We promote the math that gets us into the Gaussian space to full float when the rect
69 // coords are large. If we don't have full float then fail. We could probably clip the
70 // rect to an outset device bounds instead.
Brian Salomonff6a7cd2018-05-10 09:42:27 -040071 if (SkScalarAbs(rect.fLeft) > 16000.f || SkScalarAbs(rect.fTop) > 16000.f ||
Brian Salomon2c596592019-08-13 20:05:04 -040072 SkScalarAbs(rect.fRight) > 16000.f || SkScalarAbs(rect.fBottom) > 16000.f) {
Brian Salomonff6a7cd2018-05-10 09:42:27 -040073 return nullptr;
74 }
75 }
Ethan Nicholas82399462017-10-16 12:35:44 -040076
Brian Salomon2c596592019-08-13 20:05:04 -040077 if (doubleProfileSize >= (float)rect.width() || doubleProfileSize >= (float)rect.height()) {
Ethan Nicholas82399462017-10-16 12:35:44 -040078 // if the blur sigma is too large so the gaussian overlaps the whole
79 // rect in either direction, fall back to CPU path for now.
80 return nullptr;
81 }
82
Brian Salomone7366842019-09-04 11:20:45 -040083 auto profile = CreateBlurProfileTexture(proxyProvider, sigma);
84 if (!profile) {
85 return nullptr;
86 }
87 // The profile is calculated such that the midpoint is at the rect's edge. To simplify
88 // calculating texture coords in the shader, we inset the rect such that the profile
89 // can be used with one end point aligned to the edges of the rect uniform. The texture
90 // coords should be scaled such that the profile is sampled over a 6 sigma range so inset
91 // by 3 sigma.
92 float halfW = 3.f * sigma;
93 auto insetR = rect.makeInset(halfW, halfW);
94 // inverse of the width over which the profile texture should be interpolated outward from
95 // the inset rect.
96 float invWidth = 1.f / (2 * halfW);
97 return std::unique_ptr<GrFragmentProcessor>(new GrRectBlurEffect(
98 insetR, std::move(profile), invWidth, GrSamplerState::ClampBilerp()));
Ethan Nicholas82399462017-10-16 12:35:44 -040099 }
100 GrRectBlurEffect(const GrRectBlurEffect& src);
101 std::unique_ptr<GrFragmentProcessor> clone() const override;
Mike Kleind6ab77a2019-03-21 08:18:24 -0500102 const char* name() const override { return "RectBlurEffect"; }
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400103 SkRect rect;
Brian Salomone7366842019-09-04 11:20:45 -0400104 TextureSampler blurProfile;
105 float invProfileWidth;
Ethan Nicholas82399462017-10-16 12:35:44 -0400106
107private:
Brian Salomone7366842019-09-04 11:20:45 -0400108 GrRectBlurEffect(SkRect rect, sk_sp<GrTextureProxy> blurProfile, float invProfileWidth,
109 GrSamplerState samplerParams)
Ethan Nicholas82399462017-10-16 12:35:44 -0400110 : INHERITED(kGrRectBlurEffect_ClassID,
111 (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag)
Ethan Nicholasbcd51e82019-04-09 10:40:41 -0400112 , rect(rect)
Brian Salomone7366842019-09-04 11:20:45 -0400113 , blurProfile(std::move(blurProfile), samplerParams)
114 , invProfileWidth(invProfileWidth) {
115 this->setTextureSamplerCnt(1);
116 }
Ethan Nicholas82399462017-10-16 12:35:44 -0400117 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
118 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
119 bool onIsEqual(const GrFragmentProcessor&) const override;
Brian Salomone7366842019-09-04 11:20:45 -0400120 const TextureSampler& onTextureSampler(int) const override;
Ethan Nicholas82399462017-10-16 12:35:44 -0400121 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Ethan Nicholas82399462017-10-16 12:35:44 -0400122 typedef GrFragmentProcessor INHERITED;
123};
124#endif