Pull texture-backed bitmap resampler out of GrTextureParamsAdjuster code into its own class.

Review URL: https://codereview.chromium.org/1420963008
This commit is contained in:
bsalomon 2015-10-29 10:49:28 -07:00 committed by Commit bot
parent 05527a65e0
commit 89fe56bb98
8 changed files with 259 additions and 107 deletions

View File

@ -273,9 +273,9 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key
#include "GrTextureParamsAdjuster.h"
class Cacherator_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
class Cacherator_GrTextureMaker : public GrTextureMaker {
public:
Cacherator_GrTextureParamsAdjuster(SkImageCacherator* cacher, const SkImage* client)
Cacherator_GrTextureMaker(SkImageCacherator* cacher, const SkImage* client)
: INHERITED(cacher->info().width(), cacher->info().height())
, fCacher(cacher)
, fClient(client)
@ -312,7 +312,7 @@ private:
const SkImage* fClient;
GrUniqueKey fOriginalKey;
typedef GrTextureParamsAdjuster INHERITED;
typedef GrTextureMaker INHERITED;
};
GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParams& params,
@ -321,7 +321,7 @@ GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParam
return nullptr;
}
return Cacherator_GrTextureParamsAdjuster(this, client).refTextureForParams(ctx, params);
return Cacherator_GrTextureMaker(this, client).refTextureForParams(ctx, params);
}
#else

View File

@ -86,7 +86,7 @@ private:
const SkIPoint fOrigin;
const uint32_t fUniqueID;
friend class Cacherator_GrTextureParamsAdjuster;
friend class Cacherator_GrTextureMaker;
};
#endif

View File

