Rewrite GrTextureMaker to disentangle bitmap case from base class and give GPU object a say in what copying needs to be done.

Review URL: https://codereview.chromium.org/1409163002
This commit is contained in:
bsalomon 2015-10-16 13:35:10 -07:00 committed by Commit bot
parent 466c2c48b9
commit fcffaf22d6
14 changed files with 483 additions and 509 deletions

View File

@ -178,6 +178,8 @@
'<(skia_src_path)/gpu/GrTextContext.cpp',
'<(skia_src_path)/gpu/GrTextContext.h',
'<(skia_src_path)/gpu/GrTexture.cpp',
'<(skia_src_path)/gpu/GrTextureParamsAdjuster.h',
'<(skia_src_path)/gpu/GrTextureParamsAdjuster.cpp',
'<(skia_src_path)/gpu/GrTextureProvider.cpp',
'<(skia_src_path)/gpu/GrTexturePriv.h',
'<(skia_src_path)/gpu/GrTextureAccess.cpp',

View File

@ -138,8 +138,8 @@ private:
friend class TestResource; // For unit test to access kMetaDataCnt.
// bmp textures require 4 uint32_t values.
SkAutoSTMalloc<kMetaDataCnt + 4, uint32_t> fKey;
// bmp textures require 5 uint32_t values.
SkAutoSTMalloc<kMetaDataCnt + 5, uint32_t> fKey;
};
/**

View File

@ -65,9 +65,11 @@ static inline GrColor SkPMColorToGrColor(SkPMColor c) {
}
////////////////////////////////////////////////////////////////////////////////
/** Returns a texture representing the bitmap that is compatible with the GrTextureParams. The
texture is inserted into the cache (unless the bitmap is marked volatile) and can be
retrieved again via this function. */
GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams&);
// TODO: Move SkImageInfo2GrPixelConfig to SkGrPriv.h (requires cleanup to SkWindow its subclasses).
GrPixelConfig SkImageInfo2GrPixelConfig(SkColorType, SkAlphaType, SkColorProfileType);

View File

