diff options
author | 2015-01-31 19:27:53 -0800 | |
---|---|---|
committer | 2015-01-31 19:27:53 -0800 | |
commit | 6c96672491b04cb782bce8fee778124df66524a0 (patch) | |
tree | 49407e533766dad8d3fae3c5794afc4536a79098 /src/gpu/SkGr.cpp | |
parent | 0b737c52a7b8bc6ba41d309e88b3f7e995746f8d (diff) |
Move npot resizing out of GrContext and simplify GrContext texture functions.
Committed: https://skia.googlesource.com/skia/+/8a8100349105c8c6de39fcb34e47679da7a67f54
Review URL: https://codereview.chromium.org/882223003
Diffstat (limited to 'src/gpu/SkGr.cpp')
-rw-r--r-- | src/gpu/SkGr.cpp | 282 |
1 files changed, 210 insertions, 72 deletions
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index 9083860db8..f4bd319a32 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,106 @@ 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 + +// 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 = context->getGpu()->createTexture(rtDesc, true, 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); + + if (optionalKey.isValid()) { + SkAssertResult(context->addResourceToCache(optionalKey, resized)); + } + + return resized; +} static GrTexture* sk_gr_allocate_texture(GrContext* ctx, - bool cache, - const GrTextureParams* params, - const SkBitmap& bm, + 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; } #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 +315,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 sk_gr_allocate_texture(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& key, 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 +387,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 = ctx->createTexture(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 +420,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 +428,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 sk_gr_allocate_texture(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 +442,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 +451,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 +459,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 +469,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 sk_gr_allocate_texture(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 +520,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 +547,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 |