| Index: src/gpu/SkGpuDevice.cpp
|
| diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
|
| index 808e896ef7da21f053a7c56fd5e4500cdc00b904..6f718e62064e5d5c59a7b00a9d121b1b793be262 100644
|
| --- a/src/gpu/SkGpuDevice.cpp
|
| +++ b/src/gpu/SkGpuDevice.cpp
|
| @@ -23,6 +23,7 @@
|
| #include "SkGlyphCache.h"
|
| #include "SkGrTexturePixelRef.h"
|
| #include "SkImageFilter.h"
|
| +#include "SkImagePriv.h"
|
| #include "SkImage_Base.h"
|
| #include "SkLayerInfo.h"
|
| #include "SkMaskFilter.h"
|
| @@ -48,16 +49,17 @@
|
| enum { kDefaultImageFilterCacheSize = 32 * 1024 * 1024 };
|
|
|
| #if 0
|
| - extern bool (*gShouldDrawProc)();
|
| - #define CHECK_SHOULD_DRAW(draw) \
|
| - do { \
|
| - if (gShouldDrawProc && !gShouldDrawProc()) return; \
|
| - this->prepareDraw(draw); \
|
| - } while (0)
|
| +extern bool (*gShouldDrawProc)();
|
| +#define CHECK_SHOULD_DRAW(draw) \
|
| + do { \
|
| + if (gShouldDrawProc && !gShouldDrawProc()) return; \
|
| + if (!this->prepareDraw(draw)) return; \
|
| + } while (0)
|
| #else
|
| - #define CHECK_SHOULD_DRAW(draw) this->prepareDraw(draw)
|
| +#define CHECK_SHOULD_DRAW(draw) if (!this->prepareDraw(draw)) return;
|
| #endif
|
|
|
| +
|
| // This constant represents the screen alignment criterion in texels for
|
| // requiring texture domain clamping to prevent color bleeding when drawing
|
| // a sub region of a larger source image.
|
| @@ -166,9 +168,20 @@ static SkSurfaceProps copy_or_default_props(const SkSurfaceProps* props) {
|
| }
|
| }
|
|
|
| +namespace {
|
| +
|
| +void wrap_surface(GrSurface* rt, SkBitmap* bm) {
|
| + bm->setInfo(rt->surfacePriv().info());
|
| + SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (rt->surfacePriv().info(), rt));
|
| + bm->setPixelRef(pr)->unref();
|
| +}
|
| +
|
| +};
|
| +
|
| SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, const SkSurfaceProps* props, unsigned flags)
|
| : INHERITED(surfaceprops_to_deviceprops(props))
|
| , fSurfaceProps(copy_or_default_props(props))
|
| + , fSurface(NULL)
|
| {
|
| fDrawProcs = NULL;
|
|
|
| @@ -177,11 +190,7 @@ SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, const SkSurfaceProps* props, unsign
|
|
|
| fRenderTarget = SkRef(rt);
|
|
|
| - SkImageInfo info = rt->surfacePriv().info();
|
| - SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, rt));
|
| - fLegacyBitmap.setInfo(info);
|
| - fLegacyBitmap.setPixelRef(pr)->unref();
|
| -
|
| + wrap_surface(fRenderTarget, &fLegacyBitmap);
|
| bool useDFT = fSurfaceProps.isUseDistanceFieldFonts();
|
| fTextContext = fContext->createTextContext(fRenderTarget, this, this->getLeakyProperties(),
|
| useDFT);
|
| @@ -250,6 +259,13 @@ SkGpuDevice::~SkGpuDevice() {
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| +void SkGpuDevice::discard() {
|
| + if (fSurface) {
|
| + fSurface->notifyContentWillChange();
|
| + }
|
| + this->prepareBackendRenderTarget(kDiscard_ModifyMode);
|
| +}
|
| +
|
| bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
|
| int x, int y) {
|
| DO_DEFERRED_CLEAR();
|
| @@ -275,6 +291,11 @@ bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, siz
|
| if (kUnknown_GrPixelConfig == config) {
|
| return false;
|
| }
|
| +
|
| + if (!this->prepareWrite()) {
|
| + return false;
|
| + }
|
| +
|
| uint32_t flags = 0;
|
| if (kUnpremul_SkAlphaType == info.alphaType()) {
|
| flags = GrContext::kUnpremul_PixelOpsFlag;
|
| @@ -288,7 +309,9 @@ bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, siz
|
| }
|
|
|
| const SkBitmap& SkGpuDevice::onAccessBitmap() {
|
| - DO_DEFERRED_CLEAR();
|
| + // Must prepare for write because user might obtain the texture from the bitmap and then modify
|
| + // it.
|
| + this->prepareWrite();
|
| return fLegacyBitmap;
|
| }
|
|
|
| @@ -307,18 +330,38 @@ void SkGpuDevice::onDetachFromCanvas() {
|
|
|
| // call this every draw call, to ensure that the context reflects our state,
|
| // and not the state from some other canvas/device
|
| -void SkGpuDevice::prepareDraw(const SkDraw& draw) {
|
| +bool SkGpuDevice::prepareDraw(const SkDraw& draw) {
|
| SkASSERT(fClipStack.get());
|
|
|
| SkASSERT(draw.fClipStack && draw.fClipStack == fClipStack);
|
|
|
| fClip.setClipStack(fClipStack, &this->getOrigin());
|
|
|
| - DO_DEFERRED_CLEAR();
|
| + if (!this->prepareBackendRenderTarget(kDrawContent_ModifyMode)) {
|
| + return false;
|
| + }
|
| +
|
| + if (fSurface) {
|
| + fSurface->notifyContentWillChange();
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool SkGpuDevice::prepareWrite() {
|
| + if (!this->prepareBackendRenderTarget(kDrawContent_ModifyMode)) {
|
| + return false;
|
| + }
|
| + if (fSurface) {
|
| + fSurface->notifyContentWillChange();
|
| + }
|
| + return true;
|
| }
|
|
|
| GrRenderTarget* SkGpuDevice::accessRenderTarget() {
|
| - DO_DEFERRED_CLEAR();
|
| + // The render target could be read through the ptr, so we must do deferred clear. The render
|
| + // target could be written to through the ptr, so we must detach the snapshot.
|
| + this->prepareWrite();
|
| return fRenderTarget;
|
| }
|
|
|
| @@ -330,38 +373,81 @@ void SkGpuDevice::clearAll() {
|
| fNeedClear = false;
|
| }
|
|
|
| -void SkGpuDevice::replaceRenderTarget(bool shouldRetainContent) {
|
| - // Caller must have accessed the render target, because it knows the rt must be replaced.
|
| - SkASSERT(!fNeedClear);
|
| +bool SkGpuDevice::prepareBackendRenderTarget(ModifyMode writeMode) {
|
| + // We are preparing for modifying the render target. This will detach the snapshot in all
|
| + // cases, so do the detach right away.
|
| + SkAutoTUnref<SkImage> snapshot;
|
| + snapshot.swap(&fSnapshot);
|
| +
|
| + bool needNewRenderTarget = false;
|
| +
|
| + if (NULL != snapshot) {
|
| + SkASSERT(!fNeedClear);
|
| + needNewRenderTarget = fRenderTarget->asTexture() == SkTextureImageGetTexture(snapshot) &&
|
| + !snapshot->unique();
|
| + }
|
| +
|
| + if (!needNewRenderTarget) {
|
| + if (writeMode == kDiscard_ModifyMode) {
|
| + fRenderTarget->discard();
|
| + fNeedClear = false;
|
| + }
|
| + if (fRenderTarget->wasDestroyed()) {
|
| + return false;
|
| + }
|
| +
|
| + DO_DEFERRED_CLEAR();
|
| + return true;
|
| + }
|
|
|
| SkSurface::Budgeted budgeted =
|
| fRenderTarget->resourcePriv().isBudgeted() ? SkSurface::kYes_Budgeted
|
| : SkSurface::kNo_Budgeted;
|
|
|
| SkAutoTUnref<GrRenderTarget> newRT(CreateRenderTarget(
|
| - fRenderTarget->getContext(), budgeted, this->imageInfo(), fRenderTarget->numSamples()));
|
| + this->context(), budgeted, this->imageInfo(), fRenderTarget->numSamples()));
|
|
|
| if (NULL == newRT) {
|
| - return;
|
| + return false;
|
| }
|
|
|
| - if (shouldRetainContent) {
|
| + if (writeMode == kDrawContent_ModifyMode) {
|
| if (fRenderTarget->wasDestroyed()) {
|
| - return;
|
| + return false;
|
| }
|
| - this->context()->copySurface(newRT, fRenderTarget);
|
| +
|
| + if (fNeedClear) {
|
| + // Clear the snapshot render target and clear the new render target.
|
| + this->clearAll();
|
| + fNeedClear = true; // Clears the new render target.
|
| + } else {
|
| + this->context()->copySurface(newRT, fRenderTarget);
|
| + }
|
| + } else {
|
| + fNeedClear = false;
|
| }
|
|
|
| SkASSERT(fRenderTarget != newRT);
|
| -
|
| fRenderTarget->unref();
|
| fRenderTarget = newRT.detach();
|
|
|
| SkASSERT(fRenderTarget->surfacePriv().info() == fLegacyBitmap.info());
|
| - SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (fRenderTarget->surfacePriv().info(), fRenderTarget));
|
| - fLegacyBitmap.setPixelRef(pr)->unref();
|
| + wrap_surface(fRenderTarget, &fLegacyBitmap);
|
| +
|
| + SkASSERT(!fRenderTarget->wasDestroyed());
|
| +
|
| + DO_DEFERRED_CLEAR();
|
| +
|
| + if (snapshot) {
|
| + SkTextureImageApplyBudgetedDecision(snapshot);
|
| + }
|
| +
|
| + return true;
|
| }
|
|
|
| +bool SkGpuDevice::isBackendBudgeted() const {
|
| + return fRenderTarget->resourcePriv().isBudgeted();
|
| +}
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
|
| @@ -759,13 +845,6 @@ GrTexture* create_mask_GPU(GrContext* context,
|
| return mask;
|
| }
|
|
|
| -SkBitmap wrap_texture(GrTexture* texture) {
|
| - SkBitmap result;
|
| - result.setInfo(texture->surfacePriv().info());
|
| - result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (result.info(), texture)))->unref();
|
| - return result;
|
| -}
|
| -
|
| };
|
|
|
| void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
|
| @@ -1507,7 +1586,9 @@ bool SkGpuDevice::filterTexture(GrContext* context, GrTexture* texture,
|
| SkDeviceImageFilterProxy proxy(this, SkSurfaceProps(0, getLeakyProperties().pixelGeometry()));
|
|
|
| if (filter->canFilterImageGPU()) {
|
| - return filter->filterImageGPU(&proxy, wrap_texture(texture), ctx, result, offset);
|
| + SkBitmap filterInput;
|
| + wrap_surface(texture, &filterInput);
|
| + return filter->filterImageGPU(&proxy, filterInput, ctx, result, offset);
|
| } else {
|
| return false;
|
| }
|
| @@ -1643,24 +1724,22 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
|
| int x, int y, const SkPaint& paint) {
|
| // clear of the source device must occur before CHECK_SHOULD_DRAW
|
| GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawDevice", fContext);
|
| - SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
|
| -
|
| // TODO: If the source device covers the whole of this device, we could
|
| // omit fNeedsClear -related flushing.
|
| - // TODO: if source needs clear, we could maybe omit the draw fully.
|
| + // TODO: if source is a gpu device, we could inspect its fNeedsClear,
|
| + // and we could maybe omit the draw fully.
|
|
|
| - // drawDevice is defined to be in device coords.
|
| - CHECK_SHOULD_DRAW(draw);
|
| -
|
| - GrRenderTarget* devRT = dev->accessRenderTarget();
|
| - GrTexture* devTex;
|
| - if (NULL == (devTex = devRT->asTexture())) {
|
| + SkAutoTUnref<SkImage> devImage(device->newImageSnapshot());
|
| + if (NULL == devImage) {
|
| + return;
|
| + }
|
| + GrTexture* devTex = devImage->getTexture();
|
| + if (NULL == devTex) {
|
| return;
|
| }
|
|
|
| - const SkImageInfo ii = dev->imageInfo();
|
| - int w = ii.width();
|
| - int h = ii.height();
|
| + int w = devImage->width();
|
| + int h = devImage->height();
|
|
|
| SkImageFilter* filter = paint.getImageFilter();
|
| // This bitmap will own the filtered result as a texture.
|
| @@ -1686,6 +1765,8 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
|
| return;
|
| }
|
| }
|
| + // drawDevice is defined to be in device coords.
|
| + CHECK_SHOULD_DRAW(draw);
|
|
|
| GrPaint grPaint;
|
| grPaint.addColorTextureProcessor(devTex, SkMatrix::I());
|
| @@ -1905,6 +1986,28 @@ void SkGpuDevice::flush() {
|
| fRenderTarget->prepareForExternalRead();
|
| }
|
|
|
| +SkImage* SkGpuDevice::newImageSnapshot() {
|
| + return this->newImageSnapshot(&fSurfaceProps, SkSurface::kYes_Budgeted);
|
| +}
|
| +
|
| +SkImage* SkGpuDevice::newImageSnapshot(const SkSurfaceProps* props, SkSurface::Budgeted budgeted) {
|
| + if (NULL == fSnapshot) {
|
| + if (fRenderTarget->wasDestroyed()) {
|
| + return NULL;
|
| + }
|
| + DO_DEFERRED_CLEAR();
|
| + const int sampleCount = fRenderTarget->numSamples();
|
| + SkImage* image = SkNewImageFromBitmapTexture(fLegacyBitmap, sampleCount, budgeted);
|
| + if (!image) {
|
| + return NULL;
|
| + }
|
| + if (props) {
|
| + as_IB(image)->initWithProps(*props);
|
| + }
|
| + fSnapshot.reset(image);
|
| + }
|
| + return SkRef(fSnapshot.get());
|
| +}
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
|
|
|