@ -204,7 +204,9 @@ public:
};
static GrTexture* set_key_and_return(GrTexture* tex, const GrUniqueKey& key) {
tex->resourcePriv().setUniqueKey(key);
if (key.isValid()) {
tex->resourcePriv().setUniqueKey(key);
}
return tex;
}
@ -217,24 +219,16 @@ static GrTexture* set_key_and_return(GrTexture* tex, const GrUniqueKey& key) {
* 4. Ask the generator to return YUV planes, which the GPU can convert
* 5. Ask the generator to return RGB(A) data, which the GPU can convert
*/
GrTexture* SkImageCacherator::lockUnstretchedTexture(GrContext* ctx, const SkImage* client) {
// textures (at least the texture-key) only support 16bit dimensions, so abort early
// if we're too big.
if (fInfo.width() > 0xFFFF || fInfo.height() > 0xFFFF) {
return nullptr;
}
GrUniqueKey key;
const GrTextureParams& noStretchParams = GrTextureParams::ClampNoFilter();
GrMakeKeyFromImageID(&key, fUniqueID, SkIRect::MakeWH(fInfo.width(), fInfo.height()),
*ctx->caps(), noStretchParams);
GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key,
const SkImage* client) {
// 1. Check the cache for a pre-existing one
if (GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key)) {
return tex;
if (key.isValid()) {
if (GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key)) {
return tex;
}
}
// 2. Ask the genreator to natively create one
// 2. Ask the generator to natively create one
{
ScopedGenerator generator(this);
SkIRect subset = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), fInfo.width(), fInfo.height());
@ -267,54 +261,62 @@ GrTexture* SkImageCacherator::lockUnstretchedTexture(GrContext* ctx, const SkIma
// 5. Ask the generator to return RGB(A) data, which the GPU can convert
SkBitmap bitmap;
if (this->tryLockAsBitmap(&bitmap, client)) {
return GrRefCachedBitmapTexture(ctx, bitmap, noStretchParams);
GrTexture* tex = GrUploadBitmapToTexture(ctx, bitmap);
if (tex) {
return set_key_and_return(tex, key);
}
}
return nullptr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#include "GrTextureMaker.h"
#include "GrTextureParamsAdjuster.h"
class Cacherator_GrTextureMaker : public GrTextureMaker {
class Cacherator_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
public:
Cacherator_GrTextureMaker(SkImageCacherator* cacher, const SkImage* client,
const GrUniqueKey& unstretchedKey)
Cacherator_GrTextureParamsAdjuster(SkImageCacherator* cacher, const SkImage* client)
: INHERITED(cacher->info().width(), cacher->info().height())
, fCacher(cacher)
, fClient(client)
, fUnstretchedKey(unstretchedKey)
{}
{
if (client) {
GrMakeKeyFromImageID(&fOriginalKey, client->uniqueID(),
SkIRect::MakeWH(this->width(), this->height()));
}
}
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* onGenerateStretchedTexture(GrContext*, const SkGrStretch&) override;
// GrTexture* generateTextureForParams(GrContext*, const SkGrStretch&) override;
GrTexture* onRefUnstretchedTexture(GrContext* ctx) override {
return fCacher->lockUnstretchedTexture(ctx, fClient);
GrTexture* refOriginalTexture(GrContext* ctx) override {
return fCacher->lockTexture(ctx, fOriginalKey, fClient);
}
bool onMakeStretchedKey(const SkGrStretch& stretch, GrUniqueKey* stretchedKey) override {
return GrMakeStretchedKey(fUnstretchedKey, stretch, stretchedKey);
void makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey) override {
if (fOriginalKey.isValid()) {
MakeCopyKeyFromOrigKey(fOriginalKey, stretch, paramsCopyKey);
}
}
void onNotifyStretchCached(const GrUniqueKey& stretchedKey) override {
void didCacheCopy(const GrUniqueKey& copyKey) override {
if (fClient) {
as_IB(fClient)->notifyAddedToCache();
}
}
bool onGetROBitmap(SkBitmap* bitmap) override {
bool getROBitmap(SkBitmap* bitmap) override {
return fCacher->lockAsBitmap(bitmap, fClient);
}
private:
SkImageCacherator* fCacher;
const SkImage* fClient;
const GrUniqueKey fUnstretchedKey;
GrUniqueKey fOriginalKey;
typedef GrTextureMaker INHERITED;
typedef GrTextureParamsAdjuster INHERITED;
};
GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParams& params,
@ -323,12 +325,7 @@ GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParam
return nullptr;
}
GrUniqueKey key;
GrMakeKeyFromImageID(&key, this->uniqueID(),
SkIRect::MakeWH(this->info().width(), this->info().height()),
*ctx->caps(), GrTextureParams::ClampNoFilter());
return Cacherator_GrTextureMaker(this, client, key).refCachedTexture(ctx, params);
return Cacherator_GrTextureParamsAdjuster(this, client).refTextureForParams(ctx, params);
}
#else

View File

@ -13,7 +13,8 @@
#include "SkTemplates.h"
class GrContext;
class GrTextureParams;
class GrTextureParams;
class GrUniqueKey;
class SkBitmap;
class SkImage;
@ -60,7 +61,9 @@ private:
bool generateBitmap(SkBitmap*);
bool tryLockAsBitmap(SkBitmap*, const SkImage*);
#if SK_SUPPORT_GPU
GrTexture* lockUnstretchedTexture(GrContext*, const SkImage* client);
// Returns the texture. If the cacherator is generating the texture and wants to cache it,
// it should use the passed in key (if the key is valid).
GrTexture* lockTexture(GrContext*, const GrUniqueKey& key, const SkImage* client);
#endif
class ScopedGenerator {
@ -83,7 +86,7 @@ private:
const SkIPoint fOrigin;
const uint32_t fUniqueID;
friend class Cacherator_GrTextureMaker;
friend class Cacherator_GrTextureParamsAdjuster;
};
#endif

View File

@ -55,6 +55,37 @@ void GrGpu::contextAbandoned() {}
////////////////////////////////////////////////////////////////////////////////
bool GrGpu::makeCopyForTextureParams(int width, int height, const GrTextureParams& textureParams,
GrTextureParamsAdjuster::CopyParams* copyParams) const {
bool doCopy = false;
const GrCaps& caps = *this->caps();
if (textureParams.isTiled() && !caps.npotTextureTileSupport() &&
(!SkIsPow2(width) || !SkIsPow2(height))) {
doCopy = true;
copyParams->fWidth = GrNextPow2(SkTMax(width, caps.minTextureSize()));
copyParams->fHeight = GrNextPow2(SkTMax(height, caps.minTextureSize()));
} else if (width < caps.minTextureSize() || height < caps.minTextureSize()) {
// The small texture issues appear to be with tiling. Hence it seems ok to scale
// them up using the GPU. If issues persist we may need to CPU-stretch.
doCopy = true;
copyParams->fWidth = SkTMax(width, caps.minTextureSize());
copyParams->fHeight = SkTMax(height, caps.minTextureSize());
}
if (doCopy) {
switch (textureParams.filterMode()) {
case GrTextureParams::kNone_FilterMode:
copyParams->fFilter = GrTextureParams::kNone_FilterMode;
break;
case GrTextureParams::kBilerp_FilterMode:
case GrTextureParams::kMipMap_FilterMode:
// We are only ever scaling up so no reason to ever indicate kMipMap.
copyParams->fFilter = GrTextureParams::kBilerp_FilterMode;
break;
}
}
return doCopy;
}
static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin, bool renderTarget) {
// By default, GrRenderTargets are GL's normal orientation so that they
// can be drawn to by the outside world without the client having

View File

@ -11,6 +11,7 @@
#include "GrPipelineBuilder.h"
#include "GrProgramDesc.h"
#include "GrStencil.h"
#include "GrTextureParamsAdjuster.h"
#include "GrXferProcessor.h"
#include "SkPath.h"
@ -378,6 +379,13 @@ public:
// clears target's entire stencil buffer to 0
virtual void clearStencil(GrRenderTarget* target) = 0;
// Determines whether a copy of a texture must be made in order to be compatible with
// 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;
// This is only to be used in GL-specific tests.
virtual const GrGLContext* glContextForTesting() const { return nullptr; }

View File

@ -1,76 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrTextureMaker_DEFINED
#define GrTextureMaker_DEFINED
#include "SkGrPriv.h"
class GrContext;
class GrTexture;
class GrTextureParams;
class GrUniqueKey;
class SkBitmap;
class GrTextureMaker {
public:
GrTextureMaker(int width, int height) : fWidth(width), fHeight(height) {}
virtual ~GrTextureMaker() {}
int width() const { return fWidth; }
int height() const { return fHeight; }
GrTexture* refCachedTexture(GrContext*, const GrTextureParams&);
protected:
/**
* Return the maker's "original" unstretched texture. It is the responsibility of the maker
* to make this efficient ... if the texture is being generated, the maker must handle
* caching it.
*/
virtual GrTexture* onRefUnstretchedTexture(GrContext*) = 0;
/**
* If we need to stretch the maker's original texture, the maker is asked to return a key
* that identifies its origianl + the stretch parameter. If the maker does not want to cache
* the stretched version (e.g. the maker is volatile), this should ignore the key parameter
* and return false.
*/
virtual bool onMakeStretchedKey(const SkGrStretch&, GrUniqueKey* stretchedKey) = 0;
/**
* Return a new (uncached) texture that is the stretch of the maker's original.
*
* The base-class handles general logic for this, and only needs access to the following
* methods:
* - onRefUnstretchedTexture()
* - onGetROBitmap()
*
* Subclass may override this if they can handle stretching more efficiently.
*/
virtual GrTexture* onGenerateStretchedTexture(GrContext*, const SkGrStretch&);
/**
* If a stretched version of the texture is generated, it may be cached (assuming that
* onMakeStretchedKey() returns true). In that case, the maker is notified in case it
* wants to note that for when the maker is destroyed.
*/
virtual void onNotifyStretchCached(const GrUniqueKey& stretchedKey) = 0;
/**
* Some GPUs are unreliable w/ very small texture sizes. If we run into that case, this
* method will be called (in service of onGenerateStretchedTexture) to return a raster version
* of the original texture.
*/
virtual bool onGetROBitmap(SkBitmap*) = 0;
private:
const int fWidth;
const int fHeight;
};
#endif

View File

@ -0,0 +1,152 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrTextureParamsAdjuster.h"
#include "GrCaps.h"
#include "GrContext.h"
#include "GrDrawContext.h"
#include "GrGpu.h"
#include "GrTexture.h"
#include "GrTextureParams.h"
#include "GrTextureProvider.h"
#include "SkCanvas.h"
#include "SkGr.h"
#include "SkGrPriv.h"
typedef GrTextureParamsAdjuster::CopyParams CopyParams;
static GrTexture* copy_on_gpu(GrTexture* inputTexture, const CopyParams& copyParams) {
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.fHeight = copyParams.fHeight;
rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig);
// If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise,
// fail.
if (!caps->isConfigRenderable(rtDesc.fConfig, false)) {
if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) {
if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
rtDesc.fConfig = kAlpha_8_GrPixelConfig;
} else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
rtDesc.fConfig = kSkia8888_GrPixelConfig;
} else {
return nullptr;
}
} else if (kRGB_GrColorComponentFlags ==
(kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) {
if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
rtDesc.fConfig = kSkia8888_GrPixelConfig;
} else {
return nullptr;
}
} else {
return nullptr;
}
}
SkAutoTUnref<GrTexture> copy(context->textureProvider()->createTexture(rtDesc, true));
if (!copy) {
return nullptr;
}
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);
SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
SkRect 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);
return copy.detach();
}
static SkBitmap copy_on_cpu(const SkBitmap& bmp, const CopyParams& copyParams) {
SkBitmap stretched;
stretched.allocN32Pixels(copyParams.fWidth, copyParams.fHeight);
SkCanvas canvas(stretched);
SkPaint paint;
switch (copyParams.fFilter) {
case GrTextureParams::kNone_FilterMode:
paint.setFilterQuality(kNone_SkFilterQuality);
break;
case GrTextureParams::kBilerp_FilterMode:
paint.setFilterQuality(kLow_SkFilterQuality);
break;
case GrTextureParams::kMipMap_FilterMode:
paint.setFilterQuality(kMedium_SkFilterQuality);
break;
}
SkRect dstRect = SkRect::MakeWH(SkIntToScalar(copyParams.fWidth),
SkIntToScalar(copyParams.fHeight));
canvas.drawBitmapRect(bmp, dstRect, &paint);
return stretched;
}
GrTexture* GrTextureParamsAdjuster::refTextureForParams(GrContext* ctx,
const GrTextureParams& params) {
CopyParams copyParams;
if (!ctx->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params,
&copyParams)) {
return this->refOriginalTexture(ctx);
}
GrUniqueKey copyKey;
this->makeCopyKey(copyParams, &copyKey);
if (copyKey.isValid()) {
GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(copyKey);
if (result) {
return result;
}
}
GrTexture* result = this->generateTextureForParams(ctx, copyParams);
if (!result) {
return nullptr;
}
if (copyKey.isValid()) {
ctx->textureProvider()->assignUniqueKeyToTexture(copyKey, result);
this->didCacheCopy(copyKey);
}
return result;
}
GrTexture* GrTextureParamsAdjuster::generateTextureForParams(GrContext* ctx,
const CopyParams& copyParams) {
if (this->width() < ctx->caps()->minTextureSize() ||
this->height() < ctx->caps()->minTextureSize())
{
// we can't trust our ability to use HW to perform the stretch, so we request
// a raster instead, and perform the stretch on the CPU.
SkBitmap bitmap;
if (!this->getROBitmap(&bitmap)) {
return nullptr;
}
SkBitmap stretchedBmp = copy_on_cpu(bitmap, copyParams);
return GrUploadBitmapToTexture(ctx, bitmap);
} else {
SkAutoTUnref<GrTexture> original(this->refOriginalTexture(ctx));
if (!original) {
return nullptr;
}
return copy_on_gpu(original, copyParams);
}
}

