From 91957941ce2fe9457babe7f83514e4599089d411 Mon Sep 17 00:00:00 2001 From: egdaniel Date: Fri, 16 Oct 2015 13:59:14 -0700 Subject: 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/ ) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- gyp/gpu.gypi | 2 - include/gpu/GrResourceKey.h | 4 +- include/gpu/SkGr.h | 6 +- src/core/SkImageCacherator.cpp | 73 ++++--- src/core/SkImageCacherator.h | 9 +- src/gpu/GrGpu.cpp | 31 --- src/gpu/GrGpu.h | 8 - src/gpu/GrTextureMaker.h | 76 +++++++ src/gpu/GrTextureParamsAdjuster.cpp | 152 ------------- src/gpu/GrTextureParamsAdjuster.h | 107 --------- src/gpu/SkGr.cpp | 418 +++++++++++++++++++++++++++--------- src/gpu/SkGrPriv.h | 43 ++-- src/image/SkImage_Gpu.cpp | 43 ++-- src/image/SkImage_Raster.cpp | 14 ++ 14 files changed, 506 insertions(+), 480 deletions(-) create mode 100644 src/gpu/GrTextureMaker.h delete mode 100644 src/gpu/GrTextureParamsAdjuster.cpp delete mode 100644 src/gpu/GrTextureParamsAdjuster.h 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 fKey; + // bmp textures require 4 uint32_t values. + SkAutoSTMalloc 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 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 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, - ©Params)) { - return this->refOriginalTexture(ctx); - } - GrUniqueKey copyKey; - this->makeCopyKey(copyParams, ©Key); - 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 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::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 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 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 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::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 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 -- cgit v1.2.3