From 423d6d9070c99dacb46a8b5d120b348550316b01 Mon Sep 17 00:00:00 2001 From: "bsalomon@google.com" Date: Fri, 30 Mar 2012 18:22:01 +0000 Subject: Improve save layer handling in SkGpuDevice http://codereview.appspot.com/5966048/ git-svn-id: http://skia.googlecode.com/svn/trunk@3563 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/gpu/SkGpuDevice.h | 22 +++--- src/gpu/SkGpuDevice.cpp | 168 +++++++++++++++++++++++++++------------------- 2 files changed, 107 insertions(+), 83 deletions(-) diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h index 409e3b30a5..ffc24a8c4b 100644 --- a/include/gpu/SkGpuDevice.h +++ b/include/gpu/SkGpuDevice.h @@ -29,14 +29,11 @@ class SK_API SkGpuDevice : public SkDevice { public: /** * New device that will create an offscreen renderTarget based on the - * config, width, height. - * - * usage is a special flag that should only be set by SkCanvas - * internally. + * config, width, height. The device's storage will not count against + * the GrContext's texture cache budget. The device's pixels will be + * uninitialized. */ - SkGpuDevice(GrContext*, SkBitmap::Config, - int width, int height, - SkDevice::Usage usage = SkDevice::kGeneral_Usage); + SkGpuDevice(GrContext*, SkBitmap::Config, int width, int height); /** * New device that will render to the specified renderTarget. @@ -118,14 +115,8 @@ public: protected: typedef GrContext::TextureCacheEntry TexCache; - enum TexType { - kBitmap_TexType, - kDeviceRenderTarget_TexType, - kSaveLayerDeviceRenderTarget_TexType - }; TexCache lockCachedTexture(const SkBitmap& bitmap, - const GrSamplerState* sampler, - TexType type = kBitmap_TexType); + const GrSamplerState* sampler); bool isBitmapInTextureCache(const SkBitmap& bitmap, const GrSamplerState& sampler) const; void unlockCachedTexture(TexCache); @@ -152,6 +143,9 @@ private: // called from rt and tex cons void initFromRenderTarget(GrContext*, GrRenderTarget*); + // used by createCompatibleDevice + SkGpuDevice(GrContext*, GrTexture* texture, TexCache, bool needClear); + // override from SkDevice virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config, int width, int height, diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index e13a0ea990..b4656b92f5 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -22,7 +22,7 @@ #include "SkTLazy.h" #include "SkUtils.h" -#define CACHE_LAYER_TEXTURES 1 +#define CACHE_COMPATIBLE_DEVICE_TEXTURES 1 #if 0 extern bool (*gShouldDrawProc)(); @@ -30,9 +30,11 @@ do { \ if (gShouldDrawProc && !gShouldDrawProc()) return; \ this->prepareRenderTarget(draw); \ + GrAssert(!fNeedClear) \ } while (0) #else - #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw) + #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw); \ + GrAssert(!fNeedClear) #endif // we use the same texture slot on GrPaint for bitmaps and shaders @@ -59,6 +61,15 @@ enum { // requiring texture domain clamping to prevent color bleeding when drawing // a sub region of a larger source image. #define COLOR_BLEED_TOLERANCE SkFloatToScalar(0.001f) + +#define DO_DEFERRED_CLEAR \ + do { \ + if (fNeedClear) { \ + this->clear(NULL); \ + fNeedClear = false; \ + } \ + } while (false) \ + /////////////////////////////////////////////////////////////////////////////// class SkGpuDevice::SkAutoCachedTexture : public ::SkNoncopyable { @@ -193,9 +204,11 @@ void SkGpuDevice::initFromRenderTarget(GrContext* context, fTextContext = NULL; } -SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width, - int height, Usage usage) -: SkDevice(config, width, height, false /*isOpaque*/) { +SkGpuDevice::SkGpuDevice(GrContext* context, + SkBitmap::Config config, + int width, + int height) + : SkDevice(config, width, height, false /*isOpaque*/) { fNeedPrepareRenderTarget = false; fDrawProcs = NULL; @@ -212,19 +225,6 @@ SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width, SkBitmap bm; bm.setConfig(config, width, height); -#if CACHE_LAYER_TEXTURES - TexType type = (kSaveLayer_Usage == usage) ? - kSaveLayerDeviceRenderTarget_TexType : - kDeviceRenderTarget_TexType; - fCache = this->lockCachedTexture(bm, NULL, type); - fTexture = fCache.texture(); - if (fTexture) { - SkASSERT(NULL != fTexture->asRenderTarget()); - // hold a ref directly on fTexture (even though fCache has one) to match - // other constructor paths. Simplifies cleanup. - fTexture->ref(); - } -#else const GrTextureDesc desc = { kRenderTarget_GrTextureFlagBit, width, @@ -234,16 +234,13 @@ SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width, }; fTexture = fContext->createUncachedTexture(desc, NULL, 0); -#endif + if (NULL != fTexture) { fRenderTarget = fTexture->asRenderTarget(); fRenderTarget->ref(); GrAssert(NULL != fRenderTarget); - // we defer the actual clear until our gainFocus() - fNeedClear = true; - // wrap the bitmap with a pixelref to expose our texture SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture); this->setPixelRef(pr, 0)->unref(); @@ -278,6 +275,7 @@ SkGpuDevice::~SkGpuDevice() { /////////////////////////////////////////////////////////////////////////////// void SkGpuDevice::makeRenderTargetCurrent() { + DO_DEFERRED_CLEAR; fContext->setRenderTarget(fRenderTarget); fContext->flush(true); fNeedPrepareRenderTarget = true; @@ -310,6 +308,7 @@ GrPixelConfig config8888_to_gr_config(SkCanvas::Config8888 config8888) { bool SkGpuDevice::onReadPixels(const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) { + DO_DEFERRED_CLEAR; SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); SkASSERT(!bitmap.isNull()); SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()))); @@ -396,13 +395,11 @@ void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix, convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin()); - if (fNeedClear) { - fContext->clear(NULL, 0x0); - fNeedClear = false; - } + DO_DEFERRED_CLEAR; } SkGpuRenderTarget* SkGpuDevice::accessRenderTarget() { + DO_DEFERRED_CLEAR; return (SkGpuRenderTarget*)fRenderTarget; } @@ -596,6 +593,7 @@ inline bool skPaint2GrPaintShader(SkGpuDevice* dev, /////////////////////////////////////////////////////////////////////////////// void SkGpuDevice::clear(SkColor color) { + fContext->setRenderTarget(fRenderTarget); fContext->clear(NULL, color); } @@ -1509,12 +1507,19 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, GR_Scalar1 * h / texture->height())); } -void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev, +void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device, int x, int y, const SkPaint& paint) { + // clear of the source device must occur before CHECK_SHOULD_DRAW + SkGpuDevice* dev = static_cast(dev); + if (dev->fNeedClear) { + // TODO: could check here whether we really need to draw at all + dev->clear(0x0); + } + CHECK_SHOULD_DRAW(draw); GrPaint grPaint; - if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) || + if (!dev->bindDeviceAsTexture(&grPaint) || !skPaint2GrPaintNoShader(paint, true, false, &grPaint)) { return; } @@ -1809,55 +1814,35 @@ bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { } void SkGpuDevice::flush() { + DO_DEFERRED_CLEAR; fContext->resolveRenderTarget(fRenderTarget); } /////////////////////////////////////////////////////////////////////////////// -SkGpuDevice::TexCache SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap, - const GrSamplerState* sampler, - TexType type) { +SkGpuDevice::TexCache SkGpuDevice::lockCachedTexture( + const SkBitmap& bitmap, + const GrSamplerState* sampler) { GrContext::TextureCacheEntry entry; GrContext* ctx = this->context(); - if (kBitmap_TexType != type) { - const GrTextureDesc desc = { - kRenderTarget_GrTextureFlagBit, - bitmap.width(), - bitmap.height(), - SkGr::Bitmap2PixelConfig(bitmap), - 0 // samples - }; - GrContext::ScratchTexMatch match; - if (kSaveLayerDeviceRenderTarget_TexType == type) { - // we know layers will only be drawn through drawDevice. - // drawDevice has been made to work with content embedded in a - // larger texture so its okay to use the approximate version. - match = GrContext::kApprox_ScratchTexMatch; - } else { - SkASSERT(kDeviceRenderTarget_TexType == type); - match = GrContext::kExact_ScratchTexMatch; - } - entry = ctx->lockScratchTexture(desc, match); - } else { - if (!bitmap.isVolatile()) { - GrContext::TextureKey key = bitmap.getGenerationID(); - key |= ((uint64_t) bitmap.pixelRefOffset()) << 32; - - entry = ctx->findAndLockTexture(key, bitmap.width(), - bitmap.height(), sampler); - if (NULL == entry.texture()) { - entry = sk_gr_create_bitmap_texture(ctx, key, sampler, - bitmap); - } - } else { - entry = sk_gr_create_bitmap_texture(ctx, gUNCACHED_KEY, - sampler, bitmap); - } + if (!bitmap.isVolatile()) { + GrContext::TextureKey key = bitmap.getGenerationID(); + key |= ((uint64_t) bitmap.pixelRefOffset()) << 32; + + entry = ctx->findAndLockTexture(key, bitmap.width(), + bitmap.height(), sampler); if (NULL == entry.texture()) { - GrPrintf("---- failed to create texture for cache [%d %d]\n", - bitmap.width(), bitmap.height()); + entry = sk_gr_create_bitmap_texture(ctx, key, sampler, + bitmap); } + } else { + entry = sk_gr_create_bitmap_texture(ctx, gUNCACHED_KEY, + sampler, bitmap); + } + if (NULL == entry.texture()) { + GrPrintf("---- failed to create texture for cache [%d %d]\n", + bitmap.width(), bitmap.height()); } return entry; } @@ -1880,8 +1865,53 @@ SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config, int width, int height, bool isOpaque, Usage usage) { - return SkNEW_ARGS(SkGpuDevice,(this->context(), config, - width, height, usage)); + GrTextureDesc desc; + desc.fConfig = fRenderTarget->config(); + desc.fFlags = kRenderTarget_GrTextureFlagBit; + desc.fWidth = width; + desc.fHeight = height; + desc.fSampleCnt = fRenderTarget->numSamples(); + + GrContext::TextureCacheEntry cacheEntry; + GrTexture* texture; + SkAutoTUnref tunref; + // Skia's convention is to only clear a device if it is a non-opaque layer. + bool needClear = !isOpaque && kSaveLayer_Usage == usage; + +#if CACHE_COMPATIBLE_DEVICE_TEXTURES + // layers are never draw in repeat modes, so we can request an approx + // match and ignore any padding. + GrContext::ScratchTexMatch matchType = (kSaveLayer_Usage == usage) ? + GrContext::kApprox_ScratchTexMatch : + GrContext::kExact_ScratchTexMatch; + cacheEntry = fContext->lockScratchTexture(desc, matchType); + texture = cacheEntry.texture(); +#else + tunref.reset(fContext->createUncachedTexture(desc, NULL, 0)); + texture = tunref.get(); +#endif + if (texture) { + return SkNEW_ARGS(SkGpuDevice,(fContext, + texture, + cacheEntry, + needClear)); + } else { + GrPrintf("---- failed to create compatible device texture [%d %d]\n", + width, height); + return NULL; + } +} + +SkGpuDevice::SkGpuDevice(GrContext* context, + GrTexture* texture, + TexCache cacheEntry, + bool needClear) + : SkDevice(make_bitmap(context, texture->asRenderTarget())) { + GrAssert(texture && texture->asRenderTarget()); + GrAssert(NULL == cacheEntry.texture() || texture == cacheEntry.texture()); + this->initFromRenderTarget(context, texture->asRenderTarget()); + fCache = cacheEntry; + fNeedClear = needClear; } GrTextContext* SkGpuDevice::getTextContext() { -- cgit v1.2.3