diff options
-rw-r--r-- | dm/DM.cpp | 1 | ||||
-rw-r--r-- | dm/DMSrcSink.cpp | 11 | ||||
-rw-r--r-- | dm/DMSrcSink.h | 6 | ||||
-rw-r--r-- | gyp/utils.gypi | 1 | ||||
-rw-r--r-- | samplecode/SampleApp.cpp | 17 | ||||
-rw-r--r-- | samplecode/SampleApp.h | 1 | ||||
-rw-r--r-- | src/utils/SkDeferredCanvas.cpp | 545 | ||||
-rw-r--r-- | src/utils/SkDeferredCanvas.h | 147 | ||||
-rw-r--r-- | tests/CanvasTest.cpp | 22 | ||||
-rw-r--r-- | tools/DumpRecord.cpp | 19 | ||||
-rw-r--r-- | tools/dump_record.cpp | 8 |
11 files changed, 777 insertions, 1 deletions
@@ -853,6 +853,7 @@ static Sink* create_via(const SkString& tag, Sink* wrapped) { VIA("pic", ViaPicture, wrapped); VIA("2ndpic", ViaSecondPicture, wrapped); VIA("sp", ViaSingletonPictures, wrapped); + VIA("defer", ViaDefer, wrapped); VIA("tiles", ViaTiles, 256, 256, nullptr, wrapped); VIA("tiles_rt", ViaTiles, 256, 256, new SkRTreeFactory, wrapped); diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp index f0b10103f7..258e94e7e6 100644 --- a/dm/DMSrcSink.cpp +++ b/dm/DMSrcSink.cpp @@ -15,6 +15,7 @@ #include "SkColorSpaceXform.h" #include "SkCommonFlags.h" #include "SkData.h" +#include "SkDeferredCanvas.h" #include "SkDocument.h" #include "SkError.h" #include "SkImageGenerator.h" @@ -1439,6 +1440,16 @@ Error ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkSt /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +Error ViaDefer::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { + auto size = src.size(); + return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { + SkDeferredCanvas deferred(canvas); + return src.draw(&deferred); + }); +} + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + // Draw the Src into two pictures, then draw the second picture into the wrapped Sink. // This tests that any shortcuts we may take while recording that second picture are legal. Error ViaSecondPicture::draw( diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h index be7d68e638..50a3b5a41a 100644 --- a/dm/DMSrcSink.h +++ b/dm/DMSrcSink.h @@ -391,6 +391,12 @@ public: Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; }; +class ViaDefer : public Via { +public: + explicit ViaDefer(Sink* sink) : Via(sink) {} + Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; +}; + class ViaTiles : public Via { public: ViaTiles(int w, int h, SkBBHFactory*, Sink*); diff --git a/gyp/utils.gypi b/gyp/utils.gypi index eeadafbe53..8ae985b835 100644 --- a/gyp/utils.gypi +++ b/gyp/utils.gypi @@ -46,6 +46,7 @@ '<(skia_src_path)/utils/SkCanvasStateUtils.cpp', '<(skia_src_path)/utils/SkDashPath.cpp', '<(skia_src_path)/utils/SkDashPathPriv.h', + '<(skia_src_path)/utils/SkDeferredCanvas.cpp', '<(skia_src_path)/utils/SkDumpCanvas.cpp', '<(skia_src_path)/utils/SkEventTracer.cpp', '<(skia_src_path)/utils/SkFloatUtils.h', diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp index a1e42e3aac..ffa507bc17 100644 --- a/samplecode/SampleApp.cpp +++ b/samplecode/SampleApp.cpp @@ -804,6 +804,7 @@ SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* dev fRequestGrabImage = false; fTilingMode = kNo_Tiling; fMeasureFPS = false; + fUseDeferredCanvas = false; fLCDState = SkOSMenu::kMixedState; fAAState = SkOSMenu::kMixedState; fSubpixelState = SkOSMenu::kMixedState; @@ -987,6 +988,9 @@ static void drawText(SkCanvas* canvas, SkString str, SkScalar left, SkScalar top #define XCLIP_N 8 #define YCLIP_N 8 +#include "SkDeferredCanvas.h" +#include "SkDumpCanvas.h" + void SampleWindow::draw(SkCanvas* canvas) { gAnimTimer.updateTime(); @@ -1001,7 +1005,11 @@ void SampleWindow::draw(SkCanvas* canvas) { SkSize tile = this->tileSize(); if (kNo_Tiling == fTilingMode) { - this->INHERITED::draw(canvas); // no looping or surfaces needed + SkDebugfDumper dumper; + SkDumpCanvas dump(&dumper); + SkDeferredCanvas deferred(canvas); + SkCanvas* c = fUseDeferredCanvas ? &deferred : canvas; + this->INHERITED::draw(c); // no looping or surfaces needed } else { const SkScalar w = SkScalarCeilToScalar(tile.width()); const SkScalar h = SkScalarCeilToScalar(tile.height()); @@ -1667,6 +1675,10 @@ bool SampleWindow::onHandleChar(SkUnichar uni) { case 'D': toggleDistanceFieldFonts(); break; + case 'E': + fUseDeferredCanvas = !fUseDeferredCanvas; + this->inval(nullptr); + break; case 'f': // only toggleFPS(); @@ -2020,6 +2032,9 @@ void SampleWindow::updateTitle() { if (fUsePicture) { title.prepend("<P> "); } + if (fUseDeferredCanvas) { + title.prepend("<E> "); + } title.prepend(trystate_str(fLCDState, "LCD ", "lcd ")); title.prepend(trystate_str(fAAState, "AA ", "aa ")); diff --git a/samplecode/SampleApp.h b/samplecode/SampleApp.h index f4be093a66..8aea272c6d 100644 --- a/samplecode/SampleApp.h +++ b/samplecode/SampleApp.h @@ -188,6 +188,7 @@ private: bool fPerspAnim; bool fRequestGrabImage; bool fMeasureFPS; + bool fUseDeferredCanvas; WallTimer fTimer; double fMeasureFPS_Time; bool fMagnify; diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp new file mode 100644 index 0000000000..14220209cc --- /dev/null +++ b/src/utils/SkDeferredCanvas.cpp @@ -0,0 +1,545 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkDeferredCanvas.h" +#include "SkDrawable.h" +#include "SkPath.h" +#include "SkRRect.h" +#include "SkSurface.h" +#include "SkTextBlob.h" + +bool SkDeferredCanvas::Rec::isConcat(SkMatrix* m) const { + switch (fType) { + case kTrans_Type: + m->setTranslate(fData.fTranslate.x(), fData.fTranslate.y()); + return true; + case kScaleTrans_Type: + m->setScaleTranslate(fData.fScaleTrans.fScale.x(), + fData.fScaleTrans.fScale.y(), + fData.fScaleTrans.fTrans.x(), + fData.fScaleTrans.fTrans.y()); + return true; + default: + break; + } + return false; +} + +void SkDeferredCanvas::Rec::setConcat(const SkMatrix& m) { + SkASSERT(m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)); + + if (m.getType() <= SkMatrix::kTranslate_Mask) { + fType = kTrans_Type; + fData.fTranslate.set(m.getTranslateX(), m.getTranslateY()); + } else { + fType = kScaleTrans_Type; + fData.fScaleTrans.fScale.set(m.getScaleX(), m.getScaleY()); + fData.fScaleTrans.fTrans.set(m.getTranslateX(), m.getTranslateY()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +SkDeferredCanvas::SkDeferredCanvas(SkCanvas* canvas) + : INHERITED(canvas->getBaseLayerSize().width(), canvas->getBaseLayerSize().height()) + , fCanvas(canvas) +{} + +SkDeferredCanvas::~SkDeferredCanvas() {} + +void SkDeferredCanvas::push_save() { + Rec* r = fRecs.append(); + r->fType = kSave_Type; +} + +void SkDeferredCanvas::push_cliprect(const SkRect& bounds) { + int index = fRecs.count() - 1; + if (index >= 0 && fRecs[index].fType == kClipRect_Type) { + if (!fRecs[index].fData.fBounds.intersect(bounds)) { + fRecs[index].fData.fBounds.setEmpty(); + } + } else { + Rec* r = fRecs.append(); + r->fType = kClipRect_Type; + r->fData.fBounds = bounds; + } +} + +bool SkDeferredCanvas::push_concat(const SkMatrix& mat) { + if (mat.getType() > (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) { + return false; + } + // At the moment, we don't know which ops can scale and which can also flip, so + // we reject negative scales for now + if (mat.getScaleX() < 0 || mat.getScaleY() < 0) { + return false; + } + + int index = fRecs.count() - 1; + SkMatrix m; + if (index >= 0 && fRecs[index].isConcat(&m)) { + m.preConcat(mat); + fRecs[index].setConcat(m); + } else { + fRecs.append()->setConcat(mat); + } + return true; +} + +void SkDeferredCanvas::emit(const Rec& rec) { + switch (rec.fType) { + case kSave_Type: + fCanvas->save(); + this->INHERITED::willSave(); + break; + case kClipRect_Type: + fCanvas->clipRect(rec.fData.fBounds); + this->INHERITED::onClipRect(rec.fData.fBounds, + SkRegion::kIntersect_Op, kHard_ClipEdgeStyle); + break; + case kTrans_Type: + case kScaleTrans_Type: { + SkMatrix mat; + rec.getConcat(&mat); + fCanvas->concat(mat); + this->INHERITED::didConcat(mat); + } break; + } +} + +void SkDeferredCanvas::flush_le(int index) { + SkASSERT(index >= -1 && index < fRecs.count()); + + int count = index + 1; + for (int i = 0; i < count; ++i) { + this->emit(fRecs[i]); + } + fRecs.remove(0, count); +} + +void SkDeferredCanvas::flush_all() { + this->flush_le(fRecs.count() - 1); +} + +void SkDeferredCanvas::flush_before_saves() { + int i; + for (i = fRecs.count() - 1; i >= 0; --i) { + if (kSave_Type != fRecs[i].fType) { + break; + } + } + this->flush_le(i); +} + +enum Flags { + kNoTranslate_Flag = 1 << 0, + kNoClip_Flag = 1 << 1, + kNoCull_Flag = 1 << 2, + kNoScale_Flag = 1 << 3, +}; + +void SkDeferredCanvas::flush_check(SkRect* bounds, const SkPaint* paint, unsigned flags) { + if (paint) { + if (paint->getShader() || paint->getImageFilter()) { + flags |= kNoTranslate_Flag | kNoScale_Flag; + } + // TODO: replace these with code to enlarge the bounds conservatively? + if (paint->getStyle() != SkPaint::kFill_Style || paint->getMaskFilter() || + paint->getImageFilter() || paint->getPathEffect()) + { + flags |= kNoCull_Flag | kNoScale_Flag | kNoClip_Flag; + } + if (paint->getLooper()) { + // to be conservative, we disable both, since embedded layers could have shaders + // or strokes etc. + flags |= kNoTranslate_Flag | kNoCull_Flag | kNoScale_Flag; + } + } + bool canClip = !(flags & kNoClip_Flag); + bool canTranslate = !(flags & kNoTranslate_Flag); + bool canCull = !(flags & kNoCull_Flag); + bool canScale = !(flags & kNoScale_Flag); + + int i; + for (i = fRecs.count() - 1; i >= 0; --i) { + const Rec& rec = fRecs[i]; + switch (rec.fType) { + case kSave_Type: + // continue to the next rec + break; + case kClipRect_Type: + if (!canCull) { + goto STOP; + } + if (canClip) { + if (!bounds->intersect(rec.fData.fBounds)) { + bounds->setEmpty(); + return; + } + // continue to the next rec + } else { + if (!rec.fData.fBounds.contains(*bounds)) { + goto STOP; + } + // continue to the next rec + } + break; + case kTrans_Type: + if (canTranslate) { + bounds->offset(rec.fData.fTranslate.x(), rec.fData.fTranslate.y()); + // continue to the next rec + } else { + goto STOP; + } + break; + case kScaleTrans_Type: + if (canScale) { + SkMatrix m; + rec.getConcat(&m); + m.mapRectScaleTranslate(bounds, *bounds); + } else { + goto STOP; + } + break; + } + } +STOP: + this->flush_le(i); +} + +void SkDeferredCanvas::flush_translate(SkScalar* x, SkScalar* y, const SkRect& bounds, + const SkPaint* paint) { + SkRect tmp = bounds; + this->flush_check(&tmp, paint, kNoClip_Flag | kNoScale_Flag); + *x += tmp.x() - bounds.x(); + *y += tmp.y() - bounds.y(); +} + +void SkDeferredCanvas::flush_translate(SkScalar* x, SkScalar* y, const SkPaint& paint) { + SkRect tmp = SkRect::MakeXYWH(*x, *y, 1, 1); + this->flush_check(&tmp, &paint, kNoClip_Flag | kNoCull_Flag | kNoScale_Flag); + *x = tmp.x(); + *y = tmp.y(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +void SkDeferredCanvas::willSave() { + this->push_save(); +} + +SkCanvas::SaveLayerStrategy SkDeferredCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { + this->flush_all(); + fCanvas->saveLayer(rec); + this->INHERITED::getSaveLayerStrategy(rec); + // No need for a layer. + return kNoLayer_SaveLayerStrategy; +} + +void SkDeferredCanvas::willRestore() { + for (int i = fRecs.count() - 1; i >= 0; --i) { + if (kSave_Type == fRecs[i].fType) { + fRecs.setCount(i); // pop off everything here and later + return; + } + } + for (int i = 0; i < fRecs.count(); ++i) { + SkASSERT(kSave_Type != fRecs[i].fType); + } + fRecs.setCount(0); + fCanvas->restore(); + this->INHERITED::willRestore(); +} + +void SkDeferredCanvas::didConcat(const SkMatrix& matrix) { + if (matrix.isIdentity()) { + return; + } + if (!this->push_concat(matrix)) { + this->flush_all(); + fCanvas->concat(matrix); + this->INHERITED::didConcat(matrix); + } +} + +void SkDeferredCanvas::didSetMatrix(const SkMatrix& matrix) { + this->flush_all(); + fCanvas->setMatrix(matrix); + this->INHERITED::didSetMatrix(matrix); +} + +void SkDeferredCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { + if (SkRegion::kIntersect_Op == op) { + this->push_cliprect(rect); + } else { + this->flush_all(); + fCanvas->clipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle); + this->INHERITED::onClipRect(rect, op, edgeStyle); + } +} + +void SkDeferredCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { + this->flush_all(); + fCanvas->clipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle); + this->INHERITED::onClipRRect(rrect, op, edgeStyle); +} + +void SkDeferredCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { + this->flush_all(); + fCanvas->clipPath(path, op, kSoft_ClipEdgeStyle == edgeStyle); + this->INHERITED::onClipPath(path, op, edgeStyle); +} + +void SkDeferredCanvas::onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) { + this->flush_all(); + fCanvas->clipRegion(deviceRgn, op); + this->INHERITED::onClipRegion(deviceRgn, op); +} + +void SkDeferredCanvas::onDrawPaint(const SkPaint& paint) { + // TODO: Can we turn this into drawRect? + this->flush_all(); + fCanvas->drawPaint(paint); +} + +void SkDeferredCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint) { + this->flush_all(); + fCanvas->drawPoints(mode, count, pts, paint); +} + +void SkDeferredCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) { + SkRect modRect = rect; + this->flush_check(&modRect, &paint); + fCanvas->drawRect(modRect, paint); +} + +void SkDeferredCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) { + SkRect modRect = rect; + this->flush_check(&modRect, &paint, kNoClip_Flag); + fCanvas->drawOval(modRect, paint); +} + +static SkRRect make_offset(const SkRRect& src, SkScalar dx, SkScalar dy) { + SkRRect dst = src; + dst.offset(dx, dy); + return dst; +} + +void SkDeferredCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { + SkRect modRect = rrect.getBounds(); + this->flush_check(&modRect, &paint, kNoClip_Flag); + fCanvas->drawRRect(make_offset(rrect, + modRect.x() - rrect.getBounds().x(), + modRect.y() - rrect.getBounds().y()), paint); +} + +void SkDeferredCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { + this->flush_all(); + fCanvas->drawDRRect(outer, inner, paint); +} + +void SkDeferredCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { + if (path.isInverseFillType()) { + this->flush_before_saves(); + } else { + SkRect modRect = path.getBounds(); + this->flush_check(&modRect, &paint, kNoClip_Flag | kNoTranslate_Flag | kNoScale_Flag); + } + fCanvas->drawPath(path, paint); +} + +void SkDeferredCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, + const SkPaint* paint) { + const SkScalar w = SkIntToScalar(bitmap.width()); + const SkScalar h = SkIntToScalar(bitmap.height()); + SkRect bounds = SkRect::MakeXYWH(x, y, w, h); + this->flush_check(&bounds, paint, kNoClip_Flag); + if (bounds.width() == w && bounds.height() == h) { + fCanvas->drawBitmap(bitmap, bounds.x(), bounds.y(), paint); + } else { + fCanvas->drawBitmapRect(bitmap, bounds, paint); + } +} + +void SkDeferredCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint) { + SkRect modRect = dst; + this->flush_check(&modRect, paint, kNoClip_Flag); + fCanvas->legacy_drawBitmapRect(bitmap, src, modRect, paint, constraint); +} + +void SkDeferredCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, + const SkRect& dst, const SkPaint* paint) { + SkRect modRect = dst; + this->flush_check(&modRect, paint, kNoClip_Flag); + fCanvas->drawBitmapNine(bitmap, center, modRect, paint); +} + +void SkDeferredCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, + const SkRect& dst, const SkPaint* paint) { + SkRect modRect = dst; + this->flush_check(&modRect, paint, kNoClip_Flag); + fCanvas->drawImageNine(image, center, modRect, paint); +} + +void SkDeferredCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, + const SkPaint* paint) { + const SkScalar w = SkIntToScalar(image->width()); + const SkScalar h = SkIntToScalar(image->height()); + SkRect bounds = SkRect::MakeXYWH(x, y, w, h); + this->flush_check(&bounds, paint, kNoClip_Flag); + if (bounds.width() == w && bounds.height() == h) { + fCanvas->drawImage(image, bounds.x(), bounds.y(), paint); + } else { + fCanvas->drawImageRect(image, bounds, paint); + } +} + +void SkDeferredCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint) { + SkRect modRect = dst; + this->flush_check(&modRect, paint, kNoClip_Flag); + fCanvas->legacy_drawImageRect(image, src, modRect, paint, constraint); +} + +void SkDeferredCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, + const SkPaint& paint) { + this->flush_translate(&x, &y, paint); + fCanvas->drawText(text, byteLength, x, y, paint); +} + +void SkDeferredCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], + const SkPaint& paint) { + this->flush_before_saves(); + fCanvas->drawPosText(text, byteLength, pos, paint); +} + +void SkDeferredCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], + SkScalar constY, const SkPaint& paint) { + this->flush_before_saves(); + fCanvas->drawPosTextH(text, byteLength, xpos, constY, paint); +} + +void SkDeferredCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, + const SkMatrix* matrix, const SkPaint& paint) { + this->flush_before_saves(); + fCanvas->drawTextOnPath(text, byteLength, path, matrix, paint); +} + +void SkDeferredCanvas::onDrawTextRSXform(const void* text, size_t byteLength, + const SkRSXform xform[], const SkRect* cullRect, + const SkPaint& paint) { + if (cullRect) { + SkRect modRect = *cullRect; + // only allow culling + this->flush_check(&modRect, &paint, kNoClip_Flag | kNoScale_Flag | kNoTranslate_Flag); + } else { + this->flush_before_saves(); + } + fCanvas->drawTextRSXform(text, byteLength, xform, cullRect, paint); +} + +void SkDeferredCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint &paint) { + this->flush_translate(&x, &y, blob->bounds(), &paint); + fCanvas->drawTextBlob(blob, x, y, paint); +} + +#include "SkPicture.h" +#include "SkCanvasPriv.h" +void SkDeferredCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, + const SkPaint* paint) { +#if 1 + SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); + picture->playback(this); +#else + this->flush_before_saves(); + fCanvas->drawPicture(picture, matrix, paint); +#endif +} + +void SkDeferredCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { + // TODO: investigate culling and applying concat to the matrix +#if 1 + drawable->draw(this, matrix); +#else + this->flush_before_saves(); + fCanvas->drawDrawable(drawable, matrix); +#endif +} + +void SkDeferredCanvas::onDrawAtlas(const SkImage* image, const SkRSXform xform[], + const SkRect rects[], const SkColor colors[], + int count, SkXfermode::Mode mode, + const SkRect* cull, const SkPaint* paint) { + this->flush_before_saves(); + fCanvas->drawAtlas(image, xform, rects, colors, count, mode, cull, paint); +} + +void SkDeferredCanvas::onDrawVertices(VertexMode vmode, int vertexCount, + const SkPoint vertices[], const SkPoint texs[], + const SkColor colors[], SkXfermode* xmode, + const uint16_t indices[], int indexCount, + const SkPaint& paint) { + this->flush_before_saves(); + fCanvas->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode, + indices, indexCount, paint); +} + +void SkDeferredCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkXfermode* xmode, + const SkPaint& paint) { + this->flush_before_saves(); + fCanvas->drawPatch(cubics, colors, texCoords, xmode, paint); +} + +void SkDeferredCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* data) { + this->flush_all(); + fCanvas->drawAnnotation(rect, key, data); +} + +#ifdef SK_SUPPORT_LEGACY_DRAWFILTER +SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) { + fCanvas->setDrawFilter(filter); + return this->INHERITED::setDrawFilter(filter); +} +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +sk_sp<SkSurface> SkDeferredCanvas::onNewSurface(const SkImageInfo& info, + const SkSurfaceProps& props) { + return fCanvas->makeSurface(info, &props); +} +SkISize SkDeferredCanvas::getBaseLayerSize() const { return fCanvas->getBaseLayerSize(); } +bool SkDeferredCanvas::getClipBounds(SkRect* bounds) const { + return fCanvas->getClipBounds(bounds); +} +bool SkDeferredCanvas::getClipDeviceBounds(SkIRect* bounds) const { + return fCanvas->getClipDeviceBounds(bounds); +} +bool SkDeferredCanvas::isClipEmpty() const { return fCanvas->isClipEmpty(); } +bool SkDeferredCanvas::isClipRect() const { return fCanvas->isClipRect(); } +bool SkDeferredCanvas::onPeekPixels(SkPixmap* pixmap) { return fCanvas->peekPixels(pixmap); } +bool SkDeferredCanvas::onAccessTopLayerPixels(SkPixmap* pixmap) { + SkImageInfo info; + size_t rowBytes; + SkIPoint* origin = nullptr; + void* addr = fCanvas->accessTopLayerPixels(&info, &rowBytes, origin); + if (addr) { + *pixmap = SkPixmap(info, addr, rowBytes); + return true; + } + return false; +} +SkImageInfo SkDeferredCanvas::onImageInfo() const { return fCanvas->imageInfo(); } +bool SkDeferredCanvas::onGetProps(SkSurfaceProps* props) const { return fCanvas->getProps(props); } +void SkDeferredCanvas::onFlush() { + this->flush_all(); + return fCanvas->flush(); +} diff --git a/src/utils/SkDeferredCanvas.h b/src/utils/SkDeferredCanvas.h new file mode 100644 index 0000000000..6400734def --- /dev/null +++ b/src/utils/SkDeferredCanvas.h @@ -0,0 +1,147 @@ + +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDeferredCanvas_DEFINED +#define SkDeferredCanvas_DEFINED + +#include "../private/SkTDArray.h" +#include "SkCanvas.h" + +class SK_API SkDeferredCanvas : public SkCanvas { +public: + SkDeferredCanvas(SkCanvas*); + ~SkDeferredCanvas() override; + +#ifdef SK_SUPPORT_LEGACY_DRAWFILTER + SkDrawFilter* setDrawFilter(SkDrawFilter*) override; +#endif + +protected: + sk_sp<SkSurface> onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override; + SkISize getBaseLayerSize() const override; + bool getClipBounds(SkRect* bounds) const override; + bool getClipDeviceBounds(SkIRect* bounds) const override; + bool isClipEmpty() const override; + bool isClipRect() const override; + bool onPeekPixels(SkPixmap*) override; + bool onAccessTopLayerPixels(SkPixmap*) override; + SkImageInfo onImageInfo() const override; + bool onGetProps(SkSurfaceProps*) const override; + void onFlush() override; +// SkCanvas* canvasForDrawIter() override; + + void willSave() override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; + void willRestore() override; + + void didConcat(const SkMatrix&) override; + void didSetMatrix(const SkMatrix&) override; + + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, + const SkPaint&) override; + virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], + const SkPaint&) override; + virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], + SkScalar constY, const SkPaint&) override; + virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, + const SkMatrix* matrix, const SkPaint&) override; + void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform[], + const SkRect* cullRect, const SkPaint&) override; + virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) override; + virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkXfermode* xmode, + const SkPaint& paint) override; + + void onDrawPaint(const SkPaint&) override; + void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; + void onDrawRect(const SkRect&, const SkPaint&) override; + void onDrawOval(const SkRect&, const SkPaint&) override; + void onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawPath(const SkPath&, const SkPaint&) override; + void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override; + void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, + SrcRectConstraint) override; + void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override; + void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, + const SkPaint*, SrcRectConstraint) override; + void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, + const SkPaint*) override; + void onDrawImageNine(const SkImage* image, const SkIRect& center, + const SkRect& dst, const SkPaint*) override; + void onDrawVertices(VertexMode vmode, int vertexCount, + const SkPoint vertices[], const SkPoint texs[], + const SkColor colors[], SkXfermode* xmode, + const uint16_t indices[], int indexCount, + const SkPaint&) override; + void onDrawAtlas(const SkImage* image, const SkRSXform xform[], + const SkRect rects[], const SkColor colors[], + int count, SkXfermode::Mode mode, + const SkRect* cull, const SkPaint* paint) override; + + void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkRegion::Op) override; + + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + void onDrawAnnotation(const SkRect&, const char[], SkData*) override; + + class Iter; + +private: + SkCanvas* fCanvas; + + enum Type { + kSave_Type, + kClipRect_Type, + kTrans_Type, + kScaleTrans_Type, + }; + struct Rec { + Type fType; + union { + SkRect fBounds; + SkVector fTranslate; + struct { + SkVector fScale; + SkVector fTrans; // post translate + } fScaleTrans; + } fData; + + bool isConcat(SkMatrix*) const; + void getConcat(SkMatrix* mat) const { + SkDEBUGCODE(bool isconcat = ) this->isConcat(mat); + SkASSERT(isconcat); + } + void setConcat(const SkMatrix&); + }; + SkTDArray<Rec> fRecs; + + void push_save(); + void push_cliprect(const SkRect&); + bool push_concat(const SkMatrix&); + + void emit(const Rec& rec); + + void flush_all(); + void flush_before_saves(); + void flush_le(int index); + void flush_translate(SkScalar* x, SkScalar* y, const SkPaint&); + void flush_translate(SkScalar* x, SkScalar* y, const SkRect& bounds, const SkPaint* = nullptr); + void flush_check(SkRect* bounds, const SkPaint*, unsigned flags = 0); + + void internal_flush_translate(SkScalar* x, SkScalar* y, const SkRect* boundsOrNull); + + typedef SkCanvas INHERITED; +}; + + +#endif diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp index 70c2c04ffa..82e065f5ac 100644 --- a/tests/CanvasTest.cpp +++ b/tests/CanvasTest.cpp @@ -813,3 +813,25 @@ DEF_TEST(PaintFilterCanvas_ConsistentState, reporter) { REPORTER_ASSERT(reporter, canvas.getClipBounds(&clip1) == filterCanvas.getClipBounds(&clip2)); REPORTER_ASSERT(reporter, clip1 == clip2); } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "SkDeferredCanvas.h" +#include "SkDumpCanvas.h" + +DEF_TEST(DeferredCanvas, r) { + SkDebugfDumper dumper; + SkDumpCanvas dumpC(&dumper); + + SkDeferredCanvas canvas(&dumpC); + + SkPaint paint; +// paint.setShader(SkShader::MakeColorShader(SK_ColorRED)); + + canvas.save(); + canvas.clipRect(SkRect::MakeWH(55, 55)); + canvas.translate(10, 20); + canvas.drawRect(SkRect::MakeWH(50, 50), paint); + canvas.restore(); +} + diff --git a/tools/DumpRecord.cpp b/tools/DumpRecord.cpp index efaf0eb58e..51a9d1f4a6 100644 --- a/tools/DumpRecord.cpp +++ b/tools/DumpRecord.cpp @@ -75,6 +75,25 @@ public: } } +#if 0 + void print(const SkRecords::DrawAnnotation& command, double ns) { + int us = (int)(ns * 1e-3); + if (!fTimeWithCommand) { + printf("%6dus ", us); + } + printf("%*d ", fDigits, fIndex++); + for (int i = 0; i < fIndent; i++) { + printf(" "); + } + if (fTimeWithCommand) { + printf("%6dus ", us); + } + printf("DrawAnnotation [%g %g %g %g] %s\n", + command.rect.left(), command.rect.top(), command.rect.right(), command.rect.bottom(), + command.key.c_str()); + } +#endif + private: template <typename T> void printNameAndTime(const T& command, double ns) { diff --git a/tools/dump_record.cpp b/tools/dump_record.cpp index 52f8f8c0b8..5d54f4d561 100644 --- a/tools/dump_record.cpp +++ b/tools/dump_record.cpp @@ -7,6 +7,7 @@ #include "DumpRecord.h" #include "SkCommandLineFlags.h" +#include "SkDeferredCanvas.h" #include "SkPicture.h" #include "SkPictureRecorder.h" #include "SkRecordDraw.h" @@ -22,6 +23,7 @@ DEFINE_bool(optimize2, false, "Run SkRecordOptimize2 before dumping."); DEFINE_int32(tile, 1000000000, "Simulated tile size."); DEFINE_bool(timeWithCommand, false, "If true, print time next to command, else in first column."); DEFINE_string2(write, w, "", "Write the (optimized) picture to the named file."); +DEFINE_bool(defer, false, "Defer clips and translates"); static void dump(const char* name, int w, int h, const SkRecord& record) { SkBitmap bitmap; @@ -54,6 +56,12 @@ int tool_main(int argc, char** argv) { SkDebugf("Could not read %s as an SkPicture.\n", FLAGS_skps[i]); return 1; } + if (FLAGS_defer) { + SkPictureRecorder recorder; + SkDeferredCanvas deferred(recorder.beginRecording(src->cullRect())); + src->playback(&deferred); + src = recorder.finishRecordingAsPicture(); + } const int w = SkScalarCeilToInt(src->cullRect().width()); const int h = SkScalarCeilToInt(src->cullRect().height()); |