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

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

Issue 12387099: first attempt to plumb fast blur code into skia mask filter (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: revert bench changes Created 7 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « src/effects/SkBlurMask.h ('k') | src/effects/SkBlurMaskFilter.cpp » ('j') | 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 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkBlurMask.h" 10 #include "SkBlurMask.h"
(...skipping 1182 matching lines...) Expand 10 before | Expand all | Expand 10 after
1193 all the time, we actually fill in the profile pre-inverted 1193 all the time, we actually fill in the profile pre-inverted
1194 (already done 255-x). 1194 (already done 255-x).
1195 1195
1196 The function returns the size of the array allocated for the 1196 The function returns the size of the array allocated for the
1197 profile. It's the responsibility of the caller to delete the 1197 profile. It's the responsibility of the caller to delete the
1198 memory returned in profile_out. 1198 memory returned in profile_out.
1199 */ 1199 */
1200 1200
1201 static int compute_profile(SkScalar radius, unsigned int **profile_out) { 1201 static int compute_profile(SkScalar radius, unsigned int **profile_out) {
1202 int size = SkScalarRoundToInt(radius * 3); 1202 int size = SkScalarRoundToInt(radius * 3);
1203 int center = size >> 1; 1203
1204 if (profile_out) {
1205 int center = size >> 1;
1206 unsigned int *profile = SkNEW_ARRAY(unsigned int, size);
1204 1207
1205 unsigned int *profile = SkNEW_ARRAY(unsigned int, size); 1208 float invr = 1.f/radius;
1206 1209
1207 float invr = 1.f/radius; 1210 profile[0] = 255;
1211 for (int x = 1 ; x < size ; ++x) {
1212 float scaled_x = (center - x - .5f) * invr;
1213 float gi = gaussianIntegral(scaled_x);
1214 profile[x] = 255 - (uint8_t) (255.f * gi);
1215 }
1208 1216
1209 profile[0] = 255; 1217 *profile_out = profile;
1210 for (int x = 1 ; x < size ; ++x) {
1211 float scaled_x = (center - x - .5f) * invr;
1212 float gi = gaussianIntegral(scaled_x);
1213 profile[x] = 255 - (uint8_t) (255.f * gi);
1214 } 1218 }
1215
1216 *profile_out = profile;
1217 return size; 1219 return size;
1218 } 1220 }
1219 1221
1220 // TODO MAYBE: Maintain a profile cache to avoid recomputing this for 1222 // TODO MAYBE: Maintain a profile cache to avoid recomputing this for
1221 // commonly used radii. Consider baking some of the most common blur radii 1223 // commonly used radii. Consider baking some of the most common blur radii
1222 // directly in as static data? 1224 // directly in as static data?
1223 1225
1224 // Implementation adapted from Michael Herf's approach: 1226 // Implementation adapted from Michael Herf's approach:
1225 // http://stereopsis.com/shadowrect/ 1227 // http://stereopsis.com/shadowrect/
1226 1228
1227 static inline unsigned int profile_lookup( unsigned int *profile, int loc, int b lurred_width, int sharp_width ) { 1229 static inline unsigned int profile_lookup( unsigned int *profile, int loc, int b lurred_width, int sharp_width ) {
1228 int dx = SkAbs32(((loc << 1) + 1) - blurred_width) - sharp_width; // how far are we from the original edge? 1230 int dx = SkAbs32(((loc << 1) + 1) - blurred_width) - sharp_width; // how far are we from the original edge?
1229 int ox = dx >> 1; 1231 int ox = dx >> 1;
1230 if (ox < 0) { 1232 if (ox < 0) {
1231 ox = 0; 1233 ox = 0;
1232 } 1234 }
1233 1235
1234 return profile[ox]; 1236 return profile[ox];
1235 } 1237 }
1236 1238
1237 bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src, 1239 bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src,
1238 SkScalar provided_radius, Style style, 1240 SkScalar provided_radius, Style style,
1239 SkIPoint *margin) { 1241 SkIPoint *margin, bool perform_blur) {
1240 int profile_size; 1242 int profile_size;
1241 unsigned int *profile; 1243 unsigned int *profile = NULL;
1242 1244
1243 float radius = SkScalarToFloat( SkScalarMul( provided_radius, kBlurRadiusFud geFactor ) ); 1245 float radius = SkScalarToFloat( SkScalarMul( provided_radius, kBlurRadiusFud geFactor ) );
1244 1246
1245 // adjust blur radius to match interpretation from boxfilter code 1247 // adjust blur radius to match interpretation from boxfilter code
1246 radius = (radius + .5f) *2.f; 1248 radius = (radius + .5f) *2.f;
bungeman-skia 2013/03/11 19:47:41 My eyes... need a space after *
1247 1249
1248 profile_size = compute_profile( radius, &profile ); 1250 profile_size = compute_profile( radius, perform_blur ? &profile : NULL );
bungeman-skia 2013/03/11 19:47:41 It feels awkward to have this check here and anoth
1249 1251
1250 SkAutoTDeleteArray<unsigned int> ada(profile); 1252 SkAutoTDeleteArray<unsigned int> ada(profile);
1251 1253
1252 int pad = profile_size/2; 1254 int pad = profile_size/2;
1253 if (margin) { 1255 if (margin) {
1254 margin->set( pad, pad ); 1256 margin->set( pad, pad );
1255 } 1257 }
1256 1258
1257 int shadow_left = -pad; 1259 int shadow_left = -pad;
1258 int shadow_top = -pad; 1260 int shadow_top = -pad;
1259 int shadow_right = (int)(src.width()) + pad; 1261 int shadow_right = (int)(src.width()) + pad;
1260 int shadow_bottom = (int)(src.height()) + pad; 1262 int shadow_bottom = (int)(src.height()) + pad;
1261 1263
1262 dst->fBounds.set(shadow_left, shadow_top, shadow_right, shadow_bottom); 1264 dst->fBounds.set(shadow_left + src.fLeft, shadow_top + src.fTop, shadow_righ t + src.fRight, shadow_bottom + src.fBottom);
bungeman-skia 2013/03/11 19:47:41 Nit: This line got really long. A few more below.
1263 1265
1264 dst->fRowBytes = dst->fBounds.width(); 1266 dst->fRowBytes = dst->fBounds.width();
1265 dst->fFormat = SkMask::kA8_Format; 1267 dst->fFormat = SkMask::kA8_Format;
1266 dst->fImage = NULL; 1268 dst->fImage = NULL;
1267 1269
1268 size_t dstSize = dst->computeImageSize();
1269 if (0 == dstSize) {
1270 return false; // too big to allocate, abort
1271 }
1272
1273 int sw = SkScalarFloorToInt(src.width()); 1270 int sw = SkScalarFloorToInt(src.width());
1274 int sh = SkScalarFloorToInt(src.height()); 1271 int sh = SkScalarFloorToInt(src.height());
1272
1273 if (perform_blur) {
bungeman-skia 2013/03/11 19:47:41 Can we put the else clause under !perform_blur and
1274 size_t dstSize = dst->computeImageSize();
1275 if (0 == dstSize) {
1276 return false; // too big to allocate, abort
1277 }
1275 1278
1276 uint8_t* dp = SkMask::AllocImage(dstSize); 1279 uint8_t* dp = SkMask::AllocImage(dstSize);
1277 1280
1278 dst->fImage = dp; 1281 dst->fImage = dp;
1279 1282
1280 int dstHeight = dst->fBounds.height(); 1283 int dstHeight = dst->fBounds.height();
1281 int dstWidth = dst->fBounds.width(); 1284 int dstWidth = dst->fBounds.width();
1282 1285
1283 // nearest odd number less than the profile size represents the center 1286 // nearest odd number less than the profile size represents the center
1284 // of the (2x scaled) profile 1287 // of the (2x scaled) profile
1285 int center = ( profile_size & ~1 ) - 1; 1288 int center = ( profile_size & ~1 ) - 1;
1286 1289
1287 int w = sw - center; 1290 int w = sw - center;
1288 int h = sh - center; 1291 int h = sh - center;
1289 1292
1290 uint8_t *outptr = dp; 1293 uint8_t *outptr = dp;
1291 1294
1292 SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); 1295 SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth);
1293 1296
1294 for (int x = 0 ; x < dstWidth ; ++x) { 1297 for (int x = 0 ; x < dstWidth ; ++x) {
1295 if (profile_size <= sw) { 1298 if (profile_size <= sw) {
1296 horizontalScanline[x] = profile_lookup(profile, x, dstWidth, w); 1299 horizontalScanline[x] = profile_lookup(profile, x, dstWidth, w);
1297 } else { 1300 } else {
1298 float span = float(sw)/radius; 1301 float span = float(sw)/radius;
1299 float giX = 1.5f - (x+.5f)/radius; 1302 float giX = 1.5f - (x+.5f)/radius;
1300 horizontalScanline[x] = (uint8_t) (255 * (gaussianIntegral(giX) - ga ussianIntegral(giX + span))); 1303 horizontalScanline[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span)));
1304 }
1305 }
1306
1307 for (int y = 0 ; y < dstHeight ; ++y) {
1308 unsigned int profile_y;
1309 if (profile_size <= sh) {
1310 profile_y = profile_lookup(profile, y, dstHeight, h);
1311 } else {
1312 float span = float(sh)/radius;
1313 float giY = 1.5f - (y+.5f)/radius;
1314 profile_y = (uint8_t) (255 * (gaussianIntegral(giY) - gaussianIn tegral(giY + span)));
1315 }
1316
1317 for (int x = 0 ; x < dstWidth ; x++) {
1318 unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], p rofile_y);
1319 *(outptr++) = maskval;
1320 }
1321 }
1322
1323 if (style == kInner_Style) {
1324 // now we allocate the "real" dst, mirror the size of src
1325 size_t srcSize = (size_t)(src.width() * src.height());
1326 if (0 == srcSize) {
1327 return false; // too big to allocate, abort
1328 }
1329 dst->fImage = SkMask::AllocImage(srcSize);
1330 for (int y = 0 ; y < sh ; y++) {
1331 uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad;
1332 uint8_t *inner_scanline = dst->fImage + y*sw;
1333 memcpy(inner_scanline, blur_scanline, sw);
1334 }
1335 SkMask::FreeImage(dp);
1336
1337 dst->fBounds.set(0, 0, sw, sh); // restore trimmed bounds
1338 dst->fRowBytes = sw;
1339
1340 } else if (style == kOuter_Style) {
1341 for (int y = pad ; y < dstHeight-pad ; y++) {
1342 uint8_t *dst_scanline = dp + y*dstWidth + pad;
1343 memset(dst_scanline, 0, sw);
1344 }
1345 }
1346 // normal and solid styles are the same for analytic rect blurs, so don' t
1347 // need to handle solid specially.
1348 } else {
1349 if (style == kInner_Style) {
1350 dst->fBounds.set(0, 0, sw, sh); // restore trimmed bounds
1351 dst->fRowBytes = sw;
1301 } 1352 }
1302 } 1353 }
1303 1354
1304 for (int y = 0 ; y < dstHeight ; ++y) {
1305 unsigned int profile_y;
1306 if (profile_size <= sh) {
1307 profile_y = profile_lookup(profile, y, dstHeight, h);
1308 } else {
1309 float span = float(sh)/radius;
1310 float giY = 1.5f - (y+.5f)/radius;
1311 profile_y = (uint8_t) (255 * (gaussianIntegral(giY) - gaussianIntegr al(giY + span)));
1312 }
1313
1314 for (int x = 0 ; x < dstWidth ; x++) {
1315 unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], profi le_y);
1316 *(outptr++) = maskval;
1317 }
1318 }
1319
1320 if (style == kInner_Style) {
1321 // now we allocate the "real" dst, mirror the size of src
1322 size_t srcSize = (size_t)(src.width() * src.height());
1323 if (0 == srcSize) {
1324 return false; // too big to allocate, abort
1325 }
1326 dst->fImage = SkMask::AllocImage(srcSize);
1327 for (int y = 0 ; y < sh ; y++) {
1328 uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad;
1329 uint8_t *inner_scanline = dst->fImage + y*sw;
1330 memcpy(inner_scanline, blur_scanline, sw);
1331 }
1332 SkMask::FreeImage(dp);
1333
1334 dst->fBounds.set(0, 0, sw, sh); // restore trimmed bounds
1335 dst->fRowBytes = sw;
1336
1337 } else if (style == kOuter_Style) {
1338 for (int y = pad ; y < dstHeight-pad ; y++) {
1339 uint8_t *dst_scanline = dp + y*dstWidth + pad;
1340 memset(dst_scanline, 0, sw);
1341 }
1342 }
1343 // normal and solid styles are the same for analytic rect blurs, so don't
1344 // need to handle solid specially.
1345
1346 return true; 1355 return true;
1347 } 1356 }
1348 1357
1349 // The "simple" blur is a direct implementation of separable convolution with a discrete 1358 // The "simple" blur is a direct implementation of separable convolution with a discrete
1350 // gaussian kernel. It's "ground truth" in a sense; too slow to be used, but ve ry 1359 // gaussian kernel. It's "ground truth" in a sense; too slow to be used, but ve ry
1351 // useful for correctness comparisons. 1360 // useful for correctness comparisons.
1352 1361
1353 bool SkBlurMask::BlurGroundTruth(SkMask* dst, const SkMask& src, SkScalar provid ed_radius, 1362 bool SkBlurMask::BlurGroundTruth(SkMask* dst, const SkMask& src, SkScalar provid ed_radius,
1354 Style style, SkIPoint* margin) { 1363 Style style, SkIPoint* margin) {
1355 1364
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
1488 (void)autoCall.detach(); 1497 (void)autoCall.detach();
1489 } 1498 }
1490 1499
1491 if (style == kInner_Style) { 1500 if (style == kInner_Style) {
1492 dst->fBounds = src.fBounds; // restore trimmed bounds 1501 dst->fBounds = src.fBounds; // restore trimmed bounds
1493 dst->fRowBytes = src.fRowBytes; 1502 dst->fRowBytes = src.fRowBytes;
1494 } 1503 }
1495 1504
1496 return true; 1505 return true;
1497 } 1506 }
OLDNEW
« no previous file with comments | « src/effects/SkBlurMask.h ('k') | src/effects/SkBlurMaskFilter.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698