View File

@ -0,0 +1,107 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrTextureMaker_DEFINED
#define GrTextureMaker_DEFINED
#include "GrTextureParams.h"
#include "GrResourceKey.h"
class GrContext;
class GrTexture;
class GrTextureParams;
class GrUniqueKey;
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.
*/
class GrTextureParamsAdjuster {
public:
struct CopyParams {
GrTextureParams::FilterMode fFilter;
int fWidth;
int fHeight;
};
GrTextureParamsAdjuster(int width, int height) : fWidth(width), fHeight(height) {}
virtual ~GrTextureParamsAdjuster() {}
int width() const { return fWidth; }
int height() const { return fHeight; }
/** Returns a texture that is safe for use with the params */
GrTexture* refTextureForParams(GrContext*, const GrTextureParams&);
protected:
/**
* 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;
/**
* If we need to copy the maker's original texture, the maker 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
* initializing the copyKey.
*/
virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey) = 0;
/**
* Return a new (uncached) texture that is the stretch of the maker's original.
*
* The base-class handles general logic for this, and only needs access to the following
* methods:
* - onRefOriginalTexture()
* - onGetROBitmap()
*
* Subclass may override this if they can handle creating the texture more directly than
* by copying.
*/
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;
/**
* Some GPUs are unreliable w/ very small texture sizes. If we run into that case, this
* method will be called (in service of onGenerateParamsTexture) to return a raster version
* of the original texture.
*/
virtual bool getROBitmap(SkBitmap*) = 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;
};
#endif

