Convert SkGpuDevice::drawTextureAdjuster to SkGpuDevice::drawTextureProducer
Move createFragmentProcessor to GrTextureProducer base class. Make non-tiled sw-bitmap draws go through drawTextureProducer. Review URL: https://codereview.chromium.org/1459433002
This commit is contained in:
parent
e59124ed1a
commit
b1b019985b
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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<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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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 ¶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<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;
|
||||
// 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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user