diff options
-rw-r--r-- | include/core/SkPicture.h | 2 | ||||
-rw-r--r-- | src/gpu/GrPictureUtils.cpp | 436 | ||||
-rw-r--r-- | src/gpu/GrPictureUtils.h | 9 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 16 | ||||
-rw-r--r-- | tests/PictureTest.cpp | 140 |
5 files changed, 334 insertions, 269 deletions
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index 936291a58a..30d08211db 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -296,7 +296,7 @@ private: friend class SkPictureData; // to access OperationList friend class SkPictureRecorder; // just for SkPicture-based constructor friend class SkGpuDevice; // for EXPERIMENTAL_getActiveOps/OperationList - friend class GrGatherCanvas; // needs to know if old or new picture + friend class CollectLayers; // access to fRecord friend class SkPicturePlayback; // to get fData & OperationList friend class SkPictureReplacementPlayback; // to access OperationList diff --git a/src/gpu/GrPictureUtils.cpp b/src/gpu/GrPictureUtils.cpp index 7295089e82..521160ac8a 100644 --- a/src/gpu/GrPictureUtils.cpp +++ b/src/gpu/GrPictureUtils.cpp @@ -6,12 +6,10 @@ */ #include "GrPictureUtils.h" -#include "SkCanvasPriv.h" -#include "SkDevice.h" -#include "SkDraw.h" + #include "SkPaintPriv.h" -#include "SkPictureData.h" -#include "SkPicturePlayback.h" +#include "SkRecord.h" +#include "SkRecords.h" SkPicture::AccelData::Key GrAccelData::ComputeAccelDataKey() { static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain(); @@ -19,261 +17,261 @@ SkPicture::AccelData::Key GrAccelData::ComputeAccelDataKey() { return gGPUID; } -// The GrGather device performs GPU-backend-specific preprocessing on -// a picture. The results are stored in a GrAccelData. -// -// Currently the only interesting work is done in drawDevice (i.e., when a -// saveLayer is collapsed back into its parent) and, maybe, in onCreateDevice. -// All the current work could be done much more efficiently by just traversing the -// raw op codes in the SkPicture (although we would still need to replay all the -// clip calls). -class GrGatherDevice : public SkBaseDevice { +// SkRecord visitor to gather saveLayer/restore information. +class CollectLayers { public: - SK_DECLARE_INST_COUNT(GrGatherDevice) - - GrGatherDevice(int width, int height, SkPicturePlayback* playback, GrAccelData* accelData, - int saveLayerDepth) { - fPlayback = playback; - fSaveLayerDepth = saveLayerDepth; - fInfo.fValid = true; - fInfo.fSize.set(width, height); - fInfo.fPaint = NULL; - fInfo.fSaveLayerOpID = fPlayback->curOpID(); - fInfo.fRestoreOpID = 0; - fInfo.fHasNestedLayers = false; - fInfo.fIsNested = (2 == fSaveLayerDepth); - - fEmptyBitmap.setInfo(SkImageInfo::MakeUnknown(fInfo.fSize.fWidth, fInfo.fSize.fHeight)); - fAccelData = accelData; - fAlreadyDrawn = false; - } - - virtual ~GrGatherDevice() { } + CollectLayers(const SkPicture* pict, GrAccelData* accelData) + : fPictureID(pict->uniqueID()) + , fCTM(&SkMatrix::I()) + , fCurrentClipBounds(SkIRect::MakeXYWH(0, 0, pict->width(), pict->height())) + , fSaveLayersInStack(0) + , fAccelData(accelData) { + + if (NULL == pict->fRecord.get()) { + return; + } - virtual SkImageInfo imageInfo() const SK_OVERRIDE { - return fEmptyBitmap.info(); - } + for (fCurrentOp = 0; fCurrentOp < pict->fRecord->count(); ++fCurrentOp) { + pict->fRecord->visit<void>(fCurrentOp, *this); + } -#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG - virtual void writePixels(const SkBitmap& bitmap, int x, int y, - SkCanvas::Config8888 config8888) SK_OVERRIDE { - NotSupported(); + while (!fSaveStack.isEmpty()) { + this->popSaveBlock(); + } } -#endif - virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; } -protected: - virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE { - return false; - } - virtual void clear(SkColor color) SK_OVERRIDE { - NothingToDo(); - } - virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE { - } - virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, - const SkPoint points[], const SkPaint& paint) SK_OVERRIDE { - } - virtual void drawRect(const SkDraw& draw, const SkRect& rect, - const SkPaint& paint) SK_OVERRIDE { - } - virtual void drawOval(const SkDraw& draw, const SkRect& rect, - const SkPaint& paint) SK_OVERRIDE { - } - virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect, - const SkPaint& paint) SK_OVERRIDE { - } - virtual void drawPath(const SkDraw& draw, const SkPath& path, - const SkPaint& paint, const SkMatrix* prePathMatrix, - bool pathIsMutable) SK_OVERRIDE { + template <typename T> void operator()(const T& op) { + this->updateCTM(op); + this->updateClipBounds(op); + this->trackSaveLayers(op); } - virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, - const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE { - } - virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, - int x, int y, const SkPaint& paint) SK_OVERRIDE { - } - virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, - const SkRect* srcOrNull, const SkRect& dst, - const SkPaint& paint, - SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE { - } - virtual void drawText(const SkDraw& draw, const void* text, size_t len, - SkScalar x, SkScalar y, - const SkPaint& paint) SK_OVERRIDE { - } - virtual void drawPosText(const SkDraw& draw, const void* text, size_t len, - const SkScalar pos[], SkScalar constY, - int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE { - } - virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len, - const SkPath& path, const SkMatrix* matrix, - const SkPaint& paint) SK_OVERRIDE { - } - virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount, - const SkPoint verts[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) SK_OVERRIDE { - } - virtual void drawDevice(const SkDraw& draw, SkBaseDevice* deviceIn, int x, int y, - const SkPaint& paint) SK_OVERRIDE { - // deviceIn is the one that is being "restored" back to its parent - GrGatherDevice* device = static_cast<GrGatherDevice*>(deviceIn); - if (device->fAlreadyDrawn) { - return; - } +private: - device->fInfo.fRestoreOpID = fPlayback->curOpID(); - device->fInfo.fCTM = *draw.fMatrix; - device->fInfo.fCTM.postTranslate(SkIntToScalar(-device->getOrigin().fX), - SkIntToScalar(-device->getOrigin().fY)); + class SaveInfo { + public: + SaveInfo() { } + SaveInfo(int opIndex, bool isSaveLayer, const SkPaint* paint, const SkIRect& bounds) + : fStartIndex(opIndex) + , fIsSaveLayer(isSaveLayer) + , fHasNestedSaveLayer(false) + , fPaint(paint) + , fBounds(bounds) { - device->fInfo.fOffset = device->getOrigin(); + } - if (NeedsDeepCopy(paint)) { - // This NULL acts as a signal that the paint was uncopyable (for now) - device->fInfo.fPaint = NULL; - device->fInfo.fValid = false; - } else { - device->fInfo.fPaint = SkNEW_ARGS(SkPaint, (paint)); + int fStartIndex; + bool fIsSaveLayer; + bool fHasNestedSaveLayer; + const SkPaint* fPaint; + SkIRect fBounds; + }; + + uint32_t fPictureID; + unsigned int fCurrentOp; + const SkMatrix* fCTM; + SkIRect fCurrentClipBounds; + int fSaveLayersInStack; + SkTDArray<SaveInfo> fSaveStack; + GrAccelData* fAccelData; + + template <typename T> void updateCTM(const T&) { /* most ops don't change the CTM */ } + void updateCTM(const SkRecords::Restore& op) { fCTM = &op.matrix; } + void updateCTM(const SkRecords::SetMatrix& op) { fCTM = &op.matrix; } + + template <typename T> void updateClipBounds(const T&) { /* most ops don't change the clip */ } + // Each of these devBounds fields is the state of the device bounds after the op. + // So Restore's devBounds are those bounds saved by its paired Save or SaveLayer. + void updateClipBounds(const SkRecords::Restore& op) { fCurrentClipBounds = op.devBounds; } + void updateClipBounds(const SkRecords::ClipPath& op) { fCurrentClipBounds = op.devBounds; } + void updateClipBounds(const SkRecords::ClipRRect& op) { fCurrentClipBounds = op.devBounds; } + void updateClipBounds(const SkRecords::ClipRect& op) { fCurrentClipBounds = op.devBounds; } + void updateClipBounds(const SkRecords::ClipRegion& op) { fCurrentClipBounds = op.devBounds; } + void updateClipBounds(const SkRecords::SaveLayer& op) { + if (NULL != op.bounds) { + fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint)); } + } - fAccelData->addSaveLayerInfo(device->fInfo); - device->fAlreadyDrawn = true; + template <typename T> void trackSaveLayers(const T& op) { + /* most ops aren't involved in saveLayers */ } - // TODO: allow this call to return failure, or move to SkBitmapDevice only. - virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE { - return fEmptyBitmap; + void trackSaveLayers(const SkRecords::Save& s) { this->pushSaveBlock(); } + void trackSaveLayers(const SkRecords::SaveLayer& sl) { this->pushSaveLayerBlock(sl.paint); } + void trackSaveLayers(const SkRecords::Restore& r) { this->popSaveBlock(); } + void trackSaveLayers(const SkRecords::DrawPicture& dp) { + // For sub-pictures, we wrap their layer information within the parent + // picture's rendering hierarchy + const GrAccelData* childData = GPUOptimize(dp.picture); + + for (int i = 0; i < childData->numSaveLayers(); ++i) { + const GrAccelData::SaveLayerInfo& src = childData->saveLayerInfo(i); + + this->updateStackForSaveLayer(); + + GrAccelData::SaveLayerInfo dst; + + // TODO: need to store an SkRect in GrAccelData::SaveLayerInfo? + SkRect srcRect = SkRect::MakeXYWH(SkIntToScalar(src.fOffset.fX), + SkIntToScalar(src.fOffset.fY), + SkIntToScalar(src.fSize.width()), + SkIntToScalar(src.fSize.height())); + SkIRect newClip(fCurrentClipBounds); + newClip.intersect(this->adjustAndMap(srcRect, dp.paint)); + + dst.fValid = true; + dst.fPictureID = dp.picture->uniqueID(); + dst.fSize = SkISize::Make(newClip.width(), newClip.height()); + dst.fOffset = SkIPoint::Make(newClip.fLeft, newClip.fTop); + dst.fOriginXform = *fCTM; + dst.fOriginXform.postConcat(src.fOriginXform); + dst.fOriginXform.postTranslate(SkIntToScalar(-newClip.fLeft), + SkIntToScalar(-newClip.fTop)); + + if (NULL == src.fPaint) { + dst.fPaint = NULL; + } else { + dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint)); + } + + dst.fSaveLayerOpID = src.fSaveLayerOpID; + dst.fRestoreOpID = src.fRestoreOpID; + dst.fHasNestedLayers = src.fHasNestedLayers; + dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested; + + fAccelData->addSaveLayerInfo(dst); + } } -#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG - virtual bool onReadPixels(const SkBitmap& bitmap, - int x, int y, - SkCanvas::Config8888 config8888) SK_OVERRIDE { - NotSupported(); - return false; + + void pushSaveBlock() { + fSaveStack.push(SaveInfo(fCurrentOp, false, NULL, SkIRect::MakeEmpty())); } -#endif - virtual void lockPixels() SK_OVERRIDE { NothingToDo(); } - virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); } - virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; } - virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; } - virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&, - SkBitmap* result, SkIPoint* offset) SK_OVERRIDE { - return false; + + // Inform all the saveLayers already on the stack that they now have a + // nested saveLayer inside them + void updateStackForSaveLayer() { + for (int index = fSaveStack.count() - 1; index >= 0; --index) { + if (fSaveStack[index].fHasNestedSaveLayer) { + break; + } + fSaveStack[index].fHasNestedSaveLayer = true; + if (fSaveStack[index].fIsSaveLayer) { + break; + } + } } -private: - // The playback object driving this rendering - SkPicturePlayback *fPlayback; + void pushSaveLayerBlock(const SkPaint* paint) { + this->updateStackForSaveLayer(); - SkBitmap fEmptyBitmap; // legacy -- need to remove + fSaveStack.push(SaveInfo(fCurrentOp, true, paint, fCurrentClipBounds)); + ++fSaveLayersInStack; + } - // All information gathered during the gather process is stored here - GrAccelData* fAccelData; + void popSaveBlock() { + if (fSaveStack.count() <= 0) { + SkASSERT(false); + return; + } - // true if this device has already been drawn back to its parent(s) at least - // once. - bool fAlreadyDrawn; + SaveInfo si; + fSaveStack.pop(&si); - // The information regarding the saveLayer call this device represents. - GrAccelData::SaveLayerInfo fInfo; + if (!si.fIsSaveLayer) { + return; + } - // The depth of this device in the saveLayer stack - int fSaveLayerDepth; + --fSaveLayersInStack; - virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE { - NotSupported(); - } + GrAccelData::SaveLayerInfo slInfo; - virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE { - // we expect to only get called via savelayer, in which case it is fine. - SkASSERT(kSaveLayer_Usage == usage); + slInfo.fValid = true; + slInfo.fPictureID = fPictureID; + slInfo.fSize = SkISize::Make(si.fBounds.width(), si.fBounds.height()); + slInfo.fOffset = SkIPoint::Make(si.fBounds.fLeft, si.fBounds.fTop); + slInfo.fOriginXform = *fCTM; + slInfo.fOriginXform.postTranslate(SkIntToScalar(-si.fBounds.fLeft), + SkIntToScalar(-si.fBounds.fTop)); - fInfo.fHasNestedLayers = true; - return SkNEW_ARGS(GrGatherDevice, (info.width(), info.height(), fPlayback, - fAccelData, fSaveLayerDepth+1)); - } + if (NULL == si.fPaint) { + slInfo.fPaint = NULL; + } else { + slInfo.fPaint = SkNEW_ARGS(SkPaint, (*si.fPaint)); + } - virtual void flush() SK_OVERRIDE {} + slInfo.fSaveLayerOpID = si.fStartIndex; + slInfo.fRestoreOpID = fCurrentOp; + slInfo.fHasNestedLayers = si.fHasNestedSaveLayer; + slInfo.fIsNested = fSaveLayersInStack > 0; - static void NotSupported() { - SkDEBUGFAIL("this method should never be called"); + fAccelData->addSaveLayerInfo(slInfo); } - static void NothingToDo() {} + // Returns true if rect was meaningfully adjusted for the effects of paint, + // false if the paint could affect the rect in unknown ways. + static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) { + if (paint) { + if (paint->canComputeFastBounds()) { + *rect = paint->computeFastBounds(*rect, rect); + return true; + } + return false; + } + return true; + } - typedef SkBaseDevice INHERITED; -}; + // Adjust rect for all paints that may affect its geometry, then map it to device space. + SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const { + // Inverted rectangles really confuse our BBHs. + rect.sort(); -// The GrGatherCanvas allows saveLayers but simplifies clipping. It is really -// only intended to be used as: -// -// GrGatherDevice dev(w, h, picture, accelData); -// GrGatherCanvas canvas(..., picture); -// canvas.gather(); -// -// which is all just to fill in 'accelData' -class SK_API GrGatherCanvas : public SkCanvas { -public: - GrGatherCanvas(GrGatherDevice* device) : INHERITED(device) {} + // Adjust the rect for its own paint. + if (!AdjustForPaint(paint, &rect)) { + // The paint could do anything to our bounds. The only safe answer is the current clip. + return fCurrentClipBounds; + } -protected: - // disable aa for speed - virtual void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE { - this->INHERITED::onClipRect(rect, op, kHard_ClipEdgeStyle); - } + // Adjust rect for all the paints from the SaveLayers we're inside. + for (int i = fSaveStack.count() - 1; i >= 0; i--) { + if (!AdjustForPaint(fSaveStack[i].fPaint, &rect)) { + // Same deal as above. + return fCurrentClipBounds; + } + } - // for speed, just respect the bounds, and disable AA. May give us a few - // false positives and negatives. - virtual void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE { - this->updateClipConservativelyUsingBounds(path.getBounds(), op, - path.isInverseFillType()); - } - virtual void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE { - this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false); - } + // Map the rect back to device space. + fCTM->mapRect(&rect); + SkIRect devRect; + rect.roundOut(&devRect); - virtual void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, - const SkPaint* paint) SK_OVERRIDE { - SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->width(), picture->height()); - - if (NULL != picture->fData.get()) { - // Disable the BBH for the old path so all the draw calls - // will be seen. The stock SkPicture::draw method can't be - // invoked since it just uses a vanilla SkPicturePlayback. - SkPicturePlayback playback(picture); - playback.setUseBBH(false); - playback.draw(this, NULL); - } else { - // Since we know this is the SkRecord path we can just call - // SkPicture::draw. - picture->draw(this); - } + // Nothing can draw outside the current clip. + // (Only bounded ops call into this method, so oddballs like Clear don't matter here.) + devRect.intersect(fCurrentClipBounds); + return devRect; } - -private: - typedef SkCanvas INHERITED; }; -// GatherGPUInfo is only intended to be called within the context of SkGpuDevice's + +// GPUOptimize is only intended to be called within the context of SkGpuDevice's // EXPERIMENTAL_optimize method. -void GatherGPUInfo(const SkPicture* pict, GrAccelData* accelData) { +const GrAccelData* GPUOptimize(const SkPicture* pict) { if (NULL == pict || 0 == pict->width() || 0 == pict->height()) { - return ; + return NULL; } - // BBH-based rendering doesn't re-issue many of the operations the gather - // process cares about (e.g., saves and restores) so it must be disabled. - SkPicturePlayback playback(pict); - playback.setUseBBH(false); + SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); + + const GrAccelData* existing = + static_cast<const GrAccelData*>(pict->EXPERIMENTAL_getAccelData(key)); + if (NULL != existing) { + return existing; + } + + SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key))); + + pict->EXPERIMENTAL_addAccelData(data); - GrGatherDevice device(pict->width(), pict->height(), &playback, accelData, 0); - GrGatherCanvas canvas(&device); + CollectLayers collector(pict, data); - canvas.clipRect(SkRect::MakeWH(SkIntToScalar(pict->width()), - SkIntToScalar(pict->height())), - SkRegion::kIntersect_Op, false); - playback.draw(&canvas, NULL); + return data; } diff --git a/src/gpu/GrPictureUtils.h b/src/gpu/GrPictureUtils.h index 46af12d2f1..1c6897ce77 100644 --- a/src/gpu/GrPictureUtils.h +++ b/src/gpu/GrPictureUtils.h @@ -21,11 +21,14 @@ public: // invalid (due to a non-invertible CTM) or 'fPaint' is NULL (due // to a non-copyable paint). bool fValid; + // ID of the picture containing the layer. This can be the ID of + // a sub-picture embedded within the picture owning the GrAccelData + uint32_t fPictureID; // The size of the saveLayer SkISize fSize; - // The CTM in which this layer's draws must occur. It already incorporates + // The matrix state in which this layer's draws must occur. It already incorporates // the translation needed to map the layer's top-left point to the origin. - SkMatrix fCTM; + SkMatrix fOriginXform; // The offset that needs to be passed to drawBitmap to correctly // position the pre-rendered layer. It is in device space. SkIPoint fOffset; @@ -74,6 +77,6 @@ private: typedef SkPicture::AccelData INHERITED; }; -void GatherGPUInfo(const SkPicture* pict, GrAccelData* accelData); +const GrAccelData* GPUOptimize(const SkPicture* pict); #endif // GrPictureUtils_DEFINED diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 61ae5ce829..b3d154b7e2 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1861,11 +1861,7 @@ void SkGpuDevice::EXPERIMENTAL_optimize(const SkPicture* picture) { return; } - SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key))); - - picture->EXPERIMENTAL_addAccelData(data); - - GatherGPUInfo(picture, data); + GPUOptimize(picture); fContext->getLayerCache()->trackPicture(picture); } @@ -2004,10 +2000,10 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture if (pullForward[i]) { const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i); - GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture->uniqueID(), - info.fSaveLayerOpID, - info.fRestoreOpID, - info.fCTM); + GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture->uniqueID(), + info.fSaveLayerOpID, + info.fRestoreOpID, + info.fOriginXform); SkPictureReplacementPlayback::PlaybackReplacements::ReplacementInfo* layerInfo = replacements.push(); @@ -2165,7 +2161,7 @@ void SkGpuDevice::unlockLayers(const SkPicture* picture) { GrCachedLayer* layer = fContext->getLayerCache()->findLayer(picture->uniqueID(), info.fSaveLayerOpID, info.fRestoreOpID, - info.fCTM); + info.fOriginXform); fContext->getLayerCache()->unlock(layer); } diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp index 3535e8e3bf..a189c1a4ae 100644 --- a/tests/PictureTest.cpp +++ b/tests/PictureTest.cpp @@ -876,7 +876,18 @@ static void test_gpu_picture_optimization(skiatest::Reporter* reporter, static const int kWidth = 100; static const int kHeight = 100; - SkAutoTUnref<SkPicture> pict; + SkAutoTUnref<SkPicture> pict, child; + + { + SkPictureRecorder recorder; + + SkCanvas* c = recorder.beginRecording(kWidth, kHeight); + + c->saveLayer(NULL, NULL); + c->restore(); + + child.reset(recorder.endRecording()); + } // create a picture with the structure: // 1) @@ -892,21 +903,26 @@ static void test_gpu_picture_optimization(skiatest::Reporter* reporter, // SaveLayer w/ copyable paint // Restore // 4) - // SaveLayer w/ non-copyable paint + // SaveLayer + // DrawPicture (which has a SaveLayer/Restore pair) + // Restore + // 5) + // SaveLayer + // DrawPicture with Matrix & Paint (with SaveLayer/Restore pair) // Restore { SkPictureRecorder recorder; - SkCanvas* c = recorder.DEPRECATED_beginRecording(kWidth, kHeight); + SkCanvas* c = recorder.beginRecording(kWidth, kHeight); // 1) - c->saveLayer(NULL, NULL); + c->saveLayer(NULL, NULL); // layer #0 c->restore(); // 2) - c->saveLayer(NULL, NULL); - c->translate(kWidth/2, kHeight/2); + c->saveLayer(NULL, NULL); // layer #1 + c->translate(kWidth/2.0f, kHeight/2.0f); SkRect r = SkRect::MakeXYWH(0, 0, kWidth/2, kHeight/2); - c->saveLayer(&r, NULL); + c->saveLayer(&r, NULL); // layer #2 c->restore(); c->restore(); @@ -914,16 +930,23 @@ static void test_gpu_picture_optimization(skiatest::Reporter* reporter, { SkPaint p; p.setColor(SK_ColorRED); - c->saveLayer(NULL, &p); + c->saveLayer(NULL, &p); // layer #3 c->restore(); } // 4) - // TODO: this case will need to be removed once the paint's are immutable + { + c->saveLayer(NULL, NULL); // layer #4 + c->drawPicture(child); // layer #5 inside picture + c->restore(); + } + // 5 { SkPaint p; - SkAutoTUnref<SkColorFilter> cf(SkLumaColorFilter::Create()); - p.setImageFilter(SkColorFilterImageFilter::Create(cf.get()))->unref(); - c->saveLayer(NULL, &p); + SkMatrix trans; + trans.setTranslate(10, 10); + + c->saveLayer(NULL, NULL); // layer #6 + c->drawPicture(child, &trans, &p); // layer #7 inside picture c->restore(); } @@ -946,53 +969,98 @@ static void test_gpu_picture_optimization(skiatest::Reporter* reporter, REPORTER_ASSERT(reporter, NULL != data); const GrAccelData *gpuData = static_cast<const GrAccelData*>(data); - REPORTER_ASSERT(reporter, 5 == gpuData->numSaveLayers()); + REPORTER_ASSERT(reporter, 8 == gpuData->numSaveLayers()); const GrAccelData::SaveLayerInfo& info0 = gpuData->saveLayerInfo(0); - // The parent/child layer appear in reverse order + // The parent/child layers appear in reverse order const GrAccelData::SaveLayerInfo& info1 = gpuData->saveLayerInfo(2); const GrAccelData::SaveLayerInfo& info2 = gpuData->saveLayerInfo(1); + const GrAccelData::SaveLayerInfo& info3 = gpuData->saveLayerInfo(3); -// const GrAccelData::SaveLayerInfo& info4 = gpuData->saveLayerInfo(4); + + // The parent/child layers appear in reverse order + const GrAccelData::SaveLayerInfo& info4 = gpuData->saveLayerInfo(5); + const GrAccelData::SaveLayerInfo& info5 = gpuData->saveLayerInfo(4); + + // The parent/child layers appear in reverse order + const GrAccelData::SaveLayerInfo& info6 = gpuData->saveLayerInfo(7); + const GrAccelData::SaveLayerInfo& info7 = gpuData->saveLayerInfo(6); REPORTER_ASSERT(reporter, info0.fValid); - REPORTER_ASSERT(reporter, kWidth == info0.fSize.fWidth && kHeight == info0.fSize.fHeight); - REPORTER_ASSERT(reporter, info0.fCTM.isIdentity()); + REPORTER_ASSERT(reporter, pict->uniqueID() == info0.fPictureID); + REPORTER_ASSERT(reporter, kWidth == info0.fSize.fWidth && + kHeight == info0.fSize.fHeight); + REPORTER_ASSERT(reporter, info0.fOriginXform.isIdentity()); REPORTER_ASSERT(reporter, 0 == info0.fOffset.fX && 0 == info0.fOffset.fY); - REPORTER_ASSERT(reporter, NULL != info0.fPaint); + REPORTER_ASSERT(reporter, NULL == info0.fPaint); REPORTER_ASSERT(reporter, !info0.fIsNested && !info0.fHasNestedLayers); REPORTER_ASSERT(reporter, info1.fValid); - REPORTER_ASSERT(reporter, kWidth == info1.fSize.fWidth && kHeight == info1.fSize.fHeight); - REPORTER_ASSERT(reporter, info1.fCTM.isIdentity()); + REPORTER_ASSERT(reporter, pict->uniqueID() == info1.fPictureID); + REPORTER_ASSERT(reporter, kWidth == info1.fSize.fWidth && + kHeight == info1.fSize.fHeight); + REPORTER_ASSERT(reporter, info1.fOriginXform.isIdentity()); REPORTER_ASSERT(reporter, 0 == info1.fOffset.fX && 0 == info1.fOffset.fY); - REPORTER_ASSERT(reporter, NULL != info1.fPaint); - REPORTER_ASSERT(reporter, !info1.fIsNested && info1.fHasNestedLayers); // has a nested SL + REPORTER_ASSERT(reporter, NULL == info1.fPaint); + REPORTER_ASSERT(reporter, !info1.fIsNested && + info1.fHasNestedLayers); // has a nested SL REPORTER_ASSERT(reporter, info2.fValid); - REPORTER_ASSERT(reporter, kWidth/2 == info2.fSize.fWidth && + REPORTER_ASSERT(reporter, pict->uniqueID() == info2.fPictureID); + REPORTER_ASSERT(reporter, kWidth / 2 == info2.fSize.fWidth && kHeight/2 == info2.fSize.fHeight); // bound reduces size - REPORTER_ASSERT(reporter, info2.fCTM.isIdentity()); // translated - REPORTER_ASSERT(reporter, kWidth/2 == info2.fOffset.fX && - kHeight/2 == info2.fOffset.fY); - REPORTER_ASSERT(reporter, NULL != info1.fPaint); + REPORTER_ASSERT(reporter, info2.fOriginXform.isIdentity()); + REPORTER_ASSERT(reporter, kWidth/2 == info2.fOffset.fX && // translated + kHeight/2 == info2.fOffset.fY); + REPORTER_ASSERT(reporter, NULL == info1.fPaint); REPORTER_ASSERT(reporter, info2.fIsNested && !info2.fHasNestedLayers); // is nested REPORTER_ASSERT(reporter, info3.fValid); - REPORTER_ASSERT(reporter, kWidth == info3.fSize.fWidth && kHeight == info3.fSize.fHeight); - REPORTER_ASSERT(reporter, info3.fCTM.isIdentity()); + REPORTER_ASSERT(reporter, pict->uniqueID() == info3.fPictureID); + REPORTER_ASSERT(reporter, kWidth == info3.fSize.fWidth && + kHeight == info3.fSize.fHeight); + REPORTER_ASSERT(reporter, info3.fOriginXform.isIdentity()); REPORTER_ASSERT(reporter, 0 == info3.fOffset.fX && 0 == info3.fOffset.fY); REPORTER_ASSERT(reporter, NULL != info3.fPaint); REPORTER_ASSERT(reporter, !info3.fIsNested && !info3.fHasNestedLayers); - #if 0 // needs more though for GrGatherCanvas - REPORTER_ASSERT(reporter, !info4.fValid); // paint is/was uncopyable - REPORTER_ASSERT(reporter, kWidth == info4.fSize.fWidth && kHeight == info4.fSize.fHeight); + REPORTER_ASSERT(reporter, info4.fValid); + REPORTER_ASSERT(reporter, pict->uniqueID() == info4.fPictureID); + REPORTER_ASSERT(reporter, kWidth == info4.fSize.fWidth && + kHeight == info4.fSize.fHeight); REPORTER_ASSERT(reporter, 0 == info4.fOffset.fX && 0 == info4.fOffset.fY); - REPORTER_ASSERT(reporter, info4.fCTM.isIdentity()); - REPORTER_ASSERT(reporter, NULL == info4.fPaint); // paint is/was uncopyable - REPORTER_ASSERT(reporter, !info4.fIsNested && !info4.fHasNestedLayers); - #endif + REPORTER_ASSERT(reporter, info4.fOriginXform.isIdentity()); + REPORTER_ASSERT(reporter, NULL == info4.fPaint); + REPORTER_ASSERT(reporter, !info4.fIsNested && + info4.fHasNestedLayers); // has a nested SL + + REPORTER_ASSERT(reporter, info5.fValid); + REPORTER_ASSERT(reporter, child->uniqueID() == info5.fPictureID); // in a child picture + REPORTER_ASSERT(reporter, kWidth == info5.fSize.fWidth && + kHeight == info5.fSize.fHeight); + REPORTER_ASSERT(reporter, 0 == info5.fOffset.fX && 0 == info5.fOffset.fY); + REPORTER_ASSERT(reporter, info5.fOriginXform.isIdentity()); + REPORTER_ASSERT(reporter, NULL == info5.fPaint); + REPORTER_ASSERT(reporter, info5.fIsNested && !info5.fHasNestedLayers); // is nested + + REPORTER_ASSERT(reporter, info6.fValid); + REPORTER_ASSERT(reporter, pict->uniqueID() == info6.fPictureID); + REPORTER_ASSERT(reporter, kWidth == info6.fSize.fWidth && + kHeight == info6.fSize.fHeight); + REPORTER_ASSERT(reporter, 0 == info6.fOffset.fX && 0 == info6.fOffset.fY); + REPORTER_ASSERT(reporter, info6.fOriginXform.isIdentity()); + REPORTER_ASSERT(reporter, NULL == info6.fPaint); + REPORTER_ASSERT(reporter, !info6.fIsNested && + info6.fHasNestedLayers); // has a nested SL + + REPORTER_ASSERT(reporter, info7.fValid); + REPORTER_ASSERT(reporter, child->uniqueID() == info7.fPictureID); // in a child picture + REPORTER_ASSERT(reporter, kWidth == info7.fSize.fWidth && + kHeight == info7.fSize.fHeight); + REPORTER_ASSERT(reporter, 0 == info7.fOffset.fX && 0 == info7.fOffset.fY); + REPORTER_ASSERT(reporter, info7.fOriginXform.isIdentity()); + REPORTER_ASSERT(reporter, NULL == info7.fPaint); + REPORTER_ASSERT(reporter, info7.fIsNested && !info7.fHasNestedLayers); // is nested } } } |