Convert SkGpuDevice::drawTextureAdjuster to SkGpuDevice::drawTextureProducer
authorbsalomon <bsalomon@google.com>
Wed, 18 Nov 2015 18:56:08 +0000 (10:56 -0800)
committerCommit bot <commit-bot@chromium.org>
Wed, 18 Nov 2015 18:56:08 +0000 (10:56 -0800)
Move createFragmentProcessor to GrTextureProducer base class.

Make non-tiled sw-bitmap draws go through drawTextureProducer.

Review URL: https://codereview.chromium.org/1459433002

src/core/SkImageCacherator.cpp
src/gpu/GrImageIDTextureAdjuster.cpp
src/gpu/GrImageIDTextureAdjuster.h
src/gpu/GrTextureParamsAdjuster.cpp
src/gpu/GrTextureParamsAdjuster.h
src/gpu/SkGpuDevice.cpp
src/gpu/SkGpuDevice.h
src/gpu/SkGpuDevice_drawTexture.cpp
src/gpu/SkGr.cpp

index 75fef5a8afe3bbd4db4078281d18c38840a84788..fb06a56917d21729aa27cccfa6306df0f67dc4e8 100644 (file)
@@ -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
index 525223cf7773470025de2981d4f43d57cd4d3202..c37c02277589c2b0f4a543cee7b46b068a21aea4 100644 (file)
@@ -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());
+}
index 6c0747a62ce337e516cb285845068f418d89517b..a20902ed581fb1fa6b2eef6696df53bb0cefc4c1 100644 (file)
@@ -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
index 0547d95053d870bd856a34b2aafe82853cc5451c..1a751ab73c7a6f51be05d98b4f838e0c081aa02d 100644 (file)
@@ -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;
     }
index cad392046643c4c2228997034a6c80d877501ea4..ed9f142af0f6d4e7ce36626906042df0fb7fc42f 100644 (file)
@@ -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;
 };
 
index 36e0342f78b2a522e1c1c47af8e1772f3a5b7b1f..7dfeba621da33ffab4b608e493c24b13c9d4afba 100644 (file)
@@ -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;
     }
index 8816589ebf3cc39dac40fcad1433bc1b9a2bd9a6..0c0987ac9f2178ebb861265a1663d4a8b5625f6a 100644 (file)
@@ -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);
 
index b41d69c6fd7aa5f690c18bb27fb4de2834235985..ccc9e2a2dd0da91dc8763c2fedee02d6e073b888 100644 (file)
@@ -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;
index 540edb6a38e728c6a5e1f018a2dc3840fda965a8..affd6cd9593b53dbc2dbc9742a5f89032974df37 100644 (file)
@@ -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);
 }
 
 ///////////////////////////////////////////////////////////////////////////////