aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2015-01-31 19:27:53 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-01-31 19:27:53 -0800
commit6c96672491b04cb782bce8fee778124df66524a0 (patch)
tree49407e533766dad8d3fae3c5794afc4536a79098
parent0b737c52a7b8bc6ba41d309e88b3f7e995746f8d (diff)
Move npot resizing out of GrContext and simplify GrContext texture functions.
-rw-r--r--include/gpu/GrContext.h101
-rw-r--r--include/gpu/GrPaint.h14
-rw-r--r--include/gpu/GrResourceKey.h1
-rw-r--r--include/gpu/GrTypes.h16
-rw-r--r--src/effects/SkBlurMaskFilter.cpp36
-rw-r--r--src/effects/SkColorCubeFilter.cpp12
-rwxr-xr-xsrc/gpu/GrContext.cpp275
-rw-r--r--src/gpu/SkGr.cpp282
-rw-r--r--src/gpu/effects/GrTextureStripAtlas.cpp6
-rw-r--r--tests/GLProgramsTest.cpp10
10 files changed, 332 insertions, 421 deletions
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index e6fdeb89f7..88a31484ed 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -169,10 +169,10 @@ public:
*/
void purgeAllUnlockedResources();
- /**
- * Stores a custom resource in the cache, based on the specified key.
+ /** Sets a content key on the resource. The resource must not already have a content key and
+ * the key must not already be in use for this to succeed.
*/
- void addResourceToCache(const GrContentKey&, GrGpuResource*);
+ bool addResourceToCache(const GrContentKey&, GrGpuResource*);
/**
* Finds a resource in the cache, based on the specified key. This is intended for use in
@@ -181,6 +181,25 @@ public:
*/
GrGpuResource* findAndRefCachedResource(const GrContentKey&);
+ /** Helper for casting resource to a texture. Caller must be sure that the resource cached
+ with the key is either NULL or a texture and not another resource type. */
+ GrTexture* findAndRefCachedTexture(const GrContentKey& key) {
+ GrGpuResource* resource = this->findAndRefCachedResource(key);
+ if (resource) {
+ GrTexture* texture = static_cast<GrSurface*>(resource)->asTexture();
+ SkASSERT(texture);
+ return texture;
+ }
+ return NULL;
+ }
+
+ /**
+ * Determines whether a resource is in the cache. If the resource is found it
+ * will not be locked or returned. This call does not affect the priority of
+ * the resource for deletion.
+ */
+ bool isResourceInCache(const GrContentKey& key) const;
+
/**
* Creates a new text rendering context that is optimal for the
* render target and the context. Caller assumes the ownership
@@ -195,57 +214,28 @@ public:
// Textures
/**
- * Creates a new entry, based on the specified key and texture and returns it. The caller owns a
+ * Creates a new texture in the resource cache and returns it. The caller owns a
* ref on the returned texture which must be balanced by a call to unref.
*
- * TODO: Move resizing logic out of GrContext and have the caller set the content key on the
- * returned texture rather than take it as a param.
- *
- * @param params The texture params used to draw a texture may help determine
- * the cache entry used. (e.g. different versions may exist
- * for different wrap modes on GPUs with limited NPOT
- * texture support). NULL implies clamp wrap modes.
* @param desc Description of the texture properties.
- * @param key Key to associate with the texture.
* @param srcData Pointer to the pixel values.
* @param rowBytes The number of bytes between rows of the texture. Zero
* implies tightly packed rows. For compressed pixel configs, this
* field is ignored.
- * @param outKey (optional) If non-NULL, we'll write the cache key we used to cacheKey. this
- * may differ from key on GPUs that don't support tiling NPOT textures.
- */
- GrTexture* createTexture(const GrTextureParams* params,
- const GrSurfaceDesc& desc,
- const GrContentKey& key,
- const void* srcData,
- size_t rowBytes,
- GrContentKey* outKey = NULL);
- /**
- * Search for an entry based on key and dimensions. If found, ref it and return it. The return
- * value will be NULL if not found. The caller must balance with a call to unref.
- *
- * TODO: Remove this function and do lookups generically.
- *
- * @param desc Description of the texture properties.
- * @param key key to use for texture look up.
- * @param params The texture params used to draw a texture may help determine
- * the cache entry used. (e.g. different versions may exist
- * for different wrap modes on GPUs with limited NPOT
- * texture support). NULL implies clamp wrap modes.
- */
- GrTexture* findAndRefTexture(const GrSurfaceDesc& desc,
- const GrContentKey& key,
- const GrTextureParams* params);
- /**
- * Determines whether a texture is in the cache. If the texture is found it
- * will not be locked or returned. This call does not affect the priority of
- * the texture for deletion.
+ */
+ GrTexture* createTexture(const GrSurfaceDesc& desc, const void* srcData, size_t rowBytes);
+
+ GrTexture* createTexture(const GrSurfaceDesc& desc) {
+ return this->createTexture(desc, NULL, 0);
+ }
+
+ /**
+ * Creates a texture that is outside the cache. Does not count against
+ * cache's budget.
*
- * TODO: Remove this function and do cache checks generically.
+ * TODO: Add a budgeted param to createTexture and remove this function.
*/
- bool isTextureInCache(const GrSurfaceDesc& desc,
- const GrContentKey& key,
- const GrTextureParams* params) const;
+ GrTexture* createUncachedTexture(const GrSurfaceDesc& desc, void* srcData, size_t rowBytes);
/**
* Enum that determines how closely a returned scratch texture must match
@@ -284,26 +274,9 @@ public:
bool internalFlag = false);
/**
- * Creates a texture that is outside the cache. Does not count against
- * cache's budget.
- *
- * Textures created by createTexture() hide the complications of
- * tiling non-power-of-two textures on APIs that don't support this (e.g.
- * unextended GLES2). NPOT uncached textures are not tilable on such APIs.
- */
- GrTexture* createUncachedTexture(const GrSurfaceDesc& desc,
- void* srcData,
- size_t rowBytes);
-
- /**
- * Returns true if the specified use of an indexed texture is supported.
- * Support may depend upon whether the texture params indicate that the
- * texture will be tiled. Passing NULL for the texture params indicates
- * clamp mode.
+ * Returns true if index8 textures are supported.
*/
- bool supportsIndex8PixelConfig(const GrTextureParams*,
- int width,
- int height) const;
+ bool supportsIndex8PixelConfig() const;
/**
* Return the max width or height of a texture supported by the current GPU.
diff --git a/include/gpu/GrPaint.h b/include/gpu/GrPaint.h
index 8163f6e4d8..64b51d2c65 100644
--- a/include/gpu/GrPaint.h
+++ b/include/gpu/GrPaint.h
@@ -25,23 +25,15 @@
* created by subclassing GrProcessor.
*
* The primitive color computation starts with the color specified by setColor(). This color is the
- * input to the first color stage. Each color stage feeds its output to the next color stage. The
- * final color stage's output color is input to the color filter specified by
- * setXfermodeColorFilter which produces the final source color, S.
+ * input to the first color stage. Each color stage feeds its output to the next color stage.
*
* Fractional pixel coverage follows a similar flow. The coverage is initially the value specified
* by setCoverage(). This is input to the first coverage stage. Coverage stages are chained
* together in the same manner as color stages. The output of the last stage is modulated by any
* fractional coverage produced by anti-aliasing. This last step produces the final coverage, C.
*
- * setBlendFunc() specifies blending coefficients for S (described above) and D, the initial value
- * of the destination pixel, labeled Bs and Bd respectively. The final value of the destination
- * pixel is then D' = (1-C)*D + C*(Bd*D + Bs*S).
- *
- * Note that the coverage is applied after the blend. This is why they are computed as distinct
- * values.
- *
- * TODO: Encapsulate setXfermodeColorFilter in a GrProcessor and remove from GrPaint.
+ * setXPFactory is used to control blending between the output color and dest. It also implements
+ * the application of fractional coverage from the coverage pipeline.
*/
class GrPaint {
public:
diff --git a/include/gpu/GrResourceKey.h b/include/gpu/GrResourceKey.h
index 4c76b68c2d..e09a2c710f 100644
--- a/include/gpu/GrResourceKey.h
+++ b/include/gpu/GrResourceKey.h
@@ -220,6 +220,7 @@ public:
Builder(GrContentKey* key, const GrContentKey& innerKey, Domain domain,
int extraData32Cnt)
: INHERITED::Builder(key, domain, Data32CntForInnerKey(innerKey) + extraData32Cnt) {
+ SkASSERT(&innerKey != key);
// add the inner key to the end of the key so that op[] can be indexed normally.
uint32_t* innerKeyData = &this->operator[](extraData32Cnt);
const uint32_t* srcData = innerKey.data();
diff --git a/include/gpu/GrTypes.h b/include/gpu/GrTypes.h
index f4fb3ab43f..7532984ebe 100644
--- a/include/gpu/GrTypes.h
+++ b/include/gpu/GrTypes.h
@@ -302,6 +302,22 @@ static inline bool GrPixelConfigIsCompressed(GrPixelConfig config) {
}
}
+/** If the pixel config is compressed, return an equivalent uncompressed format. */
+static inline GrPixelConfig GrMakePixelConfigUncompressed(GrPixelConfig config) {
+ switch (config) {
+ case kIndex_8_GrPixelConfig:
+ case kETC1_GrPixelConfig:
+ case kASTC_12x12_GrPixelConfig:
+ return kRGBA_8888_GrPixelConfig;
+ case kLATC_GrPixelConfig:
+ case kR11_EAC_GrPixelConfig:
+ return kAlpha_8_GrPixelConfig;
+ default:
+ SkASSERT(!GrPixelConfigIsCompressed(config));
+ return config;
+ }
+}
+
// Returns true if the pixel config is 32 bits per pixel
static inline bool GrPixelConfigIs8888(GrPixelConfig config) {
switch (config) {
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 3487ae40b4..d284717f93 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -750,7 +750,6 @@ void GrGLRectBlurEffect::setData(const GrGLProgramDataManager& pdman,
bool GrRectBlurEffect::CreateBlurProfileTexture(GrContext *context, float sigma,
GrTexture **blurProfileTexture) {
- GrTextureParams params;
GrSurfaceDesc texDesc;
unsigned int profileSize = SkScalarCeilToInt(6*sigma);
@@ -768,18 +767,19 @@ bool GrRectBlurEffect::CreateBlurProfileTexture(GrContext *context, float sigma,
uint8_t *profile = NULL;
SkAutoTDeleteArray<uint8_t> ada(NULL);
- *blurProfileTexture = context->findAndRefTexture(texDesc, key, &params);
+ *blurProfileTexture = context->findAndRefCachedTexture(key);
if (NULL == *blurProfileTexture) {
SkBlurMask::ComputeBlurProfile(sigma, &profile);
ada.reset(profile);
- *blurProfileTexture = context->createTexture(&params, texDesc, key, profile, 0);
+ *blurProfileTexture = context->createTexture(texDesc, profile, 0);
if (NULL == *blurProfileTexture) {
return false;
}
+ SkAssertResult(context->addResourceToCache(key, *blurProfileTexture));
}
return true;
@@ -925,21 +925,13 @@ GrFragmentProcessor* GrRRectBlurEffect::Create(GrContext* context, float sigma,
builder[1] = cornerRadius;
builder.finish();
- GrTextureParams params;
- params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
-
- unsigned int smallRectSide = 2*(blurRadius + cornerRadius) + 1;
- unsigned int texSide = smallRectSide + 2*blurRadius;
- GrSurfaceDesc texDesc;
- texDesc.fWidth = texSide;
- texDesc.fHeight = texSide;
- texDesc.fConfig = kAlpha_8_GrPixelConfig;
-
- GrTexture *blurNinePatchTexture = context->findAndRefTexture(texDesc, key, &params);
+ GrTexture *blurNinePatchTexture = context->findAndRefCachedTexture(key);
if (NULL == blurNinePatchTexture) {
SkMask mask;
+ unsigned int smallRectSide = 2*(blurRadius + cornerRadius) + 1;
+
mask.fBounds = SkIRect::MakeWH(smallRectSide, smallRectSide);
mask.fFormat = SkMask::kA8_Format;
mask.fRowBytes = mask.fBounds.width();
@@ -957,12 +949,22 @@ GrFragmentProcessor* GrRRectBlurEffect::Create(GrContext* context, float sigma,
SkPath path;
path.addRRect( smallRRect );
- SkDraw::DrawToMask(path, &mask.fBounds, NULL, NULL, &mask, SkMask::kJustRenderImage_CreateMode, SkPaint::kFill_Style);
+ SkDraw::DrawToMask(path, &mask.fBounds, NULL, NULL, &mask,
+ SkMask::kJustRenderImage_CreateMode, SkPaint::kFill_Style);
SkMask blurred_mask;
- SkBlurMask::BoxBlur(&blurred_mask, mask, sigma, kNormal_SkBlurStyle, kHigh_SkBlurQuality, NULL, true );
+ SkBlurMask::BoxBlur(&blurred_mask, mask, sigma, kNormal_SkBlurStyle, kHigh_SkBlurQuality,
+ NULL, true );
+
+ unsigned int texSide = smallRectSide + 2*blurRadius;
+ GrSurfaceDesc texDesc;
+ texDesc.fWidth = texSide;
+ texDesc.fHeight = texSide;
+ texDesc.fConfig = kAlpha_8_GrPixelConfig;
+
+ blurNinePatchTexture = context->createTexture(texDesc, blurred_mask.fImage, 0);
+ SkAssertResult(context->addResourceToCache(key, blurNinePatchTexture));
- blurNinePatchTexture = context->createTexture(&params, texDesc, key, blurred_mask.fImage, 0);
SkMask::FreeImage(blurred_mask.fImage);
}
diff --git a/src/effects/SkColorCubeFilter.cpp b/src/effects/SkColorCubeFilter.cpp
index bfe28396ff..f4ffefc889 100644
--- a/src/effects/SkColorCubeFilter.cpp
+++ b/src/effects/SkColorCubeFilter.cpp
@@ -354,12 +354,12 @@ GrFragmentProcessor* SkColorCubeFilter::asFragmentProcessor(GrContext* context)
desc.fHeight = fCache.cubeDimension() * fCache.cubeDimension();
desc.fConfig = kRGBA_8888_GrPixelConfig;
- GrSurface* surface = static_cast<GrSurface*>(context->findAndRefCachedResource(key));
- SkAutoTUnref<GrTexture> textureCube;
- if (surface) {
- textureCube.reset(surface->asTexture());
- } else {
- textureCube.reset(context->createTexture(NULL, desc, key, fCubeData->data(), 0));
+ SkAutoTUnref<GrTexture> textureCube(context->findAndRefCachedTexture(key));
+ if (!textureCube) {
+ textureCube.reset(context->createTexture(desc, fCubeData->data(), 0));
+ if (textureCube) {
+ SkAssertResult(context->addResourceToCache(key, textureCube));
+ }
}
return textureCube ? GrColorCubeEffect::Create(textureCube) : NULL;
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 13b0bfaec5..07073a5ee5 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -223,219 +223,9 @@ GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
////////////////////////////////////////////////////////////////////////////////
-static void stretch_image(void* dst,
- int dstW,
- int dstH,
- const void* src,
- int srcW,
- int srcH,
- size_t bpp) {
- SkFixed dx = (srcW << 16) / dstW;
- SkFixed dy = (srcH << 16) / dstH;
-
- SkFixed y = dy >> 1;
-
- size_t dstXLimit = dstW*bpp;
- for (int j = 0; j < dstH; ++j) {
- SkFixed x = dx >> 1;
- const uint8_t* srcRow = reinterpret_cast<const uint8_t *>(src) + (y>>16)*srcW*bpp;
- uint8_t* dstRow = reinterpret_cast<uint8_t *>(dst) + j*dstW*bpp;
- for (size_t i = 0; i < dstXLimit; i += bpp) {
- memcpy(dstRow + i, srcRow + (x>>16)*bpp, bpp);
- x += dx;
- }
- y += dy;
- }
-}
-
-enum ResizeFlags {
- /**
- * The kStretchToPOT bit is set when the texture is NPOT and is being repeated or mipped but the
- * hardware doesn't support that feature.
- */
- kStretchToPOT_ResizeFlag = 0x1,
- /**
- * The kBilerp bit can only be set when the kStretchToPOT flag is set and indicates whether the
- * stretched texture should be bilerped.
- */
- kBilerp_ResizeFlag = 0x2,
-};
-
-static uint32_t get_texture_flags(const GrGpu* gpu,
- const GrTextureParams* params,
- const GrSurfaceDesc& desc) {
- uint32_t flags = 0;
- bool tiled = params && params->isTiled();
- if (tiled && !gpu->caps()->npotTextureTileSupport()) {
- if (!SkIsPow2(desc.fWidth) || !SkIsPow2(desc.fHeight)) {
- flags |= kStretchToPOT_ResizeFlag;
- switch(params->filterMode()) {
- case GrTextureParams::kNone_FilterMode:
- break;
- case GrTextureParams::kBilerp_FilterMode:
- case GrTextureParams::kMipMap_FilterMode:
- flags |= kBilerp_ResizeFlag;
- break;
- }
- }
- }
- return flags;
-}
-// The desired texture is NPOT and tiled but that isn't supported by
-// the current hardware. Resize the texture to be a POT
-GrTexture* GrContext::createResizedTexture(const GrSurfaceDesc& desc,
- const GrContentKey& origKey,
- const void* srcData,
- size_t rowBytes,
- bool filter) {
- SkAutoTUnref<GrTexture> clampedTexture(this->findAndRefTexture(desc, origKey, NULL));
- if (NULL == clampedTexture) {
- clampedTexture.reset(this->createTexture(NULL, desc, origKey, srcData, rowBytes));
-
- if (NULL == clampedTexture) {
- return NULL;
- }
- clampedTexture->cacheAccess().setContentKey(origKey);
- }
-
- GrSurfaceDesc rtDesc = desc;
- rtDesc.fFlags = rtDesc.fFlags |
- kRenderTarget_GrSurfaceFlag |
- kNoStencil_GrSurfaceFlag;
- rtDesc.fWidth = GrNextPow2(desc.fWidth);
- rtDesc.fHeight = GrNextPow2(desc.fHeight);
-
- GrTexture* texture = fGpu->createTexture(rtDesc, true, NULL, 0);
-
- if (texture) {
- GrPipelineBuilder pipelineBuilder;
- pipelineBuilder.setRenderTarget(texture->asRenderTarget());
-
- // 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,
- filter ? GrTextureParams::kBilerp_FilterMode :
- GrTextureParams::kNone_FilterMode);
- pipelineBuilder.addColorTextureProcessor(clampedTexture, SkMatrix::I(), params);
-
- uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType |
- GrDefaultGeoProcFactory::kLocalCoord_GPType;
- SkAutoTUnref<const GrGeometryProcessor> gp(
- GrDefaultGeoProcFactory::Create(flags, GrColor_WHITE));
-
- GrDrawTarget::AutoReleaseGeometry arg(fDrawBuffer, 4, gp->getVertexStride(), 0);
- SkASSERT(gp->getVertexStride() == 2 * sizeof(SkPoint));
-
- if (arg.succeeded()) {
- SkPoint* verts = (SkPoint*) arg.vertices();
- verts[0].setIRectFan(0, 0, texture->width(), texture->height(), 2 * sizeof(SkPoint));
- verts[1].setIRectFan(0, 0, 1, 1, 2 * sizeof(SkPoint));
- fDrawBuffer->drawNonIndexed(&pipelineBuilder, gp, kTriangleFan_GrPrimitiveType, 0, 4);
- } else {
- texture->unref();
- texture = NULL;
- }
- } else {
- // TODO: Our CPU stretch doesn't filter. But we create separate
- // stretched textures when the texture params is either filtered or
- // not. Either implement filtered stretch blit on CPU or just create
- // one when FBO case fails.
-
- rtDesc.fFlags = kNone_GrSurfaceFlags;
- // no longer need to clamp at min RT size.
- rtDesc.fWidth = GrNextPow2(desc.fWidth);
- rtDesc.fHeight = GrNextPow2(desc.fHeight);
-
- // We shouldn't be resizing a compressed texture.
- SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
-
- size_t bpp = GrBytesPerPixel(desc.fConfig);
- GrAutoMalloc<128*128*4> stretchedPixels(bpp * rtDesc.fWidth * rtDesc.fHeight);
- stretch_image(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
- srcData, desc.fWidth, desc.fHeight, bpp);
-
- size_t stretchedRowBytes = rtDesc.fWidth * bpp;
-
- texture = fGpu->createTexture(rtDesc, true, stretchedPixels.get(), stretchedRowBytes);
- SkASSERT(texture);
- }
-
- return texture;
-}
-
-static GrContentKey::Domain ResizeDomain() {
- static const GrContentKey::Domain kDomain = GrContentKey::GenerateDomain();
- return kDomain;
-}
-
-GrTexture* GrContext::createTexture(const GrTextureParams* params,
- const GrSurfaceDesc& desc,
- const GrContentKey& origKey,
- const void* srcData,
- size_t rowBytes,
- GrContentKey* outKey) {
- GrTexture* texture;
- uint32_t flags = get_texture_flags(fGpu, params, desc);
- SkTCopyOnFirstWrite<GrContentKey> key(origKey);
- if (flags) {
- // We don't have a code path to resize compressed textures.
- if (GrPixelConfigIsCompressed(desc.fConfig)) {
- return NULL;
- }
- texture = this->createResizedTexture(desc, origKey, srcData, rowBytes,
- SkToBool(flags & kBilerp_ResizeFlag));
-
- GrContentKey::Builder builder(key.writable(), origKey, ResizeDomain(), 1);
- builder[0] = flags;
-
- } else {
- texture = fGpu->createTexture(desc, true, srcData, rowBytes);
- }
-
- if (texture) {
- if (texture->cacheAccess().setContentKey(*key)) {
- if (outKey) {
- *outKey = *key;
- }
- } else {
- texture->unref();
- texture = NULL;
- }
- }
-
- return texture;
-}
-
-GrTexture* GrContext::findAndRefTexture(const GrSurfaceDesc& desc,
- const GrContentKey& origKey,
- const GrTextureParams* params) {
- uint32_t flags = get_texture_flags(fGpu, params, desc);
- SkTCopyOnFirstWrite<GrContentKey> key(origKey);
- if (flags) {
- GrContentKey::Builder builder(key.writable(), origKey, ResizeDomain(), 1);
- builder[0] = flags;
- }
-
- GrGpuResource* resource = this->findAndRefCachedResource(*key);
- if (resource) {
- SkASSERT(static_cast<GrSurface*>(resource)->asTexture());
- return static_cast<GrSurface*>(resource)->asTexture();
- }
- return NULL;
-}
-
-bool GrContext::isTextureInCache(const GrSurfaceDesc& desc,
- const GrContentKey& origKey,
- const GrTextureParams* params) const {
- uint32_t flags = get_texture_flags(fGpu, params, desc);
- SkTCopyOnFirstWrite<GrContentKey> key(origKey);
- if (flags) {
- GrContentKey::Builder builder(key.writable(), origKey, ResizeDomain(), 1);
- builder[0] = flags;
- }
-
- return fResourceCache2->hasContentKey(*key);
+GrTexture* GrContext::createTexture(const GrSurfaceDesc& desc, const void* srcData,
+ size_t rowBytes) {
+ return fGpu->createTexture(desc, true, srcData, rowBytes);
}
GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& inDesc, ScratchTexMatch match,
@@ -526,19 +316,6 @@ GrTexture* GrContext::createUncachedTexture(const GrSurfaceDesc& desc,
return fGpu->createTexture(desc, false, srcData, rowBytes);
}
-void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
- if (maxTextures) {
- *maxTextures = fResourceCache2->getMaxResourceCount();
- }
- if (maxTextureBytes) {
- *maxTextureBytes = fResourceCache2->getMaxResourceBytes();
- }
-}
-
-void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
- fResourceCache2->setLimits(maxTextures, maxTextureBytes);
-}
-
int GrContext::getMaxTextureSize() const {
return SkTMin(fGpu->caps()->maxTextureSize(), fMaxTextureSizeOverride);
}
@@ -563,22 +340,9 @@ GrRenderTarget* GrContext::wrapBackendRenderTarget(const GrBackendRenderTargetDe
///////////////////////////////////////////////////////////////////////////////
-bool GrContext::supportsIndex8PixelConfig(const GrTextureParams* params,
- int width, int height) const {
+bool GrContext::supportsIndex8PixelConfig() const {
const GrDrawTargetCaps* caps = fGpu->caps();
- if (!caps->isConfigTexturable(kIndex_8_GrPixelConfig)) {
- return false;
- }
-
- bool isPow2 = SkIsPow2(width) && SkIsPow2(height);
-
- if (!isPow2) {
- bool tiled = params && params->isTiled();
- if (tiled && !caps->npotTextureTileSupport()) {
- return false;
- }
- }
- return true;
+ return caps->isConfigTexturable(kIndex_8_GrPixelConfig);
}
@@ -1767,14 +1531,39 @@ const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
}
}
-void GrContext::addResourceToCache(const GrContentKey& key, GrGpuResource* resource) {
- resource->cacheAccess().setContentKey(key);
+//////////////////////////////////////////////////////////////////////////////
+
+void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
+ if (maxTextures) {
+ *maxTextures = fResourceCache2->getMaxResourceCount();
+ }
+ if (maxTextureBytes) {
+ *maxTextureBytes = fResourceCache2->getMaxResourceBytes();
+ }
+}
+
+void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
+ fResourceCache2->setLimits(maxTextures, maxTextureBytes);
+}
+
+bool GrContext::addResourceToCache(const GrContentKey& key, GrGpuResource* resource) {
+ ASSERT_OWNED_RESOURCE(resource);
+ if (!resource || resource->wasDestroyed()) {
+ return false;
+ }
+ return resource->cacheAccess().setContentKey(key);
+}
+
+bool GrContext::isResourceInCache(const GrContentKey& key) const {
+ return fResourceCache2->hasContentKey(key);
}
GrGpuResource* GrContext::findAndRefCachedResource(const GrContentKey& key) {
return fResourceCache2->findAndRefContentResource(key);
}
+//////////////////////////////////////////////////////////////////////////////
+
void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
fGpu->addGpuTraceMarker(marker);
if (fDrawBuffer) {
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 9083860db8..f4bd319a32 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -9,6 +9,7 @@
#include "GrDrawTargetCaps.h"
#include "GrGpu.h"
+#include "GrGpuResourceCacheAccess.h"
#include "GrXferProcessor.h"
#include "SkColorFilter.h"
#include "SkConfig8888.h"
@@ -86,7 +87,45 @@ static void build_index8_data(void* buffer, const SkBitmap& bitmap) {
////////////////////////////////////////////////////////////////////////////////
-static void generate_bitmap_key(const SkBitmap& bitmap, GrContentKey* key) {
+enum Stretch {
+ kNo_Stretch,
+ kBilerp_Stretch,
+ kNearest_Stretch
+};
+
+static Stretch get_stretch_type(const GrContext* ctx, int width, int height,
+ const GrTextureParams* params) {
+ if (params && params->isTiled()) {
+ const GrDrawTargetCaps* caps = ctx->getGpu()->caps();
+ if (!caps->npotTextureTileSupport() && (!SkIsPow2(width) || !SkIsPow2(height))) {
+ switch(params->filterMode()) {
+ case GrTextureParams::kNone_FilterMode:
+ return kNearest_Stretch;
+ case GrTextureParams::kBilerp_FilterMode:
+ case GrTextureParams::kMipMap_FilterMode:
+ return kBilerp_Stretch;
+ }
+ }
+ }
+ return kNo_Stretch;
+}
+
+static bool make_resize_key(const GrContentKey& origKey, Stretch stretch, GrContentKey* resizeKey) {
+ if (origKey.isValid() && kNo_Stretch != stretch) {
+ static const GrContentKey::Domain kDomain = GrContentKey::GenerateDomain();
+ GrContentKey::Builder builder(resizeKey, origKey, kDomain, 1);
+ builder[0] = stretch;
+ builder.finish();
+ return true;
+ }
+ SkASSERT(!resizeKey->isValid());
+ return false;
+}
+
+static void generate_bitmap_keys(const SkBitmap& bitmap,
+ Stretch stretch,
+ GrContentKey* key,
+ GrContentKey* resizedKey) {
// Our id includes the offset, width, and height so that bitmaps created by extractSubset()
// are unique.
uint32_t genID = bitmap.getGenerationID();
@@ -100,6 +139,11 @@ static void generate_bitmap_key(const SkBitmap& bitmap, GrContentKey* key) {
builder[1] = origin.fX;
builder[2] = origin.fY;
builder[3] = width | (height << 16);
+ builder.finish();
+
+ if (kNo_Stretch != stretch) {
+ make_resize_key(*key, stretch, resizedKey);
+ }
}
static void generate_bitmap_texture_desc(const SkBitmap& bitmap, GrSurfaceDesc* desc) {
@@ -127,45 +171,106 @@ private:
} // namespace
+#if 0 // TODO: plug this back up
static void add_genID_listener(const GrContentKey& key, SkPixelRef* pixelRef) {
SkASSERT(pixelRef);
pixelRef->addGenIDChangeListener(SkNEW_ARGS(GrResourceInvalidator, (key)));
}
+#endif
+
+// creates a new texture that is the input texture scaled up to the next power of two in
+// width or height. If optionalKey is valid it will be set on the new texture. stretch
+// controls whether the scaling is done using nearest or bilerp filtering.
+GrTexture* resize_texture(GrTexture* inputTexture, Stretch stretch,
+ const GrContentKey& optionalKey) {
+ SkASSERT(kNo_Stretch != stretch);
+
+ GrContext* context = inputTexture->getContext();
+ SkASSERT(context);
+
+ // 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 |
+ kNoStencil_GrSurfaceFlag;
+ rtDesc.fWidth = GrNextPow2(rtDesc.fWidth);
+ rtDesc.fHeight = GrNextPow2(rtDesc.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 (!context->isConfigRenderable(rtDesc.fConfig, false)) {
+ if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) {
+ if (context->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
+ rtDesc.fConfig = kAlpha_8_GrPixelConfig;
+ } else if (context->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
+ rtDesc.fConfig = kSkia8888_GrPixelConfig;
+ } else {
+ return NULL;
+ }
+ } else if (kRGB_GrColorComponentFlags ==
+ (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) {
+ if (context->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
+ rtDesc.fConfig = kSkia8888_GrPixelConfig;
+ } else {
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+ }
+
+ GrTexture* resized = context->getGpu()->createTexture(rtDesc, true, NULL, 0);
+
+ if (!resized) {
+ return NULL;
+ }
+ 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,
+ kBilerp_Stretch == stretch ? 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);
+
+ GrContext::AutoRenderTarget autoRT(context, resized->asRenderTarget());
+ GrContext::AutoClip ac(context, GrContext::AutoClip::kWideOpen_InitialClip);
+ context->drawNonAARectToRect(paint, SkMatrix::I(), rect, localRect);
+
+ if (optionalKey.isValid()) {
+ SkAssertResult(context->addResourceToCache(optionalKey, resized));
+ }
+
+ return resized;
+}
static GrTexture* sk_gr_allocate_texture(GrContext* ctx,
- bool cache,
- const GrTextureParams* params,
- const SkBitmap& bm,
+ const GrContentKey& optionalKey,
GrSurfaceDesc desc,
const void* pixels,
size_t rowBytes) {
GrTexture* result;
- if (cache) {
- // This texture is likely to be used again so leave it in the cache
- GrContentKey key;
- generate_bitmap_key(bm, &key);
-
- result = ctx->createTexture(params, desc, key, pixels, rowBytes, &key);
+ if (optionalKey.isValid()) {
+ result = ctx->createTexture(desc, pixels, rowBytes);
if (result) {
- add_genID_listener(key, bm.pixelRef());
+ SkAssertResult(ctx->addResourceToCache(optionalKey, result));
}
- } else {
- // This texture is unlikely to be used again (in its present form) so
- // just use a scratch texture. This will remove the texture from the
- // cache so no one else can find it. Additionally, once unlocked, the
- // scratch texture will go to the end of the list for purging so will
- // likely be available for this volatile bitmap the next time around.
+
+ } else {
result = ctx->refScratchTexture(desc, GrContext::kExact_ScratchTexMatch);
- if (pixels) {
- result->writePixels(0, 0, bm.width(), bm.height(), desc.fConfig, pixels, rowBytes);
+ if (pixels && result) {
+ result->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, pixels, rowBytes);
}
}
return result;
}
#ifndef SK_IGNORE_ETC1_SUPPORT
-static GrTexture *load_etc1_texture(GrContext* ctx, bool cache,
- const GrTextureParams* params,
+static GrTexture *load_etc1_texture(GrContext* ctx, const GrContentKey& optionalKey,
const SkBitmap &bm, GrSurfaceDesc desc) {
SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
@@ -210,11 +315,11 @@ static GrTexture *load_etc1_texture(GrContext* ctx, bool cache,
return NULL;
}
- return sk_gr_allocate_texture(ctx, cache, params, bm, desc, bytes, 0);
+ return sk_gr_allocate_texture(ctx, optionalKey, desc, bytes, 0);
}
#endif // SK_IGNORE_ETC1_SUPPORT
-static GrTexture *load_yuv_texture(GrContext* ctx, bool cache, const GrTextureParams* params,
+static GrTexture* load_yuv_texture(GrContext* ctx, const GrContentKey& key,
const SkBitmap& bm, const GrSurfaceDesc& desc) {
// Subsets are not supported, the whole pixelRef is loaded when using YUV decoding
SkPixelRef* pixelRef = bm.pixelRef();
@@ -282,30 +387,31 @@ static GrTexture *load_yuv_texture(GrContext* ctx, bool cache, const GrTexturePa
kRenderTarget_GrSurfaceFlag |
kNoStencil_GrSurfaceFlag;
- GrTexture* result = sk_gr_allocate_texture(ctx, cache, params, bm, rtDesc, NULL, 0);
-
- GrRenderTarget* renderTarget = result ? result->asRenderTarget() : NULL;
- if (renderTarget) {
- SkAutoTUnref<GrFragmentProcessor> yuvToRgbProcessor(GrYUVtoRGBEffect::Create(
- yuvTextures[0], yuvTextures[1], yuvTextures[2], yuvInfo.fColorSpace));
- GrPaint paint;
- paint.addColorProcessor(yuvToRgbProcessor);
- SkRect r = SkRect::MakeWH(SkIntToScalar(yuvInfo.fSize[0].fWidth),
- SkIntToScalar(yuvInfo.fSize[0].fHeight));
- GrContext::AutoRenderTarget autoRT(ctx, renderTarget);
- GrContext::AutoClip ac(ctx, GrContext::AutoClip::kWideOpen_InitialClip);
- ctx->drawRect(paint, SkMatrix::I(), r);
- } else {
- SkSafeSetNull(result);
+ GrTexture* result = ctx->createTexture(rtDesc, NULL, 0);
+ if (!result) {
+ return NULL;
}
+ GrRenderTarget* renderTarget = result->asRenderTarget();
+ SkASSERT(renderTarget);
+
+ SkAutoTUnref<GrFragmentProcessor>
+ yuvToRgbProcessor(GrYUVtoRGBEffect::Create(yuvTextures[0], yuvTextures[1], yuvTextures[2],
+ yuvInfo.fColorSpace));
+ GrPaint paint;
+ paint.addColorProcessor(yuvToRgbProcessor);
+ SkRect r = SkRect::MakeWH(SkIntToScalar(yuvInfo.fSize[0].fWidth),
+ SkIntToScalar(yuvInfo.fSize[0].fHeight));
+ GrContext::AutoRenderTarget autoRT(ctx, renderTarget);
+ GrContext::AutoClip ac(ctx, GrContext::AutoClip::kWideOpen_InitialClip);
+ ctx->drawRect(paint, SkMatrix::I(), r);
+
return result;
}
-static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
- bool cache,
- const GrTextureParams* params,
- const SkBitmap& origBitmap) {
+static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
+ const SkBitmap& origBitmap,
+ const GrContentKey& optionalKey) {
SkBitmap tmpBitmap;
const SkBitmap* bitmap = &origBitmap;
@@ -314,9 +420,7 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
generate_bitmap_texture_desc(*bitmap, &desc);
if (kIndex_8_SkColorType == bitmap->colorType()) {
- // build_compressed_data doesn't do npot->pot expansion
- // and paletted textures can't be sub-updated
- if (cache && ctx->supportsIndex8PixelConfig(params, bitmap->width(), bitmap->height())) {
+ if (ctx->supportsIndex8PixelConfig()) {
size_t imageSize = GrCompressedFormatDataSize(kIndex_8_GrPixelConfig,
bitmap->width(), bitmap->height());
SkAutoMalloc storage(imageSize);
@@ -324,8 +428,7 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
// our compressed data will be trimmed, so pass width() for its
// "rowBytes", since they are the same now.
- return sk_gr_allocate_texture(ctx, cache, params, origBitmap,
- desc, storage.get(), bitmap->width());
+ return sk_gr_allocate_texture(ctx, optionalKey, desc, storage.get(), bitmap->width());
} else {
origBitmap.copyTo(&tmpBitmap, kN32_SkColorType);
// now bitmap points to our temp, which has been promoted to 32bits
@@ -339,7 +442,7 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
else if (
// We do not support scratch ETC1 textures, hence they should all be at least
// trying to go to the cache.
- cache
+ optionalKey.isValid()
// Make sure that the underlying device supports ETC1 textures before we go ahead
// and check the data.
&& ctx->getGpu()->caps()->isConfigTexturable(kETC1_GrPixelConfig)
@@ -348,7 +451,7 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
// the bitmap has available pixels, then they might not be what the decompressed
// data is.
&& !(bitmap->readyToDraw())) {
- GrTexture *texture = load_etc1_texture(ctx, cache, params, *bitmap, desc);
+ GrTexture *texture = load_etc1_texture(ctx, optionalKey, *bitmap, desc);
if (texture) {
return texture;
}
@@ -356,7 +459,7 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
#endif // SK_IGNORE_ETC1_SUPPORT
else {
- GrTexture *texture = load_yuv_texture(ctx, cache, params, *bitmap, desc);
+ GrTexture *texture = load_yuv_texture(ctx, optionalKey, *bitmap, desc);
if (texture) {
return texture;
}
@@ -366,8 +469,32 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
return NULL;
}
- return sk_gr_allocate_texture(ctx, cache, params, origBitmap, desc,
- bitmap->getPixels(), bitmap->rowBytes());
+ return sk_gr_allocate_texture(ctx, optionalKey, desc, bitmap->getPixels(), bitmap->rowBytes());
+}
+
+static GrTexture* create_bitmap_texture(GrContext* ctx,
+ const SkBitmap& bmp,
+ Stretch stretch,
+ const GrContentKey& unstretchedKey,
+ const GrContentKey& stretchedKey) {
+ if (kNo_Stretch != stretch) {
+ SkAutoTUnref<GrTexture> unstretched;
+ // Check if we have the unstretched version in the cache, if not create it.
+ if (unstretchedKey.isValid()) {
+ unstretched.reset(ctx->findAndRefCachedTexture(unstretchedKey));
+ }
+ if (!unstretched) {
+ unstretched.reset(create_unstretched_bitmap_texture(ctx, bmp, unstretchedKey));
+ if (!unstretched) {
+ return NULL;
+ }
+ }
+ GrTexture* resized = resize_texture(unstretched, stretch, stretchedKey);
+ return resized;
+ }
+
+ return create_unstretched_bitmap_texture(ctx, bmp, unstretchedKey);
+
}
static GrTexture* get_texture_backing_bmp(const SkBitmap& bitmap, const GrContext* context,
@@ -393,12 +520,23 @@ bool GrIsBitmapInCache(const GrContext* ctx,
return true;
}
- GrContentKey key;
- generate_bitmap_key(bitmap, &key);
+ // We don't cache volatile bitmaps
+ if (bitmap.isVolatile()) {
+ return false;
+ }
+
+ // If it is inherently texture backed, consider it in the cache
+ if (bitmap.getTexture()) {
+ return true;
+ }
+
+ Stretch stretch = get_stretch_type(ctx, bitmap.width(), bitmap.height(), params);
+ GrContentKey key, resizedKey;
+ generate_bitmap_keys(bitmap, stretch, &key, &resizedKey);
GrSurfaceDesc desc;
generate_bitmap_texture_desc(bitmap, &desc);
- return ctx->isTextureInCache(desc, key, params);
+ return ctx->isResourceInCache((kNo_Stretch == stretch) ? key : resizedKey);
}
GrTexture* GrRefCachedBitmapTexture(GrContext* ctx,
@@ -409,29 +547,29 @@ GrTexture* GrRefCachedBitmapTexture(GrContext* ctx,
return SkRef(result);
}
- bool cache = !bitmap.isVolatile();
+ Stretch stretch = get_stretch_type(ctx, bitmap.width(), bitmap.height(), params);
+ GrContentKey key, resizedKey;
- if (cache) {
+ if (!bitmap.isVolatile()) {
// If the bitmap isn't changing try to find a cached copy first.
+ generate_bitmap_keys(bitmap, stretch, &key, &resizedKey);
- GrContentKey key;
- generate_bitmap_key(bitmap, &key);
-
- GrSurfaceDesc desc;
- generate_bitmap_texture_desc(bitmap, &desc);
-
- result = ctx->findAndRefTexture(desc, key, params);
- }
- if (NULL == result) {
- result = sk_gr_create_bitmap_texture(ctx, cache, params, bitmap);
+ result = ctx->findAndRefCachedTexture(resizedKey.isValid() ? resizedKey : key);
+ if (result) {
+ return result;
+ }
}
- if (NULL == result) {
- SkDebugf("---- failed to create texture for cache [%d %d]\n",
- bitmap.width(), bitmap.height());
+
+ result = create_bitmap_texture(ctx, bitmap, stretch, key, resizedKey);
+ if (result) {
+ return result;
}
- return result;
-}
+ SkDebugf("---- failed to create texture for cache [%d %d]\n",
+ bitmap.width(), bitmap.height());
+
+ return NULL;
+}
///////////////////////////////////////////////////////////////////////////////
// alphatype is ignore for now, but if GrPixelConfig is expanded to encompass
diff --git a/src/gpu/effects/GrTextureStripAtlas.cpp b/src/gpu/effects/GrTextureStripAtlas.cpp
index 2305586844..880a739525 100644
--- a/src/gpu/effects/GrTextureStripAtlas.cpp
+++ b/src/gpu/effects/GrTextureStripAtlas.cpp
@@ -190,7 +190,6 @@ GrTextureStripAtlas::AtlasRow* GrTextureStripAtlas::getLRU() {
}
void GrTextureStripAtlas::lockTexture() {
- GrTextureParams params;
GrSurfaceDesc texDesc;
texDesc.fWidth = fDesc.fWidth;
texDesc.fHeight = fDesc.fHeight;
@@ -202,9 +201,10 @@ void GrTextureStripAtlas::lockTexture() {
builder[0] = static_cast<uint32_t>(fCacheKey);
builder.finish();
- fTexture = fDesc.fContext->findAndRefTexture(texDesc, key, &params);
+ fTexture = fDesc.fContext->findAndRefCachedTexture(key);
if (NULL == fTexture) {
- fTexture = fDesc.fContext->createTexture(&params, texDesc, key, NULL, 0);
+ fTexture = fDesc.fContext->createTexture(texDesc, NULL, 0);
+ SkAssertResult(fDesc.fContext->addResourceToCache(key, fTexture));
// This is a new texture, so all of our cache info is now invalid
this->initLRU();
fKeyTable.rewind();
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index c3752c48bb..16d44fd9df 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -114,14 +114,14 @@ static GrRenderTarget* random_render_target(GrContext* context, SkRandom* random
builder[0] = texDesc.fOrigin;
builder.finish();
- SkAutoTUnref<GrTexture> texture(context->findAndRefTexture(texDesc, key, &params));
+ GrTexture* texture = context->findAndRefCachedTexture(key);
if (!texture) {
- texture.reset(context->createTexture(&params, texDesc, key, 0, 0));
- if (!texture) {
- return NULL;
+ texture = context->createTexture(texDesc);
+ if (texture) {
+ SkAssertResult(context->addResourceToCache(key, texture));
}
}
- return SkRef(texture->asRenderTarget());
+ return texture ? texture->asRenderTarget() : NULL;
}
static void set_random_xpf(GrContext* context, const GrDrawTargetCaps& caps,