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

Side by Side Diff: src/gpu/SkGpuDevice.cpp

Issue 264303008: Disable filtering in draw Bitmap operation when pixels are aligned (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years, 7 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 | « include/gpu/SkGpuDevice.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 2011 Google Inc. 2 * Copyright 2011 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 "SkGpuDevice.h" 8 #include "SkGpuDevice.h"
9 9
10 #include "effects/GrBicubicEffect.h" 10 #include "effects/GrBicubicEffect.h"
(...skipping 1119 matching lines...) Expand 10 before | Expand all | Expand 10 after
1130 } 1130 }
1131 1131
1132 if (iRect->fRight > clamp.fRight) { 1132 if (iRect->fRight > clamp.fRight) {
1133 iRect->fRight = clamp.fRight; 1133 iRect->fRight = clamp.fRight;
1134 } 1134 }
1135 if (iRect->fBottom > clamp.fBottom) { 1135 if (iRect->fBottom > clamp.fBottom) {
1136 iRect->fBottom = clamp.fBottom; 1136 iRect->fBottom = clamp.fBottom;
1137 } 1137 }
1138 } 1138 }
1139 1139
1140 static bool has_aligned_samples(const SkRect& srcRect,
1141 const SkRect& transformedRect) {
1142 // detect pixel disalignment
1143 if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) -
1144 transformedRect.left()) < COLOR_BLEED_TOLERANCE &&
1145 SkScalarAbs(SkScalarRoundToScalar(transformedRect.top()) -
1146 transformedRect.top()) < COLOR_BLEED_TOLERANCE &&
1147 SkScalarAbs(transformedRect.width() - srcRect.width()) <
1148 COLOR_BLEED_TOLERANCE &&
1149 SkScalarAbs(transformedRect.height() - srcRect.height()) <
1150 COLOR_BLEED_TOLERANCE) {
1151 return true;
1152 }
1153 return false;
1154 }
1155
1156 static bool may_color_bleed(const SkRect& srcRect,
1157 const SkRect& transformedRect,
1158 const SkMatrix& m) {
1159 // Only gets called if has_aligned_samples returned false.
1160 // So we can assume that sampling is axis aligned but not texel aligned.
1161 SkASSERT(!has_aligned_samples(srcRect, transformedRect));
1162 SkRect innerSrcRect(srcRect), innerTransformedRect,
1163 outerTransformedRect(transformedRect);
1164 innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf);
1165 m.mapRect(&innerTransformedRect, innerSrcRect);
1166
1167 // The gap between outerTransformedRect and innerTransformedRect
1168 // represents the projection of the source border area, which is
1169 // problematic for color bleeding. We must check whether any
1170 // destination pixels sample the border area.
1171 outerTransformedRect.inset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
1172 innerTransformedRect.outset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
1173 SkIRect outer, inner;
1174 outerTransformedRect.round(&outer);
1175 innerTransformedRect.round(&inner);
1176 // If the inner and outer rects round to the same result, it means the
1177 // border does not overlap any pixel centers. Yay!
1178 return inner != outer;
1179 }
1180
1181 bool SkGpuDevice::needsTextureDomain(const SkBitmap& bitmap,
1182 const SkRect& srcRect,
1183 GrTextureParams &params,
1184 bool bicubic) {
1185 bool needsTextureDomain = false;
1186
1187 if (bicubic || params.filterMode() != GrTextureParams::kNone_FilterMode) {
1188 // Need texture domain if drawing a sub rect
1189 needsTextureDomain = srcRect.width() < bitmap.width() ||
1190 srcRect.height() < bitmap.height();
1191 if (!bicubic && needsTextureDomain && fContext->getMatrix().rectStaysRec t()) {
1192 const SkMatrix& matrix = fContext->getMatrix();
bsalomon 2014/05/08 14:13:23 Is accessing the matrix the only reason why this i
1193 // sampling is axis-aligned
1194 SkRect transformedRect;
1195 matrix.mapRect(&transformedRect, srcRect);
1196
1197 if (has_aligned_samples(srcRect, transformedRect)) {
1198 params.setFilterMode(GrTextureParams::kNone_FilterMode);
1199 needsTextureDomain = false;
1200 } else {
1201 needsTextureDomain = may_color_bleed(srcRect, transformedRect, m atrix);
1202 }
1203 }
1204 }
1205 return needsTextureDomain;
1206 }
1207
1140 void SkGpuDevice::drawBitmapCommon(const SkDraw& draw, 1208 void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
1141 const SkBitmap& bitmap, 1209 const SkBitmap& bitmap,
1142 const SkRect* srcRectPtr, 1210 const SkRect* srcRectPtr,
1143 const SkSize* dstSizePtr, 1211 const SkSize* dstSizePtr,
1144 const SkPaint& paint, 1212 const SkPaint& paint,
1145 SkCanvas::DrawBitmapRectFlags flags) { 1213 SkCanvas::DrawBitmapRectFlags flags) {
1146 CHECK_SHOULD_DRAW(draw, false); 1214 CHECK_SHOULD_DRAW(draw, false);
1147 1215
1148 SkRect srcRect; 1216 SkRect srcRect;
1149 SkSize dstSize; 1217 SkSize dstSize;
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
1268 int maxTileSize = fContext->getMaxTextureSize() - 2 * tileFilterPad; 1336 int maxTileSize = fContext->getMaxTextureSize() - 2 * tileFilterPad;
1269 int tileSize; 1337 int tileSize;
1270 1338
1271 SkIRect clippedSrcRect; 1339 SkIRect clippedSrcRect;
1272 if (this->shouldTileBitmap(bitmap, params, srcRectPtr, maxTileSize, &tileSiz e, 1340 if (this->shouldTileBitmap(bitmap, params, srcRectPtr, maxTileSize, &tileSiz e,
1273 &clippedSrcRect)) { 1341 &clippedSrcRect)) {
1274 this->drawTiledBitmap(bitmap, srcRect, clippedSrcRect, params, paint, fl ags, tileSize, 1342 this->drawTiledBitmap(bitmap, srcRect, clippedSrcRect, params, paint, fl ags, tileSize,
1275 doBicubic); 1343 doBicubic);
1276 } else { 1344 } else {
1277 // take the simple case 1345 // take the simple case
1278 this->internalDrawBitmap(bitmap, srcRect, params, paint, flags, doBicubi c); 1346 bool needsTextureDomain = this->needsTextureDomain(bitmap, srcRect, para ms, doBicubic);
1347 this->internalDrawBitmap(bitmap,
1348 srcRect,
1349 params,
1350 paint,
1351 flags,
1352 doBicubic,
1353 needsTextureDomain);
1279 } 1354 }
1280 } 1355 }
1281 1356
1282 // Break 'bitmap' into several tiles to draw it since it has already 1357 // Break 'bitmap' into several tiles to draw it since it has already
1283 // been determined to be too large to fit in VRAM 1358 // been determined to be too large to fit in VRAM
1284 void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, 1359 void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
1285 const SkRect& srcRect, 1360 const SkRect& srcRect,
1286 const SkIRect& clippedSrcIRect, 1361 const SkIRect& clippedSrcIRect,
1287 const GrTextureParams& params, 1362 const GrTextureParams& params,
1288 const SkPaint& paint, 1363 const SkPaint& paint,
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1334 // not bleed across the original clamped edges) 1409 // not bleed across the original clamped edges)
1335 srcRect.roundOut(&iClampRect); 1410 srcRect.roundOut(&iClampRect);
1336 } 1411 }
1337 int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1; 1412 int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1;
1338 clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect) ; 1413 clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect) ;
1339 } 1414 }
1340 1415
1341 if (bitmap.extractSubset(&tmpB, iTileR)) { 1416 if (bitmap.extractSubset(&tmpB, iTileR)) {
1342 // now offset it to make it "local" to our tmp bitmap 1417 // now offset it to make it "local" to our tmp bitmap
1343 tileR.offset(-offset.fX, -offset.fY); 1418 tileR.offset(-offset.fX, -offset.fY);
1344 1419 GrTextureParams paramsTemp = params;
1345 this->internalDrawBitmap(tmpB, tileR, params, paint, flags, bicu bic); 1420 bool needsTextureDomain = this->needsTextureDomain(bitmap,
1421 srcRect,
1422 paramsTemp,
1423 bicubic);
1424 this->internalDrawBitmap(tmpB,
1425 tileR,
1426 paramsTemp,
1427 paint,
1428 flags,
1429 bicubic,
1430 needsTextureDomain);
1346 } 1431 }
1347 } 1432 }
1348 } 1433 }
1349 } 1434 }
1350 1435
1351 static bool has_aligned_samples(const SkRect& srcRect,
1352 const SkRect& transformedRect) {
1353 // detect pixel disalignment
1354 if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) -
1355 transformedRect.left()) < COLOR_BLEED_TOLERANCE &&
1356 SkScalarAbs(SkScalarRoundToScalar(transformedRect.top()) -
1357 transformedRect.top()) < COLOR_BLEED_TOLERANCE &&
1358 SkScalarAbs(transformedRect.width() - srcRect.width()) <
1359 COLOR_BLEED_TOLERANCE &&
1360 SkScalarAbs(transformedRect.height() - srcRect.height()) <
1361 COLOR_BLEED_TOLERANCE) {
1362 return true;
1363 }
1364 return false;
1365 }
1366
1367 static bool may_color_bleed(const SkRect& srcRect,
1368 const SkRect& transformedRect,
1369 const SkMatrix& m) {
1370 // Only gets called if has_aligned_samples returned false.
1371 // So we can assume that sampling is axis aligned but not texel aligned.
1372 SkASSERT(!has_aligned_samples(srcRect, transformedRect));
1373 SkRect innerSrcRect(srcRect), innerTransformedRect,
1374 outerTransformedRect(transformedRect);
1375 innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf);
1376 m.mapRect(&innerTransformedRect, innerSrcRect);
1377
1378 // The gap between outerTransformedRect and innerTransformedRect
1379 // represents the projection of the source border area, which is
1380 // problematic for color bleeding. We must check whether any
1381 // destination pixels sample the border area.
1382 outerTransformedRect.inset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
1383 innerTransformedRect.outset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
1384 SkIRect outer, inner;
1385 outerTransformedRect.round(&outer);
1386 innerTransformedRect.round(&inner);
1387 // If the inner and outer rects round to the same result, it means the
1388 // border does not overlap any pixel centers. Yay!
1389 return inner != outer;
1390 }
1391
1392 1436
1393 /* 1437 /*
1394 * This is called by drawBitmap(), which has to handle images that may be too 1438 * This is called by drawBitmap(), which has to handle images that may be too
1395 * large to be represented by a single texture. 1439 * large to be represented by a single texture.
1396 * 1440 *
1397 * internalDrawBitmap assumes that the specified bitmap will fit in a texture 1441 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1398 * and that non-texture portion of the GrPaint has already been setup. 1442 * and that non-texture portion of the GrPaint has already been setup.
1399 */ 1443 */
1400 void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap, 1444 void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
1401 const SkRect& srcRect, 1445 const SkRect& srcRect,
1402 const GrTextureParams& params, 1446 const GrTextureParams& params,
1403 const SkPaint& paint, 1447 const SkPaint& paint,
1404 SkCanvas::DrawBitmapRectFlags flags, 1448 SkCanvas::DrawBitmapRectFlags flags,
1405 bool bicubic) { 1449 bool bicubic,
1450 bool needsTextureDomain) {
1406 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() && 1451 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1407 bitmap.height() <= fContext->getMaxTextureSize()); 1452 bitmap.height() <= fContext->getMaxTextureSize());
1408 1453
1409 GrTexture* texture; 1454 GrTexture* texture;
1410 SkAutoCachedTexture act(this, bitmap, &params, &texture); 1455 SkAutoCachedTexture act(this, bitmap, &params, &texture);
1411 if (NULL == texture) { 1456 if (NULL == texture) {
1412 return; 1457 return;
1413 } 1458 }
1414 1459
1415 SkRect dstRect = {0, 0, srcRect.width(), srcRect.height() }; 1460 SkRect dstRect = {0, 0, srcRect.width(), srcRect.height() };
1416 SkRect paintRect; 1461 SkRect paintRect;
1417 SkScalar wInv = SkScalarInvert(SkIntToScalar(texture->width())); 1462 SkScalar wInv = SkScalarInvert(SkIntToScalar(texture->width()));
1418 SkScalar hInv = SkScalarInvert(SkIntToScalar(texture->height())); 1463 SkScalar hInv = SkScalarInvert(SkIntToScalar(texture->height()));
1419 paintRect.setLTRB(SkScalarMul(srcRect.fLeft, wInv), 1464 paintRect.setLTRB(SkScalarMul(srcRect.fLeft, wInv),
1420 SkScalarMul(srcRect.fTop, hInv), 1465 SkScalarMul(srcRect.fTop, hInv),
1421 SkScalarMul(srcRect.fRight, wInv), 1466 SkScalarMul(srcRect.fRight, wInv),
1422 SkScalarMul(srcRect.fBottom, hInv)); 1467 SkScalarMul(srcRect.fBottom, hInv));
1423 1468
1424 bool needsTextureDomain = false;
1425 if (!(flags & SkCanvas::kBleed_DrawBitmapRectFlag) &&
1426 (bicubic || params.filterMode() != GrTextureParams::kNone_FilterMode)) {
1427 // Need texture domain if drawing a sub rect
1428 needsTextureDomain = srcRect.width() < bitmap.width() ||
1429 srcRect.height() < bitmap.height();
1430 if (!bicubic && needsTextureDomain && fContext->getMatrix().rectStaysRec t()) {
1431 const SkMatrix& matrix = fContext->getMatrix();
1432 // sampling is axis-aligned
1433 SkRect transformedRect;
1434 matrix.mapRect(&transformedRect, srcRect);
1435
1436 if (has_aligned_samples(srcRect, transformedRect)) {
1437 // We could also turn off filtering here (but we already did a c ache lookup with
1438 // params).
1439 needsTextureDomain = false;
1440 } else {
1441 needsTextureDomain = may_color_bleed(srcRect, transformedRect, m atrix);
1442 }
1443 }
1444 }
1445
1446 SkRect textureDomain = SkRect::MakeEmpty(); 1469 SkRect textureDomain = SkRect::MakeEmpty();
1447 SkAutoTUnref<GrEffectRef> effect; 1470 SkAutoTUnref<GrEffectRef> effect;
1448 if (needsTextureDomain) { 1471 if (needsTextureDomain && !(flags & SkCanvas::kBleed_DrawBitmapRectFlag)) {
1449 // Use a constrained texture domain to avoid color bleeding 1472 // Use a constrained texture domain to avoid color bleeding
1450 SkScalar left, top, right, bottom; 1473 SkScalar left, top, right, bottom;
1451 if (srcRect.width() > SK_Scalar1) { 1474 if (srcRect.width() > SK_Scalar1) {
1452 SkScalar border = SK_ScalarHalf / texture->width(); 1475 SkScalar border = SK_ScalarHalf / texture->width();
1453 left = paintRect.left() + border; 1476 left = paintRect.left() + border;
1454 right = paintRect.right() - border; 1477 right = paintRect.right() - border;
1455 } else { 1478 } else {
1456 left = right = SkScalarHalf(paintRect.left() + paintRect.right()); 1479 left = right = SkScalarHalf(paintRect.left() + paintRect.right());
1457 } 1480 }
1458 if (srcRect.height() > SK_Scalar1) { 1481 if (srcRect.height() > SK_Scalar1) {
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after
1998 const GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrC reate(picture, i); 2021 const GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrC reate(picture, i);
1999 2022
2000 SkDebugf("%d (%d), ", i, layer->layerID()); 2023 SkDebugf("%d (%d), ", i, layer->layerID());
2001 } 2024 }
2002 } 2025 }
2003 SkDebugf("\n"); 2026 SkDebugf("\n");
2004 #endif 2027 #endif
2005 2028
2006 return false; 2029 return false;
2007 } 2030 }
OLDNEW
« no previous file with comments | « include/gpu/SkGpuDevice.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698