aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar egdaniel <egdaniel@google.com>2015-10-16 13:59:14 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-10-16 13:59:14 -0700
commit91957941ce2fe9457babe7f83514e4599089d411 (patch)
tree5a81c0bfe1494b59b260371b137567368594b62e
parentfcffaf22d697f06f903c3193308f9dc54a959f79 (diff)
Revert of Rewrite GrTextureMaker to disentangle bitmap case from base class and give GPU object a say in what… (patchset #4 id:60001 of https://codereview.chromium.org/1409163002/ )
Reason for revert: breaking nanobench Original issue's description: > Rewrite GrTextureMaker to disentangle bitmap case from base class and give GPU object a say in what copying needs to be done. > > Committed: https://skia.googlesource.com/skia/+/fcffaf22d697f06f903c3193308f9dc54a959f79 TBR=reed@google.com,bsalomon@google.com NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true Review URL: https://codereview.chromium.org/1409923003
-rw-r--r--gyp/gpu.gypi2
-rw-r--r--include/gpu/GrResourceKey.h4
-rw-r--r--include/gpu/SkGr.h6
-rw-r--r--src/core/SkImageCacherator.cpp73
-rw-r--r--src/core/SkImageCacherator.h9
-rw-r--r--src/gpu/GrGpu.cpp31
-rw-r--r--src/gpu/GrGpu.h8
-rw-r--r--src/gpu/GrTextureMaker.h76
-rw-r--r--src/gpu/GrTextureParamsAdjuster.cpp152
-rw-r--r--src/gpu/GrTextureParamsAdjuster.h107
-rw-r--r--src/gpu/SkGr.cpp418
-rw-r--r--src/gpu/SkGrPriv.h43
-rw-r--r--src/image/SkImage_Gpu.cpp43
-rw-r--r--src/image/SkImage_Raster.cpp14
14 files changed, 506 insertions, 480 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index d0a3e919db..b86e5d4f41 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -178,8 +178,6 @@
'<(skia_src_path)/gpu/GrTextContext.cpp',
'<(skia_src_path)/gpu/GrTextContext.h',
'<(skia_src_path)/gpu/GrTexture.cpp',
- '<(skia_src_path)/gpu/GrTextureParamsAdjuster.h',
- '<(skia_src_path)/gpu/GrTextureParamsAdjuster.cpp',
'<(skia_src_path)/gpu/GrTextureProvider.cpp',
'<(skia_src_path)/gpu/GrTexturePriv.h',
'<(skia_src_path)/gpu/GrTextureAccess.cpp',
diff --git a/include/gpu/GrResourceKey.h b/include/gpu/GrResourceKey.h
index 9958cfc872..6cfa90fd8a 100644
--- a/include/gpu/GrResourceKey.h
+++ b/include/gpu/GrResourceKey.h
@@ -138,8 +138,8 @@ private:
friend class TestResource; // For unit test to access kMetaDataCnt.
- // bmp textures require 5 uint32_t values.
- SkAutoSTMalloc<kMetaDataCnt + 5, uint32_t> fKey;
+ // bmp textures require 4 uint32_t values.
+ SkAutoSTMalloc<kMetaDataCnt + 4, uint32_t> fKey;
};
/**
diff --git a/include/gpu/SkGr.h b/include/gpu/SkGr.h
index 17625c4e4e..591d3d88a4 100644
--- a/include/gpu/SkGr.h
+++ b/include/gpu/SkGr.h
@@ -65,11 +65,9 @@ static inline GrColor SkPMColorToGrColor(SkPMColor c) {
}
////////////////////////////////////////////////////////////////////////////////
-/** Returns a texture representing the bitmap that is compatible with the GrTextureParams. The
- texture is inserted into the cache (unless the bitmap is marked volatile) and can be
- retrieved again via this function. */
-GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams&);
+GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams&);
+
// TODO: Move SkImageInfo2GrPixelConfig to SkGrPriv.h (requires cleanup to SkWindow its subclasses).
GrPixelConfig SkImageInfo2GrPixelConfig(SkColorType, SkAlphaType, SkColorProfileType);
diff --git a/src/core/SkImageCacherator.cpp b/src/core/SkImageCacherator.cpp
index f59be32411..cd5ae57699 100644
--- a/src/core/SkImageCacherator.cpp
+++ b/src/core/SkImageCacherator.cpp
@@ -204,9 +204,7 @@ public:
};
static GrTexture* set_key_and_return(GrTexture* tex, const GrUniqueKey& key) {
- if (key.isValid()) {
- tex->resourcePriv().setUniqueKey(key);
- }
+ tex->resourcePriv().setUniqueKey(key);
return tex;
}
@@ -219,16 +217,24 @@ 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::lockTexture(GrContext* ctx, const GrUniqueKey& key,
- const SkImage* client) {
+GrTexture* SkImageCacherator::lockUnstretchedTexture(GrContext* ctx, 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) {
+ return nullptr;
+ }
+
+ GrUniqueKey key;
+ const GrTextureParams& noStretchParams = GrTextureParams::ClampNoFilter();
+ GrMakeKeyFromImageID(&key, fUniqueID, SkIRect::MakeWH(fInfo.width(), fInfo.height()),
+ *ctx->caps(), noStretchParams);
+
// 1. Check the cache for a pre-existing one
- if (key.isValid()) {
- if (GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key)) {
- return tex;
- }
+ if (GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key)) {
+ return tex;
}
- // 2. Ask the generator to natively create one
+ // 2. Ask the genreator to natively create one
{
ScopedGenerator generator(this);
SkIRect subset = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), fInfo.width(), fInfo.height());
@@ -261,62 +267,54 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key
// 5. Ask the generator to return RGB(A) data, which the GPU can convert
SkBitmap bitmap;
if (this->tryLockAsBitmap(&bitmap, client)) {
- GrTexture* tex = GrUploadBitmapToTexture(ctx, bitmap);
- if (tex) {
- return set_key_and_return(tex, key);
- }
+ return GrRefCachedBitmapTexture(ctx, bitmap, noStretchParams);
}
return nullptr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-#include "GrTextureParamsAdjuster.h"
+#include "GrTextureMaker.h"
-class Cacherator_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
+class Cacherator_GrTextureMaker : public GrTextureMaker {
public:
- Cacherator_GrTextureParamsAdjuster(SkImageCacherator* cacher, const SkImage* client)
+ Cacherator_GrTextureMaker(SkImageCacherator* cacher, const SkImage* client,
+ const GrUniqueKey& unstretchedKey)
: INHERITED(cacher->info().width(), cacher->info().height())
, fCacher(cacher)
, fClient(client)
- {
- if (client) {
- GrMakeKeyFromImageID(&fOriginalKey, client->uniqueID(),
- SkIRect::MakeWH(this->width(), this->height()));
- }
- }
+ , 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* generateTextureForParams(GrContext*, const SkGrStretch&) override;
+// GrTexture* onGenerateStretchedTexture(GrContext*, const SkGrStretch&) override;
- GrTexture* refOriginalTexture(GrContext* ctx) override {
- return fCacher->lockTexture(ctx, fOriginalKey, fClient);
+ GrTexture* onRefUnstretchedTexture(GrContext* ctx) override {
+ return fCacher->lockUnstretchedTexture(ctx, fClient);
}
- void makeCopyKey(const CopyParams& stretch, GrUniqueKey* paramsCopyKey) override {
- if (fOriginalKey.isValid()) {
- MakeCopyKeyFromOrigKey(fOriginalKey, stretch, paramsCopyKey);
- }
+ bool onMakeStretchedKey(const SkGrStretch& stretch, GrUniqueKey* stretchedKey) override {
+ return GrMakeStretchedKey(fUnstretchedKey, stretch, stretchedKey);
}
- void didCacheCopy(const GrUniqueKey& copyKey) override {
+ void onNotifyStretchCached(const GrUniqueKey& stretchedKey) override {
if (fClient) {
as_IB(fClient)->notifyAddedToCache();
}
}
- bool getROBitmap(SkBitmap* bitmap) override {
+ bool onGetROBitmap(SkBitmap* bitmap) override {
return fCacher->lockAsBitmap(bitmap, fClient);
}
private:
SkImageCacherator* fCacher;
const SkImage* fClient;
- GrUniqueKey fOriginalKey;
+ const GrUniqueKey fUnstretchedKey;
- typedef GrTextureParamsAdjuster INHERITED;
+ typedef GrTextureMaker INHERITED;
};
GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParams& params,
@@ -325,7 +323,12 @@ GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParam
return nullptr;
}
- return Cacherator_GrTextureParamsAdjuster(this, client).refTextureForParams(ctx, params);
+ GrUniqueKey key;
+ GrMakeKeyFromImageID(&key, this->uniqueID(),
+ SkIRect::MakeWH(this->info().width(), this->info().height()),
+ *ctx->caps(), GrTextureParams::ClampNoFilter());
+
+ return Cacherator_GrTextureMaker(this, client, key).refCachedTexture(ctx, params);
}
#else
diff --git a/src/core/SkImageCacherator.h b/src/core/SkImageCacherator.h
index ac112d78cb..7508f34fe7 100644
--- a/src/core/SkImageCacherator.h
+++ b/src/core/SkImageCacherator.h
@@ -13,8 +13,7 @@
#include "SkTemplates.h"
class GrContext;
-class GrTextureParams;
-class GrUniqueKey;
+class GrTextureParams;
class SkBitmap;
class SkImage;
@@ -61,9 +60,7 @@ private:
bool generateBitmap(SkBitmap*);
bool tryLockAsBitmap(SkBitmap*, const SkImage*);
#if SK_SUPPORT_GPU
- // Returns the texture. If the cacherator is generating the texture and wants to cache it,
- // it should use the passed in key (if the key is valid).
- GrTexture* lockTexture(GrContext*, const GrUniqueKey& key, const SkImage* client);
+ GrTexture* lockUnstretchedTexture(GrContext*, const SkImage* client);
#endif
class ScopedGenerator {
@@ -86,7 +83,7 @@ private:
const SkIPoint fOrigin;
const uint32_t fUniqueID;
- friend class Cacherator_GrTextureParamsAdjuster;
+ friend class Cacherator_GrTextureMaker;
};
#endif
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 48fc740ae0..96728f3ba8 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -55,37 +55,6 @@ void GrGpu::contextAbandoned() {}
////////////////////////////////////////////////////////////////////////////////
-bool GrGpu::makeCopyForTextureParams(int width, int height, const GrTextureParams& textureParams,
- GrTextureParamsAdjuster::CopyParams* copyParams) const {
- bool doCopy = false;
- const GrCaps& caps = *this->caps();
- if (textureParams.isTiled() && !caps.npotTextureTileSupport() &&
- (!SkIsPow2(width) || !SkIsPow2(height))) {
- doCopy = true;
- copyParams->fWidth = GrNextPow2(SkTMax(width, caps.minTextureSize()));
- copyParams->fHeight = GrNextPow2(SkTMax(height, caps.minTextureSize()));
- } else if (width < caps.minTextureSize() || height < caps.minTextureSize()) {
- // The small texture issues appear to be with tiling. Hence it seems ok to scale
- // them up using the GPU. If issues persist we may need to CPU-stretch.
- doCopy = true;
- copyParams->fWidth = SkTMax(width, caps.minTextureSize());
- copyParams->fHeight = SkTMax(height, caps.minTextureSize());
- }
- if (doCopy) {
- switch (textureParams.filterMode()) {
- case GrTextureParams::kNone_FilterMode:
- copyParams->fFilter = GrTextureParams::kNone_FilterMode;
- break;
- case GrTextureParams::kBilerp_FilterMode:
- case GrTextureParams::kMipMap_FilterMode:
- // We are only ever scaling up so no reason to ever indicate kMipMap.
- copyParams->fFilter = GrTextureParams::kBilerp_FilterMode;
- break;
- }
- }
- return doCopy;
-}
-
static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin, bool renderTarget) {
// By default, GrRenderTargets are GL's normal orientation so that they
// can be drawn to by the outside world without the client having
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 4714d36913..d8e5681de1 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -11,7 +11,6 @@
#include "GrPipelineBuilder.h"
#include "GrProgramDesc.h"
#include "GrStencil.h"
-#include "GrTextureParamsAdjuster.h"
#include "GrXferProcessor.h"
#include "SkPath.h"
@@ -379,13 +378,6 @@ public:
// clears target's entire stencil buffer to 0
virtual void clearStencil(GrRenderTarget* target) = 0;
-
- // Determines whether a copy of a texture must be made in order to be compatible with
- // a given GrTextureParams. If so, the width, height and filter used for the copy are
- // output via the CopyParams.
- bool makeCopyForTextureParams(int width, int height, const GrTextureParams&,
- GrTextureParamsAdjuster::CopyParams*) const;
-
// This is only to be used in GL-specific tests.
virtual const GrGLContext* glContextForTesting() const { return nullptr; }
diff --git a/src/gpu/GrTextureMaker.h b/src/gpu/GrTextureMaker.h
new file mode 100644
index 0000000000..47141bdfb0
--- /dev/null
+++ b/src/gpu/GrTextureMaker.h
@@ -0,0 +1,76 @@
+/*
+ * 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 GrTextureMaker_DEFINED
+#define GrTextureMaker_DEFINED
+
+#include "SkGrPriv.h"
+
+class GrContext;
+class GrTexture;
+class GrTextureParams;
+class GrUniqueKey;
+class SkBitmap;
+
+class GrTextureMaker {
+public:
+ GrTextureMaker(int width, int height) : fWidth(width), fHeight(height) {}
+ virtual ~GrTextureMaker() {}
+
+ int width() const { return fWidth; }
+ int height() const { return fHeight; }
+
+ GrTexture* refCachedTexture(GrContext*, const GrTextureParams&);
+
+protected:
+ /**
+ * Return the maker's "original" unstretched texture. It is the responsibility of the maker
+ * to make this efficient ... if the texture is being generated, the maker must handle
+ * caching it.
+ */
+ virtual GrTexture* onRefUnstretchedTexture(GrContext*) = 0;
+
+ /**
+ * If we need to stretch the maker's original texture, the maker is asked to return a key
+ * that identifies its origianl + the stretch parameter. If the maker does not want to cache
+ * the stretched version (e.g. the maker is volatile), this should ignore the key parameter
+ * and return false.
+ */
+ virtual bool onMakeStretchedKey(const SkGrStretch&, GrUniqueKey* stretchedKey) = 0;
+
+ /**
+ * Return a new (uncached) texture that is the stretch of the maker's original.
+ *
+ * The base-class handles general logic for this, and only needs access to the following
+ * methods:
+ * - onRefUnstretchedTexture()
+ * - onGetROBitmap()
+ *
+ * Subclass may override this if they can handle stretching more efficiently.
+ */
+ virtual GrTexture* onGenerateStretchedTexture(GrContext*, const SkGrStretch&);
+
+ /**
+ * If a stretched version of the texture is generated, it may be cached (assuming that
+ * onMakeStretchedKey() returns true). In that case, the maker is notified in case it
+ * wants to note that for when the maker is destroyed.
+ */
+ virtual void onNotifyStretchCached(const GrUniqueKey& stretchedKey) = 0;
+
+ /**
+ * Some GPUs are unreliable w/ very small texture sizes. If we run into that case, this
+ * method will be called (in service of onGenerateStretchedTexture) to return a raster version
+ * of the original texture.
+ */
+ virtual bool onGetROBitmap(SkBitmap*) = 0;
+
+private:
+ const int fWidth;
+ const int fHeight;
+};
+
+#endif
diff --git a/src/gpu/GrTextureParamsAdjuster.cpp b/src/gpu/GrTextureParamsAdjuster.cpp
deleted file mode 100644
index adeec45c8a..0000000000
--- a/src/gpu/GrTextureParamsAdjuster.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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 "GrTextureParamsAdjuster.h"
-
-#include "GrCaps.h"
-#include "GrContext.h"
-#include "GrDrawContext.h"
-#include "GrGpu.h"
-#include "GrTexture.h"
-#include "GrTextureParams.h"
-#include "GrTextureProvider.h"
-#include "SkCanvas.h"
-#include "SkGr.h"
-#include "SkGrPriv.h"
-
-typedef GrTextureParamsAdjuster::CopyParams CopyParams;
-
-static GrTexture* copy_on_gpu(GrTexture* inputTexture, const CopyParams& copyParams) {
- GrContext* context = inputTexture->getContext();
- SkASSERT(context);
- const GrCaps* caps = context->caps();
-
- // Either it's a cache miss or the original wasn't cached to begin with.
- GrSurfaceDesc rtDesc = inputTexture->desc();
- rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
- rtDesc.fWidth = copyParams.fWidth;
- rtDesc.fHeight = copyParams.fHeight;
- rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig);
-
- // If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise,
- // fail.
- if (!caps->isConfigRenderable(rtDesc.fConfig, false)) {
- if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) {
- if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
- rtDesc.fConfig = kAlpha_8_GrPixelConfig;
- } else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
- rtDesc.fConfig = kSkia8888_GrPixelConfig;
- } else {
- return nullptr;
- }
- } else if (kRGB_GrColorComponentFlags ==
- (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) {
- if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
- rtDesc.fConfig = kSkia8888_GrPixelConfig;
- } else {
- return nullptr;
- }
- } else {
- return nullptr;
- }
- }
-
- SkAutoTUnref<GrTexture> copy(context->textureProvider()->createTexture(rtDesc, true));
- if (!copy) {
- return nullptr;
- }
-
- GrPaint paint;
-
- // If filtering is not desired then we want to ensure all texels in the resampled image are
- // copies of texels from the original.
- GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
- paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);
-
- SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
- SkRect localRect = SkRect::MakeWH(1.f, 1.f);
-
- SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(copy->asRenderTarget()));
- if (!drawContext) {
- return nullptr;
- }
-
- drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, localRect);
- return copy.detach();
-}
-
-static SkBitmap copy_on_cpu(const SkBitmap& bmp, const CopyParams& copyParams) {
- SkBitmap stretched;
- stretched.allocN32Pixels(copyParams.fWidth, copyParams.fHeight);
- SkCanvas canvas(stretched);
- SkPaint paint;
- switch (copyParams.fFilter) {
- case GrTextureParams::kNone_FilterMode:
- paint.setFilterQuality(kNone_SkFilterQuality);
- break;
- case GrTextureParams::kBilerp_FilterMode:
- paint.setFilterQuality(kLow_SkFilterQuality);
- break;
- case GrTextureParams::kMipMap_FilterMode:
- paint.setFilterQuality(kMedium_SkFilterQuality);
- break;
- }
- SkRect dstRect = SkRect::MakeWH(SkIntToScalar(copyParams.fWidth),
- SkIntToScalar(copyParams.fHeight));
- canvas.drawBitmapRect(bmp, dstRect, &paint);
- return stretched;
-}
-
-GrTexture* GrTextureParamsAdjuster::refTextureForParams(GrContext* ctx,
- const GrTextureParams& params) {
- CopyParams copyParams;
- if (!ctx->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params,
- &copyParams)) {
- return this->refOriginalTexture(ctx);
- }
- GrUniqueKey copyKey;
- this->makeCopyKey(copyParams, &copyKey);
- if (copyKey.isValid()) {
- GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(copyKey);
- if (result) {
- return result;
- }
- }
-
- GrTexture* result = this->generateTextureForParams(ctx, copyParams);
- if (!result) {
- return nullptr;
- }
-
- if (copyKey.isValid()) {
- ctx->textureProvider()->assignUniqueKeyToTexture(copyKey, result);
- this->didCacheCopy(copyKey);
- }
- return result;
-}
-
-GrTexture* GrTextureParamsAdjuster::generateTextureForParams(GrContext* ctx,
- const CopyParams& copyParams) {
- if (this->width() < ctx->caps()->minTextureSize() ||
- this->height() < ctx->caps()->minTextureSize())
- {
- // we can't trust our ability to use HW to perform the stretch, so we request
- // a raster instead, and perform the stretch on the CPU.
- SkBitmap bitmap;
- if (!this->getROBitmap(&bitmap)) {
- return nullptr;
- }
- SkBitmap stretchedBmp = copy_on_cpu(bitmap, copyParams);
- return GrUploadBitmapToTexture(ctx, bitmap);
- } else {
- SkAutoTUnref<GrTexture> original(this->refOriginalTexture(ctx));
- if (!original) {
- return nullptr;
- }
- return copy_on_gpu(original, copyParams);
- }
-}
diff --git a/src/gpu/GrTextureParamsAdjuster.h b/src/gpu/GrTextureParamsAdjuster.h
deleted file mode 100644
index e1aa80e982..0000000000
--- a/src/gpu/GrTextureParamsAdjuster.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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 GrTextureMaker_DEFINED
-#define GrTextureMaker_DEFINED
-
-#include "GrTextureParams.h"
-#include "GrResourceKey.h"
-
-class GrContext;
-class GrTexture;
-class GrTextureParams;
-class GrUniqueKey;
-class SkBitmap;
-
-/**
- * Different GPUs and API extensions have different requirements with respect to what texture
- * sampling parameters may be used with textures of various types. This class facilitates making
- * texture compatible with a given GrTextureParams. It abstracts the source of the original data
- * which may be an already existing texture, CPU pixels, a codec, ... so that various sources can
- * be used with common code that scales or copies the data to make it compatible with a
- * GrTextureParams.
- */
-class GrTextureParamsAdjuster {
-public:
- struct CopyParams {
- GrTextureParams::FilterMode fFilter;
- int fWidth;
- int fHeight;
- };
-
- GrTextureParamsAdjuster(int width, int height) : fWidth(width), fHeight(height) {}
- virtual ~GrTextureParamsAdjuster() {}
-
- int width() const { return fWidth; }
- int height() const { return fHeight; }
-
- /** Returns a texture that is safe for use with the params */
- GrTexture* refTextureForParams(GrContext*, const GrTextureParams&);
-
-protected:
- /**
- * Return the maker's "original" texture. It is the responsibility of the maker
- * to make this efficient ... if the texture is being generated, the maker must handle
- * caching it (if desired).
- */
- virtual GrTexture* refOriginalTexture(GrContext*) = 0;
-
- /**
- * If we need to copy the maker's original texture, the maker is asked to return a key
- * that identifies its original + the CopyParms parameter. If the maker does not want to cache
- * the stretched version (e.g. the maker is volatile), this should simply return without
- * initializing the copyKey.
- */
- virtual void makeCopyKey(const CopyParams&, GrUniqueKey* copyKey) = 0;
-
- /**
- * Return a new (uncached) texture that is the stretch of the maker's original.
- *
- * The base-class handles general logic for this, and only needs access to the following
- * methods:
- * - onRefOriginalTexture()
- * - onGetROBitmap()
- *
- * Subclass may override this if they can handle creating the texture more directly than
- * by copying.
- */
- virtual GrTexture* generateTextureForParams(GrContext*, const CopyParams&);
-
- /**
- * If a stretched version of the texture is generated, it may be cached (assuming that
- * onMakeParamsKey() returns true). In that case, the maker is notified in case it
- * wants to note that for when the maker is destroyed.
- */
- virtual void didCacheCopy(const GrUniqueKey& copyKey) = 0;
-
- /**
- * Some GPUs are unreliable w/ very small texture sizes. If we run into that case, this
- * method will be called (in service of onGenerateParamsTexture) to return a raster version
- * of the original texture.
- */
- virtual bool getROBitmap(SkBitmap*) = 0;
-
- /** Helper for creating a key for a copy from an original key. */
- static void MakeCopyKeyFromOrigKey(const GrUniqueKey& origKey,
- const CopyParams& copyParams,
- GrUniqueKey* copyKey) {
- SkASSERT(!copyKey->isValid());
- if (origKey.isValid()) {
- static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
- GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3);
- builder[0] = copyParams.fFilter;
- builder[1] = copyParams.fWidth;
- builder[2] = copyParams.fHeight;
- }
- }
-
-private:
- const int fWidth;
- const int fHeight;
-};
-
-#endif
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 42922b3e27..d8444968da 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -5,13 +5,13 @@
* found in the LICENSE file.
*/
+#include "GrTextureMaker.h"
#include "SkGr.h"
#include "GrCaps.h"
#include "GrContext.h"
-#include "GrTextureParamsAdjuster.h"
-#include "GrGpuResourcePriv.h"
+#include "GrDrawContext.h"
#include "GrXferProcessor.h"
#include "GrYUVProvider.h"
@@ -48,17 +48,64 @@ GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info) {
return desc;
}
-void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds) {
- SkASSERT(key);
- SkASSERT(imageID);
- SkASSERT(!imageBounds.isEmpty());
- static const GrUniqueKey::Domain kImageIDDomain = GrUniqueKey::GenerateDomain();
- GrUniqueKey::Builder builder(key, kImageIDDomain, 5);
+static void get_stretch(const GrCaps& caps, int width, int height,
+ const GrTextureParams& params, SkGrStretch* stretch) {
+ stretch->fType = SkGrStretch::kNone_Type;
+ bool doStretch = false;
+ if (params.isTiled() && !caps.npotTextureTileSupport() &&
+ (!SkIsPow2(width) || !SkIsPow2(height))) {
+ doStretch = true;
+ stretch->fWidth = GrNextPow2(SkTMax(width, caps.minTextureSize()));
+ stretch->fHeight = GrNextPow2(SkTMax(height, caps.minTextureSize()));
+ } else if (width < caps.minTextureSize() || height < caps.minTextureSize()) {
+ // The small texture issues appear to be with tiling. Hence it seems ok to scale them
+ // up using the GPU. If issues persist we may need to CPU-stretch.
+ doStretch = true;
+ stretch->fWidth = SkTMax(width, caps.minTextureSize());
+ stretch->fHeight = SkTMax(height, caps.minTextureSize());
+ }
+ if (doStretch) {
+ switch (params.filterMode()) {
+ case GrTextureParams::kNone_FilterMode:
+ stretch->fType = SkGrStretch::kNearest_Type;
+ break;
+ case GrTextureParams::kBilerp_FilterMode:
+ case GrTextureParams::kMipMap_FilterMode:
+ stretch->fType = SkGrStretch::kBilerp_Type;
+ break;
+ }
+ } else {
+ stretch->fWidth = -1;
+ stretch->fHeight = -1;
+ stretch->fType = SkGrStretch::kNone_Type;
+ }
+}
+
+static void make_unstretched_key(GrUniqueKey* key, uint32_t imageID, const SkIRect& subset) {
+ SkASSERT(SkIsU16(subset.width()));
+ SkASSERT(SkIsU16(subset.height()));
+
+ static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
+ GrUniqueKey::Builder builder(key, kDomain, 4);
builder[0] = imageID;
- builder[1] = imageBounds.fLeft;
- builder[2] = imageBounds.fTop;
- builder[3] = imageBounds.fRight;
- builder[4] = imageBounds.fBottom;
+ builder[1] = subset.x();
+ builder[2] = subset.y();
+ builder[3] = subset.width() | (subset.height() << 16);
+}
+
+void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& subset,
+ const GrCaps& caps, const GrTextureParams& params) {
+ SkGrStretch stretch;
+ get_stretch(caps, subset.width(), subset.height(), params, &stretch);
+ if (SkGrStretch::kNone_Type != stretch.fType) {
+ GrUniqueKey tmpKey;
+ make_unstretched_key(&tmpKey, imageID, subset);
+ if (!GrMakeStretchedKey(tmpKey, stretch, key)) {
+ *key = tmpKey;
+ }
+ } else {
+ make_unstretched_key(key, imageID, subset);
+ }
}
GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data,
@@ -103,19 +150,16 @@ GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data,
return kUnknown_GrPixelConfig;
}
-//////////////////////////////////////////////////////////////////////////////
+/* Fill out buffer with the compressed format Ganesh expects from a colortable
+ based bitmap. [palette (colortable) + indices].
-/**
- * Fill out buffer with the compressed format Ganesh expects from a colortable
- * based bitmap. [palette (colortable) + indices].
- *
- * At the moment Ganesh only supports 8bit version. If Ganesh allowed we others
- * we could detect that the colortable.count is <= 16, and then repack the
- * indices as nibbles to save RAM, but it would take more time (i.e. a lot
- * slower than memcpy), so skipping that for now.
- *
- * Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big
- * as the colortable.count says it is.
+ At the moment Ganesh only supports 8bit version. If Ganesh allowed we others
+ we could detect that the colortable.count is <= 16, and then repack the
+ indices as nibbles to save RAM, but it would take more time (i.e. a lot
+ slower than memcpy), so skipping that for now.
+
+ Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big
+ as the colortable.count says it is.
*/
static void build_index8_data(void* buffer, const SkBitmap& bitmap) {
SkASSERT(kIndex_8_SkColorType == bitmap.colorType());
@@ -163,7 +207,130 @@ static void build_index8_data(void* buffer, const SkBitmap& bitmap) {
}
}
-/**
+////////////////////////////////////////////////////////////////////////////////
+
+
+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);
+ static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
+ GrUniqueKey::Builder builder(stretchedKey, origKey, kDomain, 2);
+ builder[0] = stretch.fType;
+ builder[1] = width | (height << 16);
+ builder.finish();
+ return true;
+ }
+ SkASSERT(!stretchedKey->isValid());
+ return false;
+}
+
+namespace {
+
+// When the SkPixelRef genID changes, invalidate a corresponding GrResource described by key.
+class BitmapInvalidator : public SkPixelRef::GenIDChangeListener {
+public:
+ explicit BitmapInvalidator(const GrUniqueKey& key) : fMsg(key) {}
+private:
+ GrUniqueKeyInvalidatedMessage fMsg;
+
+ void onChange() override {
+ SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
+ }
+};
+
+} // namespace
+
+
+GrTexture* GrCreateTextureForPixels(GrContext* ctx,
+ const GrUniqueKey& optionalKey,
+ GrSurfaceDesc desc,
+ SkPixelRef* pixelRefForInvalidationNotification,
+ const void* pixels,
+ size_t rowBytes) {
+ GrTexture* result = ctx->textureProvider()->createTexture(desc, true, pixels, rowBytes);
+ if (result && optionalKey.isValid()) {
+ if (pixelRefForInvalidationNotification) {
+ BitmapInvalidator* listener = new BitmapInvalidator(optionalKey);
+ pixelRefForInvalidationNotification->addGenIDChangeListener(listener);
+ }
+ ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, result);
+ }
+ return result;
+}
+
+// creates a new texture that is the input texture scaled up. If optionalKey is valid it will be
+// set on the new texture. stretch controls whether the scaling is done using nearest or bilerp
+// filtering and the size to stretch the texture to.
+GrTexture* stretch_texture(GrTexture* inputTexture, const SkGrStretch& stretch,
+ SkPixelRef* pixelRef,
+ const GrUniqueKey& optionalKey) {
+ SkASSERT(SkGrStretch::kNone_Type != stretch.fType);
+
+ GrContext* context = inputTexture->getContext();
+ SkASSERT(context);
+ const GrCaps* caps = context->caps();
+
+ // Either it's a cache miss or the original wasn't cached to begin with.
+ GrSurfaceDesc rtDesc = inputTexture->desc();
+ rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
+ rtDesc.fWidth = stretch.fWidth;
+ rtDesc.fHeight = stretch.fHeight;
+ rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig);
+
+ // If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise,
+ // fail.
+ if (!caps->isConfigRenderable(rtDesc.fConfig, false)) {
+ if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) {
+ if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
+ rtDesc.fConfig = kAlpha_8_GrPixelConfig;
+ } else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
+ rtDesc.fConfig = kSkia8888_GrPixelConfig;
+ } else {
+ return nullptr;
+ }
+ } else if (kRGB_GrColorComponentFlags ==
+ (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) {
+ if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
+ rtDesc.fConfig = kSkia8888_GrPixelConfig;
+ } else {
+ return nullptr;
+ }
+ } else {
+ return nullptr;
+ }
+ }
+
+ SkAutoTUnref<GrTexture> stretched(GrCreateTextureForPixels(context, optionalKey, rtDesc,
+ pixelRef, nullptr,0));
+ if (!stretched) {
+ return nullptr;
+ }
+ GrPaint paint;
+
+ // If filtering is not desired then we want to ensure all texels in the resampled image are
+ // copies of texels from the original.
+ GrTextureParams params(SkShader::kClamp_TileMode,
+ SkGrStretch::kBilerp_Type == stretch.fType ?
+ GrTextureParams::kBilerp_FilterMode :
+ GrTextureParams::kNone_FilterMode);
+ paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);
+
+ SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
+ SkRect localRect = SkRect::MakeWH(1.f, 1.f);
+
+ SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(stretched->asRenderTarget()));
+ if (!drawContext) {
+ return nullptr;
+ }
+
+ drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, localRect);
+
+ return stretched.detach();
+}
+
+/*
* Once we have made SkImages handle all lazy/deferred/generated content, the YUV apis will
* be gone from SkPixelRef, and we can remove this subclass entirely.
*/
@@ -183,22 +350,33 @@ public:
}
};
-static GrTexture* create_texture_from_yuv(GrContext* ctx, const SkBitmap& bm,
- const GrSurfaceDesc& desc) {
+static GrTexture* load_yuv_texture(GrContext* ctx, const GrUniqueKey& optionalKey,
+ const SkBitmap& bm, const GrSurfaceDesc& desc) {
// Subsets are not supported, the whole pixelRef is loaded when using YUV decoding
SkPixelRef* pixelRef = bm.pixelRef();
if ((nullptr == pixelRef) ||
- (pixelRef->info().width() != bm.info().width()) ||
+ (pixelRef->info().width() != bm.info().width()) ||
(pixelRef->info().height() != bm.info().height())) {
return nullptr;
}
+ const bool useCache = optionalKey.isValid();
PixelRef_GrYUVProvider provider(pixelRef);
+ GrTexture* texture = provider.refAsTexture(ctx, desc, useCache);
+ if (!texture) {
+ return nullptr;
+ }
- return provider.refAsTexture(ctx, desc, !bm.isVolatile());
+ if (useCache) {
+ BitmapInvalidator* listener = new BitmapInvalidator(optionalKey);
+ pixelRef->addGenIDChangeListener(listener);
+ ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, texture);
+ }
+ return texture;
}
-static GrTexture* load_etc1_texture(GrContext* ctx, const SkBitmap &bm, GrSurfaceDesc desc) {
+static GrTexture* load_etc1_texture(GrContext* ctx, const GrUniqueKey& optionalKey,
+ const SkBitmap &bm, GrSurfaceDesc desc) {
SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
if (!data) {
return nullptr;
@@ -211,19 +389,19 @@ static GrTexture* load_etc1_texture(GrContext* ctx, const SkBitmap &bm, GrSurfac
return nullptr;
}
- return ctx->textureProvider()->createTexture(desc, true, startOfTexData, 0);
+ return GrCreateTextureForPixels(ctx, optionalKey, desc, bm.pixelRef(), startOfTexData, 0);
}
-GrTexture* GrUploadBitmapToTexture(GrContext* ctx, const SkBitmap& bmp) {
- SkASSERT(!bmp.getTexture());
-
- if (bmp.width() < ctx->caps()->minTextureSize() ||
- bmp.height() < ctx->caps()->minTextureSize()) {
+static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
+ const SkBitmap& origBitmap,
+ const GrUniqueKey& optionalKey) {
+ if (origBitmap.width() < ctx->caps()->minTextureSize() ||
+ origBitmap.height() < ctx->caps()->minTextureSize()) {
return nullptr;
}
-
SkBitmap tmpBitmap;
- const SkBitmap* bitmap = &bmp;
+
+ const SkBitmap* bitmap = &origBitmap;
GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap->info());
const GrCaps* caps = ctx->caps();
@@ -233,14 +411,14 @@ GrTexture* GrUploadBitmapToTexture(GrContext* ctx, const SkBitmap& bmp) {
size_t imageSize = GrCompressedFormatDataSize(kIndex_8_GrPixelConfig,
bitmap->width(), bitmap->height());
SkAutoMalloc storage(imageSize);
- build_index8_data(storage.get(), bmp);
+ build_index8_data(storage.get(), origBitmap);
// our compressed data will be trimmed, so pass width() for its
// "rowBytes", since they are the same now.
- return ctx->textureProvider()->createTexture(desc, true, storage.get(),
- bitmap->width());
+ return GrCreateTextureForPixels(ctx, optionalKey, desc, origBitmap.pixelRef(),
+ storage.get(), bitmap->width());
} else {
- bmp.copyTo(&tmpBitmap, kN32_SkColorType);
+ origBitmap.copyTo(&tmpBitmap, kN32_SkColorType);
// now bitmap points to our temp, which has been promoted to 32bits
bitmap = &tmpBitmap;
desc.fConfig = SkImageInfo2GrPixelConfig(bitmap->info());
@@ -250,16 +428,13 @@ GrTexture* GrUploadBitmapToTexture(GrContext* ctx, const SkBitmap& bmp) {
// compressed data on 'refEncodedData' and upload it. Probably not good, since if
// the bitmap has available pixels, then they might not be what the decompressed
// data is.
-
- // Really?? We aren't doing this with YUV.
-
- GrTexture *texture = load_etc1_texture(ctx, *bitmap, desc);
+ GrTexture *texture = load_etc1_texture(ctx, optionalKey, *bitmap, desc);
if (texture) {
return texture;
}
}
- GrTexture *texture = create_texture_from_yuv(ctx, *bitmap, desc);
+ GrTexture *texture = load_yuv_texture(ctx, optionalKey, *bitmap, desc);
if (texture) {
return texture;
}
@@ -269,90 +444,83 @@ GrTexture* GrUploadBitmapToTexture(GrContext* ctx, const SkBitmap& bmp) {
return nullptr;
}
- return ctx->textureProvider()->createTexture(desc, true, bitmap->getPixels(),
- bitmap->rowBytes());
+ return GrCreateTextureForPixels(ctx, optionalKey, desc, origBitmap.pixelRef(),
+ bitmap->getPixels(), bitmap->rowBytes());
}
+static SkBitmap stretch_on_cpu(const SkBitmap& bmp, const SkGrStretch& stretch) {
+ SkBitmap stretched;
+ stretched.allocN32Pixels(stretch.fWidth, stretch.fHeight);
+ SkCanvas canvas(stretched);
+ SkPaint paint;
+ switch (stretch.fType) {
+ case SkGrStretch::kNearest_Type:
+ paint.setFilterQuality(kNone_SkFilterQuality);
+ break;
+ case SkGrStretch::kBilerp_Type:
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ break;
+ case SkGrStretch::kNone_Type:
+ SkDEBUGFAIL("Shouldn't get here.");
+ break;
+ }
+ SkRect dstRect = SkRect::MakeWH(SkIntToScalar(stretch.fWidth), SkIntToScalar(stretch.fHeight));
+ canvas.drawBitmapRect(bmp, dstRect, &paint);
+ return stretched;
+}
-////////////////////////////////////////////////////////////////////////////////
-
-class Bitmap_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
+class Bitmap_GrTextureMaker : public GrTextureMaker {
public:
- Bitmap_GrTextureParamsAdjuster(const SkBitmap& bitmap)
+ Bitmap_GrTextureMaker(const SkBitmap& bitmap)
: INHERITED(bitmap.width(), bitmap.height())
, fBitmap(bitmap)
- {
- if (!bitmap.isVolatile()) {
- SkIPoint origin = bitmap.pixelRefOrigin();
- SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, bitmap.width(),
- bitmap.height());
- GrMakeKeyFromImageID(&fOriginalKey, bitmap.pixelRef()->getGenerationID(), subset);
- }
- }
+ {}
protected:
- GrTexture* refOriginalTexture(GrContext* ctx) {
+ GrTexture* onRefUnstretchedTexture(GrContext* ctx) override {
GrTexture* tex = fBitmap.getTexture();
if (tex) {
return SkRef(tex);
}
- if (fOriginalKey.isValid()) {
- tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(fOriginalKey);
- if (tex) {
- return tex;
- }
- }
+ GrUniqueKey unstretchedKey;
+ make_unstretched_key(&unstretchedKey, fBitmap.getGenerationID(), fBitmap.getSubset());
- tex = GrUploadBitmapToTexture(ctx, fBitmap);
- if (tex) {
- tex->resourcePriv().setUniqueKey(fOriginalKey);
- InstallInvalidator(fOriginalKey, fBitmap.pixelRef());
+ GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(unstretchedKey);
+ if (result) {
+ return result;
}
- return tex;
+ return create_unstretched_bitmap_texture(ctx, fBitmap, unstretchedKey);
}
- void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) override {
- if (fOriginalKey.isValid()) {
- MakeCopyKeyFromOrigKey(fOriginalKey, copyParams, copyKey);
+ bool onMakeStretchedKey(const SkGrStretch& stretch, GrUniqueKey* stretchedKey) override {
+ if (fBitmap.isVolatile()) {
+ return false;
}
+
+ GrUniqueKey unstretchedKey;
+ make_unstretched_key(&unstretchedKey, fBitmap.getGenerationID(), fBitmap.getSubset());
+ return GrMakeStretchedKey(unstretchedKey, stretch, stretchedKey);
}
- void didCacheCopy(const GrUniqueKey& copyKey) override {
- InstallInvalidator(copyKey, fBitmap.pixelRef());
+ void onNotifyStretchCached(const GrUniqueKey& stretchedKey) override {
+ fBitmap.pixelRef()->addGenIDChangeListener(new BitmapInvalidator(stretchedKey));
}
- bool getROBitmap(SkBitmap* bitmap) override {
- SkASSERT(!fBitmap.getTexture());
+ bool onGetROBitmap(SkBitmap* bitmap) override {
*bitmap = fBitmap;
return true;
}
private:
- static void InstallInvalidator(const GrUniqueKey& key, SkPixelRef* pixelRef) {
- class Invalidator : public SkPixelRef::GenIDChangeListener {
- public:
- explicit Invalidator(const GrUniqueKey& key) : fMsg(key) {}
- private:
- GrUniqueKeyInvalidatedMessage fMsg;
-
- void onChange() override {
- SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
- }
- };
- Invalidator* listener = new Invalidator(key);
- pixelRef->addGenIDChangeListener(listener);
- }
-
- const SkBitmap fBitmap;
- GrUniqueKey fOriginalKey;
+ const SkBitmap fBitmap;
- typedef GrTextureParamsAdjuster INHERITED;
+ typedef GrTextureMaker INHERITED;
};
GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap,
const GrTextureParams& params) {
- return Bitmap_GrTextureParamsAdjuster(bitmap).refTextureForParams(ctx, params);
+ return Bitmap_GrTextureMaker(bitmap).refCachedTexture(ctx, params);
}
///////////////////////////////////////////////////////////////////////////////
@@ -424,6 +592,7 @@ bool GrPixelConfig2ColorAndProfileType(GrPixelConfig config, SkColorType* ctOut,
return true;
}
+
////////////////////////////////////////////////////////////////////////////////////////////////
static inline bool blend_requires_shader(const SkXfermode::Mode mode, bool primitiveIsSrc) {
@@ -673,3 +842,54 @@ GrTextureParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality pain
}
return textureFilterMode;
}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+GrTexture* GrTextureMaker::refCachedTexture(GrContext* ctx, const GrTextureParams& params) {
+ SkGrStretch stretch;
+ get_stretch(*ctx->caps(), this->width(), this->height(), params, &stretch);
+
+ if (SkGrStretch::kNone_Type == stretch.fType) {
+ return this->onRefUnstretchedTexture(ctx);
+ }
+
+ GrUniqueKey stretchedKey;
+ if (this->onMakeStretchedKey(stretch, &stretchedKey)) {
+ GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(stretchedKey);
+ if (result) {
+ return result;
+ }
+ }
+
+ GrTexture* result = this->onGenerateStretchedTexture(ctx, stretch);
+ if (!result) {
+ return nullptr;
+ }
+
+ if (stretchedKey.isValid()) {
+ ctx->textureProvider()->assignUniqueKeyToTexture(stretchedKey, result);
+ this->onNotifyStretchCached(stretchedKey);
+ }
+ return result;
+}
+
+GrTexture* GrTextureMaker::onGenerateStretchedTexture(GrContext* ctx, const SkGrStretch& stretch) {
+ if (this->width() < ctx->caps()->minTextureSize() ||
+ this->height() < ctx->caps()->minTextureSize())
+ {
+ // we can't trust our ability to use HW to perform the stretch, so we request
+ // a raster instead, and perform the stretch on the CPU.
+ SkBitmap bitmap;
+ if (!this->onGetROBitmap(&bitmap)) {
+ return nullptr;
+ }
+ SkBitmap stretchedBmp = stretch_on_cpu(bitmap, stretch);
+ return create_unstretched_bitmap_texture(ctx, stretchedBmp, GrUniqueKey());
+ } else {
+ SkAutoTUnref<GrTexture> unstretched(this->onRefUnstretchedTexture(ctx));
+ if (!unstretched) {
+ return nullptr;
+ }
+ return stretch_texture(unstretched, stretch, nullptr, GrUniqueKey());
+ }
+}
diff --git a/src/gpu/SkGrPriv.h b/src/gpu/SkGrPriv.h
index 593530997f..c92e580885 100644
--- a/src/gpu/SkGrPriv.h
+++ b/src/gpu/SkGrPriv.h
@@ -26,18 +26,34 @@ class SkPaint;
class SkPixelRef;
struct SkIRect;
+struct SkGrStretch {
+ enum Type {
+ kNone_Type,
+ kBilerp_Type,
+ kNearest_Type
+ } fType;
+ int fWidth;
+ int fHeight;
+};
+
/**
* 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())
+ * 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, const SkIRect& imageBounds);
+void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds,
+ const GrCaps&, const GrTextureParams&);
+
+/**
+ * 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. The primitive itself has no color. */
@@ -87,24 +103,21 @@ GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo&);
bool GrPixelConfig2ColorAndProfileType(GrPixelConfig, SkColorType*, SkColorProfileType*);
/**
- * If the compressed data in the SkData is supported (as a texture format, this returns
- * the pixel-config that should be used, and sets outStartOfDataToUpload to the ptr into
- * the data where the actual raw data starts (skipping any header bytes).
- *
- * If the compressed data is not supported, this returns kUnknown_GrPixelConfig, and
- * ignores outStartOfDataToUpload.
- */
+* If the compressed data in the SkData is supported (as a texture format, this returns
+* the pixel-config that should be used, and sets outStartOfDataToUpload to the ptr into
+* the data where the actual raw data starts (skipping any header bytes).
+*
+* If the compressed data is not supported, this returns kUnknown_GrPixelConfig, and
+* ignores outStartOfDataToUpload.
+*/
GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data,
int expectedW, int expectedH,
const void** outStartOfDataToUpload);
+GrTexture* GrCreateTextureForPixels(GrContext*, const GrUniqueKey& optionalKey, GrSurfaceDesc,
+ SkPixelRef* pixelRefForInvalidationNotificationOrNull,
+ const void* pixels, size_t rowBytesOrZero);
-/**
- * Creates a new texture for the bitmap. Does not concern itself with cache keys or texture params.
- * The bitmap must have CPU-accessible pixels. Attempts to take advantage of faster paths for
- * compressed textures and yuv planes.
- */
-GrTexture* GrUploadBitmapToTexture(GrContext*, const SkBitmap&);
//////////////////////////////////////////////////////////////////////////////
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 039bbdd100..67d1b8cd86 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -10,7 +10,7 @@
#include "GrCaps.h"
#include "GrContext.h"
#include "GrDrawContext.h"
-#include "GrTextureParamsAdjuster.h"
+#include "GrTextureMaker.h"
#include "effects/GrYUVtoRGBEffect.h"
#include "SkCanvas.h"
#include "SkGpuDevice.h"
@@ -64,51 +64,56 @@ bool SkImage_Gpu::getROPixels(SkBitmap* dst) const {
return true;
}
-static void make_raw_texture_stretched_key(uint32_t imageID,
- const GrTextureParamsAdjuster::CopyParams& params,
+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, 4);
+ GrUniqueKey::Builder builder(stretchedKey, kDomain, 3);
builder[0] = imageID;
- builder[1] = params.fFilter;
- builder[2] = params.fWidth;
- builder[3] = params.fHeight;
+ builder[1] = stretch.fType;
+ builder[2] = width | (height << 16);
+ builder.finish();
}
-class Texture_GrTextureParamsAdjuster : public GrTextureParamsAdjuster {
+class Texture_GrTextureMaker : public GrTextureMaker {
public:
- Texture_GrTextureParamsAdjuster(const SkImage* image, GrTexture* unstretched)
+ Texture_GrTextureMaker(const SkImage* image, GrTexture* unstretched)
: INHERITED(image->width(), image->height())
, fImage(image)
- , fOriginal(unstretched)
+ , fUnstretched(unstretched)
{}
protected:
- GrTexture* refOriginalTexture(GrContext* ctx) override {
- return SkRef(fOriginal);
+ GrTexture* onRefUnstretchedTexture(GrContext* ctx) override {
+ return SkRef(fUnstretched);
}
- void makeCopyKey(const CopyParams& copyParams, GrUniqueKey* copyKey) override {
- make_raw_texture_stretched_key(fImage->uniqueID(), copyParams, copyKey);
+ bool onMakeStretchedKey(const SkGrStretch& stretch, GrUniqueKey* stretchedKey) override {
+ make_raw_texture_stretched_key(fImage->uniqueID(), stretch, stretchedKey);
+ return stretchedKey->isValid();
}
- void didCacheCopy(const GrUniqueKey& copyKey) override {
+ void onNotifyStretchCached(const GrUniqueKey& stretchedKey) override {
as_IB(fImage)->notifyAddedToCache();
}
- bool getROBitmap(SkBitmap* bitmap) override {
+ bool onGetROBitmap(SkBitmap* bitmap) override {
return as_IB(fImage)->getROPixels(bitmap);
}
private:
const SkImage* fImage;
- GrTexture* fOriginal;
+ GrTexture* fUnstretched;
- typedef GrTextureParamsAdjuster INHERITED;
+ typedef GrTextureMaker INHERITED;
};
GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrTextureParams& params) const {
- return Texture_GrTextureParamsAdjuster(this, fTexture).refTextureForParams(ctx, params);
+ return Texture_GrTextureMaker(this, fTexture).refCachedTexture(ctx, params);
}
bool SkImage_Gpu::isOpaque() const {
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index 9c90ba908b..b78818db6b 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -173,6 +173,20 @@ GrTexture* SkImage_Raster::asTextureRef(GrContext* ctx, const GrTextureParams& p
return nullptr;
}
+ // textures (at least the texture-key) only support 16bit dimensions, so abort early
+ // if we're too big.
+ if (fBitmap.width() > 0xFFFF || fBitmap.height() > 0xFFFF) {
+ return nullptr;
+ }
+
+ GrUniqueKey key;
+ GrMakeKeyFromImageID(&key, fBitmap.getGenerationID(),
+ SkIRect::MakeWH(fBitmap.width(), fBitmap.height()),
+ *ctx->caps(), params);
+
+ if (GrTexture* tex = ctx->textureProvider()->findAndRefTextureByUniqueKey(key)) {
+ return tex;
+ }
return GrRefCachedBitmapTexture(ctx, fBitmap, params);
#endif