Use SkImageCacherator in SkImages

Possible follow-up changes to consider

1. Roll SkImage_Raster and _Gpu into _Generator, where the generator (or cacherator) is backed by a pre-existing texture or raster.
2. Evolve SkImageUsageType into a verb requiring stretching, and have the caller (common code) digest the caps() and usage, so that subclasses are just told what to do (stretch or not)
3. Common code/utility to convert an unstretched texture into a stretch one (and cache it) if the generator can only make an unstretched one.

BUG=skia:

Review URL: https://codereview.chromium.org/1282363002
This commit is contained in:
reed 2015-09-10 14:33:38 -07:00 committed by Commit bot
parent e70afc9f48
commit 85d9178832
15 changed files with 368 additions and 115 deletions

View File

@ -249,6 +249,7 @@
'<(skia_src_path)/doc/SkDocument.cpp', '<(skia_src_path)/doc/SkDocument.cpp',
'<(skia_src_path)/image/SkImage.cpp', '<(skia_src_path)/image/SkImage.cpp',
'<(skia_src_path)/image/SkImage_Generator.cpp',
# '<(skia_src_path)/image/SkImage_Gpu.cpp', # '<(skia_src_path)/image/SkImage_Gpu.cpp',
'<(skia_src_path)/image/SkImage_Raster.cpp', '<(skia_src_path)/image/SkImage_Raster.cpp',
'<(skia_src_path)/image/SkSurface.cpp', '<(skia_src_path)/image/SkSurface.cpp',

View File

@ -214,6 +214,11 @@ public:
SkIRect bounds() const { return fInfo.bounds(); } SkIRect bounds() const { return fInfo.bounds(); }
SkISize dimensions() const { return fInfo.dimensions(); } SkISize dimensions() const { return fInfo.dimensions(); }
// Returns the bounds of this bitmap, offset by its pixelref origin.
SkIRect getSubset() const {
return SkIRect::MakeXYWH(fPixelRefOrigin.x(), fPixelRefOrigin.y(),
fInfo.width(), fInfo.height());
}
bool setInfo(const SkImageInfo&, size_t rowBytes = 0); bool setInfo(const SkImageInfo&, size_t rowBytes = 0);

View File

@ -150,6 +150,8 @@ public:
int width() const { return fWidth; } int width() const { return fWidth; }
int height() const { return fHeight; } int height() const { return fHeight; }
SkISize dimensions() const { return SkISize::Make(fWidth, fHeight); }
SkIRect bounds() const { return SkIRect::MakeWH(fWidth, fHeight); }
uint32_t uniqueID() const { return fUniqueID; } uint32_t uniqueID() const { return fUniqueID; }
virtual bool isOpaque() const { return false; } virtual bool isOpaque() const { return false; }

View File

@ -81,7 +81,10 @@ GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data,
int expectedW, int expectedH, int expectedW, int expectedH,
const void** outStartOfDataToUpload); const void** outStartOfDataToUpload);
// Helper that calls GrIsImageInCache assuming bitmap is not volatile.
bool GrIsBitmapInCache(const GrContext*, const SkBitmap&, const GrTextureParams*); bool GrIsBitmapInCache(const GrContext*, const SkBitmap&, const GrTextureParams*);
bool GrIsImageInCache(const GrContext* ctx, uint32_t imageID, const SkIRect& subset,
GrTexture* nativeTexture, const GrTextureParams*);
GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams*); GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams*);
GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, SkImageUsageType); GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, SkImageUsageType);

View File

