diff options
-rw-r--r-- | include/core/SkCanvas.h | 5 | ||||
-rw-r--r-- | include/core/SkDevice.h | 23 | ||||
-rw-r--r-- | include/gpu/SkGpuDevice.h | 14 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 20 | ||||
-rw-r--r-- | src/core/SkDevice.cpp | 4 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 85 | ||||
-rw-r--r-- | src/utils/SkDeferredCanvas.cpp | 3 |
7 files changed, 128 insertions, 26 deletions
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 178364cb43..0868574525 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -978,6 +978,7 @@ private: uint32_t fMCRecStorage[32]; SkBounder* fBounder; + SkDevice* fLastDeviceToGainFocus; int fSaveLayerCount; // number of successful saveLayer calls SkMetaData* fMetaData; @@ -988,7 +989,9 @@ private: fSurfaceBase = sb; } friend class SkSurface_Base; - + + void prepareForDeviceDraw(SkDevice*, const SkMatrix&, const SkRegion&); + bool fDeviceCMDirty; // cleared by updateDeviceCMCache() void updateDeviceCMCache(); diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h index 2ce64ee44f..f0aa8e0a02 100644 --- a/include/core/SkDevice.h +++ b/include/core/SkDevice.h @@ -187,6 +187,28 @@ protected: */ virtual bool filterTextFlags(const SkPaint& paint, TextFlags*); + /** + * Called with the correct matrix and clip before this device is drawn + * to using those settings. If your subclass overrides this, be sure to + * call through to the base class as well. + * + * The clipstack is another view of the clip. It records the actual + * geometry that went into building the region. It is present for devices + * that want to parse it, but is not required: the region is a complete + * picture of the current clip. (i.e. if you regionize all of the geometry + * in the clipstack, you will arrive at an equivalent region to the one + * passed in). + */ + virtual void setMatrixClip(const SkMatrix&, const SkRegion&, + const SkClipStack&); + + /** Called when this device gains focus (i.e becomes the current device + for drawing). + */ + virtual void gainFocus(const SkMatrix&, const SkRegion&) { + SkASSERT(fAttachedToCanvas); + } + /** Clears the entire device to the specified color (including alpha). * Ignores the clip. */ @@ -363,6 +385,7 @@ protected: private: friend class SkCanvas; + friend struct DeviceCM; //for setMatrixClip friend class SkDraw; friend class SkDrawIter; friend class SkDeviceFilteredPaint; diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h index b941894221..790d4a9ca1 100644 --- a/include/gpu/SkGpuDevice.h +++ b/include/gpu/SkGpuDevice.h @@ -51,6 +51,12 @@ public: GrContext* context() const { return fContext; } + /** + * Override from SkGpuDevice, so we can set our FBO to be the render target + * The canvas parameter must be a SkGpuCanvas + */ + virtual void gainFocus(const SkMatrix&, const SkRegion&) SK_OVERRIDE; + virtual SkGpuRenderTarget* accessRenderTarget() SK_OVERRIDE; // overrides from SkDevice @@ -59,6 +65,9 @@ public: virtual void writePixels(const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) SK_OVERRIDE; + virtual void setMatrixClip(const SkMatrix& matrix, const SkRegion& clip, + const SkClipStack&) SK_OVERRIDE; + virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE; virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count, const SkPoint[], const SkPaint& paint) SK_OVERRIDE; @@ -125,9 +134,10 @@ private: GrClipData fClipData; - // state for our render-target + // state for our offscreen render-target GrRenderTarget* fRenderTarget; bool fNeedClear; + bool fNeedPrepareRenderTarget; // called from rt and tex cons void initFromRenderTarget(GrContext*, GrRenderTarget*, bool cached); @@ -144,7 +154,7 @@ private: SkDrawProcs* initDrawForText(GrTextContext*); bool bindDeviceAsTexture(GrPaint* paint); - void prepareDraw(const SkDraw&); // sets the render target, clip, and matrix on GrContext. + void prepareRenderTarget(const SkDraw&); bool shouldTileBitmap(const SkBitmap& bitmap, const GrTextureParams& sampler, const SkRect* srcRectPtr) const; diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index b6d8c293cf..5e476c6c9e 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -124,6 +124,8 @@ struct DeviceCM { SkRegion::kDifference_Op); } + fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack); + #ifdef SK_DEBUG if (!fClip.isEmpty()) { SkIRect deviceR; @@ -242,6 +244,7 @@ public: } // fCurrLayer may be NULL now + fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip); return true; } return false; @@ -438,6 +441,7 @@ SkDevice* SkCanvas::init(SkDevice* device) { fBounder = NULL; fLocalBoundsCompareType.setEmpty(); fLocalBoundsCompareTypeDirty = true; + fLastDeviceToGainFocus = NULL; fDeviceCMDirty = false; fSaveLayerCount = 0; fMetaData = NULL; @@ -660,6 +664,15 @@ void SkCanvas::updateDeviceCMCache() { } } +void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix, + const SkRegion& clip) { + SkASSERT(device); + if (fLastDeviceToGainFocus != device) { + device->gainFocus(matrix, clip); + fLastDeviceToGainFocus = device; + } +} + /////////////////////////////////////////////////////////////////////////////// int SkCanvas::internalSave(SaveFlags flags) { @@ -846,6 +859,13 @@ void SkCanvas::internalRestore() { fDeviceCMDirty = true; fLocalBoundsCompareTypeDirty = true; + // Dirty this pointer to handle the case of a new device created at the same address as the + // device we are restoring from. E.g.: + // saveLayer (creates a device) + // drawSomething + // restore (deletes the device) + // saveLayer (oops new device at the same address) + fLastDeviceToGainFocus = NULL; fClipStack.restore(); // reserve our layer (if any) diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 6d8958d804..7da9a6b442 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -122,6 +122,10 @@ void SkDevice::clear(SkColor color) { const SkBitmap& SkDevice::onAccessBitmap(SkBitmap* bitmap) {return *bitmap;} +void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region, + const SkClipStack& clipStack) { +} + bool SkDevice::canHandleImageFilter(SkImageFilter*) { return false; } diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index b168e57e63..9a495c9703 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -30,10 +30,12 @@ #define CHECK_SHOULD_DRAW(draw) \ do { \ if (gShouldDrawProc && !gShouldDrawProc()) return; \ - this->prepareDraw(draw); \ + this->prepareRenderTarget(draw); \ + GrAssert(!fNeedClear) \ } while (0) #else - #define CHECK_SHOULD_DRAW(draw) this->prepareDraw(draw) + #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw); \ + GrAssert(!fNeedClear) #endif // we use the same texture slot on GrPaint for bitmaps and shaders @@ -44,6 +46,7 @@ enum { kColorFilterTextureIdx = 1 }; + #define MAX_BLUR_SIGMA 4.0f // FIXME: This value comes from from SkBlurMaskFilter.cpp. // Should probably be put in a common header someplace. @@ -61,10 +64,11 @@ enum { // a sub region of a larger source image. #define COLOR_BLEED_TOLERANCE SkFloatToScalar(0.001f) -#define DO_DEFERRED_CLEAR() \ +#define DO_DEFERRED_CLEAR \ do { \ if (fNeedClear) { \ this->clear(0x0); \ + fNeedClear = false; \ } \ } while (false) \ @@ -178,6 +182,7 @@ SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget) void SkGpuDevice::initFromRenderTarget(GrContext* context, GrRenderTarget* renderTarget, bool cached) { + fNeedPrepareRenderTarget = false; fDrawProcs = NULL; fContext = context; @@ -209,6 +214,7 @@ SkGpuDevice::SkGpuDevice(GrContext* context, int height) : SkDevice(config, width, height, false /*isOpaque*/) { + fNeedPrepareRenderTarget = false; fDrawProcs = NULL; fContext = context; @@ -252,11 +258,9 @@ SkGpuDevice::~SkGpuDevice() { delete fDrawProcs; } - // The GrContext takes a ref on the target. We don't want to cause the render - // target to be unnecessarily kept alive. - if (fContext->getRenderTarget() == fRenderTarget) { - fContext->setRenderTarget(NULL); - } + // The SkGpuDevice gives the context the render target (e.g., in gainFocus) + // This call gives the context a chance to relinquish it + fContext->setRenderTarget(NULL); SkSafeUnref(fRenderTarget); fContext->unref(); @@ -265,8 +269,9 @@ SkGpuDevice::~SkGpuDevice() { /////////////////////////////////////////////////////////////////////////////// void SkGpuDevice::makeRenderTargetCurrent() { - DO_DEFERRED_CLEAR(); + DO_DEFERRED_CLEAR; fContext->setRenderTarget(fRenderTarget); + fNeedPrepareRenderTarget = true; } /////////////////////////////////////////////////////////////////////////////// @@ -303,7 +308,7 @@ GrPixelConfig config8888_to_grconfig_and_flags(SkCanvas::Config8888 config8888, bool SkGpuDevice::onReadPixels(const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) { - DO_DEFERRED_CLEAR(); + 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()))); @@ -406,29 +411,64 @@ static void check_bounds(const GrClipData& clipData, /////////////////////////////////////////////////////////////////////////////// +static void set_matrix_and_clip(GrContext* context, const SkMatrix& matrix, + GrClipData& clipData, + const SkRegion& clipRegion, + const SkIPoint& origin, + int renderTargetWidth, int renderTargetHeight) { + context->setMatrix(matrix); + + clipData.fOrigin = origin; + +#ifdef SK_DEBUG + check_bounds(clipData, clipRegion, + renderTargetWidth, renderTargetHeight); +#endif + + context->setClip(&clipData); +} + // 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) { +void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) { GrAssert(NULL != fClipData.fClipStack); - fContext->setRenderTarget(fRenderTarget); + if (fNeedPrepareRenderTarget || + fContext->getRenderTarget() != fRenderTarget) { + + fContext->setRenderTarget(fRenderTarget); + SkASSERT(draw.fClipStack && draw.fClipStack == fClipData.fClipStack); - SkASSERT(draw.fClipStack && draw.fClipStack == fClipData.fClipStack); + set_matrix_and_clip(fContext, *draw.fMatrix, + fClipData, *draw.fClip, this->getOrigin(), + fRenderTarget->width(), fRenderTarget->height()); + fNeedPrepareRenderTarget = false; + } +} - fContext->setMatrix(*draw.fMatrix); - fClipData.fOrigin = this->getOrigin(); +void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip, + const SkClipStack& clipStack) { + this->INHERITED::setMatrixClip(matrix, clip, clipStack); + // We don't need to set them now because the context may not reflect this device. + fNeedPrepareRenderTarget = true; +} -#ifdef SK_DEBUG - check_bounds(fClipData, *draw.fClip, fRenderTarget->width(), fRenderTarget->height()); -#endif +void SkGpuDevice::gainFocus(const SkMatrix& matrix, const SkRegion& clip) { - fContext->setClip(&fClipData); + GrAssert(NULL != fClipData.fClipStack); - DO_DEFERRED_CLEAR(); + fContext->setRenderTarget(fRenderTarget); + + this->INHERITED::gainFocus(matrix, clip); + + set_matrix_and_clip(fContext, matrix, fClipData, clip, this->getOrigin(), + fRenderTarget->width(), fRenderTarget->height()); + + DO_DEFERRED_CLEAR; } SkGpuRenderTarget* SkGpuDevice::accessRenderTarget() { - DO_DEFERRED_CLEAR(); + DO_DEFERRED_CLEAR; return (SkGpuRenderTarget*)fRenderTarget; } @@ -622,7 +662,6 @@ inline bool skPaint2GrPaintShader(SkGpuDevice* dev, /////////////////////////////////////////////////////////////////////////////// void SkGpuDevice::clear(SkColor color) { fContext->clear(NULL, color, fRenderTarget); - fNeedClear = false; } void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { @@ -1888,7 +1927,7 @@ bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { } void SkGpuDevice::flush() { - DO_DEFERRED_CLEAR(); + DO_DEFERRED_CLEAR; fContext->resolveRenderTarget(fRenderTarget); } diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp index c3de393290..eaba50342e 100644 --- a/src/utils/SkDeferredCanvas.cpp +++ b/src/utils/SkDeferredCanvas.cpp @@ -268,6 +268,9 @@ protected: virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {return false;} + virtual void setMatrixClip(const SkMatrix&, const SkRegion&, + const SkClipStack&) SK_OVERRIDE + {} // None of the following drawing methods should ever get called on the // deferred device |