diff options
author | bsalomon <bsalomon@google.com> | 2015-01-31 19:27:53 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-01-31 19:27:53 -0800 |
commit | 6c96672491b04cb782bce8fee778124df66524a0 (patch) | |
tree | 49407e533766dad8d3fae3c5794afc4536a79098 | |
parent | 0b737c52a7b8bc6ba41d309e88b3f7e995746f8d (diff) |
Move npot resizing out of GrContext and simplify GrContext texture functions.
Committed: https://skia.googlesource.com/skia/+/8a8100349105c8c6de39fcb34e47679da7a67f54
Review URL: https://codereview.chromium.org/882223003
-rw-r--r-- | include/gpu/GrContext.h | 101 | ||||
-rw-r--r-- | include/gpu/GrPaint.h | 14 | ||||
-rw-r--r-- | include/gpu/GrResourceKey.h | 1 | ||||
-rw-r--r-- | include/gpu/GrTypes.h | 16 | ||||
-rw-r--r-- | src/effects/SkBlurMaskFilter.cpp | 36 | ||||
-rw-r--r-- | src/effects/SkColorCubeFilter.cpp | 12 | ||||
-rwxr-xr-x | src/gpu/GrContext.cpp | 275 | ||||
-rw-r--r-- | src/gpu/SkGr.cpp | 282 | ||||
-rw-r--r-- | src/gpu/effects/GrTextureStripAtlas.cpp | 6 | ||||
-rw-r--r-- | tests/GLProgramsTest.cpp | 10 |
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, ¶ms); + *blurProfileTexture = context->findAndRefCachedTexture(key); if (NULL == *blurProfileTexture) { SkBlurMask::ComputeBlurProfile(sigma, &profile); ada.reset(profile); - *blurProfileTexture = context->createTexture(¶ms, 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, ¶ms); + 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(¶ms, 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, ¶ms); + fTexture = fDesc.fContext->findAndRefCachedTexture(key); if (NULL == fTexture) { - fTexture = fDesc.fContext->createTexture(¶ms, 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, ¶ms)); + GrTexture* texture = context->findAndRefCachedTexture(key); if (!texture) { - texture.reset(context->createTexture(¶ms, 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, |