@ -17,6 +17,7 @@
#include "GrGpuResourcePriv.h" #include "GrGpuResourcePriv.h"
#include "GrResourceKey.h" #include "GrResourceKey.h"
#include "GrTextureAccess.h" #include "GrTextureAccess.h"
#include "GrYUVProvider.h"
#include "SkGr.h" #include "SkGr.h"
#include "SkGrPriv.h" #include "SkGrPriv.h"
#endif #endif
@ -158,6 +159,49 @@ bool SkImageCacherator::lockAsBitmap(SkBitmap* bitmap) {
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
static void make_texture_desc(const SkImageInfo& info, GrSurfaceDesc* desc) {
desc->fFlags = kNone_GrSurfaceFlags;
desc->fWidth = info.width();
desc->fHeight = info.height();
desc->fConfig = SkImageInfo2GrPixelConfig(info);
desc->fSampleCnt = 0;
}
static GrTexture* load_compressed_into_texture(GrContext* ctx, SkData* data, GrSurfaceDesc desc) {
const void* rawStart;
GrPixelConfig config = GrIsCompressedTextureDataSupported(ctx, data, desc.fWidth, desc.fHeight,
&rawStart);
if (kUnknown_GrPixelConfig == config) {
return nullptr;
}
desc.fConfig = config;
return ctx->textureProvider()->createTexture(desc, true, rawStart, 0);
}
class Generator_GrYUVProvider : public GrYUVProvider {
SkImageGenerator* fGen;
public:
Generator_GrYUVProvider(SkImageGenerator* gen) : fGen(gen) {}
uint32_t onGetID() override { return fGen->uniqueID(); }
bool onGetYUVSizes(SkISize sizes[3]) override {
return fGen->getYUV8Planes(sizes, nullptr, nullptr, nullptr);
}
bool onGetYUVPlanes(SkISize sizes[3], void* planes[3], size_t rowBytes[3],
SkYUVColorSpace* space) override {
return fGen->getYUV8Planes(sizes, planes, rowBytes, space);
}
};
static GrTexture* set_key_and_return(GrTexture* tex, const GrUniqueKey& key) {
tex->resourcePriv().setUniqueKey(key);
return tex;
}
#endif
/* /*
* We have a 5 ways to try to return a texture (in sorted order) * We have a 5 ways to try to return a texture (in sorted order)
* *
@ -173,10 +217,19 @@ GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, SkImageUsageType usa
return nullptr; return nullptr;
} }
// 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; GrUniqueKey key;
GrMakeKeyFromImageID(&key, fUniqueID, fInfo.width(), fInfo.height(), SkIPoint::Make(0, 0), GrMakeKeyFromImageID(&key, fUniqueID, SkIRect::MakeWH(fInfo.width(), fInfo.height()),
*ctx->caps(), usage); *ctx->caps(), usage);
GrSurfaceDesc desc;
make_texture_desc(fInfo, &desc);
// 1. Check the cache for a pre-existing one // 1. Check the cache for a pre-existing one
if (GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key)) { if (GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key)) {
return tex; return tex;
@ -187,26 +240,36 @@ GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, SkImageUsageType usa
ScopedGenerator generator(this); ScopedGenerator generator(this);
SkIRect subset = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), fInfo.width(), fInfo.height()); SkIRect subset = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), fInfo.width(), fInfo.height());
if (GrTexture* tex = generator->generateTexture(ctx, usage, &subset)) { if (GrTexture* tex = generator->generateTexture(ctx, usage, &subset)) {
tex->resourcePriv().setUniqueKey(key); return set_key_and_return(tex, key);
return tex;
} }
} }
// 3. Ask the generator to return a compressed form that the GPU might support // 3. Ask the generator to return a compressed form that the GPU might support
// TODO SkAutoTUnref<SkData> data(this->refEncoded());
if (data) {
GrTexture* tex = load_compressed_into_texture(ctx, data, desc);
if (tex) {
return set_key_and_return(tex, key);
}
}
// 4. Ask the generator to return YUV planes, which the GPU can convert // 4. Ask the generator to return YUV planes, which the GPU can convert
// TODO {
ScopedGenerator generator(this);
Generator_GrYUVProvider provider(generator);
GrTexture* tex = provider.refAsTexture(ctx, desc, true);
if (tex) {
return set_key_and_return(tex, key);
}
}
// 5. Ask the generator to return RGB(A) data, which the GPU can convert // 5. Ask the generator to return RGB(A) data, which the GPU can convert
SkBitmap bitmap; SkBitmap bitmap;
if (!this->generateBitmap(&bitmap)) { if (this->generateBitmap(&bitmap)) {
return nullptr; return GrRefCachedBitmapTexture(ctx, bitmap, usage);
} }
return GrRefCachedBitmapTexture(ctx, bitmap, usage);
#else
return nullptr;
#endif #endif
return nullptr;
} }

View File

@ -693,7 +693,7 @@ static inline int get_tile_count(const SkIRect& srcRect, int tileSize) {
return tilesX * tilesY; return tilesX * tilesY;
} }
static int determine_tile_size(const SkBitmap& bitmap, const SkIRect& src, int maxTileSize) { static int determine_tile_size(const SkIRect& src, int maxTileSize) {
if (maxTileSize <= kBmpSmallTileSize) { if (maxTileSize <= kBmpSmallTileSize) {
return maxTileSize; return maxTileSize;
} }
@ -716,7 +716,7 @@ static int determine_tile_size(const SkBitmap& bitmap, const SkIRect& src, int m
static void determine_clipped_src_rect(const GrRenderTarget* rt, static void determine_clipped_src_rect(const GrRenderTarget* rt,
const GrClip& clip, const GrClip& clip,
const SkMatrix& viewMatrix, const SkMatrix& viewMatrix,
const SkBitmap& bitmap, const SkISize& imageSize,
const SkRect* srcRectPtr, const SkRect* srcRectPtr,
SkIRect* clippedSrcIRect) { SkIRect* clippedSrcIRect) {
clip.getConservativeBounds(rt, clippedSrcIRect, nullptr); clip.getConservativeBounds(rt, clippedSrcIRect, nullptr);
@ -736,12 +736,61 @@ static void determine_clipped_src_rect(const GrRenderTarget* rt,
} }
} }
clippedSrcRect.roundOut(clippedSrcIRect); clippedSrcRect.roundOut(clippedSrcIRect);
SkIRect bmpBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); SkIRect bmpBounds = SkIRect::MakeSize(imageSize);
if (!clippedSrcIRect->intersect(bmpBounds)) { if (!clippedSrcIRect->intersect(bmpBounds)) {
clippedSrcIRect->setEmpty(); clippedSrcIRect->setEmpty();
} }
} }
bool SkGpuDevice::shouldTileImageID(uint32_t imageID, const SkIRect& imageRect,
const SkMatrix& viewMatrix,
const GrTextureParams& params,
const SkRect* srcRectPtr,
int maxTileSize,
int* tileSize,
SkIRect* clippedSubset) const {
// if it's larger than the max tile size, then we have no choice but tiling.
if (imageRect.width() > maxTileSize || imageRect.height() > maxTileSize) {
determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, imageRect.size(),
srcRectPtr, clippedSubset);
*tileSize = determine_tile_size(*clippedSubset, maxTileSize);
return true;
}
const size_t area = imageRect.width() * imageRect.height();
if (area < 4 * kBmpSmallTileSize * kBmpSmallTileSize) {
return false;
}
// if the entire image/bitmap is already in our cache then no reason to tile it
if (GrIsImageInCache(fContext, imageID, imageRect, nullptr, &params)) {
return false;
}
// At this point we know we could do the draw by uploading the entire bitmap
// as a texture. However, if the texture would be large compared to the
// cache size and we don't require most of it for this draw then tile to
// reduce the amount of upload and cache spill.
// assumption here is that sw bitmap size is a good proxy for its size as
// a texture
size_t bmpSize = area * sizeof(SkPMColor); // assume 32bit pixels
size_t cacheSize;
fContext->getResourceCacheLimits(nullptr, &cacheSize);
if (bmpSize < cacheSize / 2) {
return false;
}
// Figure out how much of the src we will need based on the src rect and clipping.
determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, imageRect.size(), srcRectPtr,
clippedSubset);
*tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
size_t usedTileBytes = get_tile_count(*clippedSubset, kBmpSmallTileSize) *
kBmpSmallTileSize * kBmpSmallTileSize;
return usedTileBytes < 2 * bmpSize;
}
bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap, bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
const SkMatrix& viewMatrix, const SkMatrix& viewMatrix,
const GrTextureParams& params, const GrTextureParams& params,
@ -754,45 +803,41 @@ bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
return false; return false;
} }
// if it's larger than the max tile size, then we have no choice but tiling. return this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), viewMatrix, params,
if (bitmap.width() > maxTileSize || bitmap.height() > maxTileSize) { srcRectPtr, maxTileSize, tileSize, clippedSrcRect);
determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, bitmap, }
srcRectPtr, clippedSrcRect);
*tileSize = determine_tile_size(bitmap, *clippedSrcRect, maxTileSize);
return true;
}
if (bitmap.width() * bitmap.height() < 4 * kBmpSmallTileSize * kBmpSmallTileSize) { bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr,
SkCanvas::SrcRectConstraint constraint, SkFilterQuality quality,
const SkMatrix& viewMatrix) const {
// if image is explictly texture backed then just use the texture
if (as_IB(image)->peekTexture()) {
return false; return false;
} }
// if the entire texture is already in our cache then no reason to tile it GrTextureParams params;
if (GrIsBitmapInCache(fContext, bitmap, &params)) { bool doBicubic;
return false; GrTextureParams::FilterMode textureFilterMode =
GrSkFilterQualityToGrFilterMode(quality, 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);
// At this point we know we could do the draw by uploading the entire bitmap int maxTileSize = fContext->caps()->maxTextureSize() - 2 * tileFilterPad;
// as a texture. However, if the texture would be large compared to the
// cache size and we don't require most of it for this draw then tile to
// reduce the amount of upload and cache spill.
// assumption here is that sw bitmap size is a good proxy for its size as // these are output, which we safely ignore, as we just want to know the predicate
// a texture int outTileSize;
size_t bmpSize = bitmap.getSize(); SkIRect outClippedSrcRect;
size_t cacheSize;
fContext->getResourceCacheLimits(nullptr, &cacheSize);
if (bmpSize < cacheSize / 2) {
return false;
}
// Figure out how much of the src we will need based on the src rect and clipping. return this->shouldTileImageID(image->unique(), image->bounds(), viewMatrix, params, srcRectPtr,
determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, bitmap, srcRectPtr, maxTileSize, &outTileSize, &outClippedSrcRect);
clippedSrcRect);
*tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
size_t usedTileBytes = get_tile_count(*clippedSrcRect, kBmpSmallTileSize) *
kBmpSmallTileSize * kBmpSmallTileSize;
return usedTileBytes < 2 * bmpSize;
} }
void SkGpuDevice::drawBitmap(const SkDraw& origDraw, void SkGpuDevice::drawBitmap(const SkDraw& origDraw,
@ -1090,11 +1135,9 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
// If there is no mask filter than it is OK to handle the src rect -> dst rect scaling using // 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. // the view matrix rather than a local matrix.
SkMatrix m;
m.setScale(dstSize.fWidth / srcRect.width(),
dstSize.fHeight / srcRect.height());
SkMatrix viewM = *draw.fMatrix; SkMatrix viewM = *draw.fMatrix;
viewM.preConcat(m); viewM.preScale(dstSize.fWidth / srcRect.width(),
dstSize.fHeight / srcRect.height());
GrTextureParams params; GrTextureParams params;
bool doBicubic; bool doBicubic;
@ -1546,8 +1589,8 @@ bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
filter, ctx, result, offset); filter, ctx, result, offset);
} }
static bool wrap_as_bm(const SkImage* image, SkBitmap* bm) { static bool wrap_as_bm(GrContext* ctx, const SkImage* image, SkBitmap* bm) {
GrTexture* tex = as_IB(image)->getTexture(); SkAutoTUnref<GrTexture> tex(as_IB(image)->asTextureRef(ctx, kUntiled_SkImageUsageType));
if (tex) { if (tex) {
GrWrapTextureInBitmap(tex, image->width(), image->height(), image->isOpaque(), bm); GrWrapTextureInBitmap(tex, image->width(), image->height(), image->isOpaque(), bm);
return true; return true;
@ -1559,18 +1602,47 @@ static bool wrap_as_bm(const SkImage* image, SkBitmap* bm) {
void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y, void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y,
const SkPaint& paint) { const SkPaint& paint) {
SkBitmap bm; SkBitmap bm;
if (wrap_as_bm(image, &bm)) { if (GrTexture* tex = as_IB(image)->peekTexture()) {
this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); GrWrapTextureInBitmap(tex, image->width(), image->height(), image->isOpaque(), &bm);
} else {
if (this->shouldTileImage(image, nullptr, SkCanvas::kFast_SrcRectConstraint,
paint.getFilterQuality(), *draw.fMatrix)) {
// only support tiling as bitmap at the moment, so force raster-version
if (!as_IB(image)->getROPixels(&bm)) {
return;
}
} else {
if (!wrap_as_bm(this->context(), image, &bm)) {
return;
}
}
} }
this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint);
} }
void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const SkRect* src, void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const SkRect* src,
const SkRect& dst, const SkPaint& paint, const SkRect& dst, const SkPaint& paint,
SkCanvas::SrcRectConstraint constraint) { SkCanvas::SrcRectConstraint constraint) {
SkBitmap bm; SkBitmap bm;
if (wrap_as_bm(image, &bm)) { if (GrTexture* tex = as_IB(image)->peekTexture()) {
this->drawBitmapRect(draw, bm, src, dst, paint, constraint); GrWrapTextureInBitmap(tex, image->width(), image->height(), image->isOpaque(), &bm);
} else {
SkMatrix viewMatrix = *draw.fMatrix;
viewMatrix.preScale(dst.width() / (src ? src->width() : image->width()),
dst.height() / (src ? src->height() : image->height()));
if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), viewMatrix)) {
// only support tiling as bitmap at the moment, so force raster-version
if (!as_IB(image)->getROPixels(&bm)) {
return;
}
} else {
if (!wrap_as_bm(this->context(), image, &bm)) {
return;
}
}
} }
this->drawBitmapRect(draw, bm, src, dst, paint, constraint);
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -194,6 +194,13 @@ private:
*/ */
// The tileSize and clippedSrcRect will be valid only if true is returned. // The tileSize and clippedSrcRect will be valid only if true is returned.
bool shouldTileImageID(uint32_t imageID, const SkIRect& imageRect,
const SkMatrix& viewMatrix,
const GrTextureParams& params,
const SkRect* srcRectPtr,
int maxTileSize,
int* tileSize,
SkIRect* clippedSubset) const;
bool shouldTileBitmap(const SkBitmap& bitmap, bool shouldTileBitmap(const SkBitmap& bitmap,
const SkMatrix& viewMatrix, const SkMatrix& viewMatrix,
const GrTextureParams& sampler, const GrTextureParams& sampler,
@ -201,6 +208,12 @@ private:
int maxTileSize, int maxTileSize,
int* tileSize, int* tileSize,
SkIRect* clippedSrcRect) const; SkIRect* clippedSrcRect) const;
// Just returns the predicate, not the out-tileSize or out-clippedSubset, as they are not
// needed at the moment.
bool shouldTileImage(const SkImage* image, const SkRect* srcRectPtr,
SkCanvas::SrcRectConstraint constraint, SkFilterQuality quality,
const SkMatrix& viewMatrix) const;
void internalDrawBitmap(const SkBitmap&, void internalDrawBitmap(const SkBitmap&,
const SkMatrix& viewMatrix, const SkMatrix& viewMatrix,
const SkRect&, const SkRect&,

View File

@ -155,21 +155,19 @@ static bool make_stretched_key(const GrUniqueKey& origKey, const Stretch& stretc
return false; return false;
} }
static void make_unstretched_key(GrUniqueKey* key, uint32_t imageID, static void make_unstretched_key(GrUniqueKey* key, uint32_t imageID, const SkIRect& subset) {
U16CPU width, U16CPU height, SkIPoint origin) { SkASSERT(SkIsU16(subset.width()));
SkASSERT((uint16_t)width == width); SkASSERT(SkIsU16(subset.height()));
SkASSERT((uint16_t)height == height);
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey::Builder builder(key, kDomain, 4); GrUniqueKey::Builder builder(key, kDomain, 4);
builder[0] = imageID; builder[0] = imageID;
builder[1] = origin.fX; builder[1] = subset.x();
builder[2] = origin.fY; builder[2] = subset.y();
builder[3] = width | (height << 16); builder[3] = subset.width() | (subset.height() << 16);
} }
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& subset,
U16CPU width, U16CPU height, SkIPoint origin,
const GrCaps& caps, SkImageUsageType usage) { const GrCaps& caps, SkImageUsageType usage) {
const Stretch::Type stretches[] = { const Stretch::Type stretches[] = {
Stretch::kNone_Type, // kUntiled_SkImageUsageType Stretch::kNone_Type, // kUntiled_SkImageUsageType
@ -177,38 +175,31 @@ void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID,
Stretch::kBilerp_Type, // kTiled_Filtered_SkImageUsageType Stretch::kBilerp_Type, // kTiled_Filtered_SkImageUsageType
}; };
const bool isPow2 = SkIsPow2(width) && SkIsPow2(height); const bool isPow2 = SkIsPow2(subset.width()) && SkIsPow2(subset.height());
const bool needToStretch = !isPow2 && const bool needToStretch = !isPow2 &&
usage != kUntiled_SkImageUsageType && usage != kUntiled_SkImageUsageType &&
!caps.npotTextureTileSupport(); !caps.npotTextureTileSupport();
if (needToStretch) { if (needToStretch) {
GrUniqueKey tmpKey; GrUniqueKey tmpKey;
make_unstretched_key(&tmpKey, imageID, width, height, origin); make_unstretched_key(&tmpKey, imageID, subset);
Stretch stretch; Stretch stretch;
stretch.fType = stretches[usage]; stretch.fType = stretches[usage];
stretch.fWidth = SkNextPow2(width); stretch.fWidth = SkNextPow2(subset.width());
stretch.fHeight = SkNextPow2(height); stretch.fHeight = SkNextPow2(subset.height());
if (!make_stretched_key(tmpKey, stretch, key)) { if (!make_stretched_key(tmpKey, stretch, key)) {
goto UNSTRETCHED; goto UNSTRETCHED;
} }
} else { } else {
UNSTRETCHED: UNSTRETCHED:
make_unstretched_key(key, imageID, width, height, origin); make_unstretched_key(key, imageID, subset);
} }
} }
static void make_unstretched_key(const SkBitmap& bitmap, GrUniqueKey* key) { static void make_image_keys(uint32_t imageID, const SkIRect& subset, const Stretch& stretch,
make_unstretched_key(key, bitmap.getGenerationID(), bitmap.width(), bitmap.height(), GrUniqueKey* key, GrUniqueKey* stretchedKey) {
bitmap.pixelRefOrigin()); make_unstretched_key(key, imageID, subset);
}
static void make_bitmap_keys(const SkBitmap& bitmap,
const Stretch& stretch,
GrUniqueKey* key,
GrUniqueKey* stretchedKey) {
make_unstretched_key(bitmap, key);
if (Stretch::kNone_Type != stretch.fType) { if (Stretch::kNone_Type != stretch.fType) {
make_stretched_key(*key, stretch, stretchedKey); make_stretched_key(*key, stretch, stretchedKey);
} }
@ -534,23 +525,17 @@ static GrTexture* create_bitmap_texture(GrContext* ctx,
return create_unstretched_bitmap_texture(ctx, bmp, unstretchedKey); return create_unstretched_bitmap_texture(ctx, bmp, unstretchedKey);
} }
bool GrIsBitmapInCache(const GrContext* ctx, bool GrIsImageInCache(const GrContext* ctx, uint32_t imageID, const SkIRect& subset,
const SkBitmap& bitmap, GrTexture* nativeTexture, const GrTextureParams* params) {
const GrTextureParams* params) {
Stretch stretch; Stretch stretch;
get_stretch(ctx, bitmap.width(), bitmap.height(), params, &stretch); get_stretch(ctx, subset.width(), subset.height(), params, &stretch);
// Handle the case where the bitmap is explicitly texture backed. // Handle the case where the bitmap/image is explicitly texture backed.
GrTexture* texture = bitmap.getTexture(); if (nativeTexture) {
if (texture) {
if (Stretch::kNone_Type == stretch.fType) { if (Stretch::kNone_Type == stretch.fType) {
return true; return true;
} }
// No keys for volatile bitmaps. const GrUniqueKey& key = nativeTexture->getUniqueKey();
if (bitmap.isVolatile()) {
return false;
}
const GrUniqueKey& key = texture->getUniqueKey();
if (!key.isValid()) { if (!key.isValid()) {
return false; return false;
} }
@ -559,17 +544,21 @@ bool GrIsBitmapInCache(const GrContext* ctx,
return ctx->textureProvider()->existsTextureWithUniqueKey(stretchedKey); return ctx->textureProvider()->existsTextureWithUniqueKey(stretchedKey);
} }
// We don't cache volatile bitmaps
if (bitmap.isVolatile()) {
return false;
}
GrUniqueKey key, stretchedKey; GrUniqueKey key, stretchedKey;
make_bitmap_keys(bitmap, stretch, &key, &stretchedKey); make_image_keys(imageID, subset, stretch, &key, &stretchedKey);
return ctx->textureProvider()->existsTextureWithUniqueKey( return ctx->textureProvider()->existsTextureWithUniqueKey(
(Stretch::kNone_Type == stretch.fType) ? key : stretchedKey); (Stretch::kNone_Type == stretch.fType) ? key : stretchedKey);
} }
bool GrIsBitmapInCache(const GrContext* ctx, const SkBitmap& bitmap,
const GrTextureParams* params) {
if (bitmap.isVolatile()) {
return false; // we don't cache volatile bitmaps.
}
return GrIsImageInCache(ctx, bitmap.getGenerationID(), bitmap.getSubset(), bitmap.getTexture(),
params);
}
GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, GrTexture* GrRefCachedBitmapTexture(GrContext* ctx,
const SkBitmap& bitmap, const SkBitmap& bitmap,
const GrTextureParams* params) { const GrTextureParams* params) {
@ -602,7 +591,7 @@ GrTexture* GrRefCachedBitmapTexture(GrContext* ctx,
if (!bitmap.isVolatile()) { if (!bitmap.isVolatile()) {
// If the bitmap isn't changing try to find a cached copy first. // If the bitmap isn't changing try to find a cached copy first.
make_bitmap_keys(bitmap, stretch, &key, &resizedKey); make_image_keys(bitmap.getGenerationID(), bitmap.getSubset(), stretch, &key, &resizedKey);
result = ctx->textureProvider()->findAndRefTextureByUniqueKey( result = ctx->textureProvider()->findAndRefTextureByUniqueKey(
resizedKey.isValid() ? resizedKey : key); resizedKey.isValid() ? resizedKey : key);

View File

@ -25,8 +25,7 @@ class GrUniqueKey;
* *
* Note: width/height must fit in 16bits for this impl. * Note: width/height must fit in 16bits for this impl.
*/ */
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds,
U16CPU width, U16CPU height, SkIPoint origin,
const GrCaps&, SkImageUsageType); const GrCaps&, SkImageUsageType);
#endif #endif

View File

@ -158,7 +158,7 @@ SkImage* SkImage::newImage(int newWidth, int newHeight, const SkIRect* subset,
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
GrTexture* SkImage::getTexture() const { GrTexture* SkImage::getTexture() const {
return as_IB(this)->getTexture(); return as_IB(this)->peekTexture();
} }
bool SkImage::isTextureBacked() const { return SkToBool(as_IB(this)->getTexture()); } bool SkImage::isTextureBacked() const { return SkToBool(as_IB(this)->getTexture()); }

View File

@ -54,7 +54,7 @@ public:
virtual void onPreroll(GrContext*) const {} virtual void onPreroll(GrContext*) const {}
virtual GrTexture* getTexture() const { return nullptr; } virtual GrTexture* peekTexture() const { return nullptr; }
// return a read-only copy of the pixels. We promise to not modify them, // return a read-only copy of the pixels. We promise to not modify them,
// but only inspect them (or encode them). // but only inspect them (or encode them).
@ -73,6 +73,9 @@ public:
virtual bool onIsLazyGenerated() const { return false; } virtual bool onIsLazyGenerated() const { return false; }
// Caller must call unref when they are done.
virtual GrTexture* asTextureRef(GrContext*, SkImageUsageType) const { return nullptr; }
private: private:
const SkSurfaceProps fProps; const SkSurfaceProps fProps;

View File

@ -0,0 +1,95 @@
/*
* 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 "SkImage_Base.h"
#include "SkBitmap.h"
#include "SkData.h"
#include "SkImageCacherator.h"
#include "SkImagePriv.h"
#include "SkPixelRef.h"
#include "SkSurface.h"
class SkImage_Generator : public SkImage_Base {
public:
SkImage_Generator(SkImageCacherator* cache)
: INHERITED(cache->info().width(), cache->info().height(), kNeedNewImageUniqueID, NULL)
, fCache(cache) // take ownership
{}
SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) const override;
bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY) const override;
const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const override;
SkData* onRefEncoded() const override;
bool isOpaque() const override { return fCache->info().isOpaque(); }
bool getROPixels(SkBitmap*) const override;
GrTexture* asTextureRef(GrContext*, SkImageUsageType) const override;
SkShader* onNewShader(SkShader::TileMode,
SkShader::TileMode,
const SkMatrix* localMatrix) const override;
bool onIsLazyGenerated() const override { return true; }
private:
SkAutoTDelete<SkImageCacherator> fCache;
typedef SkImage_Base INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
SkShader* SkImage_Generator::onNewShader(SkShader::TileMode tileX, SkShader::TileMode tileY,
const SkMatrix* localMatrix) const {
// TODO: need a native Shader that takes Cacherator (or this image) so we can natively return
// textures as output from the shader.
SkBitmap bm;
if (this->getROPixels(&bm)) {
return SkShader::CreateBitmapShader(bm, tileX, tileY, localMatrix);
}
return nullptr;
}
SkSurface* SkImage_Generator::onNewSurface(const SkImageInfo& info,
const SkSurfaceProps& props) const {
return SkSurface::NewRaster(info, &props);
}
bool SkImage_Generator::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
int srcX, int srcY) const {
SkBitmap bm;
if (this->getROPixels(&bm)) {
return bm.readPixels(dstInfo, dstPixels, dstRB, srcX, srcY);
}
return false;
}
const void* SkImage_Generator::onPeekPixels(SkImageInfo* infoPtr, size_t* rowBytesPtr) const {
return NULL;
}
SkData* SkImage_Generator::onRefEncoded() const {
return fCache->refEncoded();
}
bool SkImage_Generator::getROPixels(SkBitmap* bitmap) const {
return fCache->lockAsBitmap(bitmap);
}
GrTexture* SkImage_Generator::asTextureRef(GrContext* ctx, SkImageUsageType usage) const {
return fCache->lockAsTexture(ctx, usage);
}
#ifndef SK_SUPPORT_LEGACY_NEWFROMGENERATOR
SkImage* SkImage::NewFromGenerator(SkImageGenerator* generator, const SkIRect* subset) {
SkImageCacherator* cache = SkImageCacherator::NewFromGenerator(generator, subset);
if (!cache) {
return nullptr;
}
return SkNEW_ARGS(SkImage_Generator, (cache));
}
#endif

View File

@ -79,6 +79,11 @@ bool SkImage_Gpu::getROPixels(SkBitmap* dst) const {
return true; return true;
} }
GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, SkImageUsageType usage) const {
fTexture->ref();
return fTexture;
}
bool SkImage_Gpu::isOpaque() const { bool SkImage_Gpu::isOpaque() const {
return GrPixelConfigIsOpaque(fTexture->config()) || fAlphaType == kOpaque_SkAlphaType; return GrPixelConfigIsOpaque(fTexture->config()) || fAlphaType == kOpaque_SkAlphaType;
} }

View File

@ -37,7 +37,9 @@ public:
} }
bool getROPixels(SkBitmap*) const override; bool getROPixels(SkBitmap*) const override;
GrTexture* getTexture() const override { return fTexture; } GrTexture* asTextureRef(GrContext* ctx, SkImageUsageType usage) const override;
GrTexture* peekTexture() const override { return fTexture; }
SkShader* onNewShader(SkShader::TileMode, SkShader* onNewShader(SkShader::TileMode,
SkShader::TileMode, SkShader::TileMode,
const SkMatrix* localMatrix) const override; const SkMatrix* localMatrix) const override;

View File

@ -231,18 +231,6 @@ SkImage* SkImage::NewFromRaster(const SkImageInfo& info, const void* pixels, siz
return new SkImage_Raster(info, data, rowBytes, ctable, nullptr); return new SkImage_Raster(info, data, rowBytes, ctable, nullptr);
} }
SkImage* SkImage::NewFromGenerator(SkImageGenerator* generator, const SkIRect* subset) {
SkBitmap bitmap;
if (!SkInstallDiscardablePixelRef(generator, subset, &bitmap, nullptr)) {
return nullptr;
}
if (0 == bitmap.width() || 0 == bitmap.height()) {
return nullptr;
}
return new SkImage_Raster(bitmap, nullptr);
}
SkImage* SkNewImageFromPixelRef(const SkImageInfo& info, SkPixelRef* pr, SkImage* SkNewImageFromPixelRef(const SkImageInfo& info, SkPixelRef* pr,
const SkIPoint& pixelRefOrigin, size_t rowBytes, const SkIPoint& pixelRefOrigin, size_t rowBytes,
const SkSurfaceProps* props) { const SkSurfaceProps* props) {
@ -301,3 +289,16 @@ bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) c
} }
return this->INHERITED::onAsLegacyBitmap(bitmap, mode); return this->INHERITED::onAsLegacyBitmap(bitmap, mode);
} }
#ifdef SK_SUPPORT_LEGACY_NEWFROMGENERATOR
SkImage* SkImage::NewFromGenerator(SkImageGenerator* generator, const SkIRect* subset) {
SkBitmap bitmap;
if (!SkInstallDiscardablePixelRef(generator, subset, &bitmap, nullptr)) {
return nullptr;
}
if (0 == bitmap.width() || 0 == bitmap.height()) {
return nullptr;
}
return new SkImage_Raster(bitmap, nullptr);
}
#endif