diff options
author | fmalita <fmalita@chromium.org> | 2015-02-26 07:48:42 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-26 15:49:27 +0000 |
commit | f5190e0b6f8f56c5f715928b4c68d39564cb1988 (patch) | |
tree | 009ea8dec014c2c1e15cd7955d924567b32501c5 /skia/ext | |
parent | 721ec7f8578afb27b9664641b109d483439b9859 (diff) | |
download | chromium_src-f5190e0b6f8f56c5f715928b4c68d39564cb1988.zip chromium_src-f5190e0b6f8f56c5f715928b4c68d39564cb1988.tar.gz chromium_src-f5190e0b6f8f56c5f715928b4c68d39564cb1988.tar.bz2 |
Refactor BenchmarkingCanvas to avoid internal Skia dependencies
Re-implement BenchmarkingCanvas functionality based on public Skia APIs
only.
Convert Skia types to base::Value() structured data hierarchies (which
are then pass through to the viewer).
BUG=457691
R=reed@google.com,robertphillips@google.com,nduca@chromium.org,pdr@chromium.org
Review URL: https://codereview.chromium.org/942533002
Cr-Commit-Position: refs/heads/master@{#318236}
Diffstat (limited to 'skia/ext')
-rw-r--r-- | skia/ext/benchmarking_canvas.cc | 866 | ||||
-rw-r--r-- | skia/ext/benchmarking_canvas.h | 87 |
2 files changed, 752 insertions, 201 deletions
diff --git a/skia/ext/benchmarking_canvas.cc b/skia/ext/benchmarking_canvas.cc index 409d56b..0dd6949 100644 --- a/skia/ext/benchmarking_canvas.cc +++ b/skia/ext/benchmarking_canvas.cc @@ -2,250 +2,760 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/containers/hash_tables.h" #include "base/logging.h" +#include "base/strings/stringprintf.h" #include "base/time/time.h" #include "skia/ext/benchmarking_canvas.h" -#include "third_party/skia/include/core/SkSurface.h" -#include "third_party/skia/include/utils/SkNWayCanvas.h" +#include "third_party/skia/include/core/SkColorFilter.h" +#include "third_party/skia/include/core/SkImageFilter.h" +#include "third_party/skia/include/core/SkPicture.h" +#include "third_party/skia/include/core/SkRegion.h" +#include "third_party/skia/include/core/SkTextBlob.h" +#include "third_party/skia/include/core/SkXfermode.h" -namespace skia { +namespace { -class AutoStamper { +class FlagsBuilder { public: - AutoStamper(TimingCanvas* timing_canvas); - ~AutoStamper(); + FlagsBuilder(char separator) + : separator_(separator) {} + + void addFlag(bool flag_val, const char flag_name[]) { + if (!flag_val) + return; + if (!oss_.str().empty()) + oss_ << separator_; + + oss_ << flag_name; + } + + std::string str() const { + return oss_.str(); + } private: - TimingCanvas* timing_canvas_; - base::TimeTicks start_ticks_; + char separator_; + std::ostringstream oss_; }; -class TimingCanvas : public SkNWayCanvas { -public: - TimingCanvas(int width, int height, const BenchmarkingCanvas* track_canvas) - : SkNWayCanvas(width, height) - , tracking_canvas_(track_canvas) { - surface_ = skia::AdoptRef(SkSurface::NewRasterN32Premul(width, height)); +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(bool b) { + scoped_ptr<base::FundamentalValue> val(new base::FundamentalValue(b)); - addCanvas(surface_->getCanvas()); - } + return val.Pass(); +} - ~TimingCanvas() override {} +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(SkScalar scalar) { + scoped_ptr<base::FundamentalValue> val(new base::FundamentalValue(scalar)); - double GetTime(size_t index) { - TimingsMap::const_iterator timing_info = timings_map_.find(index); - return timing_info != timings_map_.end() - ? timing_info->second.InMillisecondsF() - : 0.0; - } + return val.Pass(); +} - // SkCanvas overrides. - void willSave() override { - AutoStamper stamper(this); - SkNWayCanvas::willSave(); - } +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkSize& size) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + val->Set("width", AsValue(size.width())); + val->Set("height", AsValue(size.height())); - SaveLayerStrategy willSaveLayer(const SkRect* bounds, - const SkPaint* paint, - SaveFlags flags) override { - AutoStamper stamper(this); - return SkNWayCanvas::willSaveLayer(bounds, paint, flags); - } + return val.Pass(); +} - void willRestore() override { - AutoStamper stamper(this); - SkNWayCanvas::willRestore(); - } +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkPoint& point) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + val->Set("x", AsValue(point.x())); + val->Set("y", AsValue(point.y())); - void onDrawPaint(const SkPaint& paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawPaint(paint); - } + return val.Pass(); +} - void onDrawPoints(PointMode mode, - size_t count, - const SkPoint pts[], - const SkPaint& paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawPoints(mode, count, pts, paint); - } +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkRect& rect) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + val->Set("left", AsValue(rect.fLeft)); + val->Set("top", AsValue(rect.fTop)); + val->Set("right", AsValue(rect.fRight)); + val->Set("bottom", AsValue(rect.fBottom)); - void onDrawOval(const SkRect& rect, const SkPaint& paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawOval(rect, paint); - } + return val.Pass(); +} - void onDrawRect(const SkRect& rect, const SkPaint& paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawRect(rect, paint); - } +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkRRect& rrect) { + scoped_ptr<base::DictionaryValue> radii_val(new base::DictionaryValue()); + radii_val->Set("upper-left", AsValue(rrect.radii(SkRRect::kUpperLeft_Corner))); + radii_val->Set("upper-right", AsValue(rrect.radii(SkRRect::kUpperRight_Corner))); + radii_val->Set("lower-right", AsValue(rrect.radii(SkRRect::kLowerRight_Corner))); + radii_val->Set("lower-left", AsValue(rrect.radii(SkRRect::kLowerLeft_Corner))); - void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawRRect(rrect, paint); - } + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + val->Set("rect", AsValue(rrect.rect())); + val->Set("radii", radii_val.Pass()); - void onDrawPath(const SkPath& path, const SkPaint& paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawPath(path, paint); - } + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkMatrix& matrix) { + scoped_ptr<base::ListValue> val(new base::ListValue()); + for (int i = 0; i < 9; ++i) + val->Append(AsValue(matrix[i]).release()); // no scoped_ptr-aware Append() variant + + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(SkColor color) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + val->SetInteger("a", SkColorGetA(color)); + val->SetInteger("r", SkColorGetR(color)); + val->SetInteger("g", SkColorGetG(color)); + val->SetInteger("b", SkColorGetB(color)); + + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(SkXfermode::Mode mode) { + scoped_ptr<base::StringValue> val( + new base::StringValue(SkXfermode::ModeName(mode))); + + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(SkCanvas::PointMode mode) { + static const char* gModeStrings[] = { "Points", "Lines", "Polygon" }; + DCHECK_LT(static_cast<size_t>(mode), SK_ARRAY_COUNT(gModeStrings)); - void onDrawBitmap(const SkBitmap& bitmap, - SkScalar left, - SkScalar top, - const SkPaint* paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawBitmap(bitmap, left, top, paint); + scoped_ptr<base::StringValue> val(new base::StringValue(gModeStrings[mode])); + + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkXfermode& xfermode) { + SkXfermode::Mode mode; + if (xfermode.asMode(&mode)) + return AsValue(mode); + + scoped_ptr<base::StringValue> val(new base::StringValue("unknown")); + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkColorFilter& filter) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + + if (unsigned flags = filter.getFlags()) { + FlagsBuilder builder('|'); + builder.addFlag(flags & SkColorFilter::kAlphaUnchanged_Flag, + "kAlphaUnchanged_Flag"); + builder.addFlag(flags & SkColorFilter::kHasFilter16_Flag, + "kHasFilter16_Flag"); + + val->SetString("flags", builder.str()); } - void onDrawBitmapRect(const SkBitmap& bitmap, - const SkRect* src, - const SkRect& dst, - const SkPaint* paint, - DrawBitmapRectFlags flags) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawBitmapRect(bitmap, src, dst, paint, flags); + SkScalar color_matrix[20]; + if (filter.asColorMatrix(color_matrix)) { + scoped_ptr<base::ListValue> color_matrix_val(new base::ListValue()); + for (unsigned i = 0; i < 20; ++i) + color_matrix_val->Append(AsValue(color_matrix[i]).release()); + + val->Set("color_matrix", color_matrix_val.Pass()); } - void onDrawSprite(const SkBitmap& bitmap, - int left, - int top, - const SkPaint* paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawSprite(bitmap, left, top, paint); + SkColor color; + SkXfermode::Mode mode; + if (filter.asColorMode(&color, &mode)) { + scoped_ptr<base::DictionaryValue> color_mode_val( + new base::DictionaryValue()); + color_mode_val->Set("color", AsValue(color)); + color_mode_val->Set("mode", AsValue(mode)); + + val->Set("color_mode", color_mode_val.Pass()); } - 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& paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawVertices(vmode, vertexCount, vertices, texs, colors, - xmode, indices, indexCount, paint); + if (filter.asComponentTable(nullptr)) { + scoped_ptr<base::DictionaryValue> component_table_val( + new base::DictionaryValue()); + // use this as a marker for now + val->Set("component_table", component_table_val.Pass()); } -protected: - void onDrawText(const void* text, - size_t byteLength, - SkScalar x, - SkScalar y, - const SkPaint& paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawText(text, byteLength, x, y, paint); + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkImageFilter& filter) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + val->SetInteger("inputs", filter.countInputs()); + + SkColorFilter* color_filter; + if (filter.asColorFilter(&color_filter)) { + val->Set("color_filter", AsValue(*color_filter)); + SkSafeUnref(color_filter); // ref'd in asColorFilter } - void onDrawPosText(const void* text, - size_t byteLength, - const SkPoint pos[], - const SkPaint& paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawPosText(text, byteLength, pos, paint); + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkPaint& paint) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + SkPaint default_paint; + + if (paint.getColor() != default_paint.getColor()) + val->Set("Color", AsValue(paint.getColor())); + + if (paint.getStyle() != default_paint.getStyle()) { + static const char* gStyleStrings[] = { "Fill", "Stroke", "StrokeFill" }; + DCHECK_LT(static_cast<size_t>(paint.getStyle()), + SK_ARRAY_COUNT(gStyleStrings)); + val->SetString("Style", gStyleStrings[paint.getStyle()]); } - void onDrawPosTextH(const void* text, - size_t byteLength, - const SkScalar xpos[], - SkScalar constY, - const SkPaint& paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawPosTextH(text, byteLength, xpos, constY, paint); + if (paint.getXfermode() != default_paint.getXfermode()) { + DCHECK(paint.getXfermode()); + val->Set("Xfermode", AsValue(*paint.getXfermode())); } - void onDrawTextOnPath(const void* text, - size_t byteLength, - const SkPath& path, - const SkMatrix* matrix, - const SkPaint& paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawTextOnPath(text, byteLength, path, matrix, paint); + if (paint.getFlags()) { + FlagsBuilder builder('|'); + builder.addFlag(paint.isAntiAlias(), "AntiAlias"); + builder.addFlag(paint.isDither(), "Dither"); + builder.addFlag(paint.isUnderlineText(), "UnderlineText"); + builder.addFlag(paint.isStrikeThruText(), "StrikeThruText"); + builder.addFlag(paint.isFakeBoldText(), "FakeBoldText"); + builder.addFlag(paint.isLinearText(), "LinearText"); + builder.addFlag(paint.isSubpixelText(), "SubpixelText"); + builder.addFlag(paint.isDevKernText(), "DevKernText"); + builder.addFlag(paint.isLCDRenderText(), "LCDRenderText"); + builder.addFlag(paint.isEmbeddedBitmapText(), "EmbeddedBitmapText"); + builder.addFlag(paint.isAutohinted(), "Autohinted"); + builder.addFlag(paint.isVerticalText(), "VerticalText"); + builder.addFlag(paint.getFlags() & SkPaint::kGenA8FromLCD_Flag, + "GenA8FromLCD"); + + val->SetString("Flags", builder.str()); } - void onClipRect(const SkRect& rect, - SkRegion::Op op, - ClipEdgeStyle edge_style) override { - AutoStamper stamper(this); - SkNWayCanvas::onClipRect(rect, op, edge_style); + if (paint.getFilterLevel() != default_paint.getFilterLevel()) { + static const char* gFilterLevelStrings[] = + { "None", "Low", "Medium", "High" }; + DCHECK_LT(static_cast<size_t>(paint.getFilterLevel()), + SK_ARRAY_COUNT(gFilterLevelStrings)); + val->SetString("FilterLevel", gFilterLevelStrings[paint.getFilterLevel()]); } - void onClipRRect(const SkRRect& rrect, - SkRegion::Op op, - ClipEdgeStyle edge_style) override { - AutoStamper stamper(this); - SkNWayCanvas::onClipRRect(rrect, op, edge_style); + if (paint.getTextSize() != default_paint.getTextSize()) + val->SetDouble("TextSize", paint.getTextSize()); + + if (paint.getTextScaleX() != default_paint.getTextScaleX()) + val->SetDouble("TextScaleX", paint.getTextScaleX()); + + if (paint.getTextSkewX() != default_paint.getTextSkewX()) + val->SetDouble("TextSkewX", paint.getTextSkewX()); + + if (paint.getColorFilter()) + val->Set("ColorFilter", AsValue(*paint.getColorFilter())); + + if (paint.getImageFilter()) + val->Set("ImageFilter", AsValue(*paint.getImageFilter())); + + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(SkCanvas::SaveFlags flags) { + FlagsBuilder builder('|'); + builder.addFlag(flags & SkCanvas::kHasAlphaLayer_SaveFlag, + "kHasAlphaLayer"); + builder.addFlag(flags & SkCanvas::kFullColorLayer_SaveFlag, + "kFullColorLayer"); + builder.addFlag(flags & SkCanvas::kClipToLayer_SaveFlag, + "kClipToLayer"); + + scoped_ptr<base::StringValue> val(new base::StringValue(builder.str())); + + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(SkRegion::Op op) { + static const char* gOpStrings[] = { "Difference", + "Intersect", + "Union", + "XOR", + "ReverseDifference", + "Replace" + }; + DCHECK_LT(static_cast<size_t>(op), SK_ARRAY_COUNT(gOpStrings)); + scoped_ptr<base::StringValue> val(new base::StringValue(gOpStrings[op])); + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkRegion& region) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + val->Set("bounds", AsValue(SkRect::Make(region.getBounds()))); + + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkPicture& picture) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + val->Set("cull-rect", AsValue(picture.cullRect())); + + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkBitmap& bitmap) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + val->Set("size", AsValue(SkSize::Make(bitmap.width(), bitmap.height()))); + + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkImage& image) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + val->Set("size", AsValue(SkSize::Make(image.width(), image.height()))); + + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkTextBlob& blob) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + val->Set("bounds", AsValue(blob.bounds())); + + return val.Pass(); +} + +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsValue(const SkPath& path) { + scoped_ptr<base::DictionaryValue> val(new base::DictionaryValue()); + + static const char* gFillStrings[] = + { "winding", "even-odd", "inverse-winding", "inverse-even-odd" }; + DCHECK_LT(static_cast<size_t>(path.getFillType()), + SK_ARRAY_COUNT(gFillStrings)); + val->SetString("fill-type", gFillStrings[path.getFillType()]); + + static const char* gConvexityStrings[] = { "Unknown", "Convex", "Concave" }; + DCHECK_LT(static_cast<size_t>(path.getConvexity()), + SK_ARRAY_COUNT(gConvexityStrings)); + val->SetString("convexity", gConvexityStrings[path.getConvexity()]); + + val->SetBoolean("is-rect", path.isRect(nullptr)); + val->Set("bounds", AsValue(path.getBounds())); + + static const char* gVerbStrings[] = + { "move", "line", "quad", "conic", "cubic", "close", "done" }; + static const int gPtsPerVerb[] = { 1, 1, 2, 2, 3, 0, 0 }; + static const int gPtOffsetPerVerb[] = { 0, 1, 1, 1, 1, 0, 0 }; + SK_COMPILE_ASSERT( + SK_ARRAY_COUNT(gVerbStrings) == static_cast<size_t>(SkPath::kDone_Verb + 1), + gVerbStrings_size_mismatch); + SK_COMPILE_ASSERT( + SK_ARRAY_COUNT(gVerbStrings) == SK_ARRAY_COUNT(gPtsPerVerb), + gPtsPerVerb_size_mismatch); + SK_COMPILE_ASSERT( + SK_ARRAY_COUNT(gVerbStrings) == SK_ARRAY_COUNT(gPtOffsetPerVerb), + gPtOffsetPerVerb_size_mismatch); + + scoped_ptr<base::ListValue> verbs_val(new base::ListValue()); + SkPath::Iter iter(const_cast<SkPath&>(path), false); + SkPoint points[4]; + + for(SkPath::Verb verb = iter.next(points, false); + verb != SkPath::kDone_Verb; verb = iter.next(points, false)) { + DCHECK_LT(static_cast<size_t>(verb), SK_ARRAY_COUNT(gVerbStrings)); + + scoped_ptr<base::DictionaryValue> verb_val(new base::DictionaryValue()); + scoped_ptr<base::ListValue> pts_val(new base::ListValue()); + + for (int i = 0; i < gPtsPerVerb[verb]; ++i) + pts_val->Append(AsValue(points[i + gPtOffsetPerVerb[verb]]).release()); + + verb_val->Set(gVerbStrings[verb], pts_val.Pass()); + + if (SkPath::kConic_Verb == verb) + verb_val->Set("weight", AsValue(iter.conicWeight())); + + verbs_val->Append(verb_val.release()); } + val->Set("verbs", verbs_val.Pass()); + + return val.Pass(); +} + +template<typename T> +WARN_UNUSED_RESULT +scoped_ptr<base::Value> AsListValue(const T array[], size_t count) { + scoped_ptr<base::ListValue> val(new base::ListValue()); + + for (size_t i = 0; i < count; ++i) + val->Append(AsValue(array[i]).release()); + + return val.Pass(); +} + +} // namespace + +namespace skia { + +class BenchmarkingCanvas::AutoOp { +public: + AutoOp(BenchmarkingCanvas* canvas, const char op_name[], + const SkPaint* paint = nullptr) + : canvas_(canvas) + , op_record_(new base::DictionaryValue()) + , op_params_(new base::ListValue()) { + + DCHECK(canvas); + DCHECK(op_name); - void onClipPath(const SkPath& path, - SkRegion::Op op, - ClipEdgeStyle edge_style) override { - AutoStamper stamper(this); - SkNWayCanvas::onClipPath(path, op, edge_style); + op_record_->SetString("cmd_string", op_name); + op_record_->Set("info", op_params_); + + if (paint) + this->addParam("paint", AsValue(*paint)); + + start_ticks_ = base::TimeTicks::Now(); } - void onClipRegion(const SkRegion& region, SkRegion::Op op) override { - AutoStamper stamper(this); - SkNWayCanvas::onClipRegion(region, op); + ~AutoOp() { + base::TimeDelta ticks = base::TimeTicks::Now() - start_ticks_; + op_record_->SetDouble("cmd_time", ticks.InMillisecondsF()); + + canvas_->op_records_.Append(op_record_); } - void onDrawPicture(const SkPicture* picture, - const SkMatrix* matrix, - const SkPaint* paint) override { - AutoStamper stamper(this); - SkNWayCanvas::onDrawPicture(picture, matrix, paint); + void addParam(const char name[], scoped_ptr<base::Value> value) { + scoped_ptr<base::DictionaryValue> param(new base::DictionaryValue()); + param->Set(name, value.Pass()); + + op_params_->Append(param.release()); } private: - typedef base::hash_map<size_t, base::TimeDelta> TimingsMap; - TimingsMap timings_map_; + BenchmarkingCanvas* canvas_; + base::DictionaryValue* op_record_; + base::ListValue* op_params_; + base::TimeTicks start_ticks_; +}; - skia::RefPtr<SkSurface> surface_; +BenchmarkingCanvas::BenchmarkingCanvas(SkCanvas* canvas, unsigned flags) + : INHERITED(canvas->imageInfo().width(), + canvas->imageInfo().height()) + , flags_(flags) { + addCanvas(canvas); +} - friend class AutoStamper; - const BenchmarkingCanvas* tracking_canvas_; -}; +BenchmarkingCanvas::~BenchmarkingCanvas() { +} -AutoStamper::AutoStamper(TimingCanvas *timing_canvas) - : timing_canvas_(timing_canvas) { - start_ticks_ = base::TimeTicks::Now(); +size_t BenchmarkingCanvas::CommandCount() const { + return op_records_.GetSize(); } -AutoStamper::~AutoStamper() { - base::TimeDelta delta = base::TimeTicks::Now() - start_ticks_; - int command_index = timing_canvas_->tracking_canvas_->CommandCount() - 1; - DCHECK_GE(command_index, 0); - timing_canvas_->timings_map_[command_index] = delta; +const base::ListValue& BenchmarkingCanvas::Commands() const { + return op_records_; } -BenchmarkingCanvas::BenchmarkingCanvas(int width, int height) - : SkNWayCanvas(width, height) { - debug_canvas_ = skia::AdoptRef(SkNEW_ARGS(SkDebugCanvas, (width, height))); - timing_canvas_ = skia::AdoptRef(SkNEW_ARGS(TimingCanvas, (width, height, this))); +double BenchmarkingCanvas::GetTime(size_t index) { + const base::DictionaryValue* op; + if (!op_records_.GetDictionary(index, &op)) + return 0; - addCanvas(debug_canvas_.get()); - addCanvas(timing_canvas_.get()); + double t; + if (!op->GetDouble("cmd_time", &t)) + return 0; + + return t; } -BenchmarkingCanvas::~BenchmarkingCanvas() { - removeAll(); +void BenchmarkingCanvas::willSave() { + AutoOp op(this, "Save"); + + INHERITED::willSave(); } -size_t BenchmarkingCanvas::CommandCount() const { - return debug_canvas_->getSize(); +SkCanvas::SaveLayerStrategy BenchmarkingCanvas::willSaveLayer(const SkRect* rect, + const SkPaint* paint, + SaveFlags flags) { + AutoOp op(this, "SaveLayer", paint); + if (rect) + op.addParam("bounds", AsValue(*rect)); + if (paint) + op.addParam("paint", AsValue(*paint)); + if (flags) + op.addParam("flags", AsValue(flags)); + + return INHERITED::willSaveLayer(rect, paint, flags); } -SkDrawCommand* BenchmarkingCanvas::GetCommand(size_t index) { - DCHECK_LT(index, static_cast<size_t>(debug_canvas_->getSize())); - return debug_canvas_->getDrawCommandAt(index); +void BenchmarkingCanvas::willRestore() { + AutoOp op(this, "Restore"); + + INHERITED::willRestore(); } -double BenchmarkingCanvas::GetTime(size_t index) { - DCHECK_LT(index, static_cast<size_t>(debug_canvas_->getSize())); - return timing_canvas_->GetTime(index); +void BenchmarkingCanvas::didConcat(const SkMatrix& m) { + AutoOp op(this, "Concat"); + op.addParam("matrix", AsValue(m)); + + INHERITED::didConcat(m); +} + +void BenchmarkingCanvas::didSetMatrix(const SkMatrix& m) { + AutoOp op(this, "SetMatrix"); + op.addParam("matrix", AsValue(m)); + + INHERITED::didSetMatrix(m); +} + +void BenchmarkingCanvas::onClipRect(const SkRect& rect, + SkRegion::Op region_op, + SkCanvas::ClipEdgeStyle style) { + AutoOp op(this, "ClipRect"); + op.addParam("rect", AsValue(rect)); + op.addParam("op", AsValue(region_op)); + op.addParam("anti-alias", AsValue(style == kSoft_ClipEdgeStyle)); + + INHERITED::onClipRect(rect, region_op, style); +} + +void BenchmarkingCanvas::onClipRRect(const SkRRect& rrect, + SkRegion::Op region_op, + SkCanvas::ClipEdgeStyle style) { + AutoOp op(this, "ClipRRect"); + op.addParam("rrect", AsValue(rrect)); + op.addParam("op", AsValue(region_op)); + op.addParam("anti-alias", AsValue(style == kSoft_ClipEdgeStyle)); + + INHERITED::onClipRRect(rrect, region_op, style); +} + +void BenchmarkingCanvas::onClipPath(const SkPath& path, + SkRegion::Op region_op, + SkCanvas::ClipEdgeStyle style) { + AutoOp op(this, "ClipPath"); + op.addParam("path", AsValue(path)); + op.addParam("op", AsValue(region_op)); + op.addParam("anti-alias", AsValue(style == kSoft_ClipEdgeStyle)); + + INHERITED::onClipPath(path, region_op, style); +} + +void BenchmarkingCanvas::onClipRegion(const SkRegion& region, + SkRegion::Op region_op) { + AutoOp op(this, "ClipRegion"); + op.addParam("region", AsValue(region)); + op.addParam("op", AsValue(region_op)); + + INHERITED::onClipRegion(region, region_op); +} + +void BenchmarkingCanvas::onDrawPaint(const SkPaint& paint) { + AutoOp op(this, "DrawPaint", &paint); + + INHERITED::onDrawPaint(paint); +} + +void BenchmarkingCanvas::onDrawPoints(PointMode mode, size_t count, + const SkPoint pts[], const SkPaint& paint) { + AutoOp op(this, "DrawPoints", &paint); + op.addParam("mode", AsValue(mode)); + op.addParam("points", AsListValue(pts, count)); + + INHERITED::onDrawPoints(mode, count, pts, paint); +} + +void BenchmarkingCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) { + AutoOp op(this, "DrawRect", &paint); + op.addParam("rect", AsValue(rect)); + + INHERITED::onDrawRect(rect, paint); +} + +void BenchmarkingCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) { + AutoOp op(this, "DrawOval", &paint); + op.addParam("rect", AsValue(rect)); + + INHERITED::onDrawOval(rect, paint); +} + +void BenchmarkingCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { + AutoOp op(this, "DrawRRect", &paint); + op.addParam("rrect", AsValue(rrect)); + + INHERITED::onDrawRRect(rrect, paint); +} + +void BenchmarkingCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, + const SkPaint& paint) { + AutoOp op(this, "DrawDRRect", &paint); + op.addParam("outer", AsValue(outer)); + op.addParam("inner", AsValue(inner)); + + INHERITED::onDrawDRRect(outer, inner, paint); +} + +void BenchmarkingCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { + AutoOp op(this, "DrawPath", &paint); + op.addParam("path", AsValue(path)); + + INHERITED::onDrawPath(path, paint); +} + +void BenchmarkingCanvas::onDrawPicture(const SkPicture* picture, + const SkMatrix* matrix, + const SkPaint* paint) { + DCHECK(picture); + AutoOp op(this, "DrawPicture", paint); + op.addParam("picture", AsValue(picture)); + if (matrix) + op.addParam("matrix", AsValue(*matrix)); + + INHERITED::drawPicture(picture, matrix, paint); +} + +void BenchmarkingCanvas::onDrawBitmap(const SkBitmap& bitmap, + SkScalar left, + SkScalar top, + const SkPaint* paint) { + AutoOp op(this, "DrawBitmap", paint); + op.addParam("bitmap", AsValue(bitmap)); + op.addParam("left", AsValue(left)); + op.addParam("top", AsValue(top)); + + INHERITED::onDrawBitmap(bitmap, left, top, paint); +} + +void BenchmarkingCanvas::onDrawBitmapRect(const SkBitmap& bitmap, + const SkRect* src, + const SkRect& dst, + const SkPaint* paint, + DrawBitmapRectFlags flags) { + AutoOp op(this, "DrawBitmapRect", paint); + op.addParam("bitmap", AsValue(bitmap)); + if (src) + op.addParam("src", AsValue(*src)); + op.addParam("dst", AsValue(dst)); + + INHERITED::onDrawBitmapRect(bitmap, src, dst, paint, flags); +} + +void BenchmarkingCanvas::onDrawImage(const SkImage* image, + SkScalar left, + SkScalar top, + const SkPaint* paint) { + DCHECK(image); + AutoOp op(this, "DrawImage", paint); + op.addParam("image", AsValue(*image)); + op.addParam("left", AsValue(left)); + op.addParam("top", AsValue(top)); + + INHERITED::onDrawImage(image, left, top, paint); +} + +void BenchmarkingCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, + const SkRect& dst, const SkPaint* paint) { + DCHECK(image); + AutoOp op(this, "DrawImageRect", paint); + op.addParam("image", AsValue(*image)); + if (src) + op.addParam("src", AsValue(*src)); + op.addParam("dst", AsValue(dst)); + + INHERITED::onDrawImageRect(image, src, dst, paint); +} + +void BenchmarkingCanvas::onDrawBitmapNine(const SkBitmap& bitmap, + const SkIRect& center, + const SkRect& dst, + const SkPaint* paint) { + AutoOp op(this, "DrawBitmapNine", paint); + op.addParam("bitmap", AsValue(bitmap)); + op.addParam("center", AsValue(SkRect::Make(center))); + op.addParam("dst", AsValue(dst)); + + INHERITED::onDrawBitmapNine(bitmap, center, dst, paint); +} + +void BenchmarkingCanvas::onDrawSprite(const SkBitmap& bitmap, int left, int top, + const SkPaint* paint) { + AutoOp op(this, "DrawSprite", paint); + op.addParam("bitmap", AsValue(bitmap)); + op.addParam("left", AsValue(SkIntToScalar(left))); + op.addParam("top", AsValue(SkIntToScalar(top))); + + INHERITED::onDrawSprite(bitmap, left, top, paint); +} + +void BenchmarkingCanvas::onDrawText(const void* text, size_t byteLength, + SkScalar x, SkScalar y, + const SkPaint& paint) { + AutoOp op(this, "DrawText", &paint); + op.addParam("count", AsValue(SkIntToScalar(paint.countText(text, byteLength)))); + op.addParam("x", AsValue(x)); + op.addParam("y", AsValue(y)); + + INHERITED::onDrawText(text, byteLength, x, y, paint); +} + +void BenchmarkingCanvas::onDrawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) { + AutoOp op(this, "DrawPosText", &paint); + + int count = paint.countText(text, byteLength); + op.addParam("count", AsValue(SkIntToScalar(count))); + op.addParam("pos", AsListValue(pos, count)); + + INHERITED::onDrawPosText(text, byteLength, pos, paint); +} + +void BenchmarkingCanvas::onDrawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, + const SkPaint& paint) { + AutoOp op(this, "DrawPosTextH", &paint); + op.addParam("constY", AsValue(constY)); + + int count = paint.countText(text, byteLength); + op.addParam("count", AsValue(SkIntToScalar(count))); + op.addParam("pos", AsListValue(xpos, count)); + + INHERITED::onDrawPosTextH(text, byteLength, xpos, constY, paint); +} + +void BenchmarkingCanvas::onDrawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) { + AutoOp op(this, "DrawTextOnPath", &paint); + op.addParam("count", AsValue(SkIntToScalar(paint.countText(text, byteLength)))); + op.addParam("path", AsValue(path)); + if (matrix) + op.addParam("matrix", AsValue(*matrix)); + + INHERITED::onDrawTextOnPath(text, byteLength, path, matrix, paint); +} + +void BenchmarkingCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) { + DCHECK(blob); + AutoOp op(this, "DrawTextBlob", &paint); + op.addParam("blob", AsValue(*blob)); + op.addParam("x", AsValue(x)); + op.addParam("y", AsValue(y)); + + INHERITED::onDrawTextBlob(blob, x, y, paint); } } // namespace skia diff --git a/skia/ext/benchmarking_canvas.h b/skia/ext/benchmarking_canvas.h index 50289a5..4f2e257 100644 --- a/skia/ext/benchmarking_canvas.h +++ b/skia/ext/benchmarking_canvas.h @@ -5,45 +5,86 @@ #ifndef SKIA_EXT_BENCHMARKING_CANVAS_H_ #define SKIA_EXT_BENCHMARKING_CANVAS_H_ -#include "base/compiler_specific.h" -#include "skia/ext/refptr.h" +#include "base/values.h" #include "third_party/skia/include/utils/SkNWayCanvas.h" -#include "third_party/skia/src/utils/debugger/SkDebugCanvas.h" namespace skia { -class TimingCanvas; - class SK_API BenchmarkingCanvas : public SkNWayCanvas { public: - BenchmarkingCanvas(int width, int height); + BenchmarkingCanvas(SkCanvas* canvas, unsigned flags = 0); ~BenchmarkingCanvas() override; + enum Flags { + // TODO(fmalita): add overdraw visualization support + // (http://crbug.com/461534) + kOverdrawVisualization_Flag = 0x01, + }; + // Returns the number of draw commands executed on this canvas. size_t CommandCount() const; - // Get draw command info for a given index. - SkDrawCommand* GetCommand(size_t index); + // Returns the list of executed draw commands. + const base::ListValue& Commands() const; // Return the recorded render time (milliseconds) for a draw command index. double GetTime(size_t index); +protected: + // SkCanvas overrides + void willSave() override; + SaveLayerStrategy willSaveLayer(const SkRect*, + const SkPaint*, + SaveFlags) override; + void willRestore() override; + + void didConcat(const SkMatrix&) override; + void didSetMatrix(const SkMatrix&) 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 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 onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + void onDrawPath(const SkPath&, const SkPaint&) override; + + void onDrawPicture(const SkPicture*, const SkMatrix*, 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*, DrawBitmapRectFlags flags) override; + void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override; + void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, + const SkPaint*) override; + void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, + const SkPaint*) override; + void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override; + + void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, + const SkPaint&) override; + void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], + const SkPaint&) override; + void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], + SkScalar constY, const SkPaint&) override; + void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, + const SkMatrix* matrix, const SkPaint&) override; + void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) override; + private: - // In order to avoid introducing a Skia version dependency, this - // implementation dispatches draw commands in lock-step to two distinct - // canvases: - // * a SkDebugCanvas used for gathering command info and tracking - // the current command index - // * a SkiaTimingCanvas used for measuring raster paint times (and relying - // on the former for tracking the current command index). - // - // This way, if the SkCanvas API is extended, we don't need to worry about - // updating content::SkiaTimingCanvas to accurately override all new methods - // (to avoid timing info indices from getting out of sync), as SkDebugCanvas - // already does that for us. - - skia::RefPtr<SkDebugCanvas> debug_canvas_; - skia::RefPtr<TimingCanvas> timing_canvas_; + typedef SkNWayCanvas INHERITED; + + class AutoOp; + + base::ListValue op_records_; + unsigned flags_; }; } |