diff options
-rw-r--r-- | gm/image_pict.cpp | 90 | ||||
-rw-r--r-- | gyp/core.gypi | 1 | ||||
-rw-r--r-- | include/core/SkImageGenerator.h | 33 | ||||
-rw-r--r-- | include/core/SkImageInfo.h | 16 | ||||
-rw-r--r-- | include/core/SkPixelRef.h | 1 | ||||
-rw-r--r-- | include/gpu/SkGr.h | 1 | ||||
-rw-r--r-- | src/core/SkImageCacherator.cpp | 144 | ||||
-rw-r--r-- | src/core/SkImageCacherator.h | 51 | ||||
-rw-r--r-- | src/core/SkImageGenerator.cpp | 13 | ||||
-rw-r--r-- | src/core/SkPictureImageGenerator.cpp | 30 | ||||
-rw-r--r-- | src/gpu/SkGr.cpp | 76 | ||||
-rw-r--r-- | src/gpu/SkGrPriv.h | 32 |
12 files changed, 477 insertions, 11 deletions
diff --git a/gm/image_pict.cpp b/gm/image_pict.cpp index ce2d2ecb0c..dd1fab549a 100644 --- a/gm/image_pict.cpp +++ b/gm/image_pict.cpp @@ -8,10 +8,14 @@ #include "gm.h" #include "SkCanvas.h" #include "SkImage.h" +#include "SkImageCacherator.h" #include "SkPictureRecorder.h" +#include "SkSurface.h" #if SK_SUPPORT_GPU #include "GrContext.h" +#include "GrTexture.h" +#include "../src/image/SkImage_Gpu.h" #endif static void draw_something(SkCanvas* canvas, const SkRect& bounds) { @@ -94,3 +98,89 @@ private: }; DEF_GM( return new ImagePictGM; ) +/////////////////////////////////////////////////////////////////////////////////////////////////// + + +class ImageCacheratorGM : public skiagm::GM { + SkAutoTUnref<SkPicture> fPicture; + SkAutoTDelete<SkImageCacherator> fCache; + +public: + ImageCacheratorGM() {} + +protected: + SkString onShortName() override { + return SkString("image-cacherator"); + } + + SkISize onISize() override { + return SkISize::Make(850, 450); + } + + void onOnceBeforeDraw() override { + const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100); + SkPictureRecorder recorder; + draw_something(recorder.beginRecording(bounds), bounds); + fPicture.reset(recorder.endRecording()); + + // extract enough just for the oval. + const SkISize size = SkISize::Make(100, 100); + + SkMatrix matrix; + matrix.setTranslate(-100, -100); + fCache.reset(new SkImageCacherator(SkImageGenerator::NewFromPicture(size, + fPicture, + &matrix, + nullptr))); + } + + void drawSet(SkCanvas* canvas) const { + SkMatrix matrix = SkMatrix::MakeTrans(-100, -100); + canvas->drawPicture(fPicture, &matrix, nullptr); + + { + SkBitmap bitmap; + fCache->lockAsBitmap(&bitmap); + canvas->drawBitmap(bitmap, 150, 0); + } +#if SK_SUPPORT_GPU + { + SkAutoTUnref<GrTexture> texture(fCache->lockAsTexture(canvas->getGrContext(), + kUntiled_SkImageUsageType)); + if (!texture) { + return; + } + // No API to draw a GrTexture directly, so we cheat and create a private image subclass + SkAutoTUnref<SkImage> image(new SkImage_Gpu(100, 100, fCache->generator()->uniqueID(), + kPremul_SkAlphaType, texture, 0, + SkSurface::kNo_Budgeted)); + canvas->drawImage(image, 300, 0); + } +#endif + } + + void onDraw(SkCanvas* canvas) override { + canvas->translate(20, 20); + + this->drawSet(canvas); + + canvas->save(); + canvas->translate(0, 130); + canvas->scale(0.25f, 0.25f); + this->drawSet(canvas); + canvas->restore(); + + canvas->save(); + canvas->translate(0, 200); + canvas->scale(2, 2); + this->drawSet(canvas); + canvas->restore(); + } + +private: + typedef skiagm::GM INHERITED; +}; +DEF_GM( return new ImageCacheratorGM; ) + + + diff --git a/gyp/core.gypi b/gyp/core.gypi index d1ac89547f..26e8f70b6f 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -114,6 +114,7 @@ '<(skia_src_path)/core/SkHalf.h', '<(skia_src_path)/core/SkImageFilter.cpp', '<(skia_src_path)/core/SkImageInfo.cpp', + '<(skia_src_path)/core/SkImageCacherator.cpp', '<(skia_src_path)/core/SkImageGenerator.cpp', '<(skia_src_path)/core/SkLayerInfo.h', '<(skia_src_path)/core/SkLocalMatrixShader.cpp', diff --git a/include/core/SkImageGenerator.h b/include/core/SkImageGenerator.h index 83f36e09a7..d5885babd7 100644 --- a/include/core/SkImageGenerator.h +++ b/include/core/SkImageGenerator.h @@ -11,8 +11,10 @@ #include "SkColor.h" #include "SkImageInfo.h" +class GrContext; class SkBitmap; class SkData; +class GrTexture; class SkImageGenerator; class SkMatrix; class SkPaint; @@ -56,6 +58,8 @@ public: */ virtual ~SkImageGenerator() { } + uint32_t uniqueID() const { return fUniqueID; } + /** * Return a ref to the encoded (i.e. compressed) representation, * of this data. @@ -123,6 +127,30 @@ public: SkYUVColorSpace* colorSpace); /** + * If the generator can natively/efficiently return its pixels as a GPU image (backed by a + * texture) this will return that image. If not, this will return NULL. + * + * Regarding the GrContext parameter: + * + * The caller may pass NULL for the context. In that case the generator may assume that its + * internal context is current. If it has no internal context, then it should just return + * null. + * + * If the caller passes a non-null context, then the generator should only succeed if: + * - it has no intrinsic context, and will use the caller's + * - its internal context is the same + * - it can somehow convert its texture into one that is valid for the provided context. + * + * Regarding the SkImageUsageType parameter: + * + * If the context (the provided one or the generator's intrinsic one) determines that to + * support the specified usage, it must return a different sized texture (from the generator's + * native size) it may, so the caller must inspect the texture's width/height + * (unless kUntiled_SkImageUsedType was specified). + */ + GrTexture* generateTexture(GrContext*, SkImageUsageType); + + /** * If the default image decoder system can interpret the specified (encoded) data, then * this returns a new ImageGenerator for it. Otherwise this returns NULL. Either way * the caller is still responsible for managing their ownership of the data. @@ -138,7 +166,7 @@ public: const SkPaint*); protected: - SkImageGenerator(const SkImageInfo& info) : fInfo(info) {} + SkImageGenerator(const SkImageInfo& info); virtual SkData* onRefEncodedData(); @@ -148,8 +176,11 @@ protected: virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], SkYUVColorSpace* colorSpace); + virtual GrTexture* onGenerateTexture(GrContext*, SkImageUsageType) { return nullptr; } + private: const SkImageInfo fInfo; + const uint32_t fUniqueID; // This is our default impl, which may be different on different platforms. // It is called from NewFromEncoded() after it has checked for any runtime factory. diff --git a/include/core/SkImageInfo.h b/include/core/SkImageInfo.h index 459a0ee43e..7b48c3a430 100644 --- a/include/core/SkImageInfo.h +++ b/include/core/SkImageInfo.h @@ -16,6 +16,22 @@ class SkReadBuffer; class SkWriteBuffer; /** + * This enum provides information about "how" an image will be used. For older GPUs that do not + * support non-power-of-2 tiling, some routines need to know this information before they create + * a texture. + */ +enum SkImageUsageType { + /* Image will not be tiled (regardless of filtering) */ + kUntiled_SkImageUsageType, + + /* Image will be tiled, but not filtered */ + kTiled_Unfiltered_SkImageUsageType, + + /* Image will be tiled and filtered */ + kTiled_Filtered_SkImageUsageType, +}; + +/** * Describes how to interpret the alpha compoent of a pixel. */ enum SkAlphaType { diff --git a/include/core/SkPixelRef.h b/include/core/SkPixelRef.h index 0ed3099126..98153b7e08 100644 --- a/include/core/SkPixelRef.h +++ b/include/core/SkPixelRef.h @@ -381,6 +381,7 @@ private: void setImmutableWithID(uint32_t genID); friend class SkImage_Gpu; + friend class SkImageCacherator; typedef SkRefCnt INHERITED; }; diff --git a/include/gpu/SkGr.h b/include/gpu/SkGr.h index e46479eb0f..db318b0b4c 100644 --- a/include/gpu/SkGr.h +++ b/include/gpu/SkGr.h @@ -72,6 +72,7 @@ static inline GrColor SkColor2GrColorJustAlpha(SkColor c) { bool GrIsBitmapInCache(const GrContext*, const SkBitmap&, const GrTextureParams*); GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams*); +GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, SkImageUsageType); //////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/SkImageCacherator.cpp b/src/core/SkImageCacherator.cpp new file mode 100644 index 0000000000..b225612a17 --- /dev/null +++ b/src/core/SkImageCacherator.cpp @@ -0,0 +1,144 @@ +/* + * 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 "SkBitmap.h" +#include "SkBitmapCache.h" +#include "SkImageCacherator.h" +#include "SkPixelRef.h" + +#if SK_SUPPORT_GPU +#include "GrContext.h" +#include "GrGpuResourcePriv.h" +#include "GrResourceKey.h" +#include "GrTextureAccess.h" +#include "SkGr.h" +#include "SkGrPriv.h" +#endif + +SkImageCacherator::SkImageCacherator(SkImageGenerator* gen) : fGenerator(gen) {} + +SkImageCacherator::~SkImageCacherator() { + delete fGenerator; +} + +static bool check_output_bitmap(const SkBitmap& bitmap, uint32_t expectedID) { + SkASSERT(bitmap.getGenerationID() == expectedID); + SkASSERT(bitmap.isImmutable()); + SkASSERT(bitmap.getPixels()); + return true; +} + +static bool generate_bitmap(SkImageGenerator* generator, SkBitmap* bitmap) { + if (!bitmap->tryAllocPixels(generator->getInfo()) || + !generator->getPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes())) + { + bitmap->reset(); + return false; + } + return true; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + +bool SkImageCacherator::tryLockAsBitmap(SkBitmap* bitmap) { + const uint32_t uniqueID = fGenerator->uniqueID(); + + if (SkBitmapCache::Find(uniqueID, bitmap)) { + return check_output_bitmap(*bitmap, uniqueID); + } + if (!generate_bitmap(fGenerator, bitmap)) { + return false; + } + + bitmap->pixelRef()->setImmutableWithID(uniqueID); + SkBitmapCache::Add(uniqueID, *bitmap); + return true; +} + +bool SkImageCacherator::lockAsBitmap(SkBitmap* bitmap) { + const uint32_t uniqueID = fGenerator->uniqueID(); + + if (this->tryLockAsBitmap(bitmap)) { + return check_output_bitmap(*bitmap, uniqueID); + } + +#if SK_SUPPORT_GPU + // Try to get a texture and read it back to raster (and then cache that with our ID) + + SkAutoTUnref<GrTexture> tex(fGenerator->generateTexture(nullptr, kUntiled_SkImageUsageType)); + if (!tex) { + bitmap->reset(); + return false; + } + + const SkImageInfo& info = this->info(); + if (!bitmap->tryAllocPixels(info)) { + bitmap->reset(); + return false; + } + + const uint32_t pixelOpsFlags = 0; + if (!tex->readPixels(0, 0, bitmap->width(), bitmap->height(), SkImageInfo2GrPixelConfig(info), + bitmap->getPixels(), bitmap->rowBytes(), pixelOpsFlags)) { + bitmap->reset(); + return false; + } + + bitmap->pixelRef()->setImmutableWithID(uniqueID); + SkBitmapCache::Add(uniqueID, *bitmap); + return check_output_bitmap(*bitmap, uniqueID); +#else + return false; +#endif +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + +GrTexture* SkImageCacherator::tryLockAsTexture(GrContext* ctx, SkImageUsageType usage) { +#if SK_SUPPORT_GPU + const uint32_t uniqueID = fGenerator->uniqueID(); + const SkImageInfo& info = this->info(); + + GrUniqueKey key; + GrMakeKeyFromImageID(&key, uniqueID, info.width(), info.height(), SkIPoint::Make(0, 0), + *ctx->caps(), usage); + GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key); + if (tex) { + return tex; // we got a cache hit! + } + + tex = fGenerator->generateTexture(ctx, usage); + if (tex) { + tex->resourcePriv().setUniqueKey(key); + } + return tex; +#else + return nullptr; +#endif +} + +GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, SkImageUsageType usage) { +#if SK_SUPPORT_GPU + if (!ctx) { + return nullptr; + } + if (GrTexture* tex = this->tryLockAsTexture(ctx, usage)) { + return tex; + } + + // Try to get a bitmap and then upload/cache it as a texture + + SkBitmap bitmap; + if (!generate_bitmap(fGenerator, &bitmap)) { + return nullptr; + } + return GrRefCachedBitmapTexture(ctx, bitmap, usage); +#else + return nullptr; +#endif +} + diff --git a/src/core/SkImageCacherator.h b/src/core/SkImageCacherator.h new file mode 100644 index 0000000000..86dbd8874f --- /dev/null +++ b/src/core/SkImageCacherator.h @@ -0,0 +1,51 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageCacherator_DEFINED +#define SkImageCacherator_DEFINED + +#include "SkImageGenerator.h" + +class GrContext; +class SkBitmap; + +/* + * Internal class to manage caching the output of an ImageGenerator. + */ +class SkImageCacherator { +public: + // Takes ownership of the generator + SkImageCacherator(SkImageGenerator* gen); + ~SkImageCacherator(); + + const SkImageInfo& info() const { return fGenerator->getInfo(); } + SkImageGenerator* generator() const { return fGenerator; } + + /** + * On success (true), bitmap will point to the pixels for this generator. If this returns + * false, the bitmap will be reset to empty. + * + * The cached bitmap is valid until it goes out of scope. + */ + bool lockAsBitmap(SkBitmap*); + + /** + * Returns a ref() on the texture produced by this generator. The caller must call unref() + * when it is done. Will return NULL on failure. + * + * The cached texture is valid until it is unref'd. + */ + GrTexture* lockAsTexture(GrContext*, SkImageUsageType); + +private: + bool tryLockAsBitmap(SkBitmap*); + GrTexture* tryLockAsTexture(GrContext*, SkImageUsageType); + + SkImageGenerator* fGenerator; +}; + +#endif diff --git a/src/core/SkImageGenerator.cpp b/src/core/SkImageGenerator.cpp index 82b42d7a97..d42ece828a 100644 --- a/src/core/SkImageGenerator.cpp +++ b/src/core/SkImageGenerator.cpp @@ -6,6 +6,12 @@ */ #include "SkImageGenerator.h" +#include "SkNextID.h" + +SkImageGenerator::SkImageGenerator(const SkImageInfo& info) + : fInfo(info) + , fUniqueID(SkNextID::ImageID()) +{} bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) { @@ -98,6 +104,13 @@ bool SkImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t return this->onGetYUV8Planes(sizes, planes, rowBytes); } +GrTexture* SkImageGenerator::generateTexture(GrContext* ctx, SkImageUsageType usage) { + if (!ctx) { + return nullptr; + } + return this->onGenerateTexture(ctx, usage); +} + ///////////////////////////////////////////////////////////////////////////////////////////// SkData* SkImageGenerator::onRefEncodedData() { diff --git a/src/core/SkPictureImageGenerator.cpp b/src/core/SkPictureImageGenerator.cpp index 6c3faef250..f92de3b986 100644 --- a/src/core/SkPictureImageGenerator.cpp +++ b/src/core/SkPictureImageGenerator.cpp @@ -6,11 +6,11 @@ */ #include "SkImageGenerator.h" - #include "SkCanvas.h" #include "SkMatrix.h" #include "SkPaint.h" #include "SkPicture.h" +#include "SkSurface.h" #include "SkTLazy.h" class SkPictureImageGenerator : SkImageGenerator { @@ -21,6 +21,9 @@ public: protected: bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) override; +#if SK_SUPPORT_GPU + GrTexture* onGenerateTexture(GrContext*, SkImageUsageType) override; +#endif private: SkPictureImageGenerator(const SkISize&, const SkPicture*, const SkMatrix*, const SkPaint*); @@ -79,3 +82,28 @@ SkImageGenerator* SkImageGenerator::NewFromPicture(const SkISize& size, const Sk const SkMatrix* matrix, const SkPaint* paint) { return SkPictureImageGenerator::Create(size, picture, matrix, paint); } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#if SK_SUPPORT_GPU +#include "GrTexture.h" + +GrTexture* SkPictureImageGenerator::onGenerateTexture(GrContext* ctx, SkImageUsageType usage) { + // + // TODO: respect the usage, by possibly creating a different (pow2) surface + // + SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(ctx, + SkSurface::kYes_Budgeted, + this->getInfo())); + if (!surface.get()) { + return nullptr; + } + surface->getCanvas()->clear(0); // does NewRenderTarget promise to do this for us? + surface->getCanvas()->drawPicture(fPicture, &fMatrix, fPaint.getMaybeNull()); + SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); + if (!image.get()) { + return nullptr; + } + return SkSafeRef(image->getTexture()); +} +#endif diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index 53f640b601..6c1ec4bed0 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -143,7 +143,7 @@ static bool make_stretched_key(const GrUniqueKey& origKey, const Stretch& stretc uint32_t width = SkToU16(stretch.fWidth); uint32_t height = SkToU16(stretch.fHeight); static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey::Builder builder(stretchedKey, origKey, kDomain, 3); + GrUniqueKey::Builder builder(stretchedKey, origKey, kDomain, 2); builder[0] = stretch.fType; builder[1] = width | (height << 16); builder.finish(); @@ -153,22 +153,55 @@ static bool make_stretched_key(const GrUniqueKey& origKey, const Stretch& stretc return false; } -static void make_unstretched_key(const SkBitmap& bitmap, GrUniqueKey* key) { - // Our id includes the offset, width, and height so that bitmaps created by extractSubset() - // are unique. - uint32_t genID = bitmap.getGenerationID(); - SkIPoint origin = bitmap.pixelRefOrigin(); - uint32_t width = SkToU16(bitmap.width()); - uint32_t height = SkToU16(bitmap.height()); +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 const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey::Builder builder(key, kDomain, 4); - builder[0] = genID; + builder[0] = imageID; builder[1] = origin.fX; builder[2] = origin.fY; builder[3] = width | (height << 16); } +void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, + U16CPU width, U16CPU height, SkIPoint origin, + const GrCaps& caps, SkImageUsageType usage) { + const Stretch::Type stretches[] = { + Stretch::kNone_Type, // kUntiled_SkImageUsageType + Stretch::kNearest_Type, // kTiled_Unfiltered_SkImageUsageType + Stretch::kBilerp_Type, // kTiled_Filtered_SkImageUsageType + }; + + const bool isPow2 = SkIsPow2(width) && SkIsPow2(height); + const bool needToStretch = !isPow2 && + usage != kUntiled_SkImageUsageType && + !caps.npotTextureTileSupport(); + + if (needToStretch) { + GrUniqueKey tmpKey; + make_unstretched_key(&tmpKey, imageID, width, height, origin); + + Stretch stretch; + stretch.fType = stretches[usage]; + stretch.fWidth = SkNextPow2(width); + stretch.fHeight = SkNextPow2(height); + if (!make_stretched_key(tmpKey, stretch, key)) { + goto UNSTRETCHED; + } + } else { + UNSTRETCHED: + make_unstretched_key(key, imageID, width, height, origin); + } +} + +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, @@ -649,6 +682,31 @@ GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, return NULL; } + +// TODO: make this be the canonical signature, and turn the version that takes GrTextureParams* +// into a wrapper that contains the inverse of these tables. +GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, + const SkBitmap& bitmap, + SkImageUsageType usage) { + // Just need a params that will trigger the correct cache key / etc, since the usage doesn't + // tell us the specifics about filter level or specific tiling. + + const SkShader::TileMode tiles[] = { + SkShader::kClamp_TileMode, // kUntiled_SkImageUsageType + SkShader::kRepeat_TileMode, // kTiled_Unfiltered_SkImageUsageType + SkShader::kRepeat_TileMode, // kTiled_Filtered_SkImageUsageType + }; + + const GrTextureParams::FilterMode filters[] = { + GrTextureParams::kNone_FilterMode, // kUntiled_SkImageUsageType + GrTextureParams::kNone_FilterMode, // kTiled_Unfiltered_SkImageUsageType + GrTextureParams::kBilerp_FilterMode, // kTiled_Filtered_SkImageUsageType + }; + + GrTextureParams params(tiles[usage], filters[usage]); + return GrRefCachedBitmapTexture(ctx, bitmap, ¶ms); +} + /////////////////////////////////////////////////////////////////////////////// // alphatype is ignore for now, but if GrPixelConfig is expanded to encompass diff --git a/src/gpu/SkGrPriv.h b/src/gpu/SkGrPriv.h new file mode 100644 index 0000000000..4688adb045 --- /dev/null +++ b/src/gpu/SkGrPriv.h @@ -0,0 +1,32 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkGrPriv_DEFINED +#define SkGrPriv_DEFINED + +#include "GrTypes.h" +#include "SkPoint.h" + +class GrCaps; +class GrUniqueKey; + +/** + * Our key includes the offset, width, and height so that bitmaps created by extractSubset() + * are unique. + * + * The imageID is in the shared namespace (see SkNextID::ImageID() + * - SkBitmap/SkPixelRef + * - SkImage + * - SkImageGenerator + * + * Note: width/height must fit in 16bits for this impl. + */ +void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, + U16CPU width, U16CPU height, SkIPoint origin, + const GrCaps&, SkImageUsageType); + +#endif |