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:
parent
e70afc9f48
commit
85d9178832
@ -249,6 +249,7 @@
|
||||
'<(skia_src_path)/doc/SkDocument.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_Raster.cpp',
|
||||
'<(skia_src_path)/image/SkSurface.cpp',
|
||||
|
@ -214,6 +214,11 @@ public:
|
||||
|
||||
SkIRect bounds() const { return fInfo.bounds(); }
|
||||
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);
|
||||
|
||||
|
@ -150,6 +150,8 @@ public:
|
||||
|
||||
int width() const { return fWidth; }
|
||||
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; }
|
||||
virtual bool isOpaque() const { return false; }
|
||||
|
||||
|
@ -81,7 +81,10 @@ GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data,
|
||||
int expectedW, int expectedH,
|
||||
const void** outStartOfDataToUpload);
|
||||
|
||||
// Helper that calls GrIsImageInCache assuming bitmap is not volatile.
|
||||
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&, SkImageUsageType);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "GrGpuResourcePriv.h"
|
||||
#include "GrResourceKey.h"
|
||||
#include "GrTextureAccess.h"
|
||||
#include "GrYUVProvider.h"
|
||||
#include "SkGr.h"
|
||||
#include "SkGrPriv.h"
|
||||
#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)
|
||||
*
|
||||
@ -173,10 +217,19 @@ GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, SkImageUsageType usa
|
||||
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;
|
||||
GrMakeKeyFromImageID(&key, fUniqueID, fInfo.width(), fInfo.height(), SkIPoint::Make(0, 0),
|
||||
GrMakeKeyFromImageID(&key, fUniqueID, SkIRect::MakeWH(fInfo.width(), fInfo.height()),
|
||||
*ctx->caps(), usage);
|
||||
|
||||
GrSurfaceDesc desc;
|
||||
make_texture_desc(fInfo, &desc);
|
||||
|
||||
// 1. Check the cache for a pre-existing one
|
||||
if (GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key)) {
|
||||
return tex;
|
||||
@ -187,26 +240,36 @@ GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, SkImageUsageType usa
|
||||
ScopedGenerator generator(this);
|
||||
SkIRect subset = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), fInfo.width(), fInfo.height());
|
||||
if (GrTexture* tex = generator->generateTexture(ctx, usage, &subset)) {
|
||||
tex->resourcePriv().setUniqueKey(key);
|
||||
return tex;
|
||||
return set_key_and_return(tex, key);
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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
|
||||
SkBitmap bitmap;
|
||||
if (!this->generateBitmap(&bitmap)) {
|
||||
return nullptr;
|
||||
if (this->generateBitmap(&bitmap)) {
|
||||
return GrRefCachedBitmapTexture(ctx, bitmap, usage);
|
||||
}
|
||||
return GrRefCachedBitmapTexture(ctx, bitmap, usage);
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -693,7 +693,7 @@ static inline int get_tile_count(const SkIRect& srcRect, int tileSize) {
|
||||
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) {
|
||||
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,
|
||||
const GrClip& clip,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkBitmap& bitmap,
|
||||
const SkISize& imageSize,
|
||||
const SkRect* srcRectPtr,
|
||||
SkIRect* clippedSrcIRect) {
|
||||
clip.getConservativeBounds(rt, clippedSrcIRect, nullptr);
|
||||
@ -736,12 +736,61 @@ static void determine_clipped_src_rect(const GrRenderTarget* rt,
|
||||
}
|
||||
}
|
||||
clippedSrcRect.roundOut(clippedSrcIRect);
|
||||
SkIRect bmpBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
|
||||
SkIRect bmpBounds = SkIRect::MakeSize(imageSize);
|
||||
if (!clippedSrcIRect->intersect(bmpBounds)) {
|
||||
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, ¶ms)) {
|
||||
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,
|
||||
const SkMatrix& viewMatrix,
|
||||
const GrTextureParams& params,
|
||||
@ -754,45 +803,41 @@ bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
|
||||
return false;
|
||||
}
|
||||
|
||||
// if it's larger than the max tile size, then we have no choice but tiling.
|
||||
if (bitmap.width() > maxTileSize || bitmap.height() > maxTileSize) {
|
||||
determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, bitmap,
|
||||
srcRectPtr, clippedSrcRect);
|
||||
*tileSize = determine_tile_size(bitmap, *clippedSrcRect, maxTileSize);
|
||||
return true;
|
||||
}
|
||||
return this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), viewMatrix, params,
|
||||
srcRectPtr, maxTileSize, tileSize, clippedSrcRect);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// if the entire texture is already in our cache then no reason to tile it
|
||||
if (GrIsBitmapInCache(fContext, bitmap, ¶ms)) {
|
||||
return false;
|
||||
GrTextureParams params;
|
||||
bool doBicubic;
|
||||
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
|
||||
// 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.
|
||||
int maxTileSize = fContext->caps()->maxTextureSize() - 2 * tileFilterPad;
|
||||
|
||||
// assumption here is that sw bitmap size is a good proxy for its size as
|
||||
// a texture
|
||||
size_t bmpSize = bitmap.getSize();
|
||||
size_t cacheSize;
|
||||
fContext->getResourceCacheLimits(nullptr, &cacheSize);
|
||||
if (bmpSize < cacheSize / 2) {
|
||||
return false;
|
||||
}
|
||||
// these are output, which we safely ignore, as we just want to know the predicate
|
||||
int outTileSize;
|
||||
SkIRect outClippedSrcRect;
|
||||
|
||||
// Figure out how much of the src we will need based on the src rect and clipping.
|
||||
determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, bitmap, srcRectPtr,
|
||||
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;
|
||||
return this->shouldTileImageID(image->unique(), image->bounds(), viewMatrix, params, srcRectPtr,
|
||||
maxTileSize, &outTileSize, &outClippedSrcRect);
|
||||
}
|
||||
|
||||
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
|
||||
// the view matrix rather than a local matrix.
|
||||
SkMatrix m;
|
||||
m.setScale(dstSize.fWidth / srcRect.width(),
|
||||
dstSize.fHeight / srcRect.height());
|
||||
SkMatrix viewM = *draw.fMatrix;
|
||||
viewM.preConcat(m);
|
||||
viewM.preScale(dstSize.fWidth / srcRect.width(),
|
||||
dstSize.fHeight / srcRect.height());
|
||||
|
||||
GrTextureParams params;
|
||||
bool doBicubic;
|
||||
@ -1546,8 +1589,8 @@ bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
|
||||
filter, ctx, result, offset);
|
||||
}
|
||||
|
||||
static bool wrap_as_bm(const SkImage* image, SkBitmap* bm) {
|
||||
GrTexture* tex = as_IB(image)->getTexture();
|
||||
static bool wrap_as_bm(GrContext* ctx, const SkImage* image, SkBitmap* bm) {
|
||||
SkAutoTUnref<GrTexture> tex(as_IB(image)->asTextureRef(ctx, kUntiled_SkImageUsageType));
|
||||
if (tex) {
|
||||
GrWrapTextureInBitmap(tex, image->width(), image->height(), image->isOpaque(), bm);
|
||||
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,
|
||||
const SkPaint& paint) {
|
||||
SkBitmap bm;
|
||||
if (wrap_as_bm(image, &bm)) {
|
||||
this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint);
|
||||
if (GrTexture* tex = as_IB(image)->peekTexture()) {
|
||||
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,
|
||||
const SkRect& dst, const SkPaint& paint,
|
||||
SkCanvas::SrcRectConstraint constraint) {
|
||||
SkBitmap bm;
|
||||
if (wrap_as_bm(image, &bm)) {
|
||||
this->drawBitmapRect(draw, bm, src, dst, paint, constraint);
|
||||
if (GrTexture* tex = as_IB(image)->peekTexture()) {
|
||||
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);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -194,6 +194,13 @@ private:
|
||||
*/
|
||||
|
||||
// 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,
|
||||
const SkMatrix& viewMatrix,
|
||||
const GrTextureParams& sampler,
|
||||
@ -201,6 +208,12 @@ private:
|
||||
int maxTileSize,
|
||||
int* tileSize,
|
||||
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&,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkRect&,
|
||||
|
@ -155,21 +155,19 @@ static bool make_stretched_key(const GrUniqueKey& origKey, const Stretch& stretc
|
||||
return false;
|
||||
}
|
||||
|
||||
static void make_unstretched_key(GrUniqueKey* key, uint32_t imageID,
|
||||
U16CPU width, U16CPU height, SkIPoint origin) {
|
||||
SkASSERT((uint16_t)width == width);
|
||||
SkASSERT((uint16_t)height == height);
|
||||
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);
|
||||
builder[0] = imageID;
|
||||
builder[1] = origin.fX;
|
||||
builder[2] = origin.fY;
|
||||
builder[3] = width | (height << 16);
|
||||
builder[1] = subset.x();
|
||||
builder[2] = subset.y();
|
||||
builder[3] = subset.width() | (subset.height() << 16);
|
||||
}
|
||||
|
||||
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID,
|
||||
U16CPU width, U16CPU height, SkIPoint origin,
|
||||
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& subset,
|
||||
const GrCaps& caps, SkImageUsageType usage) {
|
||||
const Stretch::Type stretches[] = {
|
||||
Stretch::kNone_Type, // kUntiled_SkImageUsageType
|
||||
@ -177,38 +175,31 @@ void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID,
|
||||
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 &&
|
||||
usage != kUntiled_SkImageUsageType &&
|
||||
!caps.npotTextureTileSupport();
|
||||
|
||||
if (needToStretch) {
|
||||
GrUniqueKey tmpKey;
|
||||
make_unstretched_key(&tmpKey, imageID, width, height, origin);
|
||||
make_unstretched_key(&tmpKey, imageID, subset);
|
||||
|
||||
Stretch stretch;
|
||||
stretch.fType = stretches[usage];
|
||||
stretch.fWidth = SkNextPow2(width);
|
||||
stretch.fHeight = SkNextPow2(height);
|
||||
stretch.fWidth = SkNextPow2(subset.width());
|
||||
stretch.fHeight = SkNextPow2(subset.height());
|
||||
if (!make_stretched_key(tmpKey, stretch, key)) {
|
||||
goto UNSTRETCHED;
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
make_unstretched_key(key, bitmap.getGenerationID(), bitmap.width(), bitmap.height(),
|
||||
bitmap.pixelRefOrigin());
|
||||
}
|
||||
|
||||
static void make_bitmap_keys(const SkBitmap& bitmap,
|
||||
const Stretch& stretch,
|
||||
GrUniqueKey* key,
|
||||
GrUniqueKey* stretchedKey) {
|
||||
make_unstretched_key(bitmap, key);
|
||||
static void make_image_keys(uint32_t imageID, const SkIRect& subset, const Stretch& stretch,
|
||||
GrUniqueKey* key, GrUniqueKey* stretchedKey) {
|
||||
make_unstretched_key(key, imageID, subset);
|
||||
if (Stretch::kNone_Type != stretch.fType) {
|
||||
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);
|
||||
}
|
||||
|
||||
bool GrIsBitmapInCache(const GrContext* ctx,
|
||||
const SkBitmap& bitmap,
|
||||
const GrTextureParams* params) {
|
||||
bool GrIsImageInCache(const GrContext* ctx, uint32_t imageID, const SkIRect& subset,
|
||||
GrTexture* nativeTexture, const GrTextureParams* params) {
|
||||
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.
|
||||
GrTexture* texture = bitmap.getTexture();
|
||||
if (texture) {
|
||||
// Handle the case where the bitmap/image is explicitly texture backed.
|
||||
if (nativeTexture) {
|
||||
if (Stretch::kNone_Type == stretch.fType) {
|
||||
return true;
|
||||
}
|
||||
// No keys for volatile bitmaps.
|
||||
if (bitmap.isVolatile()) {
|
||||
return false;
|
||||
}
|
||||
const GrUniqueKey& key = texture->getUniqueKey();
|
||||
const GrUniqueKey& key = nativeTexture->getUniqueKey();
|
||||
if (!key.isValid()) {
|
||||
return false;
|
||||
}
|
||||
@ -559,17 +544,21 @@ bool GrIsBitmapInCache(const GrContext* ctx,
|
||||
return ctx->textureProvider()->existsTextureWithUniqueKey(stretchedKey);
|
||||
}
|
||||
|
||||
// We don't cache volatile bitmaps
|
||||
if (bitmap.isVolatile()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GrUniqueKey key, stretchedKey;
|
||||
make_bitmap_keys(bitmap, stretch, &key, &stretchedKey);
|
||||
make_image_keys(imageID, subset, stretch, &key, &stretchedKey);
|
||||
return ctx->textureProvider()->existsTextureWithUniqueKey(
|
||||
(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,
|
||||
const SkBitmap& bitmap,
|
||||
const GrTextureParams* params) {
|
||||
@ -602,7 +591,7 @@ GrTexture* GrRefCachedBitmapTexture(GrContext* ctx,
|
||||
|
||||
if (!bitmap.isVolatile()) {
|
||||
// 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(
|
||||
resizedKey.isValid() ? resizedKey : key);
|
||||
|
@ -25,8 +25,7 @@ class GrUniqueKey;
|
||||
*
|
||||
* Note: width/height must fit in 16bits for this impl.
|
||||
*/
|
||||
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID,
|
||||
U16CPU width, U16CPU height, SkIPoint origin,
|
||||
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds,
|
||||
const GrCaps&, SkImageUsageType);
|
||||
|
||||
#endif
|
||||
|
@ -158,7 +158,7 @@ SkImage* SkImage::newImage(int newWidth, int newHeight, const SkIRect* subset,
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
GrTexture* SkImage::getTexture() const {
|
||||
return as_IB(this)->getTexture();
|
||||
return as_IB(this)->peekTexture();
|
||||
}
|
||||
|
||||
bool SkImage::isTextureBacked() const { return SkToBool(as_IB(this)->getTexture()); }
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
|
||||
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,
|
||||
// but only inspect them (or encode them).
|
||||
@ -73,6 +73,9 @@ public:
|
||||
|
||||
virtual bool onIsLazyGenerated() const { return false; }
|
||||
|
||||
// Caller must call unref when they are done.
|
||||
virtual GrTexture* asTextureRef(GrContext*, SkImageUsageType) const { return nullptr; }
|
||||
|
||||
private:
|
||||
const SkSurfaceProps fProps;
|
||||
|
||||
|
95
src/image/SkImage_Generator.cpp
Normal file
95
src/image/SkImage_Generator.cpp
Normal 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
|
@ -79,6 +79,11 @@ bool SkImage_Gpu::getROPixels(SkBitmap* dst) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, SkImageUsageType usage) const {
|
||||
fTexture->ref();
|
||||
return fTexture;
|
||||
}
|
||||
|
||||
bool SkImage_Gpu::isOpaque() const {
|
||||
return GrPixelConfigIsOpaque(fTexture->config()) || fAlphaType == kOpaque_SkAlphaType;
|
||||
}
|
||||
|
@ -37,7 +37,9 @@ public:
|
||||
}
|
||||
|
||||
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::TileMode,
|
||||
const SkMatrix* localMatrix) const override;
|
||||
|
@ -231,18 +231,6 @@ SkImage* SkImage::NewFromRaster(const SkImageInfo& info, const void* pixels, siz
|
||||
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,
|
||||
const SkIPoint& pixelRefOrigin, size_t rowBytes,
|
||||
const SkSurfaceProps* props) {
|
||||
@ -301,3 +289,16 @@ bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) c
|
||||
}
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user