diff --git a/src/core/SkImageCacherator.cpp b/src/core/SkImageCacherator.cpp index 75fef5a8af..fb06a56917 100644 --- a/src/core/SkImageCacherator.cpp +++ b/src/core/SkImageCacherator.cpp @@ -275,11 +275,10 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key class Cacherator_GrTextureMaker : public GrTextureMaker { public: - Cacherator_GrTextureMaker(SkImageCacherator* cacher, const SkImage* client) - : INHERITED(cacher->info().width(), cacher->info().height()) + Cacherator_GrTextureMaker(GrContext* context, SkImageCacherator* cacher, const SkImage* client) + : INHERITED(context, cacher->info().width(), cacher->info().height()) , fCacher(cacher) - , fClient(client) - { + , fClient(client) { if (client) { GrMakeKeyFromImageID(&fOriginalKey, client->uniqueID(), SkIRect::MakeWH(this->width(), this->height())); @@ -289,10 +288,10 @@ public: protected: // TODO: consider overriding this, for the case where the underlying generator might be // able to efficiently produce a "stretched" texture natively (e.g. picture-backed) - // GrTexture* generateTextureForParams(GrContext*, const SkGrStretch&) override; + // GrTexture* generateTextureForParams(const CopyParams&) override; - GrTexture* refOriginalTexture(GrContext* ctx) override { - return fCacher->lockTexture(ctx, fOriginalKey, fClient); + GrTexture* refOriginalTexture() override { + return fCacher->lockTexture(this->context(), fOriginalKey, fClient); } void makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey) override { @@ -321,7 +320,7 @@ GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParam return nullptr; } - return Cacherator_GrTextureMaker(this, client).refTextureForParams(ctx, params); + return Cacherator_GrTextureMaker(ctx, this, client).refTextureForParams(params); } #else 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, - ©Params)) { - return this->refOriginalTexture(ctx); + if (!fContext->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params, + ©Params)) { + return this->refOriginalTexture(); } GrUniqueKey copyKey; this->makeCopyKey(copyParams, ©Key); 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 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 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 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&); + + const GrFragmentProcessor* createFragmentProcessor( + const SkMatrix& textureMatrix, + const SkRect& constraintRect, + FilterConstraint filterConstraint, + bool coordsLimitedToConstraintRect, + const GrTextureParams::FilterMode* filterOrNullForBicubic) override; protected: - GrTextureMaker(int width, int height) : INHERITED(width, height) {} + GrTextureMaker(GrContext* context, int width, int height) + : INHERITED(width, height) + , fContext(context) {} /** - * 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). + * Return the maker's "original" texture. It is the responsibility of the maker to handle any + * caching of the original if desired. */ - virtual GrTexture* refOriginalTexture(GrContext*) = 0; - - /** - * 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. - */ - 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 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 ¶ms, - 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 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 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 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 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; + // 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); + + 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; + } } - SkSize dstSize; - dstSize.fWidth = tmpDst.width(); - dstSize.fHeight = tmpDst.height(); - - this->drawBitmapCommon(*draw, bitmap, &tmpSrc, &dstSize, paint, constraint); + 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; /** @@ -181,16 +181,6 @@ private: // sets the render target and clip on context 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 fp(adjuster->createFragmentProcessor( + SkAutoTUnref 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); } ///////////////////////////////////////////////////////////////////////////////