aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/GrImageIDTextureAdjuster.cpp46
-rw-r--r--src/gpu/GrImageIDTextureAdjuster.h21
-rw-r--r--src/gpu/GrTextureParamsAdjuster.cpp116
-rw-r--r--src/gpu/GrTextureParamsAdjuster.h101
-rw-r--r--src/gpu/SkGpuDevice.cpp482
-rw-r--r--src/gpu/SkGpuDevice.h28
-rw-r--r--src/gpu/SkGpuDevice_drawTexture.cpp85
-rw-r--r--src/gpu/SkGr.cpp53
8 files changed, 423 insertions, 509 deletions
diff --git a/src/gpu/GrImageIDTextureAdjuster.cpp b/src/gpu/GrImageIDTextureAdjuster.cpp
index 525223cf77..c37c022775 100644
--- a/src/gpu/GrImageIDTextureAdjuster.cpp
+++ b/src/gpu/GrImageIDTextureAdjuster.cpp
@@ -7,10 +7,12 @@
#include "GrImageIDTextureAdjuster.h"
+#include "GrContext.h"
+#include "GrGpuResourcePriv.h"
#include "SkBitmap.h"
#include "SkGrPriv.h"
#include "SkImage_Base.h"
-
+#include "SkPixelRef.h"
GrBitmapTextureAdjuster::GrBitmapTextureAdjuster(const SkBitmap* bmp)
: INHERITED(bmp->getTexture(), SkIRect::MakeWH(bmp->width(), bmp->height()))
@@ -52,3 +54,45 @@ void GrImageTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey*
void GrImageTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey) {
// We don't currently have a mechanism for notifications on Images!
}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GrBitmapTextureMaker::GrBitmapTextureMaker(GrContext* context, const SkBitmap& bitmap)
+ : INHERITED(context, bitmap.width(), bitmap.height())
+ , fBitmap(bitmap) {
+ SkASSERT(!bitmap.getTexture());
+ if (!bitmap.isVolatile()) {
+ SkIPoint origin = bitmap.pixelRefOrigin();
+ SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, bitmap.width(),
+ bitmap.height());
+ GrMakeKeyFromImageID(&fOriginalKey, bitmap.pixelRef()->getGenerationID(), subset);
+ }
+}
+
+GrTexture* GrBitmapTextureMaker::refOriginalTexture() {
+ GrTexture* tex;
+
+ if (fOriginalKey.isValid()) {
+ tex = this->context()->textureProvider()->findAndRefTextureByUniqueKey(fOriginalKey);
+ if (tex) {
+ return tex;
+ }
+ }
+
+ tex = GrUploadBitmapToTexture(this->context(), fBitmap);
+ if (tex && fOriginalKey.isValid()) {
+ tex->resourcePriv().setUniqueKey(fOriginalKey);
+ GrInstallBitmapUniqueKeyInvalidator(fOriginalKey, fBitmap.pixelRef());
+ }
+ return tex;
+}
+
+void GrBitmapTextureMaker::makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) {
+ if (fOriginalKey.isValid()) {
+ MakeCopyKeyFromOrigKey(fOriginalKey, copyParams, copyKey);
+ }
+}
+
+void GrBitmapTextureMaker::didCacheCopy(const GrUniqueKey& copyKey) {
+ GrInstallBitmapUniqueKeyInvalidator(copyKey, fBitmap.pixelRef());
+}
diff --git a/src/gpu/GrImageIDTextureAdjuster.h b/src/gpu/GrImageIDTextureAdjuster.h
index 6c0747a62c..a20902ed58 100644
--- a/src/gpu/GrImageIDTextureAdjuster.h
+++ b/src/gpu/GrImageIDTextureAdjuster.h
@@ -45,4 +45,25 @@ private:
typedef GrTextureAdjuster INHERITED;
};
+/** This class manages the conversion of SW-backed bitmaps to GrTextures. If the input bitmap is
+ non-volatile the texture is cached using a key created from the pixels' image id and the
+ subset of the pixelref specified by the bitmap. */
+class GrBitmapTextureMaker : public GrTextureMaker {
+public:
+ GrBitmapTextureMaker(GrContext* context, const SkBitmap& bitmap);
+
+protected:
+ GrTexture* refOriginalTexture() override;
+
+ void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) override;
+
+ void didCacheCopy(const GrUniqueKey& copyKey) override;
+
+private:
+ const SkBitmap fBitmap;
+ GrUniqueKey fOriginalKey;
+
+ typedef GrTextureMaker INHERITED;
+};
+
#endif
diff --git a/src/gpu/GrTextureParamsAdjuster.cpp b/src/gpu/GrTextureParamsAdjuster.cpp
index 0547d95053..1a751ab73c 100644
--- a/src/gpu/GrTextureParamsAdjuster.cpp
+++ b/src/gpu/GrTextureParamsAdjuster.cpp
@@ -213,7 +213,7 @@ static DomainMode determine_domain_mode(
return kNoDomain_DomainMode;
}
- bool restrictFilterToRect = (filterConstraint == GrTextureAdjuster::kYes_FilterConstraint);
+ bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint);
// If we can filter outside the constraint rect, and there is no non-content area of the
// texture, and we aren't going to generate sample coords outside the constraint rect then we
@@ -237,8 +237,11 @@ static DomainMode determine_domain_mode(
filterHalfWidth = .5f;
break;
case GrTextureParams::kMipMap_FilterMode:
- // No domain can save use here.
- return kTightCopy_DomainMode;
+ if (restrictFilterToRect || textureContentArea) {
+ // No domain can save us here.
+ return kTightCopy_DomainMode;
+ }
+ return kNoDomain_DomainMode;
}
} else {
// bicubic does nearest filtering internally.
@@ -324,6 +327,33 @@ static DomainMode determine_domain_mode(
return kDomain_DomainMode;
}
+static const GrFragmentProcessor* create_fp_for_domain_and_filter(
+ GrTexture* texture,
+ const SkMatrix& textureMatrix,
+ DomainMode domainMode,
+ const SkRect& domain,
+ const GrTextureParams::FilterMode* filterOrNullForBicubic) {
+ SkASSERT(kTightCopy_DomainMode != domainMode);
+ if (filterOrNullForBicubic) {
+ if (kDomain_DomainMode == domainMode) {
+ return GrTextureDomainEffect::Create(texture, textureMatrix, domain,
+ GrTextureDomain::kClamp_Mode,
+ *filterOrNullForBicubic);
+ } else {
+ GrTextureParams params(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
+ return GrSimpleTextureEffect::Create(texture, textureMatrix, params);
+ }
+ } else {
+ if (kDomain_DomainMode == domainMode) {
+ return GrBicubicEffect::Create(texture, textureMatrix, domain);
+ } else {
+ static const SkShader::TileMode kClampClamp[] =
+ { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode };
+ return GrBicubicEffect::Create(texture, textureMatrix, kClampClamp);
+ }
+ }
+}
+
const GrFragmentProcessor* GrTextureAdjuster::createFragmentProcessor(
const SkMatrix& origTextureMatrix,
const SkRect& origConstraintRect,
@@ -368,57 +398,83 @@ const GrFragmentProcessor* GrTextureAdjuster::createFragmentProcessor(
SkASSERT(kNoDomain_DomainMode == domainMode ||
(domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom));
textureMatrix.postIDiv(texture->width(), texture->height());
- if (filterOrNullForBicubic) {
- if (kDomain_DomainMode == domainMode) {
- return GrTextureDomainEffect::Create(texture, textureMatrix, domain,
- GrTextureDomain::kClamp_Mode,
- *filterOrNullForBicubic);
- } else {
- GrTextureParams params(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
- return GrSimpleTextureEffect::Create(texture, textureMatrix, params);
- }
- } else {
- if (kDomain_DomainMode == domainMode) {
- return GrBicubicEffect::Create(texture, textureMatrix, domain);
- } else {
- static const SkShader::TileMode kClampClamp[] =
- { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode };
- return GrBicubicEffect::Create(texture, textureMatrix, kClampClamp);
- }
- }
+ return create_fp_for_domain_and_filter(texture, textureMatrix, domainMode, domain,
+ filterOrNullForBicubic);
}
//////////////////////////////////////////////////////////////////////////////
-GrTexture* GrTextureMaker::refTextureForParams(GrContext* ctx, const GrTextureParams& params) {
+GrTexture* GrTextureMaker::refTextureForParams(const GrTextureParams& params) {
CopyParams copyParams;
- if (!ctx->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params,
- &copyParams)) {
- return this->refOriginalTexture(ctx);
+ if (!fContext->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params,
+ &copyParams)) {
+ return this->refOriginalTexture();
}
GrUniqueKey copyKey;
this->makeCopyKey(copyParams, &copyKey);
if (copyKey.isValid()) {
- GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(copyKey);
+ GrTexture* result = fContext->textureProvider()->findAndRefTextureByUniqueKey(copyKey);
if (result) {
return result;
}
}
- GrTexture* result = this->generateTextureForParams(ctx, copyParams);
+ GrTexture* result = this->generateTextureForParams(copyParams);
if (!result) {
return nullptr;
}
if (copyKey.isValid()) {
- ctx->textureProvider()->assignUniqueKeyToTexture(copyKey, result);
+ fContext->textureProvider()->assignUniqueKeyToTexture(copyKey, result);
this->didCacheCopy(copyKey);
}
return result;
}
-GrTexture* GrTextureMaker::generateTextureForParams(GrContext* ctx, const CopyParams& copyParams) {
- SkAutoTUnref<GrTexture> original(this->refOriginalTexture(ctx));
+const GrFragmentProcessor* GrTextureMaker::createFragmentProcessor(
+ const SkMatrix& textureMatrix,
+ const SkRect& constraintRect,
+ FilterConstraint filterConstraint,
+ bool coordsLimitedToConstraintRect,
+ const GrTextureParams::FilterMode* filterOrNullForBicubic) {
+
+ const GrTextureParams::FilterMode* fmForDetermineDomain = filterOrNullForBicubic;
+ if (filterOrNullForBicubic && GrTextureParams::kMipMap_FilterMode == *filterOrNullForBicubic &&
+ kYes_FilterConstraint == filterConstraint) {
+ // TODo: Here we should force a copy restricted to the constraintRect since MIP maps will
+ // read outside the constraint rect. However, as in the adjuster case, we aren't currently
+ // doing that.
+ // We instead we compute the domain as though were bilerping which is only correct if we
+ // only sample level 0.
+ static const GrTextureParams::FilterMode kBilerp = GrTextureParams::kBilerp_FilterMode;
+ fmForDetermineDomain = &kBilerp;
+ }
+
+ GrTextureParams params;
+ if (filterOrNullForBicubic) {
+ params.reset(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
+ } else {
+ // Bicubic doesn't use filtering for it's texture accesses.
+ params.reset(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
+ }
+ SkAutoTUnref<GrTexture> texture(this->refTextureForParams(params));
+ if (!texture) {
+ return nullptr;
+ }
+ SkRect domain;
+ DomainMode domainMode =
+ determine_domain_mode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
+ texture->width(), texture->height(), nullptr, fmForDetermineDomain,
+ &domain);
+ SkASSERT(kTightCopy_DomainMode != domainMode);
+ SkMatrix normalizedTextureMatrix = textureMatrix;
+ normalizedTextureMatrix.postIDiv(texture->width(), texture->height());
+ return create_fp_for_domain_and_filter(texture, normalizedTextureMatrix, domainMode, domain,
+ filterOrNullForBicubic);
+}
+
+GrTexture* GrTextureMaker::generateTextureForParams(const CopyParams& copyParams) {
+ SkAutoTUnref<GrTexture> original(this->refOriginalTexture());
if (!original) {
return nullptr;
}
diff --git a/src/gpu/GrTextureParamsAdjuster.h b/src/gpu/GrTextureParamsAdjuster.h
index cad3920466..ed9f142af0 100644
--- a/src/gpu/GrTextureParamsAdjuster.h
+++ b/src/gpu/GrTextureParamsAdjuster.h
@@ -34,6 +34,38 @@ public:
int fHeight;
};
+ enum FilterConstraint {
+ kYes_FilterConstraint,
+ kNo_FilterConstraint,
+ };
+
+ /**
+ * Helper for creating a fragment processor to sample the texture with a given filtering mode.
+ * It attempts to avoid making texture copies or using domains whenever possible.
+ *
+ * @param textureMatrix Matrix used to access the texture. It is applied to
+ * the local coords. The post-transformed coords should
+ * be in texel units (rather than normalized) with
+ * respect to this Producer's bounds (width()/height()).
+ * @param constraintRect A rect that represents the area of the texture to be
+ * sampled. It must be contained in the Producer's bounds
+ * as defined by width()/height().
+ * @param filterConstriant Indicates whether filtering is limited to
+ * constraintRect.
+ * @param coordsLimitedToConstraintRect Is it known that textureMatrix*localCoords is bound
+ * by the portion of the texture indicated by
+ * constraintRect (without consideration of filter
+ * width, just the raw coords).
+ * @param filterOrNullForBicubic If non-null indicates the filter mode. If null means
+ * use bicubic filtering.
+ **/
+ virtual const GrFragmentProcessor* createFragmentProcessor(
+ const SkMatrix& textureMatrix,
+ const SkRect& constraintRect,
+ FilterConstraint filterConstraint,
+ bool coordsLimitedToConstraintRect,
+ const GrTextureParams::FilterMode* filterOrNullForBicubic) = 0;
+
virtual ~GrTextureProducer() {}
int width() const { return fWidth; }
@@ -92,37 +124,12 @@ public:
does not match subset's dimensions then the contents are scaled to fit the copy.*/
GrTexture* refTextureSafeForParams(const GrTextureParams&, SkIPoint* outOffset);
- enum FilterConstraint {
- kYes_FilterConstraint,
- kNo_FilterConstraint,
- };
-
- /**
- * Helper for creating a fragment processor to sample the texture with a given filtering mode.
- * It attempts to avoids making a copy of the texture and avoid using a texture domain unless
- * necessary.
- *
- * @param textureMatrix Matrix to apply to local coordinates to compute
- * texel coordinates. The post-transformed coordinates
- * should be in texels (relative to this->width() and
- * this->height()) and not be normalized.
- * @param constraintRect Subrect of content area to be rendered. The
- * constraint rect is relative to the content area.
- * @param filterConstriant Indicates whether filtering is limited to
- * constraintRect.
- * @param coordsLimitedToConstraintRect Is it known that textureMatrix*localCoords is bound
- * by the portion of the texture indicated by
- * constraintRect (without consideration of filter
- * width, just the raw coords).
- * @param filterOrNullForBicubic If non-null indicates the filter mode. If null means
- * use bicubic filtering.
- **/
const GrFragmentProcessor* createFragmentProcessor(
- const SkMatrix& textureMatrix,
- const SkRect& constraintRect,
- FilterConstraint filterConstraint,
- bool coordsLimitedToConstraintRect,
- const GrTextureParams::FilterMode* filterOrNullForBicubic);
+ const SkMatrix& textureMatrix,
+ const SkRect& constraintRect,
+ FilterConstraint,
+ bool coordsLimitedToConstraintRect,
+ const GrTextureParams::FilterMode* filterOrNullForBicubic) override;
protected:
/** The whole texture is content. */
@@ -153,25 +160,25 @@ public:
/** Returns a texture that is safe for use with the params. If the size of the returned texture
does not match width()/height() then the contents of the original must be scaled to fit
the texture. */
- GrTexture* refTextureForParams(GrContext*, const GrTextureParams&);
+ GrTexture* refTextureForParams(const GrTextureParams&);
-protected:
- GrTextureMaker(int width, int height) : INHERITED(width, height) {}
+ const GrFragmentProcessor* createFragmentProcessor(
+ const SkMatrix& textureMatrix,
+ const SkRect& constraintRect,
+ FilterConstraint filterConstraint,
+ bool coordsLimitedToConstraintRect,
+ const GrTextureParams::FilterMode* filterOrNullForBicubic) override;
- /**
- * Return the maker's "original" texture. It is the responsibility of the maker
- * to make this efficient ... if the texture is being generated, the maker must handle
- * caching it (if desired).
- */
- virtual GrTexture* refOriginalTexture(GrContext*) = 0;
+protected:
+ GrTextureMaker(GrContext* context, int width, int height)
+ : INHERITED(width, height)
+ , fContext(context) {}
/**
- * If we need to copy the producer's original texture, the producer is asked to return a key
- * that identifies its original + the CopyParms parameter. If the maker does not want to cache
- * the stretched version (e.g. the producer is volatile), this should simply return without
- * initializing the copyKey.
+ * Return the maker's "original" texture. It is the responsibility of the maker to handle any
+ * caching of the original if desired.
*/
- virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey) = 0;
+ virtual GrTexture* refOriginalTexture() = 0;
/**
* Return a new (uncached) texture that is the stretch of the maker's original.
@@ -183,9 +190,13 @@ protected:
* Subclass may override this if they can handle creating the texture more directly than
* by copying.
*/
- virtual GrTexture* generateTextureForParams(GrContext*, const CopyParams&);
+ virtual GrTexture* generateTextureForParams(const CopyParams&);
+
+ GrContext* context() const { return fContext; }
private:
+ GrContext* fContext;
+
typedef GrTextureProducer INHERITED;
};
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 36e0342f78..7dfeba621d 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -63,11 +63,6 @@ enum { kDefaultImageFilterCacheSize = 32 * 1024 * 1024 };
#define CHECK_SHOULD_DRAW(draw) this->prepareDraw(draw)
#endif
-// This constant represents the screen alignment criterion in texels for
-// requiring texture domain clamping to prevent color bleeding when drawing
-// a sub region of a larger source image.
-#define COLOR_BLEED_TOLERANCE 0.001f
-
#define DO_DEFERRED_CLEAR() \
do { \
if (fNeedClear) { \
@@ -842,26 +837,61 @@ void SkGpuDevice::drawBitmap(const SkDraw& origDraw,
const SkBitmap& bitmap,
const SkMatrix& m,
const SkPaint& paint) {
-
- GrTexture* texture = bitmap.getTexture();
- if (texture) {
- CHECK_SHOULD_DRAW(origDraw);
- bool alphaOnly = kAlpha_8_SkColorType == bitmap.colorType();
+ CHECK_SHOULD_DRAW(origDraw);
+ bool alphaOnly = kAlpha_8_SkColorType == bitmap.colorType();
+ SkMatrix viewMatrix;
+ viewMatrix.setConcat(*origDraw.fMatrix, m);
+ if (bitmap.getTexture()) {
GrBitmapTextureAdjuster adjuster(&bitmap);
- SkMatrix viewMatrix;
- viewMatrix.setConcat(*origDraw.fMatrix, m);
- this->drawTextureAdjuster(&adjuster, alphaOnly, nullptr, nullptr,
+ // We can use kFast here because we know texture-backed bitmaps don't support extractSubset.
+ this->drawTextureProducer(&adjuster, alphaOnly, nullptr, nullptr,
SkCanvas::kFast_SrcRectConstraint, viewMatrix, fClip, paint);
return;
}
- SkMatrix concat;
- SkTCopyOnFirstWrite<SkDraw> draw(origDraw);
- if (!m.isIdentity()) {
- concat.setConcat(*draw->fMatrix, m);
- draw.writable()->fMatrix = &concat;
+ int maxTileSize = fContext->caps()->maxTileSize();
+
+ // The tile code path doesn't currently support AA, so if the paint asked for aa and we could
+ // draw untiled, then we bypass checking for tiling purely for optimization reasons.
+ bool drawAA = !fRenderTarget->isUnifiedMultisampled() &&
+ paint.isAntiAlias() &&
+ bitmap.width() <= maxTileSize &&
+ bitmap.height() <= maxTileSize;
+
+ bool skipTileCheck = drawAA || paint.getMaskFilter();
+
+ if (!skipTileCheck) {
+ SkRect srcRect = SkRect::MakeIWH(bitmap.width(), bitmap.height());
+ int tileSize;
+ SkIRect clippedSrcRect;
+
+ GrTextureParams params;
+ bool doBicubic;
+ GrTextureParams::FilterMode textureFilterMode =
+ GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, SkMatrix::I(),
+ &doBicubic);
+
+ int tileFilterPad;
+
+ if (doBicubic) {
+ tileFilterPad = GrBicubicEffect::kFilterTexelPad;
+ } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) {
+ tileFilterPad = 0;
+ } else {
+ tileFilterPad = 1;
+ }
+ params.setFilterMode(textureFilterMode);
+
+ int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
+ if (this->shouldTileBitmap(bitmap, viewMatrix, params, &srcRect,
+ maxTileSizeForFilter, &tileSize, &clippedSrcRect)) {
+ this->drawTiledBitmap(bitmap, viewMatrix, srcRect, clippedSrcRect, params, paint,
+ SkCanvas::kStrict_SrcRectConstraint, tileSize, doBicubic);
+ return;
+ }
}
- this->drawBitmapCommon(*draw, bitmap, nullptr, nullptr, paint,
- SkCanvas::kStrict_SrcRectConstraint);
+ GrBitmapTextureMaker maker(fContext, bitmap);
+ this->drawTextureProducer(&maker, alphaOnly, nullptr, nullptr,
+ SkCanvas::kStrict_SrcRectConstraint, viewMatrix, fClip, paint);
}
// This method outsets 'iRect' by 'outset' all around and then clamps its extents to
@@ -897,300 +927,6 @@ static inline void clamped_outset_with_offset(SkIRect* iRect,
}
}
-static bool has_aligned_samples(const SkRect& srcRect,
- const SkRect& transformedRect) {
- // detect pixel disalignment
- if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) -
- transformedRect.left()) < COLOR_BLEED_TOLERANCE &&
- SkScalarAbs(SkScalarRoundToScalar(transformedRect.top()) -
- transformedRect.top()) < COLOR_BLEED_TOLERANCE &&
- SkScalarAbs(transformedRect.width() - srcRect.width()) <
- COLOR_BLEED_TOLERANCE &&
- SkScalarAbs(transformedRect.height() - srcRect.height()) <
- COLOR_BLEED_TOLERANCE) {
- return true;
- }
- return false;
-}
-
-static bool may_color_bleed(const SkRect& srcRect,
- const SkRect& transformedRect,
- const SkMatrix& m,
- bool isMSAA) {
- // Only gets called if has_aligned_samples returned false.
- // So we can assume that sampling is axis aligned but not texel aligned.
- SkASSERT(!has_aligned_samples(srcRect, transformedRect));
- SkRect innerSrcRect(srcRect), innerTransformedRect,
- outerTransformedRect(transformedRect);
- if (isMSAA) {
- innerSrcRect.inset(SK_Scalar1, SK_Scalar1);
- } else {
- innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf);
- }
- m.mapRect(&innerTransformedRect, innerSrcRect);
-
- // The gap between outerTransformedRect and innerTransformedRect
- // represents the projection of the source border area, which is
- // problematic for color bleeding. We must check whether any
- // destination pixels sample the border area.
- outerTransformedRect.inset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
- innerTransformedRect.outset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
- SkIRect outer, inner;
- outerTransformedRect.round(&outer);
- innerTransformedRect.round(&inner);
- // If the inner and outer rects round to the same result, it means the
- // border does not overlap any pixel centers. Yay!
- return inner != outer;
-}
-
-static bool needs_texture_domain(const SkBitmap& bitmap,
- const SkRect& srcRect,
- GrTextureParams &params,
- const SkMatrix& contextMatrix,
- bool bicubic,
- bool isMSAA) {
- bool needsTextureDomain = false;
- GrTexture* tex = bitmap.getTexture();
- int width = tex ? tex->width() : bitmap.width();
- int height = tex ? tex->height() : bitmap.height();
-
- if (bicubic || params.filterMode() != GrTextureParams::kNone_FilterMode) {
- // Need texture domain if drawing a sub rect
- needsTextureDomain = srcRect.width() < width ||
- srcRect.height() < height;
- if (!bicubic && needsTextureDomain && contextMatrix.rectStaysRect()) {
- // sampling is axis-aligned
- SkRect transformedRect;
- contextMatrix.mapRect(&transformedRect, srcRect);
-
- if (has_aligned_samples(srcRect, transformedRect)) {
- params.setFilterMode(GrTextureParams::kNone_FilterMode);
- needsTextureDomain = false;
- } else {
- needsTextureDomain = may_color_bleed(srcRect, transformedRect,
- contextMatrix, isMSAA);
- }
- }
- }
- return needsTextureDomain;
-}
-
-static void draw_aa_bitmap(GrDrawContext* drawContext, GrContext* context,
- GrRenderTarget* renderTarget, const GrClip& clip,
- const SkMatrix& viewMatrix, const SkMatrix& srcRectToDstRect,
- const SkPaint& paint, const SkBitmap* bitmapPtr, const SkSize& dstSize) {
- SkShader::TileMode tm[] = {
- SkShader::kClamp_TileMode,
- SkShader::kClamp_TileMode,
- };
-
- bool doBicubic;
- GrTextureParams::FilterMode textureFilterMode =
- GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix,
- srcRectToDstRect,
- &doBicubic);
-
- // Setup texture to wrap bitmap
- GrTextureParams params(tm, textureFilterMode);
- SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, *bitmapPtr, params));
-
- if (!texture) {
- SkErrorInternals::SetError(kInternalError_SkError,
- "Couldn't convert bitmap to texture.");
- return;
- }
-
-
- GrPaint grPaint;
-
- // Create and insert texture effect
- SkAutoTUnref<const GrFragmentProcessor> fp;
- if (doBicubic) {
- fp.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), tm));
- } else {
- fp.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), params));
- }
-
- if (kAlpha_8_SkColorType == bitmapPtr->colorType()) {
- fp.reset(GrFragmentProcessor::MulOutputByInputUnpremulColor(fp));
- } else {
- fp.reset(GrFragmentProcessor::MulOutputByInputAlpha(fp));
- }
-
- if (!SkPaintToGrPaintReplaceShader(context, paint, fp, &grPaint)) {
- return;
- }
-
- // Setup dst rect and final matrix
- SkRect dstRect = {0, 0, dstSize.fWidth, dstSize.fHeight};
-
- SkRect devRect;
- viewMatrix.mapRect(&devRect, dstRect);
-
- SkMatrix matrix;
- matrix.setIDiv(bitmapPtr->width(), bitmapPtr->height());
-
- SkMatrix dstRectToSrcRect;
- if (!srcRectToDstRect.invert(&dstRectToSrcRect)) {
- return;
- }
- matrix.preConcat(dstRectToSrcRect);
-
- SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateAAFill(grPaint.getColor(),
- viewMatrix,
- matrix,
- dstRect,
- devRect));
-
- drawContext->drawBatch(clip, grPaint, batch);
-}
-
-static bool can_ignore_strict_subset_constraint(const SkBitmap& bitmap, const SkRect& subset) {
- GrTexture* tex = bitmap.getTexture();
- int width = tex ? tex->width() : bitmap.width();
- int height = tex ? tex->height() : bitmap.height();
- return subset.contains(SkRect::MakeIWH(width, height));
-}
-
-void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
- const SkBitmap& bitmap,
- const SkRect* srcRectPtr,
- const SkSize* dstSizePtr,
- const SkPaint& paint,
- SkCanvas::SrcRectConstraint constraint) {
- CHECK_SHOULD_DRAW(draw);
-
- SkRect srcRect;
- SkSize dstSize;
- // If there is no src rect, or the src rect contains the entire bitmap then we're effectively
- // in the (easier) bleed case, so update flags.
- if (nullptr == srcRectPtr) {
- SkScalar w = SkIntToScalar(bitmap.width());
- SkScalar h = SkIntToScalar(bitmap.height());
- dstSize.fWidth = w;
- dstSize.fHeight = h;
- srcRect.set(0, 0, w, h);
- } else {
- SkASSERT(dstSizePtr);
- srcRect = *srcRectPtr;
- dstSize = *dstSizePtr;
- }
-
- if (can_ignore_strict_subset_constraint(bitmap, srcRect)) {
- constraint = SkCanvas::kFast_SrcRectConstraint;
- }
-
- // If the render target is not msaa and draw is antialiased, we call
- // drawRect instead of drawing on the render target directly.
- // FIXME: the tiled bitmap code path doesn't currently support
- // anti-aliased edges, we work around that for now by drawing directly
- // if the image size exceeds maximum texture size.
- int maxTileSize = fContext->caps()->maxTileSize();
- bool drawAA = !fRenderTarget->isUnifiedMultisampled() &&
- paint.isAntiAlias() &&
- bitmap.width() <= maxTileSize &&
- bitmap.height() <= maxTileSize;
-
- if (paint.getMaskFilter() || drawAA) {
- // Convert the bitmap to a shader so that the rect can be drawn
- // through drawRect, which supports mask filters.
- SkBitmap tmp; // subset of bitmap, if necessary
- const SkBitmap* bitmapPtr = &bitmap;
- SkMatrix srcRectToDstRect;
- if (srcRectPtr) {
- srcRectToDstRect.setTranslate(-srcRectPtr->fLeft, -srcRectPtr->fTop);
- srcRectToDstRect.postScale(dstSize.fWidth / srcRectPtr->width(),
- dstSize.fHeight / srcRectPtr->height());
- // In bleed mode we position and trim the bitmap based on the src rect which is
- // already accounted for in 'm' and 'srcRect'. In clamp mode we need to chop out
- // the desired portion of the bitmap and then update 'm' and 'srcRect' to
- // compensate.
- if (SkCanvas::kStrict_SrcRectConstraint == constraint) {
- SkIRect iSrc;
- srcRect.roundOut(&iSrc);
-
- SkPoint offset = SkPoint::Make(SkIntToScalar(iSrc.fLeft),
- SkIntToScalar(iSrc.fTop));
-
- if (!bitmap.extractSubset(&tmp, iSrc)) {
- return; // extraction failed
- }
- bitmapPtr = &tmp;
- srcRect.offset(-offset.fX, -offset.fY);
-
- // The source rect has changed so update the matrix
- srcRectToDstRect.preTranslate(offset.fX, offset.fY);
- }
- } else {
- srcRectToDstRect.reset();
- }
-
- // If we have a maskfilter then we can't batch, so we take a slow path. However, we fast
- // path the case where we are drawing an AA rect so we can batch many drawImageRect calls
- if (paint.getMaskFilter()) {
- SkPaint paintWithShader(paint);
- paintWithShader.setShader(SkShader::CreateBitmapShader(*bitmapPtr,
- SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
- &srcRectToDstRect))->unref();
- SkRect dstRect = {0, 0, dstSize.fWidth, dstSize.fHeight};
- this->drawRect(draw, dstRect, paintWithShader);
- } else {
- draw_aa_bitmap(fDrawContext, fContext, fRenderTarget, fClip, *draw.fMatrix,
- srcRectToDstRect, paint, bitmapPtr, dstSize);
- }
-
- return;
- }
-
- // If there is no mask filter than it is OK to handle the src rect -> dst rect scaling using
- // the view matrix rather than a local matrix.
- SkMatrix viewM = *draw.fMatrix;
- viewM.preScale(dstSize.fWidth / srcRect.width(),
- dstSize.fHeight / srcRect.height());
-
- GrTextureParams params;
- bool doBicubic;
- GrTextureParams::FilterMode textureFilterMode =
- GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewM, SkMatrix::I(),
- &doBicubic);
-
- int tileFilterPad;
- if (doBicubic) {
- tileFilterPad = GrBicubicEffect::kFilterTexelPad;
- } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) {
- tileFilterPad = 0;
- } else {
- tileFilterPad = 1;
- }
- params.setFilterMode(textureFilterMode);
-
- maxTileSize = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
- int tileSize;
-
- SkIRect clippedSrcRect;
- if (this->shouldTileBitmap(bitmap, viewM, params, srcRectPtr, maxTileSize, &tileSize,
- &clippedSrcRect)) {
- this->drawTiledBitmap(bitmap, viewM, srcRect, clippedSrcRect, params, paint, constraint,
- tileSize, doBicubic);
- } else {
- // take the simple case
- bool needsTextureDomain = needs_texture_domain(bitmap,
- srcRect,
- params,
- viewM,
- doBicubic,
- fRenderTarget->isUnifiedMultisampled());
- this->internalDrawBitmap(bitmap,
- viewM,
- srcRect,
- params,
- paint,
- constraint,
- doBicubic,
- needsTextureDomain);
- }
-}
-
// Break 'bitmap' into several tiles to draw it since it has already
// been determined to be too large to fit in VRAM
void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
@@ -1269,10 +1005,8 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
// now offset it to make it "local" to our tmp bitmap
tileR.offset(-offset.fX, -offset.fY);
GrTextureParams paramsTemp = params;
- bool needsTextureDomain = needs_texture_domain(
- bitmap, srcRect, paramsTemp,
- viewM, bicubic,
- fRenderTarget->isUnifiedMultisampled());
+ // de-optimized this determination
+ bool needsTextureDomain = true;
this->internalDrawBitmap(tmpB,
viewM,
tileR,
@@ -1502,58 +1236,92 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
SK_Scalar1 * h / texture->height()));
}
-void SkGpuDevice::drawBitmapRect(const SkDraw& origDraw, const SkBitmap& bitmap,
- const SkRect* src, const SkRect& dst,
+void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
+ const SkRect* src, const SkRect& origDst,
const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
- if (GrTexture* tex = bitmap.getTexture()) {
- CHECK_SHOULD_DRAW(origDraw);
- bool alphaOnly = GrPixelConfigIsAlphaOnly(tex->config());
+ bool alphaOnly = kAlpha_8_SkColorType == bitmap.colorType();
+ if (bitmap.getTexture()) {
+ CHECK_SHOULD_DRAW(draw);
GrBitmapTextureAdjuster adjuster(&bitmap);
- this->drawTextureAdjuster(&adjuster, alphaOnly, src, &dst, constraint, *origDraw.fMatrix,
+ this->drawTextureProducer(&adjuster, alphaOnly, src, &origDst, constraint, *draw.fMatrix,
fClip, paint);
return;
}
-
- SkMatrix matrix;
- SkRect bitmapBounds, tmpSrc;
-
- bitmapBounds.set(0, 0,
- SkIntToScalar(bitmap.width()),
- SkIntToScalar(bitmap.height()));
-
+ // The src rect is inferred to be the bmp bounds if not provided. Otherwise, the src rect must
+ // be clipped to the bmp bounds. To determine tiling parameters we need the filter mode which
+ // in turn requires knowing the src-to-dst mapping. If the src was clipped to the bmp bounds
+ // then we use the src-to-dst mapping to compute a new clipped dst rect.
+ const SkRect* dst = &origDst;
+ const SkRect bmpBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
// Compute matrix from the two rectangles
- if (src) {
- tmpSrc = *src;
- } else {
- tmpSrc = bitmapBounds;
+ if (!src) {
+ src = &bmpBounds;
}
- matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
-
- // clip the tmpSrc to the bounds of the bitmap. No check needed if src==null.
- if (src) {
- if (!bitmapBounds.contains(tmpSrc)) {
- if (!tmpSrc.intersect(bitmapBounds)) {
+ SkMatrix srcToDstMatrix;
+ if (!srcToDstMatrix.setRectToRect(*src, *dst, SkMatrix::kFill_ScaleToFit)) {
+ return;
+ }
+ SkRect tmpSrc, tmpDst;
+ if (src != &bmpBounds) {
+ if (!bmpBounds.contains(*src)) {
+ tmpSrc = *src;
+ if (!tmpSrc.intersect(bmpBounds)) {
return; // nothing to draw
}
+ src = &tmpSrc;
+ srcToDstMatrix.mapRect(&tmpDst, *src);
+ dst = &tmpDst;
}
}
- SkRect tmpDst;
- matrix.mapRect(&tmpDst, tmpSrc);
+ int maxTileSize = fContext->caps()->maxTileSize();
- SkTCopyOnFirstWrite<SkDraw> draw(origDraw);
- if (0 != tmpDst.fLeft || 0 != tmpDst.fTop) {
- // Translate so that tempDst's top left is at the origin.
- matrix = *origDraw.fMatrix;
- matrix.preTranslate(tmpDst.fLeft, tmpDst.fTop);
- draw.writable()->fMatrix = &matrix;
- }
- SkSize dstSize;
- dstSize.fWidth = tmpDst.width();
- dstSize.fHeight = tmpDst.height();
+ // The tile code path doesn't currently support AA, so if the paint asked for aa and we could
+ // draw untiled, then we bypass checking for tiling purely for optimization reasons.
+ bool drawAA = !fRenderTarget->isUnifiedMultisampled() &&
+ paint.isAntiAlias() &&
+ bitmap.width() <= maxTileSize &&
+ bitmap.height() <= maxTileSize;
+
+ bool skipTileCheck = drawAA || paint.getMaskFilter();
+
+ if (!skipTileCheck) {
+ int tileSize;
+ SkIRect clippedSrcRect;
+
+ GrTextureParams params;
+ bool doBicubic;
+ GrTextureParams::FilterMode textureFilterMode =
+ GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), *draw.fMatrix, srcToDstMatrix,
+ &doBicubic);
+
+ int tileFilterPad;
+
+ if (doBicubic) {
+ tileFilterPad = GrBicubicEffect::kFilterTexelPad;
+ } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) {
+ tileFilterPad = 0;
+ } else {
+ tileFilterPad = 1;
+ }
+ params.setFilterMode(textureFilterMode);
- this->drawBitmapCommon(*draw, bitmap, &tmpSrc, &dstSize, paint, constraint);
+ int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
+ // Fold the dst rect into the view matrix. This is only OK because we don't get here if
+ // we have a mask filter.
+ SkMatrix viewMatrix = *draw.fMatrix;
+ viewMatrix.preTranslate(dst->fLeft, dst->fTop);
+ viewMatrix.preScale(dst->width()/src->width(), dst->height()/src->height());
+ if (this->shouldTileBitmap(bitmap, viewMatrix, params, src,
+ maxTileSizeForFilter, &tileSize, &clippedSrcRect)) {
+ this->drawTiledBitmap(bitmap, viewMatrix, *src, clippedSrcRect, params, paint,
+ constraint, tileSize, doBicubic);
+ return;
+ }
+ }
+ GrBitmapTextureMaker maker(fContext, bitmap);
+ this->drawTextureProducer(&maker, alphaOnly, src, dst, constraint, *draw.fMatrix, fClip, paint);
}
void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
@@ -1680,7 +1448,7 @@ void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x
viewMatrix.preTranslate(x, y);
bool alphaOnly = GrPixelConfigIsAlphaOnly(tex->config());
GrImageTextureAdjuster adjuster(as_IB(image));
- this->drawTextureAdjuster(&adjuster, alphaOnly, nullptr, nullptr,
+ this->drawTextureProducer(&adjuster, alphaOnly, nullptr, nullptr,
SkCanvas::kFast_SrcRectConstraint, viewMatrix, fClip, paint);
return;
} else {
@@ -1706,7 +1474,7 @@ void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const
CHECK_SHOULD_DRAW(draw);
GrImageTextureAdjuster adjuster(as_IB(image));
bool alphaOnly = GrPixelConfigIsAlphaOnly(tex->config());
- this->drawTextureAdjuster(&adjuster, alphaOnly, src, &dst, constraint, *draw.fMatrix,
+ this->drawTextureProducer(&adjuster, alphaOnly, src, &dst, constraint, *draw.fMatrix,
fClip, paint);
return;
}
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index 8816589ebf..0c0987ac9f 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -22,7 +22,7 @@ struct SkDrawProcs;
struct GrSkDrawProcs;
class GrAccelData;
-class GrTextureAdjuster;
+class GrTextureProducer;
struct GrCachedLayer;
/**
@@ -182,16 +182,6 @@ private:
void prepareDraw(const SkDraw&);
/**
- * Implementation for both drawBitmap and drawBitmapRect.
- */
- void drawBitmapCommon(const SkDraw&,
- const SkBitmap& bitmap,
- const SkRect* srcRectPtr,
- const SkSize* dstSizePtr, // ignored iff srcRectPtr == nullptr
- const SkPaint&,
- SkCanvas::SrcRectConstraint);
-
- /**
* Helper functions called by drawBitmapCommon. By the time these are called the SkDraw's
* matrix, clip, and the device's render target has already been set on GrContext.
*/
@@ -236,24 +226,24 @@ private:
int tileSize,
bool bicubic);
- void drawTextureAdjuster(GrTextureAdjuster* adjuster,
+ void drawTextureProducer(GrTextureProducer*,
bool alphaOnly,
const SkRect* srcRect,
const SkRect* dstRect,
- SkCanvas::SrcRectConstraint constraint,
+ SkCanvas::SrcRectConstraint,
const SkMatrix& viewMatrix,
- const GrClip& clip,
- const SkPaint& paint);
+ const GrClip&,
+ const SkPaint&);
- void drawTextureAdjusterImpl(GrTextureAdjuster*,
+ void drawTextureProducerImpl(GrTextureProducer*,
bool alphaOnly,
const SkRect& clippedSrcRect,
const SkRect& clippedDstRect,
- SkCanvas::SrcRectConstraint constraint,
+ SkCanvas::SrcRectConstraint,
const SkMatrix& viewMatrix,
const SkMatrix& srcToDstMatrix,
- const GrClip& clip,
- const SkPaint& paint);
+ const GrClip&,
+ const SkPaint&);
bool drawDashLine(const SkPoint pts[2], const SkPaint& paint);
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp
index b41d69c6fd..ccc9e2a2dd 100644
--- a/src/gpu/SkGpuDevice_drawTexture.cpp
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp
@@ -52,7 +52,71 @@ static const GrFragmentProcessor* mix_texture_fp_with_paint_color_and_shader(
}
}
-void SkGpuDevice::drawTextureAdjuster(GrTextureAdjuster* adjuster,
+//////////////////////////////////////////////////////////////////////////////
+// Helper functions for dropping src rect constraint in bilerp mode.
+
+static const SkScalar kColorBleedTolerance = 0.001f;
+
+static bool has_aligned_samples(const SkRect& srcRect, const SkRect& transformedRect) {
+ // detect pixel disalignment
+ if (SkScalarAbs(SkScalarFraction(transformedRect.left())) < kColorBleedTolerance &&
+ SkScalarAbs(SkScalarFraction(transformedRect.top())) < kColorBleedTolerance &&
+ SkScalarAbs(transformedRect.width() - srcRect.width()) < kColorBleedTolerance &&
+ SkScalarAbs(transformedRect.height() - srcRect.height()) < kColorBleedTolerance) {
+ return true;
+ }
+ return false;
+}
+
+static bool may_color_bleed(const SkRect& srcRect,
+ const SkRect& transformedRect,
+ const SkMatrix& m,
+ bool isMSAA) {
+ // Only gets called if has_aligned_samples returned false.
+ // So we can assume that sampling is axis aligned but not texel aligned.
+ SkASSERT(!has_aligned_samples(srcRect, transformedRect));
+ SkRect innerSrcRect(srcRect), innerTransformedRect, outerTransformedRect(transformedRect);
+ if (isMSAA) {
+ innerSrcRect.inset(SK_Scalar1, SK_Scalar1);
+ } else {
+ innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf);
+ }
+ m.mapRect(&innerTransformedRect, innerSrcRect);
+
+ // The gap between outerTransformedRect and innerTransformedRect
+ // represents the projection of the source border area, which is
+ // problematic for color bleeding. We must check whether any
+ // destination pixels sample the border area.
+ outerTransformedRect.inset(kColorBleedTolerance, kColorBleedTolerance);
+ innerTransformedRect.outset(kColorBleedTolerance, kColorBleedTolerance);
+ SkIRect outer, inner;
+ outerTransformedRect.round(&outer);
+ innerTransformedRect.round(&inner);
+ // If the inner and outer rects round to the same result, it means the
+ // border does not overlap any pixel centers. Yay!
+ return inner != outer;
+}
+
+static bool can_ignore_bilerp_constraint(const GrTextureProducer& producer,
+ const SkRect& srcRect,
+ const SkMatrix& srcRectToDeviceSpace,
+ bool isMSAA) {
+ if (srcRectToDeviceSpace.rectStaysRect()) {
+ // sampling is axis-aligned
+ SkRect transformedRect;
+ srcRectToDeviceSpace.mapRect(&transformedRect, srcRect);
+
+ if (has_aligned_samples(srcRect, transformedRect) ||
+ !may_color_bleed(srcRect, transformedRect, srcRectToDeviceSpace, isMSAA)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void SkGpuDevice::drawTextureProducer(GrTextureProducer* producer,
bool alphaOnly,
const SkRect* srcRect,
const SkRect* dstRect,
@@ -65,7 +129,7 @@ void SkGpuDevice::drawTextureAdjuster(GrTextureAdjuster* adjuster,
// the matrix that maps the src rect to the dst rect.
SkRect clippedSrcRect;
SkRect clippedDstRect;
- const SkRect srcBounds = SkRect::MakeIWH(adjuster->width(), adjuster->height());
+ const SkRect srcBounds = SkRect::MakeIWH(producer->width(), producer->height());
SkMatrix srcToDstMatrix;
if (srcRect) {
if (!dstRect) {
@@ -100,11 +164,11 @@ void SkGpuDevice::drawTextureAdjuster(GrTextureAdjuster* adjuster,
}
}
- this->drawTextureAdjusterImpl(adjuster, alphaOnly, clippedSrcRect, clippedDstRect, constraint,
+ this->drawTextureProducerImpl(producer, alphaOnly, clippedSrcRect, clippedDstRect, constraint,
viewMatrix, srcToDstMatrix, clip, paint);
}
-void SkGpuDevice::drawTextureAdjusterImpl(GrTextureAdjuster* adjuster,
+void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer,
bool alphaTexture,
const SkRect& clippedSrcRect,
const SkRect& clippedDstRect,
@@ -141,6 +205,17 @@ void SkGpuDevice::drawTextureAdjusterImpl(GrTextureAdjuster* adjuster,
// This is conservative as a mask filter does not have to expand the bounds rendered.
bool coordsAllInsideSrcRect = !paint.isAntiAlias() && !mf;
+ // Check for optimization to drop the src rect constraint when on bilerp.
+ if (filterMode && GrTextureParams::kBilerp_FilterMode == *filterMode &&
+ GrTextureAdjuster::kYes_FilterConstraint == constraintMode && coordsAllInsideSrcRect) {
+ SkMatrix combinedMatrix;
+ combinedMatrix.setConcat(viewMatrix, srcToDstMatrix);
+ if (can_ignore_bilerp_constraint(*producer, clippedSrcRect, combinedMatrix,
+ fRenderTarget->isUnifiedMultisampled())) {
+ constraintMode = GrTextureAdjuster::kNo_FilterConstraint;
+ }
+ }
+
const SkMatrix* textureMatrix;
SkMatrix tempMatrix;
if (canUseTextureCoordsAsLocalCoords) {
@@ -151,7 +226,7 @@ void SkGpuDevice::drawTextureAdjusterImpl(GrTextureAdjuster* adjuster,
}
textureMatrix = &tempMatrix;
}
- SkAutoTUnref<const GrFragmentProcessor> fp(adjuster->createFragmentProcessor(
+ SkAutoTUnref<const GrFragmentProcessor> fp(producer->createFragmentProcessor(
*textureMatrix, clippedSrcRect, constraintMode, coordsAllInsideSrcRect, filterMode));
if (!fp) {
return;
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 540edb6a38..affd6cd959 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -285,63 +285,12 @@ void GrInstallBitmapUniqueKeyInvalidator(const GrUniqueKey& key, SkPixelRef* pix
pixelRef->addGenIDChangeListener(new Invalidator(key));
}
-class RasterBitmap_GrTextureMaker : public GrTextureMaker {
-public:
- RasterBitmap_GrTextureMaker(const SkBitmap& bitmap)
- : INHERITED(bitmap.width(), bitmap.height())
- , fBitmap(bitmap)
- {
- SkASSERT(!bitmap.getTexture());
- if (!bitmap.isVolatile()) {
- SkIPoint origin = bitmap.pixelRefOrigin();
- SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, bitmap.width(),
- bitmap.height());
- GrMakeKeyFromImageID(&fOriginalKey, bitmap.pixelRef()->getGenerationID(), subset);
- }
- }
-
-protected:
- GrTexture* refOriginalTexture(GrContext* ctx) override {
- GrTexture* tex;
-
- if (fOriginalKey.isValid()) {
- tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(fOriginalKey);
- if (tex) {
- return tex;
- }
- }
-
- tex = GrUploadBitmapToTexture(ctx, fBitmap);
- if (tex && fOriginalKey.isValid()) {
- tex->resourcePriv().setUniqueKey(fOriginalKey);
- GrInstallBitmapUniqueKeyInvalidator(fOriginalKey, fBitmap.pixelRef());
- }
- return tex;
- }
-
- void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) override {
- if (fOriginalKey.isValid()) {
- MakeCopyKeyFromOrigKey(fOriginalKey, copyParams, copyKey);
- }
- }
-
- void didCacheCopy(const GrUniqueKey& copyKey) override {
- GrInstallBitmapUniqueKeyInvalidator(copyKey, fBitmap.pixelRef());
- }
-
-private:
- const SkBitmap fBitmap;
- GrUniqueKey fOriginalKey;
-
- typedef GrTextureMaker INHERITED;
-};
-
GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap,
const GrTextureParams& params) {
if (bitmap.getTexture()) {
return GrBitmapTextureAdjuster(&bitmap).refTextureSafeForParams(params, nullptr);
}
- return RasterBitmap_GrTextureMaker(bitmap).refTextureForParams(ctx, params);
+ return GrBitmapTextureMaker(ctx, bitmap).refTextureForParams(params);
}
///////////////////////////////////////////////////////////////////////////////