aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/image_pict.cpp171
-rw-r--r--include/core/SkImageGenerator.h6
-rw-r--r--src/core/SkImageCacherator.cpp110
-rw-r--r--src/core/SkImageCacherator.h13
-rw-r--r--src/core/SkImageGenerator.cpp7
-rw-r--r--src/core/SkPictureImageGenerator.cpp17
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;