aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar reed <reed@google.com>2015-08-13 13:32:39 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-08-13 13:32:39 -0700
commit8f34372f7e97482e5e61ab298b7edaa008ba2f4c (patch)
tree48581497c1bcfb3420c6aba6c6fe27d344f96855 /src
parent5a16cf654548190841b5af27af04e7995582ad7b (diff)
Extend SkImageGenerator to support natively generated GrTextures. As part of this, added uniqueID() to the generator, and made it be in the same namespace is bitmaps, pixelrefs, images.
To do this, create SkImageCacherator, which wraps a generator and provides an interface to get a cached answer for either the raster or texture output of the generator. BUG=skia: Review URL: https://codereview.chromium.org/1291803002
Diffstat (limited to 'src')
-rw-r--r--src/core/SkImageCacherator.cpp144
-rw-r--r--src/core/SkImageCacherator.h51
-rw-r--r--src/core/SkImageGenerator.cpp13
-rw-r--r--src/core/SkPictureImageGenerator.cpp30
-rw-r--r--src/gpu/SkGr.cpp76
-rw-r--r--src/gpu/SkGrPriv.h32
6 files changed, 336 insertions, 10 deletions
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, &params);
+}
+
///////////////////////////////////////////////////////////////////////////////
// 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