зеркало из https://github.com/mozilla/moz-skia.git
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
This commit is contained in:
Родитель
6de0bfc51a
Коммит
423d6d9070
|
@ -29,14 +29,11 @@ class SK_API SkGpuDevice : public SkDevice {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* New device that will create an offscreen renderTarget based on the
|
* New device that will create an offscreen renderTarget based on the
|
||||||
* config, width, height.
|
* config, width, height. The device's storage will not count against
|
||||||
*
|
* the GrContext's texture cache budget. The device's pixels will be
|
||||||
* usage is a special flag that should only be set by SkCanvas
|
* uninitialized.
|
||||||
* internally.
|
|
||||||
*/
|
*/
|
||||||
SkGpuDevice(GrContext*, SkBitmap::Config,
|
SkGpuDevice(GrContext*, SkBitmap::Config, int width, int height);
|
||||||
int width, int height,
|
|
||||||
SkDevice::Usage usage = SkDevice::kGeneral_Usage);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* New device that will render to the specified renderTarget.
|
* New device that will render to the specified renderTarget.
|
||||||
|
@ -118,14 +115,8 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef GrContext::TextureCacheEntry TexCache;
|
typedef GrContext::TextureCacheEntry TexCache;
|
||||||
enum TexType {
|
|
||||||
kBitmap_TexType,
|
|
||||||
kDeviceRenderTarget_TexType,
|
|
||||||
kSaveLayerDeviceRenderTarget_TexType
|
|
||||||
};
|
|
||||||
TexCache lockCachedTexture(const SkBitmap& bitmap,
|
TexCache lockCachedTexture(const SkBitmap& bitmap,
|
||||||
const GrSamplerState* sampler,
|
const GrSamplerState* sampler);
|
||||||
TexType type = kBitmap_TexType);
|
|
||||||
bool isBitmapInTextureCache(const SkBitmap& bitmap,
|
bool isBitmapInTextureCache(const SkBitmap& bitmap,
|
||||||
const GrSamplerState& sampler) const;
|
const GrSamplerState& sampler) const;
|
||||||
void unlockCachedTexture(TexCache);
|
void unlockCachedTexture(TexCache);
|
||||||
|
@ -152,6 +143,9 @@ private:
|
||||||
// called from rt and tex cons
|
// called from rt and tex cons
|
||||||
void initFromRenderTarget(GrContext*, GrRenderTarget*);
|
void initFromRenderTarget(GrContext*, GrRenderTarget*);
|
||||||
|
|
||||||
|
// used by createCompatibleDevice
|
||||||
|
SkGpuDevice(GrContext*, GrTexture* texture, TexCache, bool needClear);
|
||||||
|
|
||||||
// override from SkDevice
|
// override from SkDevice
|
||||||
virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
|
virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "SkTLazy.h"
|
#include "SkTLazy.h"
|
||||||
#include "SkUtils.h"
|
#include "SkUtils.h"
|
||||||
|
|
||||||
#define CACHE_LAYER_TEXTURES 1
|
#define CACHE_COMPATIBLE_DEVICE_TEXTURES 1
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
extern bool (*gShouldDrawProc)();
|
extern bool (*gShouldDrawProc)();
|
||||||
|
@ -30,9 +30,11 @@
|
||||||
do { \
|
do { \
|
||||||
if (gShouldDrawProc && !gShouldDrawProc()) return; \
|
if (gShouldDrawProc && !gShouldDrawProc()) return; \
|
||||||
this->prepareRenderTarget(draw); \
|
this->prepareRenderTarget(draw); \
|
||||||
|
GrAssert(!fNeedClear) \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
|
#define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw); \
|
||||||
|
GrAssert(!fNeedClear)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// we use the same texture slot on GrPaint for bitmaps and shaders
|
// 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
|
// requiring texture domain clamping to prevent color bleeding when drawing
|
||||||
// a sub region of a larger source image.
|
// a sub region of a larger source image.
|
||||||
#define COLOR_BLEED_TOLERANCE SkFloatToScalar(0.001f)
|
#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 {
|
class SkGpuDevice::SkAutoCachedTexture : public ::SkNoncopyable {
|
||||||
|
@ -193,9 +204,11 @@ void SkGpuDevice::initFromRenderTarget(GrContext* context,
|
||||||
fTextContext = NULL;
|
fTextContext = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
|
SkGpuDevice::SkGpuDevice(GrContext* context,
|
||||||
int height, Usage usage)
|
SkBitmap::Config config,
|
||||||
: SkDevice(config, width, height, false /*isOpaque*/) {
|
int width,
|
||||||
|
int height)
|
||||||
|
: SkDevice(config, width, height, false /*isOpaque*/) {
|
||||||
fNeedPrepareRenderTarget = false;
|
fNeedPrepareRenderTarget = false;
|
||||||
fDrawProcs = NULL;
|
fDrawProcs = NULL;
|
||||||
|
|
||||||
|
@ -212,19 +225,6 @@ SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
|
||||||
SkBitmap bm;
|
SkBitmap bm;
|
||||||
bm.setConfig(config, width, height);
|
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 = {
|
const GrTextureDesc desc = {
|
||||||
kRenderTarget_GrTextureFlagBit,
|
kRenderTarget_GrTextureFlagBit,
|
||||||
width,
|
width,
|
||||||
|
@ -234,16 +234,13 @@ SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
|
||||||
};
|
};
|
||||||
|
|
||||||
fTexture = fContext->createUncachedTexture(desc, NULL, 0);
|
fTexture = fContext->createUncachedTexture(desc, NULL, 0);
|
||||||
#endif
|
|
||||||
if (NULL != fTexture) {
|
if (NULL != fTexture) {
|
||||||
fRenderTarget = fTexture->asRenderTarget();
|
fRenderTarget = fTexture->asRenderTarget();
|
||||||
fRenderTarget->ref();
|
fRenderTarget->ref();
|
||||||
|
|
||||||
GrAssert(NULL != fRenderTarget);
|
GrAssert(NULL != fRenderTarget);
|
||||||
|
|
||||||
// we defer the actual clear until our gainFocus()
|
|
||||||
fNeedClear = true;
|
|
||||||
|
|
||||||
// wrap the bitmap with a pixelref to expose our texture
|
// wrap the bitmap with a pixelref to expose our texture
|
||||||
SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
|
SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
|
||||||
this->setPixelRef(pr, 0)->unref();
|
this->setPixelRef(pr, 0)->unref();
|
||||||
|
@ -278,6 +275,7 @@ SkGpuDevice::~SkGpuDevice() {
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void SkGpuDevice::makeRenderTargetCurrent() {
|
void SkGpuDevice::makeRenderTargetCurrent() {
|
||||||
|
DO_DEFERRED_CLEAR;
|
||||||
fContext->setRenderTarget(fRenderTarget);
|
fContext->setRenderTarget(fRenderTarget);
|
||||||
fContext->flush(true);
|
fContext->flush(true);
|
||||||
fNeedPrepareRenderTarget = true;
|
fNeedPrepareRenderTarget = true;
|
||||||
|
@ -310,6 +308,7 @@ GrPixelConfig config8888_to_gr_config(SkCanvas::Config8888 config8888) {
|
||||||
bool SkGpuDevice::onReadPixels(const SkBitmap& bitmap,
|
bool SkGpuDevice::onReadPixels(const SkBitmap& bitmap,
|
||||||
int x, int y,
|
int x, int y,
|
||||||
SkCanvas::Config8888 config8888) {
|
SkCanvas::Config8888 config8888) {
|
||||||
|
DO_DEFERRED_CLEAR;
|
||||||
SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
|
SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
|
||||||
SkASSERT(!bitmap.isNull());
|
SkASSERT(!bitmap.isNull());
|
||||||
SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
|
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());
|
convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
|
||||||
|
|
||||||
if (fNeedClear) {
|
DO_DEFERRED_CLEAR;
|
||||||
fContext->clear(NULL, 0x0);
|
|
||||||
fNeedClear = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkGpuRenderTarget* SkGpuDevice::accessRenderTarget() {
|
SkGpuRenderTarget* SkGpuDevice::accessRenderTarget() {
|
||||||
|
DO_DEFERRED_CLEAR;
|
||||||
return (SkGpuRenderTarget*)fRenderTarget;
|
return (SkGpuRenderTarget*)fRenderTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,6 +593,7 @@ inline bool skPaint2GrPaintShader(SkGpuDevice* dev,
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void SkGpuDevice::clear(SkColor color) {
|
void SkGpuDevice::clear(SkColor color) {
|
||||||
|
fContext->setRenderTarget(fRenderTarget);
|
||||||
fContext->clear(NULL, color);
|
fContext->clear(NULL, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1509,12 +1507,19 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
|
||||||
GR_Scalar1 * h / texture->height()));
|
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) {
|
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);
|
CHECK_SHOULD_DRAW(draw);
|
||||||
|
|
||||||
GrPaint grPaint;
|
GrPaint grPaint;
|
||||||
if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
|
if (!dev->bindDeviceAsTexture(&grPaint) ||
|
||||||
!skPaint2GrPaintNoShader(paint, true, false, &grPaint)) {
|
!skPaint2GrPaintNoShader(paint, true, false, &grPaint)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1809,55 +1814,35 @@ bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkGpuDevice::flush() {
|
void SkGpuDevice::flush() {
|
||||||
|
DO_DEFERRED_CLEAR;
|
||||||
fContext->resolveRenderTarget(fRenderTarget);
|
fContext->resolveRenderTarget(fRenderTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkGpuDevice::TexCache SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
|
SkGpuDevice::TexCache SkGpuDevice::lockCachedTexture(
|
||||||
const GrSamplerState* sampler,
|
const SkBitmap& bitmap,
|
||||||
TexType type) {
|
const GrSamplerState* sampler) {
|
||||||
GrContext::TextureCacheEntry entry;
|
GrContext::TextureCacheEntry entry;
|
||||||
GrContext* ctx = this->context();
|
GrContext* ctx = this->context();
|
||||||
|
|
||||||
if (kBitmap_TexType != type) {
|
if (!bitmap.isVolatile()) {
|
||||||
const GrTextureDesc desc = {
|
GrContext::TextureKey key = bitmap.getGenerationID();
|
||||||
kRenderTarget_GrTextureFlagBit,
|
key |= ((uint64_t) bitmap.pixelRefOffset()) << 32;
|
||||||
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(),
|
entry = ctx->findAndLockTexture(key, bitmap.width(),
|
||||||
bitmap.height(), sampler);
|
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()) {
|
if (NULL == entry.texture()) {
|
||||||
GrPrintf("---- failed to create texture for cache [%d %d]\n",
|
entry = sk_gr_create_bitmap_texture(ctx, key, sampler,
|
||||||
bitmap.width(), bitmap.height());
|
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;
|
return entry;
|
||||||
}
|
}
|
||||||
|
@ -1880,8 +1865,53 @@ SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
bool isOpaque,
|
bool isOpaque,
|
||||||
Usage usage) {
|
Usage usage) {
|
||||||
return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
|
GrTextureDesc desc;
|
||||||
width, height, usage));
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
GrTextContext* SkGpuDevice::getTextContext() {
|
GrTextContext* SkGpuDevice::getTextContext() {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче