blob: 3e582be829f7d708a83496a52b6a7a7ec741209d [file] [log] [blame]
jvanverth6c177a12016-08-17 07:59:41 -07001/*
2 * Copyright 2016 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#include "SkGaussianEdgeShader.h"
9#include "SkReadBuffer.h"
10#include "SkWriteBuffer.h"
11
12 /** \class SkGaussianEdgeShaderImpl
13 This subclass of shader applies a Gaussian to shadow edge
jvanverthd7315f912016-08-17 10:06:18 -070014
jvanverthd99858a2016-09-12 07:51:04 -070015 If largerBlur is false:
jvanvertha4f1af82016-08-29 07:17:47 -070016 The radius of the Gaussian blur is specified by the g value of the color, in 6.2 fixed point.
17 For spot shadows, we increase the stroke width to set the shadow against the shape. This pad
18 is specified by b, also in 6.2 fixed point. The r value represents the max final alpha.
19 The incoming alpha should be 1.
jvanverthd99858a2016-09-12 07:51:04 -070020
21 If largerBlur is true:
22 The radius of the Gaussian blur is specified by the r & g values of the color in 14.2 fixed point.
23 For spot shadows, we increase the stroke width to set the shadow against the shape. This pad
24 is specified by b, also in 6.2 fixed point. The a value represents the max final alpha.
25
26 LargerBlur will be removed once Android is migrated to the updated shader.
jvanverth6c177a12016-08-17 07:59:41 -070027 */
28class SkGaussianEdgeShaderImpl : public SkShader {
29public:
jvanverthd99858a2016-09-12 07:51:04 -070030 SkGaussianEdgeShaderImpl()
31 : fLargerBlur(false) {}
32
33 SkGaussianEdgeShaderImpl(bool largerBlur)
34 : fLargerBlur(largerBlur) {}
jvanverth6c177a12016-08-17 07:59:41 -070035
36 bool isOpaque() const override;
37
38#if SK_SUPPORT_GPU
39 sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
40#endif
41
42 SK_TO_STRING_OVERRIDE()
43 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkGaussianEdgeShaderImpl)
44
45protected:
46 void flatten(SkWriteBuffer&) const override;
47
48private:
49 friend class SkGaussianEdgeShader;
jvanverthd99858a2016-09-12 07:51:04 -070050 bool fLargerBlur;
jvanverth6c177a12016-08-17 07:59:41 -070051
52 typedef SkShader INHERITED;
53};
54
55////////////////////////////////////////////////////////////////////////////
56
57#if SK_SUPPORT_GPU
58
59#include "GrCoordTransform.h"
60#include "GrFragmentProcessor.h"
61#include "GrInvariantOutput.h"
62#include "glsl/GrGLSLFragmentProcessor.h"
63#include "glsl/GrGLSLFragmentShaderBuilder.h"
64#include "glsl/GrGLSLProgramDataManager.h"
65#include "glsl/GrGLSLUniformHandler.h"
66#include "SkGr.h"
67#include "SkGrPriv.h"
68
69class GaussianEdgeFP : public GrFragmentProcessor {
70public:
jvanverthd99858a2016-09-12 07:51:04 -070071 GaussianEdgeFP(bool largerBlur) : fLargerBlur(largerBlur) {
jvanverth6c177a12016-08-17 07:59:41 -070072 this->initClassID<GaussianEdgeFP>();
73
74 // enable output of distance information for shape
75 fUsesDistanceVectorField = true;
76 }
77
78 class GLSLGaussianEdgeFP : public GrGLSLFragmentProcessor {
79 public:
jvanverthd99858a2016-09-12 07:51:04 -070080 GLSLGaussianEdgeFP(bool largerBlur) : fLargerBlur(largerBlur) {}
jvanverth6c177a12016-08-17 07:59:41 -070081
82 void emitCode(EmitArgs& args) override {
jvanverth6c177a12016-08-17 07:59:41 -070083 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
84
robertphillips05a4cf52016-09-08 09:02:43 -070085 if (!args.fGpImplementsDistanceVector) {
86 fragBuilder->codeAppendf("// GP does not implement fsDistanceVector - "
87 " returning grey in GLSLGaussianEdgeFP\n");
88 fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor);
jvanverthdb856652016-09-12 10:09:16 -070089 fragBuilder->codeAppendf("%s = vec4(0.0, 0.0, 0.0, color.r);", args.fOutputColor);
jvanverthd99858a2016-09-12 07:51:04 -070090 } else if (fLargerBlur) {
91 fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor);
jvanverthdb856652016-09-12 10:09:16 -070092 fragBuilder->codeAppend("float radius = color.r*256.0*64.0 + color.g*64.0;");
93 fragBuilder->codeAppend("float pad = color.b*64.0;");
jvanverthd99858a2016-09-12 07:51:04 -070094
jvanverthdb856652016-09-12 10:09:16 -070095 fragBuilder->codeAppendf("float factor = 1.0 - clamp((%s.z - pad)/radius, 0.0, 1.0);",
jvanverthd99858a2016-09-12 07:51:04 -070096 fragBuilder->distanceVectorName());
jvanverthdb856652016-09-12 10:09:16 -070097 fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
98 fragBuilder->codeAppendf("%s = factor*vec4(0.0, 0.0, 0.0, color.a);",
jvanverthd99858a2016-09-12 07:51:04 -070099 args.fOutputColor);
robertphillips05a4cf52016-09-08 09:02:43 -0700100 } else {
101 fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor);
jvanverthdb856652016-09-12 10:09:16 -0700102 fragBuilder->codeAppend("float radius = color.g*64.0;");
103 fragBuilder->codeAppend("float pad = color.b*64.0;");
jvanverthd7315f912016-08-17 10:06:18 -0700104
jvanverthdb856652016-09-12 10:09:16 -0700105 fragBuilder->codeAppendf("float factor = 1.0 - clamp((%s.z - pad)/radius, 0.0, 1.0);",
robertphillips05a4cf52016-09-08 09:02:43 -0700106 fragBuilder->distanceVectorName());
jvanverthdb856652016-09-12 10:09:16 -0700107 fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
108 fragBuilder->codeAppendf("%s = factor*vec4(0.0, 0.0, 0.0, color.r);",
robertphillips05a4cf52016-09-08 09:02:43 -0700109 args.fOutputColor);
110 }
jvanverth6c177a12016-08-17 07:59:41 -0700111 }
112
113 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
114 GrProcessorKeyBuilder* b) {
jvanverthd99858a2016-09-12 07:51:04 -0700115 const GaussianEdgeFP& gefp = proc.cast<GaussianEdgeFP>();
116 b->add32(gefp.fLargerBlur ? 0x1 : 0x0);
jvanverth6c177a12016-08-17 07:59:41 -0700117 }
118
119 protected:
120 void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {}
jvanverthd99858a2016-09-12 07:51:04 -0700121
122 bool fLargerBlur;
jvanverth6c177a12016-08-17 07:59:41 -0700123 };
124
125 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
126 GLSLGaussianEdgeFP::GenKey(*this, caps, b);
127 }
128
129 const char* name() const override { return "GaussianEdgeFP"; }
130
131 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
132 inout->mulByUnknownFourComponents();
133 }
134
135private:
jvanverthd99858a2016-09-12 07:51:04 -0700136 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
137 return new GLSLGaussianEdgeFP(fLargerBlur);
138 }
jvanverth6c177a12016-08-17 07:59:41 -0700139
140 bool onIsEqual(const GrFragmentProcessor& proc) const override { return true; }
jvanverthd99858a2016-09-12 07:51:04 -0700141
142 bool fLargerBlur;
jvanverth6c177a12016-08-17 07:59:41 -0700143};
144
145////////////////////////////////////////////////////////////////////////////
146
147sk_sp<GrFragmentProcessor> SkGaussianEdgeShaderImpl::asFragmentProcessor(const AsFPArgs& args) const {
jvanverthd99858a2016-09-12 07:51:04 -0700148 return sk_make_sp<GaussianEdgeFP>(fLargerBlur);
jvanverth6c177a12016-08-17 07:59:41 -0700149}
150
151#endif
152
153////////////////////////////////////////////////////////////////////////////
154
155bool SkGaussianEdgeShaderImpl::isOpaque() const {
156 return false;
157}
158
159////////////////////////////////////////////////////////////////////////////
160
161#ifndef SK_IGNORE_TO_STRING
162void SkGaussianEdgeShaderImpl::toString(SkString* str) const {
163 str->appendf("GaussianEdgeShader: ()");
164}
165#endif
166
167sk_sp<SkFlattenable> SkGaussianEdgeShaderImpl::CreateProc(SkReadBuffer& buf) {
168 return sk_make_sp<SkGaussianEdgeShaderImpl>();
169}
170
171void SkGaussianEdgeShaderImpl::flatten(SkWriteBuffer& buf) const {
jvanverth6c177a12016-08-17 07:59:41 -0700172}
173
174///////////////////////////////////////////////////////////////////////////////
175
jvanverthd99858a2016-09-12 07:51:04 -0700176sk_sp<SkShader> SkGaussianEdgeShader::Make(bool largerBlur) {
177 return sk_make_sp<SkGaussianEdgeShaderImpl>(largerBlur);
jvanverth6c177a12016-08-17 07:59:41 -0700178}
179
180///////////////////////////////////////////////////////////////////////////////
181
182SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGaussianEdgeShader)
183SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkGaussianEdgeShaderImpl)
184SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
185
186///////////////////////////////////////////////////////////////////////////////