@ -56,7 +56,7 @@ void GrGpu::contextAbandoned() {}
////////////////////////////////////////////////////////////////////////////////
bool GrGpu::makeCopyForTextureParams(int width, int height, const GrTextureParams& textureParams,
GrTextureParamsAdjuster::CopyParams* copyParams) const {
GrTextureProducer::CopyParams* copyParams) const {
const GrCaps& caps = *this->caps();
if (textureParams.isTiled() && !caps.npotTextureTileSupport() &&
(!SkIsPow2(width) || !SkIsPow2(height))) {

View File

@ -384,7 +384,7 @@ public:
// a given GrTextureParams. If so, the width, height and filter used for the copy are
// output via the CopyParams.
bool makeCopyForTextureParams(int width, int height, const GrTextureParams&,
GrTextureParamsAdjuster::CopyParams*) const;
GrTextureProducer::CopyParams*) const;
// This is only to be used in GL-specific tests.
virtual const GrGLContext* glContextForTesting() const { return nullptr; }

View File

@ -11,24 +11,31 @@
#include "GrContext.h"
#include "GrDrawContext.h"
#include "GrGpu.h"
#include "GrGpuResourcePriv.h"
#include "GrResourceKey.h"
#include "GrTexture.h"
#include "GrTextureParams.h"
#include "GrTextureProvider.h"
#include "SkCanvas.h"
#include "SkGr.h"
#include "SkGrPriv.h"
#include "effects/GrTextureDomain.h"
typedef GrTextureParamsAdjuster::CopyParams CopyParams;
typedef GrTextureProducer::CopyParams CopyParams;
static GrTexture* copy_on_gpu(GrTexture* inputTexture, const CopyParams& copyParams) {
//////////////////////////////////////////////////////////////////////////////
static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset,
const CopyParams& copyParams) {
SkASSERT(!subset || !subset->isEmpty());
GrContext* context = inputTexture->getContext();
SkASSERT(context);
const GrCaps* caps = context->caps();
// Either it's a cache miss or the original wasn't cached to begin with.
GrSurfaceDesc rtDesc = inputTexture->desc();
rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
rtDesc.fWidth = copyParams.fWidth;
rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
rtDesc.fWidth = copyParams.fWidth;
rtDesc.fHeight = copyParams.fHeight;
rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig);
@ -60,27 +67,107 @@ static GrTexture* copy_on_gpu(GrTexture* inputTexture, const CopyParams& copyPar
return nullptr;
}
// TODO: If no scaling is being performed then use copySurface.
GrPaint paint;
// If filtering is not desired then we want to ensure all texels in the resampled image are
// copies of texels from the original.
GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);
SkScalar sx;
SkScalar sy;
if (subset) {
sx = 1.f / inputTexture->width();
sy = 1.f / inputTexture->height();
}
SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
SkRect localRect = SkRect::MakeWH(1.f, 1.f);
if (copyParams.fFilter != GrTextureParams::kNone_FilterMode && subset &&
(subset->width() != copyParams.fWidth || subset->height() != copyParams.fHeight)) {
SkRect domain;
domain.fLeft = (subset->fLeft + 0.5f) * sx;
domain.fTop = (subset->fTop + 0.5f)* sy;
domain.fRight = (subset->fRight - 0.5f) * sx;
domain.fBottom = (subset->fBottom - 0.5f) * sy;
// This would cause us to read values from outside the subset. Surely, the caller knows
// better!
SkASSERT(copyParams.fFilter != GrTextureParams::kMipMap_FilterMode);
paint.addColorFragmentProcessor(
GrTextureDomainEffect::Create(inputTexture, SkMatrix::I(), domain,
GrTextureDomain::kClamp_Mode,
copyParams.fFilter))->unref();
} else {
GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);
}
SkRect localRect;
if (subset) {
localRect = SkRect::Make(*subset);
localRect.fLeft *= sx;
localRect.fTop *= sy;
localRect.fRight *= sx;
localRect.fBottom *= sy;
} else {
localRect = SkRect::MakeWH(1.f, 1.f);
}
SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(copy->asRenderTarget()));
if (!drawContext) {
return nullptr;
}
drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, localRect);
SkRect dstRect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), dstRect, localRect);
return copy.detach();
}
GrTexture* GrTextureParamsAdjuster::refTextureForParams(GrContext* ctx,
const GrTextureParams& params) {
GrTextureAdjuster::GrTextureAdjuster(GrTexture* original, const SkIRect& subset)
: fOriginal(original) {
if (subset.fLeft > 0 || subset.fTop > 0 ||
subset.fRight < original->width() || subset.fBottom < original->height()) {
fSubset.set(subset);
}
}
GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrTextureParams& params,
SkIPoint* outOffset) {
GrTexture* texture = this->originalTexture();
GrContext* context = texture->getContext();
CopyParams copyParams;
const SkIRect* subset = this->subset();
if (!context->getGpu()->makeCopyForTextureParams(texture->width(), texture->height(), params,
&copyParams)) {
if (outOffset) {
if (subset) {
outOffset->set(subset->fLeft, subset->fRight);
} else {
outOffset->set(0, 0);
}
}
return SkRef(texture);
}
GrUniqueKey key;
this->makeCopyKey(copyParams, &key);
if (key.isValid()) {
GrTexture* result = context->textureProvider()->findAndRefTextureByUniqueKey(key);
if (result) {
return result;
}
}
GrTexture* result = copy_on_gpu(texture, subset, copyParams);
if (result) {
if (key.isValid()) {
result->resourcePriv().setUniqueKey(key);
this->didCacheCopy(key);
}
if (outOffset) {
outOffset->set(0, 0);
}
}
return result;
}
//////////////////////////////////////////////////////////////////////////////
GrTexture* GrTextureMaker::refTextureForParams(GrContext* ctx, const GrTextureParams& params) {
CopyParams copyParams;
if (!ctx->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params,
&copyParams)) {
@ -107,11 +194,10 @@ GrTexture* GrTextureParamsAdjuster::refTextureForParams(GrContext* ctx,
return result;
}
GrTexture* GrTextureParamsAdjuster::generateTextureForParams(GrContext* ctx,
const CopyParams& copyParams) {
GrTexture* GrTextureMaker::generateTextureForParams(GrContext* ctx, const CopyParams& copyParams) {
SkAutoTUnref<GrTexture> original(this->refOriginalTexture(ctx));
if (!original) {
return nullptr;
}
return copy_on_gpu(original, copyParams);
return copy_on_gpu(original, nullptr, copyParams);
}

View File

@ -10,6 +10,7 @@
#include "GrTextureParams.h"
#include "GrResourceKey.h"
#include "SkTLazy.h"
class GrContext;
class GrTexture;
@ -20,12 +21,12 @@ class SkBitmap;
/**
* Different GPUs and API extensions have different requirements with respect to what texture
* sampling parameters may be used with textures of various types. This class facilitates making
* texture compatible with a given GrTextureParams. It abstracts the source of the original data
* which may be an already existing texture, CPU pixels, a codec, ... so that various sources can
* be used with common code that scales or copies the data to make it compatible with a
* GrTextureParams.
* texture compatible with a given GrTextureParams. There are two immediate subclasses defined
* below. One is a base class for sources that are inherently texture-backed (e.g. a texture-backed
* SkImage). It supports subsetting the original texture. The other is for use cases where the
* source can generate a texture that represents some content (e.g. cpu pixels, SkPicture, ...).
*/
class GrTextureParamsAdjuster {
class GrTextureProducer : public SkNoncopyable {
public:
struct CopyParams {
GrTextureParams::FilterMode fFilter;
@ -33,13 +34,85 @@ public:
int fHeight;
};
GrTextureParamsAdjuster(int width, int height) : fWidth(width), fHeight(height) {}
virtual ~GrTextureParamsAdjuster() {}
virtual ~GrTextureProducer() {}
protected:
/** Helper for creating a key for a copy from an original key. */
static void MakeCopyKeyFromOrigKey(const GrUniqueKey& origKey,
const CopyParams& copyParams,
GrUniqueKey* copyKey) {
SkASSERT(!copyKey->isValid());
if (origKey.isValid()) {
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3);
builder[0] = copyParams.fFilter;
builder[1] = copyParams.fWidth;
builder[2] = copyParams.fHeight;
}
}
/**
* If we need to make a copy in order to be compatible with GrTextureParams producer is asked to
* return a key that identifies its original content + the CopyParms parameter. If the producer
* 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;
/**
* If a stretched version of the texture is generated, it may be cached (assuming that
* makeCopyKey() returns true). In that case, the maker is notified in case it
* wants to note that for when the maker is destroyed.
*/
virtual void didCacheCopy(const GrUniqueKey& copyKey) = 0;
typedef SkNoncopyable INHERITED;
};
/** Base class for sources that start out as textures */
class GrTextureAdjuster : public GrTextureProducer {
public:
/** Makes the subset of the texture safe to use with the given texture parameters.
outOffset will be the top-left corner of the subset if a copy is not made. Otherwise,
the copy will be tight to the contents and outOffset will be (0, 0). If the copy's size
does not match subset's dimensions then the contents are scaled to fit the copy.*/
GrTexture* refTextureSafeForParams(const GrTextureParams&, SkIPoint* outOffset);
protected:
/** No subset, use the whole texture */
explicit GrTextureAdjuster(GrTexture* original): fOriginal(original) {}
GrTextureAdjuster(GrTexture* original, const SkIRect& subset);
GrTexture* originalTexture() { return fOriginal; }
/** Returns the subset or null for the whole original texture */
const SkIRect* subset() { return fSubset.getMaybeNull(); }
private:
GrTexture* internalRefTextureSafeForParams(GrTexture*, const SkIRect* subset,
const GrTextureParams&, SkIPoint* outOffset);
SkTLazy<SkIRect> fSubset;
GrTexture* fOriginal;
typedef GrTextureProducer INHERITED;
};
/**
* Base class for sources that start out as something other than a texture (encoded image,
* picture, ...).
*/
class GrTextureMaker : public GrTextureProducer {
public:
GrTextureMaker(int width, int height) : fWidth(width), fHeight(height) {}
int width() const { return fWidth; }
int height() const { return fHeight; }
/** Returns a texture that is safe for use with the params */
/** 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&);
protected:
@ -51,9 +124,9 @@ protected:
virtual GrTexture* refOriginalTexture(GrContext*) = 0;
/**
* If we need to copy the maker's original texture, the maker is asked to return a key
* 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 maker is volatile), this should simply return without
* 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;
@ -70,30 +143,11 @@ protected:
*/
virtual GrTexture* generateTextureForParams(GrContext*, const CopyParams&);
/**
* If a stretched version of the texture is generated, it may be cached (assuming that
* onMakeParamsKey() returns true). In that case, the maker is notified in case it
* wants to note that for when the maker is destroyed.
*/
virtual void didCacheCopy(const GrUniqueKey& copyKey) = 0;
/** Helper for creating a key for a copy from an original key. */
static void MakeCopyKeyFromOrigKey(const GrUniqueKey& origKey,
const CopyParams& copyParams,
GrUniqueKey* copyKey) {
SkASSERT(!copyKey->isValid());
if (origKey.isValid()) {
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3);
builder[0] = copyParams.fFilter;
builder[1] = copyParams.fWidth;
builder[2] = copyParams.fHeight;
}
}
private:
const int fWidth;
const int fHeight;
typedef GrTextureProducer INHERITED;
};
#endif

View File

@ -271,12 +271,26 @@ GrTexture* GrUploadBitmapToTexture(GrContext* ctx, const SkBitmap& bmp) {
////////////////////////////////////////////////////////////////////////////////
class Bitmap_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
static void install_bmp_key_invalidator(const GrUniqueKey& key, SkPixelRef* pixelRef) {
class Invalidator : public SkPixelRef::GenIDChangeListener {
public:
explicit Invalidator(const GrUniqueKey& key) : fMsg(key) {}
private:
GrUniqueKeyInvalidatedMessage fMsg;
void onChange() override { SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); }
};
pixelRef->addGenIDChangeListener(new Invalidator(key));
}
class RasterBitmap_GrTextureMaker : public GrTextureMaker {
public:
Bitmap_GrTextureParamsAdjuster(const SkBitmap& bitmap)
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(),
@ -287,10 +301,7 @@ public:
protected:
GrTexture* refOriginalTexture(GrContext* ctx) override {
GrTexture* tex = fBitmap.getTexture();
if (tex) {
return SkRef(tex);
}
GrTexture* tex;
if (fOriginalKey.isValid()) {
tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(fOriginalKey);
@ -302,7 +313,7 @@ protected:
tex = GrUploadBitmapToTexture(ctx, fBitmap);
if (tex && fOriginalKey.isValid()) {
tex->resourcePriv().setUniqueKey(fOriginalKey);
InstallInvalidator(fOriginalKey, fBitmap.pixelRef());
install_bmp_key_invalidator(fOriginalKey, fBitmap.pixelRef());
}
return tex;
}
@ -314,34 +325,51 @@ protected:
}
void didCacheCopy(const GrUniqueKey& copyKey) override {
InstallInvalidator(copyKey, fBitmap.pixelRef());
install_bmp_key_invalidator(copyKey, fBitmap.pixelRef());
}
private:
static void InstallInvalidator(const GrUniqueKey& key, SkPixelRef* pixelRef) {
class Invalidator : public SkPixelRef::GenIDChangeListener {
public:
explicit Invalidator(const GrUniqueKey& key) : fMsg(key) {}
private:
GrUniqueKeyInvalidatedMessage fMsg;
void onChange() override {
SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
}
};
Invalidator* listener = new Invalidator(key);
pixelRef->addGenIDChangeListener(listener);
}
const SkBitmap fBitmap;
GrUniqueKey fOriginalKey;
typedef GrTextureParamsAdjuster INHERITED;
typedef GrTextureMaker INHERITED;
};
class TextureBitmap_GrTextureAdjuster : public GrTextureAdjuster {
public:
explicit TextureBitmap_GrTextureAdjuster(const SkBitmap* bmp)
: INHERITED(bmp->getTexture(), SkIRect::MakeWH(bmp->width(), bmp->height()))
, fBmp(bmp) {}
private:
void makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) override {
if (fBmp->isVolatile()) {
return;
}
// The texture subset must represent the whole bitmap. Texture-backed bitmaps don't support
// extractSubset(). Therefore, either the bitmap and the teture are the same size or the
// subset's dimensions are the bitmap's dimensions.
GrUniqueKey baseKey;
GrMakeKeyFromImageID(&baseKey, fBmp->getGenerationID(),
SkIRect::MakeWH(fBmp->width(), fBmp->height()));
MakeCopyKeyFromOrigKey(baseKey, params, copyKey);
}
void didCacheCopy(const GrUniqueKey& copyKey) override {
install_bmp_key_invalidator(copyKey, fBmp->pixelRef());
}
const SkBitmap* fBmp;
typedef GrTextureAdjuster INHERITED;
};
GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap,
const GrTextureParams& params) {
return Bitmap_GrTextureParamsAdjuster(bitmap).refTextureForParams(ctx, params);
if (bitmap.getTexture()) {
return TextureBitmap_GrTextureAdjuster(&bitmap).refTextureSafeForParams(params, nullptr);
}
return RasterBitmap_GrTextureMaker(bitmap).refTextureForParams(ctx, params);
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -14,7 +14,7 @@
#include "effects/GrYUVtoRGBEffect.h"
#include "SkCanvas.h"
#include "SkGpuDevice.h"
#include "SkGr.h"
#include "SkGrPriv.h"
#include "SkPixelRef.h"
SkImage_Gpu::SkImage_Gpu(int w, int h, uint32_t uniqueID, SkAlphaType at, GrTexture* tex,
@ -67,47 +67,31 @@ bool SkImage_Gpu::getROPixels(SkBitmap* dst) const {
return true;
}
static void make_raw_texture_stretched_key(uint32_t imageID,
const GrTextureParamsAdjuster::CopyParams& params,
GrUniqueKey* stretchedKey) {
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey::Builder builder(stretchedKey, kDomain, 4);
builder[0] = imageID;
builder[1] = params.fFilter;
builder[2] = params.fWidth;
builder[3] = params.fHeight;
}
class Texture_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
class GpuImage_GrTextureAdjuster : public GrTextureAdjuster {
public:
Texture_GrTextureParamsAdjuster(const SkImage* image, GrTexture* unstretched)
: INHERITED(image->width(), image->height())
GpuImage_GrTextureAdjuster(const SkImage_Gpu* image)
: INHERITED(image->peekTexture())
, fImage(image)
, fOriginal(unstretched)
{}
protected:
GrTexture* refOriginalTexture(GrContext* ctx) override {
return SkRef(fOriginal);
void makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) override {
GrUniqueKey baseKey;
GrMakeKeyFromImageID(&baseKey, fImage->uniqueID(),
SkIRect::MakeWH(fImage->width(), fImage->height()));
MakeCopyKeyFromOrigKey(baseKey, params, copyKey);
}
void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) override {
make_raw_texture_stretched_key(fImage->uniqueID(), copyParams, copyKey);
}
void didCacheCopy(const GrUniqueKey& copyKey) override {
as_IB(fImage)->notifyAddedToCache();
}
void didCacheCopy(const GrUniqueKey& copyKey) override { as_IB(fImage)->notifyAddedToCache(); }
private:
const SkImage* fImage;
GrTexture* fOriginal;
typedef GrTextureParamsAdjuster INHERITED;
typedef GrTextureAdjuster INHERITED;
};
GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrTextureParams& params) const {
return Texture_GrTextureParamsAdjuster(this, fTexture).refTextureForParams(ctx, params);
return GpuImage_GrTextureAdjuster(this).refTextureSafeForParams(params, nullptr);
}
bool SkImage_Gpu::isOpaque() const {