Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Side by Side Diff: src/effects/GrCircleBlurFragmentProcessor.cpp

Issue 2242973002: Improvements for circluar blurs in GPU backend. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fix double to float conversion on windows Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/effects/GrCircleBlurFragmentProcessor.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « src/effects/GrCircleBlurFragmentProcessor.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698