| Index: src/gpu/SkGr.cpp
|
| diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
|
| index 9083860db84420fc0bac47c4edaaa2ce3185e189..885b453df5f353c88b74ed9381241db01c4dc26a 100644
|
| --- a/src/gpu/SkGr.cpp
|
| +++ b/src/gpu/SkGr.cpp
|
| @@ -9,6 +9,7 @@
|
|
|
| #include "GrDrawTargetCaps.h"
|
| #include "GrGpu.h"
|
| +#include "GrGpuResourceCacheAccess.h"
|
| #include "GrXferProcessor.h"
|
| #include "SkColorFilter.h"
|
| #include "SkConfig8888.h"
|
| @@ -86,7 +87,45 @@ static void build_index8_data(void* buffer, const SkBitmap& bitmap) {
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
|
|
| -static void generate_bitmap_key(const SkBitmap& bitmap, GrContentKey* key) {
|
| +enum Stretch {
|
| + kNo_Stretch,
|
| + kBilerp_Stretch,
|
| + kNearest_Stretch
|
| +};
|
| +
|
| +static Stretch get_stretch_type(const GrContext* ctx, int width, int height,
|
| + const GrTextureParams* params) {
|
| + if (params && params->isTiled()) {
|
| + const GrDrawTargetCaps* caps = ctx->getGpu()->caps();
|
| + if (!caps->npotTextureTileSupport() && (!SkIsPow2(width) || !SkIsPow2(height))) {
|
| + switch(params->filterMode()) {
|
| + case GrTextureParams::kNone_FilterMode:
|
| + return kNearest_Stretch;
|
| + case GrTextureParams::kBilerp_FilterMode:
|
| + case GrTextureParams::kMipMap_FilterMode:
|
| + return kBilerp_Stretch;
|
| + }
|
| + }
|
| + }
|
| + return kNo_Stretch;
|
| +}
|
| +
|
| +static bool make_resize_key(const GrContentKey& origKey, Stretch stretch, GrContentKey* resizeKey) {
|
| + if (origKey.isValid() && kNo_Stretch != stretch) {
|
| + static const GrContentKey::Domain kDomain = GrContentKey::GenerateDomain();
|
| + GrContentKey::Builder builder(resizeKey, origKey, kDomain, 1);
|
| + builder[0] = stretch;
|
| + builder.finish();
|
| + return true;
|
| + }
|
| + SkASSERT(!resizeKey->isValid());
|
| + return false;
|
| +}
|
| +
|
| +static void generate_bitmap_keys(const SkBitmap& bitmap,
|
| + Stretch stretch,
|
| + GrContentKey* key,
|
| + GrContentKey* resizedKey) {
|
| // Our id includes the offset, width, and height so that bitmaps created by extractSubset()
|
| // are unique.
|
| uint32_t genID = bitmap.getGenerationID();
|
| @@ -100,6 +139,11 @@ static void generate_bitmap_key(const SkBitmap& bitmap, GrContentKey* key) {
|
| builder[1] = origin.fX;
|
| builder[2] = origin.fY;
|
| builder[3] = width | (height << 16);
|
| + builder.finish();
|
| +
|
| + if (kNo_Stretch != stretch) {
|
| + make_resize_key(*key, stretch, resizedKey);
|
| + }
|
| }
|
|
|
| static void generate_bitmap_texture_desc(const SkBitmap& bitmap, GrSurfaceDesc* desc) {
|
| @@ -127,45 +171,101 @@ private:
|
|
|
| } // namespace
|
|
|
| +#if 0 // TODO: plug this back up
|
| static void add_genID_listener(const GrContentKey& key, SkPixelRef* pixelRef) {
|
| SkASSERT(pixelRef);
|
| pixelRef->addGenIDChangeListener(SkNEW_ARGS(GrResourceInvalidator, (key)));
|
| }
|
| +#endif
|
|
|
| -static GrTexture* sk_gr_allocate_texture(GrContext* ctx,
|
| - bool cache,
|
| - const GrTextureParams* params,
|
| - const SkBitmap& bm,
|
| +static GrTexture* create_texture_for_bmp(GrContext* ctx,
|
| + const GrContentKey& optionalKey,
|
| GrSurfaceDesc desc,
|
| const void* pixels,
|
| size_t rowBytes) {
|
| GrTexture* result;
|
| - if (cache) {
|
| - // This texture is likely to be used again so leave it in the cache
|
| - GrContentKey key;
|
| - generate_bitmap_key(bm, &key);
|
| -
|
| - result = ctx->createTexture(params, desc, key, pixels, rowBytes, &key);
|
| + if (optionalKey.isValid()) {
|
| + result = ctx->createTexture(desc, pixels, rowBytes);
|
| if (result) {
|
| - add_genID_listener(key, bm.pixelRef());
|
| + SkAssertResult(ctx->addResourceToCache(optionalKey, result));
|
| }
|
| - } else {
|
| - // This texture is unlikely to be used again (in its present form) so
|
| - // just use a scratch texture. This will remove the texture from the
|
| - // cache so no one else can find it. Additionally, once unlocked, the
|
| - // scratch texture will go to the end of the list for purging so will
|
| - // likely be available for this volatile bitmap the next time around.
|
| + } else {
|
| result = ctx->refScratchTexture(desc, GrContext::kExact_ScratchTexMatch);
|
| - if (pixels) {
|
| - result->writePixels(0, 0, bm.width(), bm.height(), desc.fConfig, pixels, rowBytes);
|
| + if (pixels && result) {
|
| + result->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, pixels, rowBytes);
|
| }
|
| }
|
| return result;
|
| }
|
|
|
| +// creates a new texture that is the input texture scaled up to the next power of two in
|
| +// width or height. If optionalKey is valid it will be set on the new texture. stretch
|
| +// controls whether the scaling is done using nearest or bilerp filtering.
|
| +GrTexture* resize_texture(GrTexture* inputTexture, Stretch stretch,
|
| + const GrContentKey& optionalKey) {
|
| + SkASSERT(kNo_Stretch != stretch);
|
| +
|
| + GrContext* context = inputTexture->getContext();
|
| + SkASSERT(context);
|
| +
|
| + // 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 |
|
| + kNoStencil_GrSurfaceFlag;
|
| + rtDesc.fWidth = GrNextPow2(rtDesc.fWidth);
|
| + rtDesc.fHeight = GrNextPow2(rtDesc.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 (!context->isConfigRenderable(rtDesc.fConfig, false)) {
|
| + if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) {
|
| + if (context->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
|
| + rtDesc.fConfig = kAlpha_8_GrPixelConfig;
|
| + } else if (context->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
|
| + rtDesc.fConfig = kSkia8888_GrPixelConfig;
|
| + } else {
|
| + return NULL;
|
| + }
|
| + } else if (kRGB_GrColorComponentFlags ==
|
| + (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) {
|
| + if (context->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
|
| + rtDesc.fConfig = kSkia8888_GrPixelConfig;
|
| + } else {
|
| + return NULL;
|
| + }
|
| + } else {
|
| + return NULL;
|
| + }
|
| + }
|
| +
|
| + GrTexture* resized = create_texture_for_bmp(context, optionalKey, rtDesc, NULL, 0);
|
| +
|
| + if (!resized) {
|
| + return NULL;
|
| + }
|
| + 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,
|
| + kBilerp_Stretch == stretch ? 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);
|
| +
|
| + GrContext::AutoRenderTarget autoRT(context, resized->asRenderTarget());
|
| + GrContext::AutoClip ac(context, GrContext::AutoClip::kWideOpen_InitialClip);
|
| + context->drawNonAARectToRect(paint, SkMatrix::I(), rect, localRect);
|
| +
|
| + return resized;
|
| +}
|
| +
|
| #ifndef SK_IGNORE_ETC1_SUPPORT
|
| -static GrTexture *load_etc1_texture(GrContext* ctx, bool cache,
|
| - const GrTextureParams* params,
|
| +static GrTexture *load_etc1_texture(GrContext* ctx, const GrContentKey& optionalKey,
|
| const SkBitmap &bm, GrSurfaceDesc desc) {
|
| SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
|
|
|
| @@ -210,11 +310,11 @@ static GrTexture *load_etc1_texture(GrContext* ctx, bool cache,
|
| return NULL;
|
| }
|
|
|
| - return sk_gr_allocate_texture(ctx, cache, params, bm, desc, bytes, 0);
|
| + return create_texture_for_bmp(ctx, optionalKey, desc, bytes, 0);
|
| }
|
| #endif // SK_IGNORE_ETC1_SUPPORT
|
|
|
| -static GrTexture *load_yuv_texture(GrContext* ctx, bool cache, const GrTextureParams* params,
|
| +static GrTexture* load_yuv_texture(GrContext* ctx, const GrContentKey& optionalKey,
|
| const SkBitmap& bm, const GrSurfaceDesc& desc) {
|
| // Subsets are not supported, the whole pixelRef is loaded when using YUV decoding
|
| SkPixelRef* pixelRef = bm.pixelRef();
|
| @@ -282,30 +382,31 @@ static GrTexture *load_yuv_texture(GrContext* ctx, bool cache, const GrTexturePa
|
| kRenderTarget_GrSurfaceFlag |
|
| kNoStencil_GrSurfaceFlag;
|
|
|
| - GrTexture* result = sk_gr_allocate_texture(ctx, cache, params, bm, rtDesc, NULL, 0);
|
| -
|
| - GrRenderTarget* renderTarget = result ? result->asRenderTarget() : NULL;
|
| - if (renderTarget) {
|
| - SkAutoTUnref<GrFragmentProcessor> yuvToRgbProcessor(GrYUVtoRGBEffect::Create(
|
| - yuvTextures[0], yuvTextures[1], yuvTextures[2], yuvInfo.fColorSpace));
|
| - GrPaint paint;
|
| - paint.addColorProcessor(yuvToRgbProcessor);
|
| - SkRect r = SkRect::MakeWH(SkIntToScalar(yuvInfo.fSize[0].fWidth),
|
| - SkIntToScalar(yuvInfo.fSize[0].fHeight));
|
| - GrContext::AutoRenderTarget autoRT(ctx, renderTarget);
|
| - GrContext::AutoClip ac(ctx, GrContext::AutoClip::kWideOpen_InitialClip);
|
| - ctx->drawRect(paint, SkMatrix::I(), r);
|
| - } else {
|
| - SkSafeSetNull(result);
|
| + GrTexture* result = create_texture_for_bmp(ctx, optionalKey, rtDesc, NULL, 0);
|
| + if (!result) {
|
| + return NULL;
|
| }
|
|
|
| + GrRenderTarget* renderTarget = result->asRenderTarget();
|
| + SkASSERT(renderTarget);
|
| +
|
| + SkAutoTUnref<GrFragmentProcessor>
|
| + yuvToRgbProcessor(GrYUVtoRGBEffect::Create(yuvTextures[0], yuvTextures[1], yuvTextures[2],
|
| + yuvInfo.fColorSpace));
|
| + GrPaint paint;
|
| + paint.addColorProcessor(yuvToRgbProcessor);
|
| + SkRect r = SkRect::MakeWH(SkIntToScalar(yuvInfo.fSize[0].fWidth),
|
| + SkIntToScalar(yuvInfo.fSize[0].fHeight));
|
| + GrContext::AutoRenderTarget autoRT(ctx, renderTarget);
|
| + GrContext::AutoClip ac(ctx, GrContext::AutoClip::kWideOpen_InitialClip);
|
| + ctx->drawRect(paint, SkMatrix::I(), r);
|
| +
|
| return result;
|
| }
|
|
|
| -static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
|
| - bool cache,
|
| - const GrTextureParams* params,
|
| - const SkBitmap& origBitmap) {
|
| +static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
|
| + const SkBitmap& origBitmap,
|
| + const GrContentKey& optionalKey) {
|
| SkBitmap tmpBitmap;
|
|
|
| const SkBitmap* bitmap = &origBitmap;
|
| @@ -314,9 +415,7 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
|
| generate_bitmap_texture_desc(*bitmap, &desc);
|
|
|
| if (kIndex_8_SkColorType == bitmap->colorType()) {
|
| - // build_compressed_data doesn't do npot->pot expansion
|
| - // and paletted textures can't be sub-updated
|
| - if (cache && ctx->supportsIndex8PixelConfig(params, bitmap->width(), bitmap->height())) {
|
| + if (ctx->supportsIndex8PixelConfig()) {
|
| size_t imageSize = GrCompressedFormatDataSize(kIndex_8_GrPixelConfig,
|
| bitmap->width(), bitmap->height());
|
| SkAutoMalloc storage(imageSize);
|
| @@ -324,8 +423,7 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
|
|
|
| // our compressed data will be trimmed, so pass width() for its
|
| // "rowBytes", since they are the same now.
|
| - return sk_gr_allocate_texture(ctx, cache, params, origBitmap,
|
| - desc, storage.get(), bitmap->width());
|
| + return create_texture_for_bmp(ctx, optionalKey, desc, storage.get(), bitmap->width());
|
| } else {
|
| origBitmap.copyTo(&tmpBitmap, kN32_SkColorType);
|
| // now bitmap points to our temp, which has been promoted to 32bits
|
| @@ -339,7 +437,7 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
|
| else if (
|
| // We do not support scratch ETC1 textures, hence they should all be at least
|
| // trying to go to the cache.
|
| - cache
|
| + optionalKey.isValid()
|
| // Make sure that the underlying device supports ETC1 textures before we go ahead
|
| // and check the data.
|
| && ctx->getGpu()->caps()->isConfigTexturable(kETC1_GrPixelConfig)
|
| @@ -348,7 +446,7 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
|
| // the bitmap has available pixels, then they might not be what the decompressed
|
| // data is.
|
| && !(bitmap->readyToDraw())) {
|
| - GrTexture *texture = load_etc1_texture(ctx, cache, params, *bitmap, desc);
|
| + GrTexture *texture = load_etc1_texture(ctx, optionalKey, *bitmap, desc);
|
| if (texture) {
|
| return texture;
|
| }
|
| @@ -356,7 +454,7 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
|
| #endif // SK_IGNORE_ETC1_SUPPORT
|
|
|
| else {
|
| - GrTexture *texture = load_yuv_texture(ctx, cache, params, *bitmap, desc);
|
| + GrTexture *texture = load_yuv_texture(ctx, optionalKey, *bitmap, desc);
|
| if (texture) {
|
| return texture;
|
| }
|
| @@ -366,8 +464,32 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
|
| return NULL;
|
| }
|
|
|
| - return sk_gr_allocate_texture(ctx, cache, params, origBitmap, desc,
|
| - bitmap->getPixels(), bitmap->rowBytes());
|
| + return create_texture_for_bmp(ctx, optionalKey, desc, bitmap->getPixels(), bitmap->rowBytes());
|
| +}
|
| +
|
| +static GrTexture* create_bitmap_texture(GrContext* ctx,
|
| + const SkBitmap& bmp,
|
| + Stretch stretch,
|
| + const GrContentKey& unstretchedKey,
|
| + const GrContentKey& stretchedKey) {
|
| + if (kNo_Stretch != stretch) {
|
| + SkAutoTUnref<GrTexture> unstretched;
|
| + // Check if we have the unstretched version in the cache, if not create it.
|
| + if (unstretchedKey.isValid()) {
|
| + unstretched.reset(ctx->findAndRefCachedTexture(unstretchedKey));
|
| + }
|
| + if (!unstretched) {
|
| + unstretched.reset(create_unstretched_bitmap_texture(ctx, bmp, unstretchedKey));
|
| + if (!unstretched) {
|
| + return NULL;
|
| + }
|
| + }
|
| + GrTexture* resized = resize_texture(unstretched, stretch, stretchedKey);
|
| + return resized;
|
| + }
|
| +
|
| + return create_unstretched_bitmap_texture(ctx, bmp, unstretchedKey);
|
| +
|
| }
|
|
|
| static GrTexture* get_texture_backing_bmp(const SkBitmap& bitmap, const GrContext* context,
|
| @@ -393,12 +515,23 @@ bool GrIsBitmapInCache(const GrContext* ctx,
|
| return true;
|
| }
|
|
|
| - GrContentKey key;
|
| - generate_bitmap_key(bitmap, &key);
|
| + // We don't cache volatile bitmaps
|
| + if (bitmap.isVolatile()) {
|
| + return false;
|
| + }
|
| +
|
| + // If it is inherently texture backed, consider it in the cache
|
| + if (bitmap.getTexture()) {
|
| + return true;
|
| + }
|
| +
|
| + Stretch stretch = get_stretch_type(ctx, bitmap.width(), bitmap.height(), params);
|
| + GrContentKey key, resizedKey;
|
| + generate_bitmap_keys(bitmap, stretch, &key, &resizedKey);
|
|
|
| GrSurfaceDesc desc;
|
| generate_bitmap_texture_desc(bitmap, &desc);
|
| - return ctx->isTextureInCache(desc, key, params);
|
| + return ctx->isResourceInCache((kNo_Stretch == stretch) ? key : resizedKey);
|
| }
|
|
|
| GrTexture* GrRefCachedBitmapTexture(GrContext* ctx,
|
| @@ -409,29 +542,29 @@ GrTexture* GrRefCachedBitmapTexture(GrContext* ctx,
|
| return SkRef(result);
|
| }
|
|
|
| - bool cache = !bitmap.isVolatile();
|
| + Stretch stretch = get_stretch_type(ctx, bitmap.width(), bitmap.height(), params);
|
| + GrContentKey key, resizedKey;
|
|
|
| - if (cache) {
|
| + if (!bitmap.isVolatile()) {
|
| // If the bitmap isn't changing try to find a cached copy first.
|
| + generate_bitmap_keys(bitmap, stretch, &key, &resizedKey);
|
|
|
| - GrContentKey key;
|
| - generate_bitmap_key(bitmap, &key);
|
| -
|
| - GrSurfaceDesc desc;
|
| - generate_bitmap_texture_desc(bitmap, &desc);
|
| -
|
| - result = ctx->findAndRefTexture(desc, key, params);
|
| - }
|
| - if (NULL == result) {
|
| - result = sk_gr_create_bitmap_texture(ctx, cache, params, bitmap);
|
| + result = ctx->findAndRefCachedTexture(resizedKey.isValid() ? resizedKey : key);
|
| + if (result) {
|
| + return result;
|
| + }
|
| }
|
| - if (NULL == result) {
|
| - SkDebugf("---- failed to create texture for cache [%d %d]\n",
|
| - bitmap.width(), bitmap.height());
|
| +
|
| + result = create_bitmap_texture(ctx, bitmap, stretch, key, resizedKey);
|
| + if (result) {
|
| + return result;
|
| }
|
| - return result;
|
| -}
|
|
|
| + SkDebugf("---- failed to create texture for cache [%d %d]\n",
|
| + bitmap.width(), bitmap.height());
|
| +
|
| + return NULL;
|
| +}
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| // alphatype is ignore for now, but if GrPixelConfig is expanded to encompass
|
|
|