aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/core.gypi2
-rw-r--r--src/core/SkImageCacherator.cpp79
-rw-r--r--src/core/SkImageCacherator.h5
-rw-r--r--src/gpu/GrTextureMaker.h1
-rw-r--r--src/gpu/SkGr.cpp68
-rw-r--r--src/gpu/SkGrPriv.h10
-rw-r--r--src/gpu/gl/GrGLGpu.cpp12
-rw-r--r--src/image/SkImage.cpp3
-rw-r--r--src/image/SkImageShader.cpp144
-rw-r--r--src/image/SkImageShader.h44
-rw-r--r--src/image/SkImage_Base.h5
-rw-r--r--src/image/SkImage_Generator.cpp16
-rw-r--r--src/image/SkImage_Gpu.cpp61
-rw-r--r--src/image/SkImage_Gpu.h3
-rw-r--r--src/image/SkImage_Raster.cpp9
15 files changed, 383 insertions, 79 deletions
diff --git a/gyp/core.gypi b/gyp/core.gypi
index 94711b9a3d..9459225bd8 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -255,6 +255,8 @@
'<(skia_src_path)/image/SkImage_Generator.cpp',
# '<(skia_src_path)/image/SkImage_Gpu.cpp',
'<(skia_src_path)/image/SkImage_Raster.cpp',
+ '<(skia_src_path)/image/SkImageShader.cpp',
+ '<(skia_src_path)/image/SkImageShader.h',
'<(skia_src_path)/image/SkSurface.cpp',
'<(skia_src_path)/image/SkSurface_Base.h',
# '<(skia_src_path)/image/SkSurface_Gpu.cpp',
diff --git a/src/core/SkImageCacherator.cpp b/src/core/SkImageCacherator.cpp
index b35e053b0d..03e358a568 100644
--- a/src/core/SkImageCacherator.cpp
+++ b/src/core/SkImageCacherator.cpp
@@ -207,7 +207,6 @@ static GrTexture* set_key_and_return(GrTexture* tex, const GrUniqueKey& key) {
tex->resourcePriv().setUniqueKey(key);
return tex;
}
-#endif
/*
* We have a 5 ways to try to return a texture (in sorted order)
@@ -218,13 +217,8 @@ static GrTexture* set_key_and_return(GrTexture* tex, const GrUniqueKey& key) {
* 4. Ask the generator to return YUV planes, which the GPU can convert
* 5. Ask the generator to return RGB(A) data, which the GPU can convert
*/
-GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, SkImageUsageType usage,
- const SkImage* client) {
-#if SK_SUPPORT_GPU
- if (!ctx) {
- return nullptr;
- }
-
+GrTexture* SkImageCacherator::lockUnstretchedTexture(GrContext* ctx, SkImageUsageType usage,
+ const SkImage* client) {
// textures (at least the texture-key) only support 16bit dimensions, so abort early
// if we're too big.
if (fInfo.width() > 0xFFFF || fInfo.height() > 0xFFFF) {
@@ -275,8 +269,75 @@ GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, SkImageUsageType usa
if (this->tryLockAsBitmap(&bitmap, client)) {
return GrRefCachedBitmapTexture(ctx, bitmap, usage);
}
-#endif
+ return nullptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "GrTextureMaker.h"
+
+class Cacherator_GrTextureMaker : public GrTextureMaker {
+public:
+ Cacherator_GrTextureMaker(SkImageCacherator* cacher, SkImageUsageType usage,
+ const SkImage* client, const GrUniqueKey& unstretchedKey)
+ : INHERITED(cacher->info().width(), cacher->info().height())
+ , fCacher(cacher)
+ , fUsage(usage)
+ , fClient(client)
+ , fUnstretchedKey(unstretchedKey)
+ {}
+
+protected:
+ // TODO: consider overriding this, for the case where the underlying generator might be
+ // able to efficiently produce a "stretched" texture natively (e.g. picture-backed)
+// GrTexture* onGenerateStretchedTexture(GrContext*, const SkGrStretch&) override;
+
+ GrTexture* onRefUnstretchedTexture(GrContext* ctx) override {
+ return fCacher->lockUnstretchedTexture(ctx, fUsage, fClient);
+ }
+
+ bool onMakeStretchedKey(const SkGrStretch& stretch, GrUniqueKey* stretchedKey) override {
+ return GrMakeStretchedKey(fUnstretchedKey, stretch, stretchedKey);
+ }
+
+ void onNotifyStretchCached(const GrUniqueKey& stretchedKey) override {
+ if (fClient) {
+ as_IB(fClient)->notifyAddedToCache();
+ }
+ }
+ bool onGetROBitmap(SkBitmap* bitmap) override {
+ return fCacher->lockAsBitmap(bitmap, fClient);
+ }
+
+private:
+ SkImageCacherator* fCacher;
+ const SkImageUsageType fUsage;
+ const SkImage* fClient;
+ const GrUniqueKey fUnstretchedKey;
+
+ typedef GrTextureMaker INHERITED;
+};
+
+GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, SkImageUsageType usage,
+ const SkImage* client) {
+ if (!ctx) {
+ return nullptr;
+ }
+
+ GrUniqueKey key;
+ GrMakeKeyFromImageID(&key, this->uniqueID(),
+ SkIRect::MakeWH(this->info().width(), this->info().height()),
+ *ctx->caps(), usage);
+
+ return Cacherator_GrTextureMaker(this, usage, client, key).refCachedTexture(ctx, usage);
+}
+
+#else
+
+GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, SkImageUsageType usage,
+ const SkImage* client) {
return nullptr;
}
+#endif
diff --git a/src/core/SkImageCacherator.h b/src/core/SkImageCacherator.h
index 6812c72fcc..c5c65498cc 100644
--- a/src/core/SkImageCacherator.h
+++ b/src/core/SkImageCacherator.h
@@ -58,6 +58,9 @@ private:
bool generateBitmap(SkBitmap*);
bool tryLockAsBitmap(SkBitmap*, const SkImage*);
+#if SK_SUPPORT_GPU
+ GrTexture* lockUnstretchedTexture(GrContext*, SkImageUsageType, const SkImage* client);
+#endif
class ScopedGenerator {
SkImageCacherator* fCacher;
@@ -78,6 +81,8 @@ private:
const SkImageInfo fInfo;
const SkIPoint fOrigin;
const uint32_t fUniqueID;
+
+ friend class Cacherator_GrTextureMaker;
};
#endif
diff --git a/src/gpu/GrTextureMaker.h b/src/gpu/GrTextureMaker.h
index 669a7eeb08..1cbf63a029 100644
--- a/src/gpu/GrTextureMaker.h
+++ b/src/gpu/GrTextureMaker.h
@@ -24,6 +24,7 @@ public:
int width() const { return fWidth; }
int height() const { return fHeight; }
+ GrTexture* refCachedTexture(GrContext*, SkImageUsageType);
GrTexture* refCachedTexture(GrContext*, const GrTextureParams*);
protected:
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 7fe8fe188b..a726939788 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -37,6 +37,33 @@
# include "etc1.h"
#endif
+bool GrTextureUsageSupported(const GrCaps& caps, int width, int height, SkImageUsageType usage) {
+ if (caps.npotTextureTileSupport()) {
+ return true;
+ }
+ const bool is_pow2 = SkIsPow2(width) && SkIsPow2(height);
+ return is_pow2 || kUntiled_SkImageUsageType == usage;
+}
+
+GrTextureParams GrImageUsageToTextureParams(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
+ };
+
+ return GrTextureParams(tiles[usage], filters[usage]);
+}
+
/* Fill out buffer with the compressed format Ganesh expects from a colortable
based bitmap. [palette (colortable) + indices].
@@ -133,8 +160,8 @@ static void get_stretch(const GrContext* ctx, int width, int height,
}
}
-static bool make_stretched_key(const GrUniqueKey& origKey, const SkGrStretch& stretch,
- GrUniqueKey* stretchedKey) {
+bool GrMakeStretchedKey(const GrUniqueKey& origKey, const SkGrStretch& stretch,
+ GrUniqueKey* stretchedKey) {
if (origKey.isValid() && SkGrStretch::kNone_Type != stretch.fType) {
uint32_t width = SkToU16(stretch.fWidth);
uint32_t height = SkToU16(stretch.fHeight);
@@ -169,12 +196,7 @@ void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& sub
SkGrStretch::kBilerp_Type, // kTiled_Filtered_SkImageUsageType
};
- const bool isPow2 = SkIsPow2(subset.width()) && SkIsPow2(subset.height());
- const bool needToStretch = !isPow2 &&
- usage != kUntiled_SkImageUsageType &&
- !caps.npotTextureTileSupport();
-
- if (needToStretch) {
+ if (!GrTextureUsageSupported(caps, subset.width(), subset.height(), usage)) {
GrUniqueKey tmpKey;
make_unstretched_key(&tmpKey, imageID, subset);
@@ -182,7 +204,7 @@ void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& sub
stretch.fType = stretches[usage];
stretch.fWidth = SkNextPow2(subset.width());
stretch.fHeight = SkNextPow2(subset.height());
- if (!make_stretched_key(tmpKey, stretch, key)) {
+ if (!GrMakeStretchedKey(tmpKey, stretch, key)) {
goto UNSTRETCHED;
}
} else {
@@ -195,7 +217,7 @@ static void make_image_keys(uint32_t imageID, const SkIRect& subset, const SkGrS
GrUniqueKey* key, GrUniqueKey* stretchedKey) {
make_unstretched_key(key, imageID, subset);
if (SkGrStretch::kNone_Type != stretch.fType) {
- make_stretched_key(*key, stretch, stretchedKey);
+ GrMakeStretchedKey(*key, stretch, stretchedKey);
}
}
@@ -510,7 +532,7 @@ bool GrIsImageInCache(const GrContext* ctx, uint32_t imageID, const SkIRect& sub
return false;
}
GrUniqueKey stretchedKey;
- make_stretched_key(key, stretch, &stretchedKey);
+ GrMakeStretchedKey(key, stretch, &stretchedKey);
return ctx->textureProvider()->existsTextureWithUniqueKey(stretchedKey);
}
@@ -551,7 +573,7 @@ protected:
GrUniqueKey unstretchedKey;
make_unstretched_key(&unstretchedKey, fBitmap.getGenerationID(), fBitmap.getSubset());
- return make_stretched_key(unstretchedKey, stretch, stretchedKey);
+ return GrMakeStretchedKey(unstretchedKey, stretch, stretchedKey);
}
void onNotifyStretchCached(const GrUniqueKey& stretchedKey) override {
@@ -579,22 +601,7 @@ GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap,
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]);
+ GrTextureParams params = GrImageUsageToTextureParams(usage);
return GrRefCachedBitmapTexture(ctx, bitmap, &params);
}
@@ -908,6 +915,11 @@ GrTextureParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality pain
////////////////////////////////////////////////////////////////////////////////////////////////
+GrTexture* GrTextureMaker::refCachedTexture(GrContext* ctx, SkImageUsageType usage) {
+ GrTextureParams params = GrImageUsageToTextureParams(usage);
+ return this->refCachedTexture(ctx, &params);
+}
+
GrTexture* GrTextureMaker::refCachedTexture(GrContext* ctx, const GrTextureParams* params) {
SkGrStretch stretch;
get_stretch(ctx, this->width(), this->height(), params, &stretch);
diff --git a/src/gpu/SkGrPriv.h b/src/gpu/SkGrPriv.h
index 1564d31bc9..25fda57d9e 100644
--- a/src/gpu/SkGrPriv.h
+++ b/src/gpu/SkGrPriv.h
@@ -9,6 +9,7 @@
#define SkGrPriv_DEFINED
#include "GrTypes.h"
+#include "GrTextureAccess.h"
#include "SkImageInfo.h"
#include "SkXfermode.h"
@@ -31,6 +32,8 @@ struct SkGrStretch {
int fHeight;
};
+GrTextureParams GrImageUsageToTextureParams(SkImageUsageType);
+
/**
* Our key includes the offset, width, and height so that bitmaps created by extractSubset()
* are unique.
@@ -45,6 +48,11 @@ struct SkGrStretch {
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds,
const GrCaps&, SkImageUsageType);
+/**
+ * Given an "unstretched" key, and a stretch rec, produce a stretched key.
+ */
+bool GrMakeStretchedKey(const GrUniqueKey& origKey, const SkGrStretch&, GrUniqueKey* stretchedKey);
+
/** Converts an SkPaint to a GrPaint for a given GrContext. The matrix is required in order
to convert the SkShader (if any) on the SkPaint. */
bool SkPaintToGrPaint(GrContext*,
@@ -76,4 +84,6 @@ bool SkPaintToGrPaintWithXfermode(GrContext* context,
bool primitiveIsSrc,
GrPaint* grPaint);
+bool GrTextureUsageSupported(const GrCaps&, int width, int height, SkImageUsageType);
+
#endif
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index cb12fefc32..5388387c3b 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2246,6 +2246,18 @@ static inline GrGLenum tile_to_gl_wrap(SkShader::TileMode tm) {
void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTexture* texture) {
SkASSERT(texture);
+#ifdef SK_DEBUG
+ if (!this->caps()->npotTextureTileSupport()) {
+ const bool tileX = SkShader::kClamp_TileMode != params.getTileModeX();
+ const bool tileY = SkShader::kClamp_TileMode != params.getTileModeY();
+ if (tileX || tileY) {
+ const int w = texture->width();
+ const int h = texture->height();
+ SkASSERT(SkIsPow2(w) && SkIsPow2(h));
+ }
+ }
+#endif
+
// If we created a rt/tex and rendered to it without using a texture and now we're texturing
// from the rt it will still be the last bound texture, but it needs resolving. So keep this
// out of the "last != next" check.
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index b639821a95..ee76a7ea39 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -11,6 +11,7 @@
#include "SkData.h"
#include "SkImageGenerator.h"
#include "SkImagePriv.h"
+#include "SkImageShader.h"
#include "SkImage_Base.h"
#include "SkNextID.h"
#include "SkPixelRef.h"
@@ -69,7 +70,7 @@ void SkImage::preroll(GrContext* ctx) const {
SkShader* SkImage::newShader(SkShader::TileMode tileX,
SkShader::TileMode tileY,
const SkMatrix* localMatrix) const {
- return as_IB(this)->onNewShader(tileX, tileY, localMatrix);
+ return SkImageShader::Create(this, tileX, tileY, localMatrix);
}
SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const {
diff --git a/src/image/SkImageShader.cpp b/src/image/SkImageShader.cpp
new file mode 100644
index 0000000000..fde0f0c9d5
--- /dev/null
+++ b/src/image/SkImageShader.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 "SkBitmapProcShader.h"
+#include "SkBitmapProvider.h"
+#include "SkImage_Base.h"
+#include "SkImageShader.h"
+#include "SkReadBuffer.h"
+#include "SkWriteBuffer.h"
+
+SkImageShader::SkImageShader(const SkImage* img, TileMode tmx, TileMode tmy, const SkMatrix* matrix)
+ : INHERITED(matrix)
+ , fImage(SkRef(img))
+ , fTileModeX(tmx)
+ , fTileModeY(tmy)
+{}
+
+SkFlattenable* SkImageShader::CreateProc(SkReadBuffer& buffer) {
+ const TileMode tx = (TileMode)buffer.readUInt();
+ const TileMode ty = (TileMode)buffer.readUInt();
+ SkMatrix matrix;
+ buffer.readMatrix(&matrix);
+ SkAutoTUnref<SkImage> img(buffer.readImage());
+ if (!img) {
+ return nullptr;
+ }
+ return new SkImageShader(img, tx, ty, &matrix);
+}
+
+void SkImageShader::flatten(SkWriteBuffer& buffer) const {
+ buffer.writeUInt(fTileModeX);
+ buffer.writeUInt(fTileModeY);
+ buffer.writeMatrix(this->getLocalMatrix());
+ buffer.writeImage(fImage);
+}
+
+bool SkImageShader::isOpaque() const {
+ return fImage->isOpaque();
+}
+
+size_t SkImageShader::contextSize() const {
+ return SkBitmapProcShader::ContextSize();
+}
+
+SkShader::Context* SkImageShader::onCreateContext(const ContextRec& rec, void* storage) const {
+ return SkBitmapProcShader::MakeContext(*this, fTileModeX, fTileModeY,
+ SkBitmapProvider(fImage), rec, storage);
+}
+
+SkShader* SkImageShader::Create(const SkImage* image, TileMode tx, TileMode ty,
+ const SkMatrix* localMatrix) {
+ if (!image) {
+ return nullptr;
+ }
+ return new SkImageShader(image, tx, ty, localMatrix);
+}
+
+#ifndef SK_IGNORE_TO_STRING
+void SkImageShader::toString(SkString* str) const {
+ const char* gTileModeName[SkShader::kTileModeCount] = {
+ "clamp", "repeat", "mirror"
+ };
+
+ str->appendf("ImageShader: ((%s %s) ", gTileModeName[fTileModeX], gTileModeName[fTileModeY]);
+ fImage->toString(str);
+ this->INHERITED::toString(str);
+ str->append(")");
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if SK_SUPPORT_GPU
+
+#include "GrTextureAccess.h"
+#include "SkGr.h"
+#include "effects/GrSimpleTextureEffect.h"
+#include "effects/GrBicubicEffect.h"
+#include "effects/GrSimpleTextureEffect.h"
+
+const GrFragmentProcessor* SkImageShader::asFragmentProcessor(GrContext* context,
+ const SkMatrix& viewM,
+ const SkMatrix* localMatrix,
+ SkFilterQuality filterQuality,
+ GrProcessorDataManager* mgr) const {
+ SkMatrix matrix;
+ matrix.setIDiv(fImage->width(), fImage->height());
+
+ SkMatrix lmInverse;
+ if (!this->getLocalMatrix().invert(&lmInverse)) {
+ return nullptr;
+ }
+ if (localMatrix) {
+ SkMatrix inv;
+ if (!localMatrix->invert(&inv)) {
+ return nullptr;
+ }
+ lmInverse.postConcat(inv);
+ }
+ matrix.preConcat(lmInverse);
+
+ SkShader::TileMode tm[] = { fTileModeX, fTileModeY };
+
+ // Must set wrap and filter on the sampler before requesting a texture. In two places below
+ // we check the matrix scale factors to determine how to interpret the filter quality setting.
+ // This completely ignores the complexity of the drawVertices case where explicit local coords
+ // are provided by the caller.
+ bool doBicubic;
+ GrTextureParams::FilterMode textureFilterMode =
+ GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(), &doBicubic);
+ GrTextureParams params(tm, textureFilterMode);
+
+ SkImageUsageType usageType;
+ if (kClamp_TileMode == fTileModeX && kClamp_TileMode == fTileModeY) {
+ usageType = kUntiled_SkImageUsageType;
+ } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) {
+ usageType = kTiled_Unfiltered_SkImageUsageType;
+ } else {
+ usageType = kTiled_Filtered_SkImageUsageType;
+ }
+
+ SkAutoTUnref<GrTexture> texture(as_IB(fImage)->asTextureRef(context, usageType));
+ if (!texture) {
+ return nullptr;
+ }
+
+ SkAutoTUnref<GrFragmentProcessor> inner;
+ if (doBicubic) {
+ inner.reset(GrBicubicEffect::Create(mgr, texture, matrix, tm));
+ } else {
+ inner.reset(GrSimpleTextureEffect::Create(mgr, texture, matrix, params));
+ }
+
+ if (GrPixelConfigIsAlphaOnly(texture->config())) {
+ return SkRef(inner.get());
+ }
+ return GrFragmentProcessor::MulOutputByInputAlpha(inner);
+}
+
+#endif
diff --git a/src/image/SkImageShader.h b/src/image/SkImageShader.h
new file mode 100644
index 0000000000..fdd7976aad
--- /dev/null
+++ b/src/image/SkImageShader.h
@@ -0,0 +1,44 @@
+/*
+ * 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 SkImageShader_DEFINED
+#define SkImageShader_DEFINED
+
+#include "SkImage.h"
+#include "SkShader.h"
+
+class SkImageShader : public SkShader {
+public:
+ static SkShader* Create(const SkImage*, TileMode tx, TileMode ty, const SkMatrix* localMatrix);
+
+ bool isOpaque() const override;
+ size_t contextSize() const override;
+
+ SK_TO_STRING_OVERRIDE()
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkImageShader)
+
+#if SK_SUPPORT_GPU
+ const GrFragmentProcessor* asFragmentProcessor(GrContext*, const SkMatrix& viewM,
+ const SkMatrix*, SkFilterQuality,
+ GrProcessorDataManager*) const override;
+#endif
+
+protected:
+ void flatten(SkWriteBuffer&) const override;
+ Context* onCreateContext(const ContextRec&, void* storage) const override;
+
+ SkAutoTUnref<const SkImage> fImage;
+ const TileMode fTileModeX;
+ const TileMode fTileModeY;
+
+private:
+ SkImageShader(const SkImage*, TileMode tx, TileMode ty, const SkMatrix* localMatrix);
+
+ typedef SkShader INHERITED;
+};
+
+#endif
diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h
index bbcf182ab8..757262ad3d 100644
--- a/src/image/SkImage_Base.h
+++ b/src/image/SkImage_Base.h
@@ -54,11 +54,8 @@ public:
// Caller must call unref when they are done.
virtual GrTexture* asTextureRef(GrContext*, SkImageUsageType) const = 0;
- virtual SkShader* onNewShader(SkShader::TileMode,
- SkShader::TileMode,
- const SkMatrix* localMatrix) const { return nullptr; }
-
virtual SkImage* onNewSubset(const SkIRect&) const = 0;
+
virtual SkData* onRefEncoded() const { return nullptr; }
virtual bool onAsLegacyBitmap(SkBitmap*, LegacyBitmapMode) const;
diff --git a/src/image/SkImage_Generator.cpp b/src/image/SkImage_Generator.cpp
index 765234fa0c..1c1b263371 100644
--- a/src/image/SkImage_Generator.cpp
+++ b/src/image/SkImage_Generator.cpp
@@ -28,11 +28,6 @@ public:
SkImage* onNewSubset(const SkIRect&) const override;
bool getROPixels(SkBitmap*) const override;
GrTexture* asTextureRef(GrContext*, SkImageUsageType) const override;
-
- SkShader* onNewShader(SkShader::TileMode,
- SkShader::TileMode,
- const SkMatrix* localMatrix) const override;
-
bool onIsLazyGenerated() const override { return true; }
private:
@@ -43,17 +38,6 @@ private:
///////////////////////////////////////////////////////////////////////////////
-SkShader* SkImage_Generator::onNewShader(SkShader::TileMode tileX, SkShader::TileMode tileY,
- const SkMatrix* localMatrix) const {
- // TODO: need a native Shader that takes Cacherator (or this image) so we can natively return
- // textures as output from the shader.
- SkBitmap bm;
- if (this->getROPixels(&bm)) {
- return SkShader::CreateBitmapShader(bm, tileX, tileY, localMatrix);
- }
- return nullptr;
-}
-
bool SkImage_Generator::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
int srcX, int srcY) const {
SkBitmap bm;
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 1a63a0d6ba..2cc0241a48 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -7,11 +7,14 @@
#include "SkBitmapCache.h"
#include "SkImage_Gpu.h"
+#include "GrCaps.h"
#include "GrContext.h"
#include "GrDrawContext.h"
+#include "GrTextureMaker.h"
#include "effects/GrYUVtoRGBEffect.h"
#include "SkCanvas.h"
#include "SkGpuDevice.h"
+#include "SkGrPriv.h"
#include "SkPixelRef.h"
SkImage_Gpu::SkImage_Gpu(int w, int h, uint32_t uniqueID, SkAlphaType at, GrTexture* tex,
@@ -35,13 +38,6 @@ extern void SkTextureImageApplyBudgetedDecision(SkImage* image) {
}
}
-SkShader* SkImage_Gpu::onNewShader(SkShader::TileMode tileX, SkShader::TileMode tileY,
- const SkMatrix* localMatrix) const {
- SkBitmap bm;
- GrWrapTextureInBitmap(fTexture, this->width(), this->height(), this->isOpaque(), &bm);
- return SkShader::CreateBitmapShader(bm, tileX, tileY, localMatrix);
-}
-
bool SkImage_Gpu::getROPixels(SkBitmap* dst) const {
if (SkBitmapCache::Find(this->uniqueID(), dst)) {
SkASSERT(dst->getGenerationID() == this->uniqueID());
@@ -65,9 +61,56 @@ bool SkImage_Gpu::getROPixels(SkBitmap* dst) const {
return true;
}
+static void make_raw_texture_stretched_key(uint32_t imageID, const SkGrStretch& stretch,
+ GrUniqueKey* stretchedKey) {
+ SkASSERT(SkGrStretch::kNone_Type != stretch.fType);
+
+ uint32_t width = SkToU16(stretch.fWidth);
+ uint32_t height = SkToU16(stretch.fHeight);
+
+ static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
+ GrUniqueKey::Builder builder(stretchedKey, kDomain, 3);
+ builder[0] = imageID;
+ builder[1] = stretch.fType;
+ builder[2] = width | (height << 16);
+ builder.finish();
+}
+
+class Texture_GrTextureMaker : public GrTextureMaker {
+public:
+ Texture_GrTextureMaker(const SkImage* image, GrTexture* unstretched)
+ : INHERITED(image->width(), image->height())
+ , fImage(image)
+ , fUnstretched(unstretched)
+ {}
+
+protected:
+ GrTexture* onRefUnstretchedTexture(GrContext* ctx) override {
+ return SkRef(fUnstretched);
+ }
+
+ bool onMakeStretchedKey(const SkGrStretch& stretch, GrUniqueKey* stretchedKey) override {
+ make_raw_texture_stretched_key(fImage->uniqueID(), stretch, stretchedKey);
+ return stretchedKey->isValid();
+ }
+
+ void onNotifyStretchCached(const GrUniqueKey& stretchedKey) override {
+ as_IB(fImage)->notifyAddedToCache();
+ }
+
+ bool onGetROBitmap(SkBitmap* bitmap) override {
+ return as_IB(fImage)->getROPixels(bitmap);
+ }
+
+private:
+ const SkImage* fImage;
+ GrTexture* fUnstretched;
+
+ typedef GrTextureMaker INHERITED;
+};
+
GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, SkImageUsageType usage) const {
- fTexture->ref();
- return fTexture;
+ return Texture_GrTextureMaker(this, fTexture).refCachedTexture(ctx, usage);
}
bool SkImage_Gpu::isOpaque() const {
diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h
index 5e847dd381..8bfdfa7cd8 100644
--- a/src/image/SkImage_Gpu.h
+++ b/src/image/SkImage_Gpu.h
@@ -40,9 +40,6 @@ public:
SkImage* onNewSubset(const SkIRect&) const override;
GrTexture* peekTexture() const override { return fTexture; }
- SkShader* onNewShader(SkShader::TileMode,
- SkShader::TileMode,
- const SkMatrix* localMatrix) const override;
bool isOpaque() const override;
bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes,
int srcX, int srcY) const override;
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index 512e788a39..c88e17689c 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -79,10 +79,6 @@ public:
SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
- SkShader* onNewShader(SkShader::TileMode,
- SkShader::TileMode,
- const SkMatrix* localMatrix) const override;
-
bool isOpaque() const override;
bool onAsLegacyBitmap(SkBitmap*, LegacyBitmapMode) const override;
@@ -143,11 +139,6 @@ SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, const SkIPoint&
SkImage_Raster::~SkImage_Raster() {}
-SkShader* SkImage_Raster::onNewShader(SkShader::TileMode tileX, SkShader::TileMode tileY,
- const SkMatrix* localMatrix) const {
- return SkShader::CreateBitmapShader(fBitmap, tileX, tileY, localMatrix);
-}
-
bool SkImage_Raster::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
int srcX, int srcY) const {
SkBitmap shallowCopy(fBitmap);