OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrCircleBlurFragmentProcessor.h" | 8 #include "GrCircleBlurFragmentProcessor.h" |
9 | 9 |
10 #if SK_SUPPORT_GPU | 10 #if SK_SUPPORT_GPU |
(...skipping 16 matching lines...) Expand all Loading... |
27 protected: | 27 protected: |
28 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override
; | 28 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override
; |
29 | 29 |
30 private: | 30 private: |
31 GrGLSLProgramDataManager::UniformHandle fDataUniform; | 31 GrGLSLProgramDataManager::UniformHandle fDataUniform; |
32 | 32 |
33 typedef GrGLSLFragmentProcessor INHERITED; | 33 typedef GrGLSLFragmentProcessor INHERITED; |
34 }; | 34 }; |
35 | 35 |
36 void GrCircleBlurFragmentProcessor::GLSLProcessor::emitCode(EmitArgs& args) { | 36 void GrCircleBlurFragmentProcessor::GLSLProcessor::emitCode(EmitArgs& args) { |
37 | |
38 const char *dataName; | 37 const char *dataName; |
39 | 38 |
40 // The data is formatted as: | 39 // The data is formatted as: |
41 // x,y - the center of the circle | 40 // x,y - the center of the circle |
42 // z - the distance at which the intensity starts falling off (e.g., the
start of the table) | 41 // z - inner radius that should map to 0th entry in the texture. |
43 // w - the inverse of the distance over which the texture is stretched. | 42 // w - the inverse of the distance over which the texture is stretched. |
44 fDataUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, | 43 fDataUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, |
45 kVec4f_GrSLType, | 44 kVec4f_GrSLType, |
46 kDefault_GrSLPrecision, | 45 kDefault_GrSLPrecision, |
47 "data", | 46 "data", |
48 &dataName); | 47 &dataName); |
49 | 48 |
50 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; | 49 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; |
51 const char *fragmentPos = fragBuilder->fragmentPosition(); | 50 const char *fragmentPos = fragBuilder->fragmentPosition(); |
52 | 51 |
53 if (args.fInputColor) { | 52 if (args.fInputColor) { |
54 fragBuilder->codeAppendf("vec4 src=%s;", args.fInputColor); | 53 fragBuilder->codeAppendf("vec4 src=%s;", args.fInputColor); |
55 } else { | 54 } else { |
56 fragBuilder->codeAppendf("vec4 src=vec4(1);"); | 55 fragBuilder->codeAppendf("vec4 src=vec4(1);"); |
57 } | 56 } |
58 | 57 |
59 // We just want to compute "length(vec) - %s.z + 0.5) * %s.w" but need to re
arrange | 58 // We just want to compute "(length(vec) - %s.z + 0.5) * %s.w" but need to r
earrange |
60 // for precision | 59 // for precision. |
61 fragBuilder->codeAppendf("vec2 vec = vec2( (%s.x - %s.x) * %s.w , (%s.y - %s
.y) * %s.w );", | 60 fragBuilder->codeAppendf("vec2 vec = vec2( (%s.x - %s.x) * %s.w , (%s.y - %s
.y) * %s.w );", |
62 fragmentPos, dataName, dataName, | 61 fragmentPos, dataName, dataName, |
63 fragmentPos, dataName, dataName); | 62 fragmentPos, dataName, dataName); |
64 fragBuilder->codeAppendf("float dist = length(vec) + ( 0.5 - %s.z ) * %s.w;"
, | 63 fragBuilder->codeAppendf("float dist = length(vec) + (0.5 - %s.z) * %s.w;", |
65 dataName, dataName); | 64 dataName, dataName); |
66 | 65 |
67 fragBuilder->codeAppendf("float intensity = "); | 66 fragBuilder->codeAppendf("float intensity = "); |
68 fragBuilder->appendTextureLookup(args.fTexSamplers[0], "vec2(dist, 0.5)"); | 67 fragBuilder->appendTextureLookup(args.fTexSamplers[0], "vec2(dist, 0.5)"); |
69 fragBuilder->codeAppend(".a;"); | 68 fragBuilder->codeAppend(".a;"); |
70 | 69 |
71 fragBuilder->codeAppendf("%s = src * intensity;\n", args.fOutputColor ); | 70 fragBuilder->codeAppendf("%s = src * intensity;\n", args.fOutputColor ); |
72 } | 71 } |
73 | 72 |
74 void GrCircleBlurFragmentProcessor::GLSLProcessor::onSetData(const GrGLSLProgram
DataManager& pdman, | 73 void GrCircleBlurFragmentProcessor::GLSLProcessor::onSetData(const GrGLSLProgram
DataManager& pdman, |
75 const GrProcessor&
proc) { | 74 const GrProcessor&
proc) { |
76 const GrCircleBlurFragmentProcessor& cbfp = proc.cast<GrCircleBlurFragmentPr
ocessor>(); | 75 const GrCircleBlurFragmentProcessor& cbfp = proc.cast<GrCircleBlurFragmentPr
ocessor>(); |
77 const SkRect& circle = cbfp.fCircle; | 76 const SkRect& circle = cbfp.fCircle; |
78 | 77 |
79 // The data is formatted as: | 78 // The data is formatted as: |
80 // x,y - the center of the circle | 79 // x,y - the center of the circle |
81 // z - the distance at which the intensity starts falling off (e.g., the
start of the table) | 80 // z - inner radius that should map to 0th entry in the texture. |
82 // w - the inverse of the distance over which the profile texture is stre
tched. | 81 // w - the inverse of the distance over which the profile texture is stre
tched. |
83 pdman.set4f(fDataUniform, circle.centerX(), circle.centerY(), cbfp.fSolidRad
ius, | 82 pdman.set4f(fDataUniform, circle.centerX(), circle.centerY(), cbfp.fSolidRad
ius, |
84 1.f / cbfp.fTextureRadius); | 83 1.f / cbfp.fTextureRadius); |
85 } | 84 } |
86 | 85 |
87 /////////////////////////////////////////////////////////////////////////////// | 86 /////////////////////////////////////////////////////////////////////////////// |
88 | 87 |
89 GrCircleBlurFragmentProcessor::GrCircleBlurFragmentProcessor(const SkRect& circl
e, | 88 GrCircleBlurFragmentProcessor::GrCircleBlurFragmentProcessor(const SkRect& circl
e, |
90 float sigma, | 89 float textureRadius
, |
91 float solidRadius, | 90 float solidRadius, |
92 float textureRadius
, | |
93 GrTexture* blurProf
ile) | 91 GrTexture* blurProf
ile) |
94 : fCircle(circle) | 92 : fCircle(circle) |
95 , fSigma(sigma) | |
96 , fSolidRadius(solidRadius) | 93 , fSolidRadius(solidRadius) |
97 , fTextureRadius(textureRadius) | 94 , fTextureRadius(textureRadius) |
98 , fBlurProfileAccess(blurProfile, GrTextureParams::kBilerp_FilterMode) { | 95 , fBlurProfileAccess(blurProfile, GrTextureParams::kBilerp_FilterMode) { |
99 this->initClassID<GrCircleBlurFragmentProcessor>(); | 96 this->initClassID<GrCircleBlurFragmentProcessor>(); |
100 this->addTextureAccess(&fBlurProfileAccess); | 97 this->addTextureAccess(&fBlurProfileAccess); |
101 this->setWillReadFragmentPosition(); | 98 this->setWillReadFragmentPosition(); |
102 } | 99 } |
103 | 100 |
104 GrGLSLFragmentProcessor* GrCircleBlurFragmentProcessor::onCreateGLSLInstance() c
onst { | 101 GrGLSLFragmentProcessor* GrCircleBlurFragmentProcessor::onCreateGLSLInstance() c
onst { |
105 return new GLSLProcessor; | 102 return new GLSLProcessor; |
106 } | 103 } |
107 | 104 |
108 void GrCircleBlurFragmentProcessor::onGetGLSLProcessorKey(const GrGLSLCaps& caps
, | 105 void GrCircleBlurFragmentProcessor::onGetGLSLProcessorKey(const GrGLSLCaps& caps
, |
109 GrProcessorKeyBuilder*
b) const { | 106 GrProcessorKeyBuilder*
b) const { |
110 // The code for this processor is always the same so there is nothing to add
to the key. | 107 // The code for this processor is always the same so there is nothing to add
to the key. |
111 return; | 108 return; |
112 } | 109 } |
113 | 110 |
114 void GrCircleBlurFragmentProcessor::onComputeInvariantOutput(GrInvariantOutput*
inout) const { | 111 void GrCircleBlurFragmentProcessor::onComputeInvariantOutput(GrInvariantOutput*
inout) const { |
115 inout->mulByUnknownSingleComponent(); | 112 inout->mulByUnknownSingleComponent(); |
116 } | 113 } |
117 | 114 |
118 // Create a Gaussian half-kernel and a summed area table given a sigma and numbe
r of discrete | 115 // Computes an unnormalized half kernel (right side). Returns the summation of a
ll the half kernel |
119 // steps. The half kernel is normalized to sum to 0.5. | 116 // values. |
120 static void make_half_kernel_and_summed_table(float* halfKernel, float* summedHa
lfKernel, | 117 static float make_unnormalized_half_kernel(float* halfKernel, int halfKernelSize
, float sigma) { |
121 int halfKernelSize, float sigma) { | |
122 const float invSigma = 1.f / sigma; | 118 const float invSigma = 1.f / sigma; |
123 const float b = -0.5f * invSigma * invSigma; | 119 const float b = -0.5f * invSigma * invSigma; |
124 float tot = 0.0f; | 120 float tot = 0.0f; |
125 // Compute half kernel values at half pixel steps out from the center. | 121 // Compute half kernel values at half pixel steps out from the center. |
126 float t = 0.5f; | 122 float t = 0.5f; |
127 for (int i = 0; i < halfKernelSize; ++i) { | 123 for (int i = 0; i < halfKernelSize; ++i) { |
128 float value = expf(t * t * b); | 124 float value = expf(t * t * b); |
129 tot += value; | 125 tot += value; |
130 halfKernel[i] = value; | 126 halfKernel[i] = value; |
131 t += 1.f; | 127 t += 1.f; |
132 } | 128 } |
| 129 return tot; |
| 130 } |
| 131 |
| 132 // Create a Gaussian half-kernel (right side) and a summed area table given a si
gma and number of |
| 133 // discrete steps. The half kernel is normalized to sum to 0.5. |
| 134 static void make_half_kernel_and_summed_table(float* halfKernel, float* summedHa
lfKernel, |
| 135 int halfKernelSize, float sigma) { |
| 136 // The half kernel should sum to 0.5 not 1.0. |
| 137 const float tot = 2.f * make_unnormalized_half_kernel(halfKernel, halfKernel
Size, sigma); |
133 float sum = 0.f; | 138 float sum = 0.f; |
134 // The half kernel should sum to 0.5 not 1.0. | |
135 tot *= 2.f; | |
136 for (int i = 0; i < halfKernelSize; ++i) { | 139 for (int i = 0; i < halfKernelSize; ++i) { |
137 halfKernel[i] /= tot; | 140 halfKernel[i] /= tot; |
138 sum += halfKernel[i]; | 141 sum += halfKernel[i]; |
139 summedHalfKernel[i] = sum; | 142 summedHalfKernel[i] = sum; |
140 } | 143 } |
141 } | 144 } |
142 | 145 |
143 // Applies the 1D half kernel vertically at points along the x axis to a circle
centered at the | 146 // Applies the 1D half kernel vertically at points along the x axis to a circle
centered at the |
144 // origin with radius circleR. | 147 // origin with radius circleR. |
145 void apply_kernel_in_y(float* results, int numSteps, float firstX, float circleR
, | 148 void apply_kernel_in_y(float* results, int numSteps, float firstX, float circleR
, |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 return SkUnitScalarClampToByte(2.f * acc); | 199 return SkUnitScalarClampToByte(2.f * acc); |
197 } | 200 } |
198 | 201 |
199 // This function creates a profile of a blurred circle. It does this by computin
g a kernel for | 202 // This function creates a profile of a blurred circle. It does this by computin
g a kernel for |
200 // half the Gaussian and a matching summed area table. The summed area table is
used to compute | 203 // half the Gaussian and a matching summed area table. The summed area table is
used to compute |
201 // an array of vertical applications of the half kernel to the circle along the
x axis. The table | 204 // an array of vertical applications of the half kernel to the circle along the
x axis. The table |
202 // of y evaluations has 2 * k + n entries where k is the size of the half kernel
and n is the size | 205 // of y evaluations has 2 * k + n entries where k is the size of the half kernel
and n is the size |
203 // of the profile being computed. Then for each of the n profile entries we walk
out k steps in each | 206 // of the profile being computed. Then for each of the n profile entries we walk
out k steps in each |
204 // horizontal direction multiplying the corresponding y evaluation by the half k
ernel entry and | 207 // horizontal direction multiplying the corresponding y evaluation by the half k
ernel entry and |
205 // sum these values to compute the profile entry. | 208 // sum these values to compute the profile entry. |
206 static uint8_t* create_profile(float sigma, float circleR, float offset, int pro
fileTextureWidth) { | 209 static uint8_t* create_circle_profile(float sigma, float circleR, int profileTex
tureWidth) { |
207 const int numSteps = profileTextureWidth; | 210 const int numSteps = profileTextureWidth; |
208 uint8_t* weights = new uint8_t[numSteps]; | 211 uint8_t* weights = new uint8_t[numSteps]; |
209 | 212 |
210 // The full kernel is 6 sigmas wide. | 213 // The full kernel is 6 sigmas wide. |
211 int halfKernelSize = SkScalarCeilToInt(6.0f*sigma); | 214 int halfKernelSize = SkScalarCeilToInt(6.0f*sigma); |
212 // round up to next multiple of 2 and then divide by 2 | 215 // round up to next multiple of 2 and then divide by 2 |
213 halfKernelSize = ((halfKernelSize + 1) & ~1) >> 1; | 216 halfKernelSize = ((halfKernelSize + 1) & ~1) >> 1; |
214 | 217 |
215 // Number of x steps at which to apply kernel in y to cover all the profile
samples in x. | 218 // Number of x steps at which to apply kernel in y to cover all the profile
samples in x. |
216 int numYSteps = numSteps + 2 * halfKernelSize; | 219 int numYSteps = numSteps + 2 * halfKernelSize; |
217 | 220 |
218 SkAutoTArray<float> bulkAlloc(halfKernelSize + halfKernelSize + numYSteps); | 221 SkAutoTArray<float> bulkAlloc(halfKernelSize + halfKernelSize + numYSteps); |
219 float* halfKernel = bulkAlloc.get(); | 222 float* halfKernel = bulkAlloc.get(); |
220 float* summedKernel = bulkAlloc.get() + halfKernelSize; | 223 float* summedKernel = bulkAlloc.get() + halfKernelSize; |
221 float* yEvals = bulkAlloc.get() + 2 * halfKernelSize; | 224 float* yEvals = bulkAlloc.get() + 2 * halfKernelSize; |
222 make_half_kernel_and_summed_table(halfKernel, summedKernel, halfKernelSize,
sigma); | 225 make_half_kernel_and_summed_table(halfKernel, summedKernel, halfKernelSize,
sigma); |
223 | 226 |
224 float firstX = offset - halfKernelSize + 0.5f; | 227 float firstX = -halfKernelSize + 0.5f; |
225 apply_kernel_in_y(yEvals, numYSteps, firstX, circleR, halfKernelSize, summed
Kernel); | 228 apply_kernel_in_y(yEvals, numYSteps, firstX, circleR, halfKernelSize, summed
Kernel); |
226 | 229 |
227 for (int i = 0; i < numSteps - 1; ++i) { | 230 for (int i = 0; i < numSteps - 1; ++i) { |
228 float evalX = offset + i + 0.5f; | 231 float evalX = i + 0.5f; |
229 weights[i] = eval_at(evalX, circleR, halfKernel, halfKernelSize, yEvals
+ i); | 232 weights[i] = eval_at(evalX, circleR, halfKernel, halfKernelSize, yEvals
+ i); |
230 } | 233 } |
231 // Ensure the tail of the Gaussian goes to zero. | 234 // Ensure the tail of the Gaussian goes to zero. |
232 weights[numSteps - 1] = 0; | 235 weights[numSteps - 1] = 0; |
233 return weights; | 236 return weights; |
234 } | 237 } |
235 | 238 |
236 static int next_pow2_16bits(int x) { | 239 static uint8_t* create_half_plane_profile(int profileWidth) { |
237 SkASSERT(x > 0); | 240 SkASSERT(!(profileWidth & 0x1)); |
238 SkASSERT(x <= SK_MaxS16); | 241 // The full kernel is 6 sigmas wide. |
239 x--; | 242 float sigma = profileWidth / 6.f; |
240 x |= x >> 1; | 243 int halfKernelSize = profileWidth / 2; |
241 x |= x >> 2; | 244 |
242 x |= x >> 4; | 245 SkAutoTArray<float> halfKernel(halfKernelSize); |
243 x |= x >> 8; | 246 uint8_t* profile = new uint8_t[profileWidth]; |
244 return x + 1; | 247 |
| 248 // The half kernel should sum to 0.5. |
| 249 const float tot = 2.f * make_unnormalized_half_kernel(halfKernel.get(), half
KernelSize, sigma); |
| 250 float sum = 0.f; |
| 251 // Populate the profile from the right edge to the middle. |
| 252 for (int i = 0; i < halfKernelSize; ++i) { |
| 253 halfKernel[halfKernelSize - i - 1] /= tot; |
| 254 sum += halfKernel[halfKernelSize - i - 1]; |
| 255 profile[profileWidth - i - 1] = SkUnitScalarClampToByte(sum); |
| 256 } |
| 257 // Populate the profile from the middle to the left edge (by flipping the ha
lf kernel and |
| 258 // continuing the summation). |
| 259 for (int i = 0; i < halfKernelSize; ++i) { |
| 260 sum += halfKernel[i]; |
| 261 profile[halfKernelSize - i - 1] = SkUnitScalarClampToByte(sum); |
| 262 } |
| 263 // Ensure tail goes to 0. |
| 264 profile[profileWidth - 1] = 0; |
| 265 return profile; |
245 } | 266 } |
246 | 267 |
247 GrTexture* GrCircleBlurFragmentProcessor::CreateCircleBlurProfileTexture( | 268 static GrTexture* create_profile_texture(GrTextureProvider* textureProvider, con
st SkRect& circle, |
248 GrTextureProvide
r* textureProvider, | 269 float sigma, float* solidRadius, float*
textureRadius) { |
249 const SkRect& ci
rcle, | |
250 float sigma, | |
251 float* solidRadi
us, | |
252 float* textureRa
dius) { | |
253 float circleR = circle.width() / 2.0f; | 270 float circleR = circle.width() / 2.0f; |
254 // Profile textures are cached by the ratio of sigma to circle radius and by
the size of the | 271 // Profile textures are cached by the ratio of sigma to circle radius and by
the size of the |
255 // profile texture (binned by powers of 2). | 272 // profile texture (binned by powers of 2). |
256 SkScalar sigmaToCircleRRatio = sigma / circleR; | 273 SkScalar sigmaToCircleRRatio = sigma / circleR; |
257 // When sigma is really small this becomes a equivalent to convolving a Gaus
sian with a half- | 274 // When sigma is really small this becomes a equivalent to convolving a Gaus
sian with a half- |
258 // plane. We could do that simpler computation. However, right now we're jus
t using a lower | 275 // plane. Similarly, in the extreme high ratio cases circle becomes a point
WRT to the Guassian |
259 // bound off the ratio. Similarly, in the extreme high ratio cases circle be
comes a point WRT to | 276 // and the profile texture is a just a Gaussian evaluation. However, we have
n't yet implemented |
260 // the Guassian and the profile texture is a just a Gaussian evaluation. | 277 // this latter optimization. |
261 sigmaToCircleRRatio = SkTPin(sigmaToCircleRRatio, 0.05f, 8.f); | 278 sigmaToCircleRRatio = SkTMin(sigmaToCircleRRatio, 8.f); |
262 // Convert to fixed point for the key. | 279 SkFixed sigmaToCircleRRatioFixed; |
263 SkFixed sigmaToCircleRRatioFixed = SkScalarToFixed(sigmaToCircleRRatio); | 280 static const SkScalar kHalfPlaneThreshold = 0.1f; |
264 // We shave off some bits to reduce the number of unique entries. We could p
robably shave off | 281 bool useHalfPlaneApprox = false; |
265 // more than we do. | 282 if (sigmaToCircleRRatio <= kHalfPlaneThreshold) { |
266 sigmaToCircleRRatioFixed &= ~0xff; | 283 useHalfPlaneApprox = true; |
267 // From the circle center to solidRadius is all 1s and represented by the le
ftmost pixel (with | 284 sigmaToCircleRRatioFixed = 0; |
268 // value 255) in the profile texture. If it is zero then there is no solid c
enter to the | 285 *solidRadius = circleR - 3 * sigma; |
269 // blurred circle. | 286 *textureRadius = 6 * sigma; |
270 if (3*sigma <= circleR) { | |
271 // The circle is bigger than the Gaussian. In this case we know the inte
rior of the | |
272 // blurred circle is solid. | |
273 *solidRadius = circleR - 3 * sigma; // This location maps to 0.5f in the
weights texture. | |
274 // It should always be 255. | |
275 *textureRadius = SkScalarCeilToScalar(6 * sigma); | |
276 } else { | 287 } else { |
277 // The Gaussian is bigger than the circle. | 288 // Convert to fixed point for the key. |
278 *solidRadius = 0.0f; | 289 sigmaToCircleRRatioFixed = SkScalarToFixed(sigmaToCircleRRatio); |
279 *textureRadius = SkScalarCeilToScalar(circleR + 3 * sigma); | 290 // We shave off some bits to reduce the number of unique entries. We cou
ld probably shave |
| 291 // off more than we do. |
| 292 sigmaToCircleRRatioFixed &= ~0xff; |
| 293 sigmaToCircleRRatio = SkFixedToScalar(sigmaToCircleRRatioFixed); |
| 294 sigma = circleR * sigmaToCircleRRatio; |
| 295 *solidRadius = 0; |
| 296 *textureRadius = circleR + 3 * sigma; |
280 } | 297 } |
281 int profileTextureWidth = SkScalarCeilToInt(*textureRadius); | |
282 profileTextureWidth = (profileTextureWidth >= 1024) ? 1024 : | |
283 next_pow2_16bits(profileTextureWidth); | |
284 | 298 |
285 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); | 299 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); |
286 GrUniqueKey key; | 300 GrUniqueKey key; |
287 GrUniqueKey::Builder builder(&key, kDomain, 2); | 301 GrUniqueKey::Builder builder(&key, kDomain, 1); |
288 builder[0] = sigmaToCircleRRatioFixed; | 302 builder[0] = sigmaToCircleRRatioFixed; |
289 builder[1] = profileTextureWidth; | |
290 builder.finish(); | 303 builder.finish(); |
291 | 304 |
292 GrTexture *blurProfile = textureProvider->findAndRefTextureByUniqueKey(key); | 305 GrTexture *blurProfile = textureProvider->findAndRefTextureByUniqueKey(key); |
293 | |
294 if (!blurProfile) { | 306 if (!blurProfile) { |
| 307 static constexpr int kProfileTextureWidth = 512; |
295 GrSurfaceDesc texDesc; | 308 GrSurfaceDesc texDesc; |
296 texDesc.fWidth = profileTextureWidth; | 309 texDesc.fWidth = kProfileTextureWidth; |
297 texDesc.fHeight = 1; | 310 texDesc.fHeight = 1; |
298 texDesc.fConfig = kAlpha_8_GrPixelConfig; | 311 texDesc.fConfig = kAlpha_8_GrPixelConfig; |
299 | 312 |
300 // Rescale params to the size of the texture we're creating. | 313 SkAutoTDeleteArray<uint8_t> profile(nullptr); |
301 SkScalar scale = profileTextureWidth / *textureRadius; | 314 if (useHalfPlaneApprox) { |
302 SkAutoTDeleteArray<uint8_t> profile(create_profile(sigma * scale, circle
R * scale, | 315 profile.reset(create_half_plane_profile(kProfileTextureWidth)); |
303 *solidRadius * scale, | 316 } else { |
304 profileTextureWidth))
; | 317 // Rescale params to the size of the texture we're creating. |
| 318 SkScalar scale = kProfileTextureWidth / *textureRadius; |
| 319 profile.reset(create_circle_profile(sigma * scale, circleR * scale, |
| 320 kProfileTextureWidth)); |
| 321 } |
305 | 322 |
306 blurProfile = textureProvider->createTexture(texDesc, SkBudgeted::kYes,
profile.get(), 0); | 323 blurProfile = textureProvider->createTexture(texDesc, SkBudgeted::kYes,
profile.get(), 0); |
307 if (blurProfile) { | 324 if (blurProfile) { |
308 textureProvider->assignUniqueKeyToTexture(key, blurProfile); | 325 textureProvider->assignUniqueKeyToTexture(key, blurProfile); |
309 } | 326 } |
310 } | 327 } |
311 | 328 |
312 return blurProfile; | 329 return blurProfile; |
313 } | 330 } |
314 | 331 |
| 332 ////////////////////////////////////////////////////////////////////////////// |
| 333 |
| 334 sk_sp<GrFragmentProcessor> GrCircleBlurFragmentProcessor::Make(GrTextureProvider
*textureProvider, |
| 335 const SkRect& cir
cle, float sigma) { |
| 336 float solidRadius; |
| 337 float textureRadius; |
| 338 SkAutoTUnref<GrTexture> profile(create_profile_texture(textureProvider, circ
le, sigma, |
| 339 &solidRadius, &textur
eRadius)); |
| 340 if (!profile) { |
| 341 return nullptr; |
| 342 } |
| 343 return sk_sp<GrFragmentProcessor>(new GrCircleBlurFragmentProcessor(circle,
textureRadius, |
| 344 solidRad
ius, profile)); |
| 345 } |
| 346 |
| 347 ////////////////////////////////////////////////////////////////////////////// |
| 348 |
315 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCircleBlurFragmentProcessor); | 349 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCircleBlurFragmentProcessor); |
316 | 350 |
317 sk_sp<GrFragmentProcessor> GrCircleBlurFragmentProcessor::TestCreate(GrProcessor
TestData* d) { | 351 sk_sp<GrFragmentProcessor> GrCircleBlurFragmentProcessor::TestCreate(GrProcessor
TestData* d) { |
318 SkScalar wh = d->fRandom->nextRangeScalar(100.f, 1000.f); | 352 SkScalar wh = d->fRandom->nextRangeScalar(100.f, 1000.f); |
319 SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f); | 353 SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f); |
320 SkRect circle = SkRect::MakeWH(wh, wh); | 354 SkRect circle = SkRect::MakeWH(wh, wh); |
321 return GrCircleBlurFragmentProcessor::Make(d->fContext->textureProvider(), c
ircle, sigma); | 355 return GrCircleBlurFragmentProcessor::Make(d->fContext->textureProvider(), c
ircle, sigma); |
322 } | 356 } |
323 | 357 |
324 #endif | 358 #endif |
OLD | NEW |