View File

@ -5,13 +5,13 @@
* found in the LICENSE file.
*/
#include "GrTextureMaker.h"
#include "SkGr.h"
#include "GrCaps.h"
#include "GrContext.h"
#include "GrDrawContext.h"
#include "GrTextureParamsAdjuster.h"
#include "GrGpuResourcePriv.h"
#include "GrXferProcessor.h"
#include "GrYUVProvider.h"
@ -48,64 +48,17 @@ GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info) {
return desc;
}
static void get_stretch(const GrCaps& caps, int width, int height,
const GrTextureParams& params, SkGrStretch* stretch) {
stretch->fType = SkGrStretch::kNone_Type;
bool doStretch = false;
if (params.isTiled() && !caps.npotTextureTileSupport() &&
(!SkIsPow2(width) || !SkIsPow2(height))) {
doStretch = true;
stretch->fWidth = GrNextPow2(SkTMax(width, caps.minTextureSize()));
stretch->fHeight = GrNextPow2(SkTMax(height, caps.minTextureSize()));
} else if (width < caps.minTextureSize() || height < caps.minTextureSize()) {
// The small texture issues appear to be with tiling. Hence it seems ok to scale them
// up using the GPU. If issues persist we may need to CPU-stretch.
doStretch = true;
stretch->fWidth = SkTMax(width, caps.minTextureSize());
stretch->fHeight = SkTMax(height, caps.minTextureSize());
}
if (doStretch) {
switch (params.filterMode()) {
case GrTextureParams::kNone_FilterMode:
stretch->fType = SkGrStretch::kNearest_Type;
break;
case GrTextureParams::kBilerp_FilterMode:
case GrTextureParams::kMipMap_FilterMode:
stretch->fType = SkGrStretch::kBilerp_Type;
break;
}
} else {
stretch->fWidth = -1;
stretch->fHeight = -1;
stretch->fType = SkGrStretch::kNone_Type;
}
}
static void make_unstretched_key(GrUniqueKey* key, uint32_t imageID, const SkIRect& subset) {
SkASSERT(SkIsU16(subset.width()));
SkASSERT(SkIsU16(subset.height()));
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey::Builder builder(key, kDomain, 4);
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds) {
SkASSERT(key);
SkASSERT(imageID);
SkASSERT(!imageBounds.isEmpty());
static const GrUniqueKey::Domain kImageIDDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey::Builder builder(key, kImageIDDomain, 5);
builder[0] = imageID;
builder[1] = subset.x();
builder[2] = subset.y();
builder[3] = subset.width() | (subset.height() << 16);
}
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& subset,
const GrCaps& caps, const GrTextureParams& params) {
SkGrStretch stretch;
get_stretch(caps, subset.width(), subset.height(), params, &stretch);
if (SkGrStretch::kNone_Type != stretch.fType) {
GrUniqueKey tmpKey;
make_unstretched_key(&tmpKey, imageID, subset);
if (!GrMakeStretchedKey(tmpKey, stretch, key)) {
*key = tmpKey;
}
} else {
make_unstretched_key(key, imageID, subset);
}
builder[1] = imageBounds.fLeft;
builder[2] = imageBounds.fTop;
builder[3] = imageBounds.fRight;
builder[4] = imageBounds.fBottom;
}
GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data,
@ -150,16 +103,19 @@ GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data,
return kUnknown_GrPixelConfig;
}
/* Fill out buffer with the compressed format Ganesh expects from a colortable
based bitmap. [palette (colortable) + indices].
//////////////////////////////////////////////////////////////////////////////
At the moment Ganesh only supports 8bit version. If Ganesh allowed we others
we could detect that the colortable.count is <= 16, and then repack the
indices as nibbles to save RAM, but it would take more time (i.e. a lot
slower than memcpy), so skipping that for now.
Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big
as the colortable.count says it is.
/**
* Fill out buffer with the compressed format Ganesh expects from a colortable
* based bitmap. [palette (colortable) + indices].
*
* At the moment Ganesh only supports 8bit version. If Ganesh allowed we others
* we could detect that the colortable.count is <= 16, and then repack the
* indices as nibbles to save RAM, but it would take more time (i.e. a lot
* slower than memcpy), so skipping that for now.
*
* Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big
* as the colortable.count says it is.
*/
static void build_index8_data(void* buffer, const SkBitmap& bitmap) {
SkASSERT(kIndex_8_SkColorType == bitmap.colorType());
@ -207,130 +163,7 @@ static void build_index8_data(void* buffer, const SkBitmap& bitmap) {
}
}
////////////////////////////////////////////////////////////////////////////////
bool GrMakeStretchedKey(const GrUniqueKey& origKey, const SkGrStretch& stretch,
GrUniqueKey* stretchedKey) {
if (origKey.isValid() && SkGrStretch::kNone_Type != stretch.fType) {
uint32_t width = SkToU16(stretch.fWidth);
uint32_t height = SkToU16(stretch.fHeight);
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey::Builder builder(stretchedKey, origKey, kDomain, 2);
builder[0] = stretch.fType;
builder[1] = width | (height << 16);
builder.finish();
return true;
}
SkASSERT(!stretchedKey->isValid());
return false;
}
namespace {
// When the SkPixelRef genID changes, invalidate a corresponding GrResource described by key.
class BitmapInvalidator : public SkPixelRef::GenIDChangeListener {
public:
explicit BitmapInvalidator(const GrUniqueKey& key) : fMsg(key) {}
private:
GrUniqueKeyInvalidatedMessage fMsg;
void onChange() override {
SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
}
};
} // namespace
GrTexture* GrCreateTextureForPixels(GrContext* ctx,
const GrUniqueKey& optionalKey,
GrSurfaceDesc desc,
SkPixelRef* pixelRefForInvalidationNotification,
const void* pixels,
size_t rowBytes) {
GrTexture* result = ctx->textureProvider()->createTexture(desc, true, pixels, rowBytes);
if (result && optionalKey.isValid()) {
if (pixelRefForInvalidationNotification) {
BitmapInvalidator* listener = new BitmapInvalidator(optionalKey);
pixelRefForInvalidationNotification->addGenIDChangeListener(listener);
}
ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, result);
}
return result;
}
// creates a new texture that is the input texture scaled up. If optionalKey is valid it will be
// set on the new texture. stretch controls whether the scaling is done using nearest or bilerp
// filtering and the size to stretch the texture to.
GrTexture* stretch_texture(GrTexture* inputTexture, const SkGrStretch& stretch,
SkPixelRef* pixelRef,
const GrUniqueKey& optionalKey) {
SkASSERT(SkGrStretch::kNone_Type != stretch.fType);
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 = stretch.fWidth;
rtDesc.fHeight = stretch.fHeight;
rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig);
// If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise,
// fail.
if (!caps->isConfigRenderable(rtDesc.fConfig, false)) {
if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) {
if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
rtDesc.fConfig = kAlpha_8_GrPixelConfig;
} else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
rtDesc.fConfig = kSkia8888_GrPixelConfig;
} else {
return nullptr;
}
} else if (kRGB_GrColorComponentFlags ==
(kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) {
if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
rtDesc.fConfig = kSkia8888_GrPixelConfig;
} else {
return nullptr;
}
} else {
return nullptr;
}
}
SkAutoTUnref<GrTexture> stretched(GrCreateTextureForPixels(context, optionalKey, rtDesc,
pixelRef, nullptr,0));
if (!stretched) {
return nullptr;
}
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,
SkGrStretch::kBilerp_Type == stretch.fType ?
GrTextureParams::kBilerp_FilterMode :
GrTextureParams::kNone_FilterMode);
paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);
SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
SkRect localRect = SkRect::MakeWH(1.f, 1.f);
SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(stretched->asRenderTarget()));
if (!drawContext) {
return nullptr;
}
drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, localRect);
return stretched.detach();
}
/*
/**
* Once we have made SkImages handle all lazy/deferred/generated content, the YUV apis will
* be gone from SkPixelRef, and we can remove this subclass entirely.
*/
@ -350,33 +183,22 @@ public:
}
};
static GrTexture* load_yuv_texture(GrContext* ctx, const GrUniqueKey& optionalKey,
const SkBitmap& bm, const GrSurfaceDesc& desc) {
static GrTexture* create_texture_from_yuv(GrContext* ctx, const SkBitmap& bm,
const GrSurfaceDesc& desc) {
// Subsets are not supported, the whole pixelRef is loaded when using YUV decoding
SkPixelRef* pixelRef = bm.pixelRef();
if ((nullptr == pixelRef) ||
(pixelRef->info().width() != bm.info().width()) ||
(pixelRef->info().width() != bm.info().width()) ||
(pixelRef->info().height() != bm.info().height())) {
return nullptr;
}
const bool useCache = optionalKey.isValid();
PixelRef_GrYUVProvider provider(pixelRef);
GrTexture* texture = provider.refAsTexture(ctx, desc, useCache);
if (!texture) {
return nullptr;
}
if (useCache) {
BitmapInvalidator* listener = new BitmapInvalidator(optionalKey);
pixelRef->addGenIDChangeListener(listener);
ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, texture);
}
return texture;
return provider.refAsTexture(ctx, desc, !bm.isVolatile());
}
static GrTexture* load_etc1_texture(GrContext* ctx, const GrUniqueKey& optionalKey,
const SkBitmap &bm, GrSurfaceDesc desc) {
static GrTexture* load_etc1_texture(GrContext* ctx, const SkBitmap &bm, GrSurfaceDesc desc) {
SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
if (!data) {
return nullptr;
@ -389,19 +211,19 @@ static GrTexture* load_etc1_texture(GrContext* ctx, const GrUniqueKey& optionalK
return nullptr;
}
return GrCreateTextureForPixels(ctx, optionalKey, desc, bm.pixelRef(), startOfTexData, 0);
return ctx->textureProvider()->createTexture(desc, true, startOfTexData, 0);
}
static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
const SkBitmap& origBitmap,
const GrUniqueKey& optionalKey) {
if (origBitmap.width() < ctx->caps()->minTextureSize() ||
origBitmap.height() < ctx->caps()->minTextureSize()) {
GrTexture* GrUploadBitmapToTexture(GrContext* ctx, const SkBitmap& bmp) {
SkASSERT(!bmp.getTexture());
if (bmp.width() < ctx->caps()->minTextureSize() ||
bmp.height() < ctx->caps()->minTextureSize()) {
return nullptr;
}
SkBitmap tmpBitmap;
const SkBitmap* bitmap = &origBitmap;
SkBitmap tmpBitmap;
const SkBitmap* bitmap = &bmp;
GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap->info());
const GrCaps* caps = ctx->caps();
@ -411,14 +233,14 @@ static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
size_t imageSize = GrCompressedFormatDataSize(kIndex_8_GrPixelConfig,
bitmap->width(), bitmap->height());
SkAutoMalloc storage(imageSize);
build_index8_data(storage.get(), origBitmap);
build_index8_data(storage.get(), bmp);
// our compressed data will be trimmed, so pass width() for its
// "rowBytes", since they are the same now.
return GrCreateTextureForPixels(ctx, optionalKey, desc, origBitmap.pixelRef(),
storage.get(), bitmap->width());
return ctx->textureProvider()->createTexture(desc, true, storage.get(),
bitmap->width());
} else {
origBitmap.copyTo(&tmpBitmap, kN32_SkColorType);
bmp.copyTo(&tmpBitmap, kN32_SkColorType);
// now bitmap points to our temp, which has been promoted to 32bits
bitmap = &tmpBitmap;
desc.fConfig = SkImageInfo2GrPixelConfig(bitmap->info());
@ -428,13 +250,16 @@ static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
// compressed data on 'refEncodedData' and upload it. Probably not good, since if
// the bitmap has available pixels, then they might not be what the decompressed
// data is.
GrTexture *texture = load_etc1_texture(ctx, optionalKey, *bitmap, desc);
// Really?? We aren't doing this with YUV.
GrTexture *texture = load_etc1_texture(ctx, *bitmap, desc);
if (texture) {
return texture;
}
}
GrTexture *texture = load_yuv_texture(ctx, optionalKey, *bitmap, desc);
GrTexture *texture = create_texture_from_yuv(ctx, *bitmap, desc);
if (texture) {
return texture;
}
@ -444,83 +269,90 @@ static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
return nullptr;
}
return GrCreateTextureForPixels(ctx, optionalKey, desc, origBitmap.pixelRef(),
bitmap->getPixels(), bitmap->rowBytes());
return ctx->textureProvider()->createTexture(desc, true, bitmap->getPixels(),
bitmap->rowBytes());
}
static SkBitmap stretch_on_cpu(const SkBitmap& bmp, const SkGrStretch& stretch) {
SkBitmap stretched;
stretched.allocN32Pixels(stretch.fWidth, stretch.fHeight);
SkCanvas canvas(stretched);
SkPaint paint;
switch (stretch.fType) {
case SkGrStretch::kNearest_Type:
paint.setFilterQuality(kNone_SkFilterQuality);
break;
case SkGrStretch::kBilerp_Type:
paint.setFilterQuality(kLow_SkFilterQuality);
break;
case SkGrStretch::kNone_Type:
SkDEBUGFAIL("Shouldn't get here.");
break;
}
SkRect dstRect = SkRect::MakeWH(SkIntToScalar(stretch.fWidth), SkIntToScalar(stretch.fHeight));
canvas.drawBitmapRect(bmp, dstRect, &paint);
return stretched;
}
class Bitmap_GrTextureMaker : public GrTextureMaker {
////////////////////////////////////////////////////////////////////////////////
class Bitmap_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
public:
Bitmap_GrTextureMaker(const SkBitmap& bitmap)
Bitmap_GrTextureParamsAdjuster(const SkBitmap& bitmap)
: INHERITED(bitmap.width(), bitmap.height())
, fBitmap(bitmap)
{}
{
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* onRefUnstretchedTexture(GrContext* ctx) override {
GrTexture* refOriginalTexture(GrContext* ctx) {
GrTexture* tex = fBitmap.getTexture();
if (tex) {
return SkRef(tex);
}
GrUniqueKey unstretchedKey;
make_unstretched_key(&unstretchedKey, fBitmap.getGenerationID(), fBitmap.getSubset());
GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(unstretchedKey);
if (result) {
return result;
}
return create_unstretched_bitmap_texture(ctx, fBitmap, unstretchedKey);
}
bool onMakeStretchedKey(const SkGrStretch& stretch, GrUniqueKey* stretchedKey) override {
if (fBitmap.isVolatile()) {
return false;
if (fOriginalKey.isValid()) {
tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(fOriginalKey);
if (tex) {
return tex;
}
}
GrUniqueKey unstretchedKey;
make_unstretched_key(&unstretchedKey, fBitmap.getGenerationID(), fBitmap.getSubset());
return GrMakeStretchedKey(unstretchedKey, stretch, stretchedKey);
tex = GrUploadBitmapToTexture(ctx, fBitmap);
if (tex) {
tex->resourcePriv().setUniqueKey(fOriginalKey);
InstallInvalidator(fOriginalKey, fBitmap.pixelRef());
}
return tex;
}
void onNotifyStretchCached(const GrUniqueKey& stretchedKey) override {
fBitmap.pixelRef()->addGenIDChangeListener(new BitmapInvalidator(stretchedKey));
void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) override {
if (fOriginalKey.isValid()) {
MakeCopyKeyFromOrigKey(fOriginalKey, copyParams, copyKey);
}
}
bool onGetROBitmap(SkBitmap* bitmap) override {
void didCacheCopy(const GrUniqueKey& copyKey) override {
InstallInvalidator(copyKey, fBitmap.pixelRef());
}
bool getROBitmap(SkBitmap* bitmap) override {
SkASSERT(!fBitmap.getTexture());
*bitmap = fBitmap;
return true;
}
private:
const SkBitmap fBitmap;
static void InstallInvalidator(const GrUniqueKey& key, SkPixelRef* pixelRef) {
class Invalidator : public SkPixelRef::GenIDChangeListener {
public:
explicit Invalidator(const GrUniqueKey& key) : fMsg(key) {}
private:
GrUniqueKeyInvalidatedMessage fMsg;
typedef GrTextureMaker INHERITED;
void onChange() override {
SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
}
};
Invalidator* listener = new Invalidator(key);
pixelRef->addGenIDChangeListener(listener);
}
const SkBitmap fBitmap;
GrUniqueKey fOriginalKey;
typedef GrTextureParamsAdjuster INHERITED;
};
GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap,
const GrTextureParams& params) {
return Bitmap_GrTextureMaker(bitmap).refCachedTexture(ctx, params);
return Bitmap_GrTextureParamsAdjuster(bitmap).refTextureForParams(ctx, params);
}
///////////////////////////////////////////////////////////////////////////////
@ -592,7 +424,6 @@ bool GrPixelConfig2ColorAndProfileType(GrPixelConfig config, SkColorType* ctOut,
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////
static inline bool blend_requires_shader(const SkXfermode::Mode mode, bool primitiveIsSrc) {
@ -842,54 +673,3 @@ GrTextureParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality pain
}
return textureFilterMode;
}
////////////////////////////////////////////////////////////////////////////////////////////////
GrTexture* GrTextureMaker::refCachedTexture(GrContext* ctx, const GrTextureParams& params) {
SkGrStretch stretch;
get_stretch(*ctx->caps(), this->width(), this->height(), params, &stretch);
if (SkGrStretch::kNone_Type == stretch.fType) {
return this->onRefUnstretchedTexture(ctx);
}
GrUniqueKey stretchedKey;
if (this->onMakeStretchedKey(stretch, &stretchedKey)) {
GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(stretchedKey);
if (result) {
return result;
}
}
GrTexture* result = this->onGenerateStretchedTexture(ctx, stretch);
if (!result) {
return nullptr;
}
if (stretchedKey.isValid()) {
ctx->textureProvider()->assignUniqueKeyToTexture(stretchedKey, result);
this->onNotifyStretchCached(stretchedKey);
}
return result;
}
GrTexture* GrTextureMaker::onGenerateStretchedTexture(GrContext* ctx, const SkGrStretch& stretch) {
if (this->width() < ctx->caps()->minTextureSize() ||
this->height() < ctx->caps()->minTextureSize())
{
// we can't trust our ability to use HW to perform the stretch, so we request
// a raster instead, and perform the stretch on the CPU.
SkBitmap bitmap;
if (!this->onGetROBitmap(&bitmap)) {
return nullptr;
}
SkBitmap stretchedBmp = stretch_on_cpu(bitmap, stretch);
return create_unstretched_bitmap_texture(ctx, stretchedBmp, GrUniqueKey());
} else {
SkAutoTUnref<GrTexture> unstretched(this->onRefUnstretchedTexture(ctx));
if (!unstretched) {
return nullptr;
}
return stretch_texture(unstretched, stretch, nullptr, GrUniqueKey());
}
}

View File

@ -26,34 +26,18 @@ class SkPaint;
class SkPixelRef;
struct SkIRect;
struct SkGrStretch {
enum Type {
kNone_Type,
kBilerp_Type,
kNearest_Type
} fType;
int fWidth;
int fHeight;
};
/**
* Our key includes the offset, width, and height so that bitmaps created by extractSubset()
* are unique.
*
* The imageID is in the shared namespace (see SkNextID::ImageID()
* The imageID is in the shared namespace (see SkNextID::ImageID())
* - SkBitmap/SkPixelRef
* - SkImage
* - SkImageGenerator
*
* Note: width/height must fit in 16bits for this impl.
*/
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds,
const GrCaps&, const GrTextureParams&);
/**
* Given an "unstretched" key, and a stretch rec, produce a stretched key.
*/
bool GrMakeStretchedKey(const GrUniqueKey& origKey, const SkGrStretch&, GrUniqueKey* stretchedKey);
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds);
/** Converts an SkPaint to a GrPaint for a given GrContext. The matrix is required in order
to convert the SkShader (if any) on the SkPaint. The primitive itself has no color. */
@ -103,21 +87,24 @@ GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo&);
bool GrPixelConfig2ColorAndProfileType(GrPixelConfig, SkColorType*, SkColorProfileType*);
/**
* If the compressed data in the SkData is supported (as a texture format, this returns
* the pixel-config that should be used, and sets outStartOfDataToUpload to the ptr into
* the data where the actual raw data starts (skipping any header bytes).
*
* If the compressed data is not supported, this returns kUnknown_GrPixelConfig, and
* ignores outStartOfDataToUpload.
*/
* If the compressed data in the SkData is supported (as a texture format, this returns
* the pixel-config that should be used, and sets outStartOfDataToUpload to the ptr into
* the data where the actual raw data starts (skipping any header bytes).
*
* If the compressed data is not supported, this returns kUnknown_GrPixelConfig, and
* ignores outStartOfDataToUpload.
*/
GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data,
int expectedW, int expectedH,
const void** outStartOfDataToUpload);
GrTexture* GrCreateTextureForPixels(GrContext*, const GrUniqueKey& optionalKey, GrSurfaceDesc,
SkPixelRef* pixelRefForInvalidationNotificationOrNull,
const void* pixels, size_t rowBytesOrZero);
/**
* Creates a new texture for the bitmap. Does not concern itself with cache keys or texture params.
* The bitmap must have CPU-accessible pixels. Attempts to take advantage of faster paths for
* compressed textures and yuv planes.
*/
GrTexture* GrUploadBitmapToTexture(GrContext*, const SkBitmap&);
//////////////////////////////////////////////////////////////////////////////

