diff options
-rw-r--r-- | gm/image_pict.cpp | 171 | ||||
-rw-r--r-- | include/core/SkImageGenerator.h | 6 | ||||
-rw-r--r-- | src/core/SkImageCacherator.cpp | 110 | ||||
-rw-r--r-- | src/core/SkImageCacherator.h | 13 | ||||
-rw-r--r-- | src/core/SkImageGenerator.cpp | 7 | ||||
-rw-r--r-- | src/core/SkPictureImageGenerator.cpp | 17 |
6 files changed, 250 insertions, 74 deletions
diff --git a/gm/image_pict.cpp b/gm/image_pict.cpp index a8abea32b3..010173974e 100644 --- a/gm/image_pict.cpp +++ b/gm/image_pict.cpp @@ -100,17 +100,102 @@ DEF_GM( return new ImagePictGM; ) /////////////////////////////////////////////////////////////////////////////////////////////////// +static SkImageGenerator* make_pic_generator(GrContext*, SkPicture* pic) { + SkMatrix matrix; + matrix.setTranslate(-100, -100); + return SkImageGenerator::NewFromPicture(SkISize::Make(100, 100), pic, &matrix, nullptr); +} + +class RasterGenerator : public SkImageGenerator { +public: + RasterGenerator(const SkBitmap& bm) : SkImageGenerator(bm.info()), fBM(bm) {} +protected: + bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, + SkPMColor*, int*) override { + return fBM.readPixels(info, pixels, rowBytes, 0, 0); + } +private: + SkBitmap fBM; +}; +static SkImageGenerator* make_ras_generator(GrContext*, SkPicture* pic) { + SkBitmap bm; + bm.allocN32Pixels(100, 100); + SkCanvas canvas(bm); + canvas.clear(0); + canvas.translate(-100, -100); + canvas.drawPicture(pic); + return new RasterGenerator(bm); +} + +class EmptyGenerator : public SkImageGenerator { +public: + EmptyGenerator(const SkImageInfo& info) : SkImageGenerator(info) {} +}; + +#if SK_SUPPORT_GPU +class TextureGenerator : public SkImageGenerator { +public: + TextureGenerator(GrContext* ctx, const SkImageInfo& info, SkPicture* pic) + : SkImageGenerator(info) + , fCtx(SkRef(ctx)) + { + SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(ctx, SkSurface::kNo_Budgeted, + info, 0)); + surface->getCanvas()->clear(0); + surface->getCanvas()->translate(-100, -100); + surface->getCanvas()->drawPicture(pic); + SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); + fTexture.reset(SkRef(image->getTexture())); + } +protected: + GrTexture* onGenerateTexture(GrContext* ctx, SkImageUsageType, const SkIRect* subset) override { + if (ctx) { + SkASSERT(ctx == fCtx.get()); + } + + if (!subset) { + return SkRef(fTexture.get()); + } + // need to copy the subset into a new texture + GrSurfaceDesc desc = fTexture->desc(); + desc.fWidth = subset->width(); + desc.fHeight = subset->height(); + + GrTexture* dst = fCtx->textureProvider()->createTexture(desc, false); + fCtx->copySurface(dst, fTexture, *subset, SkIPoint::Make(0, 0)); + return dst; + } +private: + SkAutoTUnref<GrContext> fCtx; + SkAutoTUnref<GrTexture> fTexture; +}; +static SkImageGenerator* make_tex_generator(GrContext* ctx, SkPicture* pic) { + const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); + + if (!ctx) { + return new EmptyGenerator(info); + } + return new TextureGenerator(ctx, info, pic); +} +#endif class ImageCacheratorGM : public skiagm::GM { - SkAutoTUnref<SkPicture> fPicture; + SkString fName; + SkImageGenerator* (*fFactory)(GrContext*, SkPicture*); + SkAutoTUnref<SkPicture> fPicture; SkAutoTDelete<SkImageCacherator> fCache; + SkAutoTDelete<SkImageCacherator> fCacheSubset; public: - ImageCacheratorGM() {} + ImageCacheratorGM(const char suffix[], SkImageGenerator* (*factory)(GrContext*, SkPicture*)) + : fFactory(factory) + { + fName.printf("image-cacherator-from-%s", suffix); + } protected: SkString onShortName() override { - return SkString("image-cacherator"); + return fName; } SkISize onISize() override { @@ -122,42 +207,66 @@ protected: 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); - auto gen = SkImageGenerator::NewFromPicture(size, fPicture, &matrix, nullptr); + void makeCaches(GrContext* ctx) { + auto gen = fFactory(ctx, fPicture); + SkDEBUGCODE(const uint32_t genID = gen->uniqueID();) fCache.reset(SkImageCacherator::NewFromGenerator(gen)); + + const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100); + + gen = fFactory(ctx, fPicture); + SkDEBUGCODE(const uint32_t genSubsetID = gen->uniqueID();) + fCacheSubset.reset(SkImageCacherator::NewFromGenerator(gen, &subset)); + + // whole caches should have the same ID as the generator. Subsets should be diff + SkASSERT(fCache->uniqueID() == genID); + SkASSERT(fCacheSubset->uniqueID() != genID); + SkASSERT(fCacheSubset->uniqueID() != genSubsetID); + + SkASSERT(fCache->info().dimensions() == SkISize::Make(100, 100)); + SkASSERT(fCacheSubset->info().dimensions() == SkISize::Make(50, 50)); } - void drawSet(SkCanvas* canvas) const { - SkMatrix matrix = SkMatrix::MakeTrans(-100, -100); - canvas->drawPicture(fPicture, &matrix, nullptr); + static void draw_as_bitmap(SkCanvas* canvas, SkImageCacherator* cache, SkScalar x, SkScalar y) { + SkBitmap bitmap; + cache->lockAsBitmap(&bitmap); + canvas->drawBitmap(bitmap, x, y); + } - { - SkBitmap bitmap; - fCache->lockAsBitmap(&bitmap); - canvas->drawBitmap(bitmap, 150, 0); - } + static void draw_as_tex(SkCanvas* canvas, SkImageCacherator* cache, SkScalar x, SkScalar y) { #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); + SkAutoTUnref<GrTexture> texture(cache->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(cache->info().width(), cache->info().height(), + cache->uniqueID(), kPremul_SkAlphaType, texture, + 0, SkSurface::kNo_Budgeted)); + canvas->drawImage(image, x, y); #endif } + void drawSet(SkCanvas* canvas) const { + SkMatrix matrix = SkMatrix::MakeTrans(-100, -100); + canvas->drawPicture(fPicture, &matrix, nullptr); + + // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This + // way we also can force the generateTexture call. + + draw_as_tex(canvas, fCache, 310, 0); + draw_as_tex(canvas, fCacheSubset, 310+101, 0); + + draw_as_bitmap(canvas, fCache, 150, 0); + draw_as_bitmap(canvas, fCacheSubset, 150+101, 0); + } + void onDraw(SkCanvas* canvas) override { + this->makeCaches(canvas->getGrContext()); + canvas->translate(20, 20); this->drawSet(canvas); @@ -178,7 +287,11 @@ protected: private: typedef skiagm::GM INHERITED; }; -DEF_GM( return new ImageCacheratorGM; ) +DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator); ) +DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator); ) +#if SK_SUPPORT_GPU + DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator); ) +#endif diff --git a/include/core/SkImageGenerator.h b/include/core/SkImageGenerator.h index aa9a6d1157..c84463def2 100644 --- a/include/core/SkImageGenerator.h +++ b/include/core/SkImageGenerator.h @@ -148,7 +148,7 @@ public: * so the caller must inspect the texture's width/height and compare them to the generator's * getInfo() width/height. */ - GrTexture* generateTexture(GrContext*, SkImageUsageType); + GrTexture* generateTexture(GrContext*, SkImageUsageType, const SkIRect* subset = nullptr); /** * If the default image decoder system can interpret the specified (encoded) data, then @@ -176,7 +176,9 @@ protected: virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], SkYUVColorSpace* colorSpace); - virtual GrTexture* onGenerateTexture(GrContext*, SkImageUsageType) { return nullptr; } + virtual GrTexture* onGenerateTexture(GrContext*, SkImageUsageType, const SkIRect*) { + return nullptr; + } private: const SkImageInfo fInfo; diff --git a/src/core/SkImageCacherator.cpp b/src/core/SkImageCacherator.cpp index 1f481d0000..863cc11b1d 100644 --- a/src/core/SkImageCacherator.cpp +++ b/src/core/SkImageCacherator.cpp @@ -8,6 +8,8 @@ #include "SkBitmap.h" #include "SkBitmapCache.h" #include "SkImageCacherator.h" +#include "SkMallocPixelRef.h" +#include "SkNextID.h" #include "SkPixelRef.h" #if SK_SUPPORT_GPU @@ -19,14 +21,43 @@ #include "SkGrPriv.h" #endif -SkImageCacherator* SkImageCacherator::NewFromGenerator(SkImageGenerator* gen) { +SkImageCacherator* SkImageCacherator::NewFromGenerator(SkImageGenerator* gen, + const SkIRect* subset) { if (!gen) { return nullptr; } - return SkNEW_ARGS(SkImageCacherator, (gen)); + const SkImageInfo& info = gen->getInfo(); + if (info.isEmpty()) { + return nullptr; + } + + uint32_t uniqueID = gen->uniqueID(); + const SkIRect bounds = SkIRect::MakeWH(info.width(), info.height()); + if (subset) { + if (!bounds.contains(*subset)) { + return nullptr; + } + if (*subset != bounds) { + // we need a different uniqueID since we really are a subset of the raw generator + uniqueID = SkNextID::ImageID(); + } + } else { + subset = &bounds; + } + + return SkNEW_ARGS(SkImageCacherator, (gen, + gen->getInfo().makeWH(subset->width(), subset->height()), + SkIPoint::Make(subset->x(), subset->y()), + uniqueID)); } -SkImageCacherator::SkImageCacherator(SkImageGenerator* gen) : fGenerator(gen) {} +SkImageCacherator::SkImageCacherator(SkImageGenerator* gen, const SkImageInfo& info, + const SkIPoint& origin, uint32_t uniqueID) + : fGenerator(gen) + , fInfo(info) + , fOrigin(origin) + , fUniqueID(uniqueID) +{} SkImageCacherator::~SkImageCacherator() { SkDELETE(fGenerator); @@ -39,65 +70,84 @@ static bool check_output_bitmap(const SkBitmap& bitmap, uint32_t expectedID) { 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(); +static bool generate_bitmap(SkBitmap* bitmap, const SkImageInfo& info, const SkIPoint& origin, + SkImageGenerator* generator) { + const size_t rowBytes = info.minRowBytes(); + if (!bitmap->tryAllocPixels(info, rowBytes)) { return false; } + SkASSERT(bitmap->rowBytes() == rowBytes); + + const SkImageInfo& genInfo = generator->getInfo(); + if (info.dimensions() == genInfo.dimensions()) { + SkASSERT(origin.x() == 0 && origin.y() == 0); + // fast-case, no copy needed + if (!generator->getPixels(bitmap->info(), bitmap->getPixels(), rowBytes)) { + bitmap->reset(); + return false; + } + } else { + // need to handle subsetting + SkBitmap full; + if (!full.tryAllocPixels(genInfo)) { + return false; + } + if (!generator->getPixels(full.info(), full.getPixels(), full.rowBytes())) { + bitmap->reset(); + return false; + } + full.readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), + origin.x(), origin.y()); + } 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 (SkBitmapCache::Find(fUniqueID, bitmap)) { + return check_output_bitmap(*bitmap, fUniqueID); } - if (!generate_bitmap(fGenerator, bitmap)) { + if (!generate_bitmap(bitmap, fInfo, fOrigin, fGenerator)) { return false; } - bitmap->pixelRef()->setImmutableWithID(uniqueID); - SkBitmapCache::Add(uniqueID, *bitmap); + bitmap->pixelRef()->setImmutableWithID(fUniqueID); + SkBitmapCache::Add(fUniqueID, *bitmap); return true; } bool SkImageCacherator::lockAsBitmap(SkBitmap* bitmap) { - const uint32_t uniqueID = fGenerator->uniqueID(); - if (this->tryLockAsBitmap(bitmap)) { - return check_output_bitmap(*bitmap, uniqueID); + return check_output_bitmap(*bitmap, fUniqueID); } #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)); + SkIRect subset = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), fInfo.width(), fInfo.height()); + SkAutoTUnref<GrTexture> tex(fGenerator->generateTexture(nullptr, kUntiled_SkImageUsageType, + &subset)); if (!tex) { bitmap->reset(); return false; } - const SkImageInfo& info = this->info(); - if (!bitmap->tryAllocPixels(info)) { + if (!bitmap->tryAllocPixels(fInfo)) { bitmap->reset(); return false; } const uint32_t pixelOpsFlags = 0; - if (!tex->readPixels(0, 0, bitmap->width(), bitmap->height(), SkImageInfo2GrPixelConfig(info), + if (!tex->readPixels(0, 0, bitmap->width(), bitmap->height(), SkImageInfo2GrPixelConfig(fInfo), bitmap->getPixels(), bitmap->rowBytes(), pixelOpsFlags)) { bitmap->reset(); return false; } - bitmap->pixelRef()->setImmutableWithID(uniqueID); - SkBitmapCache::Add(uniqueID, *bitmap); - return check_output_bitmap(*bitmap, uniqueID); + bitmap->pixelRef()->setImmutableWithID(fUniqueID); + SkBitmapCache::Add(fUniqueID, *bitmap); + return check_output_bitmap(*bitmap, fUniqueID); #else return false; #endif @@ -107,18 +157,16 @@ bool SkImageCacherator::lockAsBitmap(SkBitmap* bitmap) { 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), + GrMakeKeyFromImageID(&key, fUniqueID, fInfo.width(), fInfo.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); + SkIRect subset = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), fInfo.width(), fInfo.height()); + tex = fGenerator->generateTexture(ctx, usage, &subset); if (tex) { tex->resourcePriv().setUniqueKey(key); } @@ -140,7 +188,7 @@ GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, SkImageUsageType usa // Try to get a bitmap and then upload/cache it as a texture SkBitmap bitmap; - if (!generate_bitmap(fGenerator, &bitmap)) { + if (!generate_bitmap(&bitmap, fInfo, fOrigin, fGenerator)) { return nullptr; } return GrRefCachedBitmapTexture(ctx, bitmap, usage); diff --git a/src/core/SkImageCacherator.h b/src/core/SkImageCacherator.h index 2403a50a04..f05147e571 100644 --- a/src/core/SkImageCacherator.h +++ b/src/core/SkImageCacherator.h @@ -19,12 +19,12 @@ class SkBitmap; class SkImageCacherator { public: // Takes ownership of the generator - static SkImageCacherator* NewFromGenerator(SkImageGenerator*); + static SkImageCacherator* NewFromGenerator(SkImageGenerator*, const SkIRect* subset = nullptr); ~SkImageCacherator(); - const SkImageInfo& info() const { return fGenerator->getInfo(); } - SkImageGenerator* generator() const { return fGenerator; } + const SkImageInfo& info() const { return fInfo; } + uint32_t uniqueID() const { return fUniqueID; } /** * On success (true), bitmap will point to the pixels for this generator. If this returns @@ -41,12 +41,15 @@ public: GrTexture* lockAsTexture(GrContext*, SkImageUsageType); private: - SkImageCacherator(SkImageGenerator* gen); + SkImageCacherator(SkImageGenerator*, const SkImageInfo&, const SkIPoint&, uint32_t uniqueID); bool tryLockAsBitmap(SkBitmap*); GrTexture* tryLockAsTexture(GrContext*, SkImageUsageType); - SkImageGenerator* fGenerator; + SkImageGenerator* fGenerator; + const SkImageInfo fInfo; + const SkIPoint fOrigin; + const uint32_t fUniqueID; }; #endif diff --git a/src/core/SkImageGenerator.cpp b/src/core/SkImageGenerator.cpp index d42ece828a..ffccb611d8 100644 --- a/src/core/SkImageGenerator.cpp +++ b/src/core/SkImageGenerator.cpp @@ -104,11 +104,12 @@ 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) { +GrTexture* SkImageGenerator::generateTexture(GrContext* ctx, SkImageUsageType usage, + const SkIRect* subset) { + if (subset && !SkIRect::MakeWH(fInfo.width(), fInfo.height()).contains(*subset)) { return nullptr; } - return this->onGenerateTexture(ctx, usage); + return this->onGenerateTexture(ctx, usage, subset); } ///////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/SkPictureImageGenerator.cpp b/src/core/SkPictureImageGenerator.cpp index f92de3b986..acff84c1b4 100644 --- a/src/core/SkPictureImageGenerator.cpp +++ b/src/core/SkPictureImageGenerator.cpp @@ -22,7 +22,7 @@ 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; + GrTexture* onGenerateTexture(GrContext*, SkImageUsageType, const SkIRect*) override; #endif private: @@ -88,18 +88,27 @@ SkImageGenerator* SkImageGenerator::NewFromPicture(const SkISize& size, const Sk #if SK_SUPPORT_GPU #include "GrTexture.h" -GrTexture* SkPictureImageGenerator::onGenerateTexture(GrContext* ctx, SkImageUsageType usage) { +GrTexture* SkPictureImageGenerator::onGenerateTexture(GrContext* ctx, SkImageUsageType usage, + const SkIRect* subset) { + const SkImageInfo& info = this->getInfo(); + SkImageInfo surfaceInfo = subset ? info.makeWH(subset->width(), subset->height()) : info; + // // TODO: respect the usage, by possibly creating a different (pow2) surface // SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(ctx, SkSurface::kYes_Budgeted, - this->getInfo())); + surfaceInfo)); if (!surface.get()) { return nullptr; } + + SkMatrix matrix = fMatrix; + if (subset) { + matrix.postTranslate(-subset->x(), -subset->y()); + } surface->getCanvas()->clear(0); // does NewRenderTarget promise to do this for us? - surface->getCanvas()->drawPicture(fPicture, &fMatrix, fPaint.getMaybeNull()); + surface->getCanvas()->drawPicture(fPicture, &matrix, fPaint.getMaybeNull()); SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); if (!image.get()) { return nullptr; |