#include "SkTLazy.h"
#include "SkUtils.h"
-#define CACHE_COMPATIBLE_DEVICE_TEXTURES 1
+#define CACHE_LAYER_TEXTURES 1
#if 0
extern bool (*gShouldDrawProc)();
do { \
if (gShouldDrawProc && !gShouldDrawProc()) return; \
this->prepareRenderTarget(draw); \
- GrAssert(!fNeedClear) \
} while (0)
#else
- #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw); \
- GrAssert(!fNeedClear)
+ #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
#endif
// we use the same texture slot on GrPaint for bitmaps and shaders
// 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 {
fTextContext = NULL;
}
-SkGpuDevice::SkGpuDevice(GrContext* context,
- SkBitmap::Config config,
- int width,
- int height)
- : SkDevice(config, width, height, false /*isOpaque*/) {
+SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
+ int height, Usage usage)
+: SkDevice(config, width, height, false /*isOpaque*/) {
fNeedPrepareRenderTarget = false;
fDrawProcs = NULL;
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,
};
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();
///////////////////////////////////////////////////////////////////////////////
void SkGpuDevice::makeRenderTargetCurrent() {
- DO_DEFERRED_CLEAR;
fContext->setRenderTarget(fRenderTarget);
fContext->flush(true);
fNeedPrepareRenderTarget = true;
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())));
convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
- DO_DEFERRED_CLEAR;
+ if (fNeedClear) {
+ fContext->clear(NULL, 0x0);
+ fNeedClear = false;
+ }
}
SkGpuRenderTarget* SkGpuDevice::accessRenderTarget() {
- DO_DEFERRED_CLEAR;
return (SkGpuRenderTarget*)fRenderTarget;
}
///////////////////////////////////////////////////////////////////////////////
void SkGpuDevice::clear(SkColor color) {
- fContext->setRenderTarget(fRenderTarget);
fContext->clear(NULL, color);
}
GR_Scalar1 * h / texture->height()));
}
-void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device,
+void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
int x, int y, const SkPaint& paint) {
- // clear of the source device must occur before CHECK_SHOULD_DRAW
- SkGpuDevice* dev = static_cast<SkGpuDevice*>(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 (!dev->bindDeviceAsTexture(&grPaint) ||
+ if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
!skPaint2GrPaintNoShader(paint, true, false, &grPaint)) {
return;
}
}
void SkGpuDevice::flush() {
- DO_DEFERRED_CLEAR;
fContext->resolveRenderTarget(fRenderTarget);
}
///////////////////////////////////////////////////////////////////////////////
-SkGpuDevice::TexCache SkGpuDevice::lockCachedTexture(
- const SkBitmap& bitmap,
- const GrSamplerState* sampler) {
+SkGpuDevice::TexCache SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
+ const GrSamplerState* sampler,
+ TexType type) {
GrContext::TextureCacheEntry entry;
GrContext* ctx = this->context();
- 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);
+ 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 {
- 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());
+ 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 (NULL == entry.texture()) {
+ GrPrintf("---- failed to create texture for cache [%d %d]\n",
+ bitmap.width(), bitmap.height());
+ }
}
return entry;
}
int width, int height,
bool isOpaque,
Usage 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<GrTexture> 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;
+ return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
+ width, height, usage));
}
GrTextContext* SkGpuDevice::getTextContext() {