View File

@ -10,7 +10,7 @@
#include "GrCaps.h"
#include "GrContext.h"
#include "GrDrawContext.h"
#include "GrTextureMaker.h"
#include "GrTextureParamsAdjuster.h"
#include "effects/GrYUVtoRGBEffect.h"
#include "SkCanvas.h"
#include "SkGpuDevice.h"
@ -64,56 +64,51 @@ bool SkImage_Gpu::getROPixels(SkBitmap* dst) const {
return true;
}
static void make_raw_texture_stretched_key(uint32_t imageID, const SkGrStretch& stretch,
static void make_raw_texture_stretched_key(uint32_t imageID,
const GrTextureParamsAdjuster::CopyParams& params,
GrUniqueKey* stretchedKey) {
SkASSERT(SkGrStretch::kNone_Type != stretch.fType);
uint32_t width = SkToU16(stretch.fWidth);
uint32_t height = SkToU16(stretch.fHeight);
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey::Builder builder(stretchedKey, kDomain, 3);
GrUniqueKey::Builder builder(stretchedKey, kDomain, 4);
builder[0] = imageID;
builder[1] = stretch.fType;
builder[2] = width | (height << 16);
builder.finish();
builder[1] = params.fFilter;
builder[2] = params.fWidth;
builder[3] = params.fHeight;
}
class Texture_GrTextureMaker : public GrTextureMaker {
class Texture_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
public:
Texture_GrTextureMaker(const SkImage* image, GrTexture* unstretched)
Texture_GrTextureParamsAdjuster(const SkImage* image, GrTexture* unstretched)
: INHERITED(image->width(), image->height())
, fImage(image)
, fUnstretched(unstretched)
, fOriginal(unstretched)
{}
protected:
GrTexture* onRefUnstretchedTexture(GrContext* ctx) override {
return SkRef(fUnstretched);
GrTexture* refOriginalTexture(GrContext* ctx) override {
return SkRef(fOriginal);
}
bool onMakeStretchedKey(const SkGrStretch& stretch, GrUniqueKey* stretchedKey) override {
make_raw_texture_stretched_key(fImage->uniqueID(), stretch, stretchedKey);
return stretchedKey->isValid();
void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) override {
make_raw_texture_stretched_key(fImage->uniqueID(), copyParams, copyKey);
}
void onNotifyStretchCached(const GrUniqueKey& stretchedKey) override {
void didCacheCopy(const GrUniqueKey& copyKey) override {
as_IB(fImage)->notifyAddedToCache();
}
bool onGetROBitmap(SkBitmap* bitmap) override {
bool getROBitmap(SkBitmap* bitmap) override {
return as_IB(fImage)->getROPixels(bitmap);
}
private:
const SkImage* fImage;
GrTexture* fUnstretched;
GrTexture* fOriginal;
typedef GrTextureMaker INHERITED;
typedef GrTextureParamsAdjuster INHERITED;
};
GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrTextureParams& params) const {
return Texture_GrTextureMaker(this, fTexture).refCachedTexture(ctx, params);
return Texture_GrTextureParamsAdjuster(this, fTexture).refTextureForParams(ctx, params);
}
bool SkImage_Gpu::isOpaque() const {

View File

@ -173,20 +173,6 @@ GrTexture* SkImage_Raster::asTextureRef(GrContext* ctx, const GrTextureParams& p
return nullptr;
}
// textures (at least the texture-key) only support 16bit dimensions, so abort early
// if we're too big.
if (fBitmap.width() > 0xFFFF || fBitmap.height() > 0xFFFF) {
return nullptr;
}
GrUniqueKey key;
GrMakeKeyFromImageID(&key, fBitmap.getGenerationID(),
SkIRect::MakeWH(fBitmap.width(), fBitmap.height()),
*ctx->caps(), params);
if (GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key)) {
return tex;
}
return GrRefCachedBitmapTexture(ctx, fBitmap, params);
#endif