diff options
-rw-r--r-- | content/renderer/skia_benchmarking_extension.cc | 53 | ||||
-rw-r--r-- | skia/ext/benchmarking_canvas.cc | 237 | ||||
-rw-r--r-- | skia/ext/benchmarking_canvas.h | 50 | ||||
-rw-r--r-- | skia/skia_chrome.gypi | 2 | ||||
-rw-r--r-- | skia/skia_library.gypi | 2 |
5 files changed, 344 insertions, 0 deletions
diff --git a/content/renderer/skia_benchmarking_extension.cc b/content/renderer/skia_benchmarking_extension.cc index 078b51d..14dfe3b 100644 --- a/content/renderer/skia_benchmarking_extension.cc +++ b/content/renderer/skia_benchmarking_extension.cc @@ -4,14 +4,17 @@ #include "content/renderer/skia_benchmarking_extension.h" +#include "base/time/time.h" #include "base/values.h" #include "cc/base/math_util.h" #include "cc/resources/picture.h" #include "content/public/renderer/v8_value_converter.h" +#include "skia/ext/benchmarking_canvas.h" #include "third_party/WebKit/public/platform/WebArrayBuffer.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkColorPriv.h" +#include "third_party/skia/include/core/SkDevice.h" #include "third_party/skia/include/core/SkGraphics.h" #include "third_party/skia/src/utils/debugger/SkDebugCanvas.h" #include "third_party/skia/src/utils/debugger/SkDrawCommand.h" @@ -79,6 +82,17 @@ class SkiaBenchmarkingWrapper : public v8::Extension { " native function GetOps();" " return GetOps(picture);" "};" + "chrome.skiaBenchmarking.getOpTimings = function(picture) {" + " /* " + " Returns timing information for the given picture." + " @param {Object} picture A json-encoded cc::Picture." + " @returns { 'total_time': {Number}, 'cmd_times': [Number, ...] }" + " @returns undefined if the arguments are invalid or the picture" + " version is not supported." + " */" + " native function GetOpTimings();" + " return GetOpTimings(picture);" + "};" ) { content::SkiaBenchmarkingExtension::InitSkGraphics(); } @@ -89,6 +103,8 @@ class SkiaBenchmarkingWrapper : public v8::Extension { return v8::FunctionTemplate::New(Rasterize); if (name->Equals(v8::String::New("GetOps"))) return v8::FunctionTemplate::New(GetOps); + if (name->Equals(v8::String::New("GetOpTimings"))) + return v8::FunctionTemplate::New(GetOpTimings); return v8::Handle<v8::FunctionTemplate>(); } @@ -218,6 +234,43 @@ class SkiaBenchmarkingWrapper : public v8::Extension { args.GetReturnValue().Set(result); } + + static void GetOpTimings(const v8::FunctionCallbackInfo<v8::Value>& args) { + if (args.Length() != 1) + return; + + scoped_refptr<cc::Picture> picture = ParsePictureArg(args[0]); + if (!picture.get()) + return; + + gfx::Rect bounds = picture->LayerRect(); + + // Measure the total time by drawing straight into a bitmap-backed canvas. + skia::RefPtr<SkDevice> device = skia::AdoptRef(SkNEW_ARGS(SkDevice, + (SkBitmap::kARGB_8888_Config, bounds.width(), bounds.height()))); + SkCanvas bitmap_canvas(device.get()); + bitmap_canvas.clear(SK_ColorTRANSPARENT); + base::TimeTicks t0 = base::TimeTicks::HighResNow(); + picture->Replay(&bitmap_canvas); + base::TimeDelta total_time = base::TimeTicks::HighResNow() - t0; + + // Gather per-op timing info by drawing into a BenchmarkingCanvas. + skia::BenchmarkingCanvas benchmarking_canvas(bounds.width(), + bounds.height()); + picture->Replay(&benchmarking_canvas); + + v8::Local<v8::Array> op_times = + v8::Array::New(benchmarking_canvas.CommandCount()); + for (size_t i = 0; i < benchmarking_canvas.CommandCount(); ++i) + op_times->Set(i, v8::Number::New(benchmarking_canvas.GetTime(i))); + + v8::Handle<v8::Object> result = v8::Object::New(); + result->Set(v8::String::New("total_time"), + v8::Number::New(total_time.InMillisecondsF())); + result->Set(v8::String::New("cmd_times"), op_times); + + args.GetReturnValue().Set(result); + } }; } // namespace diff --git a/skia/ext/benchmarking_canvas.cc b/skia/ext/benchmarking_canvas.cc new file mode 100644 index 0000000..6039515 --- /dev/null +++ b/skia/ext/benchmarking_canvas.cc @@ -0,0 +1,237 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// 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/time/time.h" +#include "skia/ext/benchmarking_canvas.h" +#include "third_party/skia/include/core/SkDevice.h" +#include "third_party/skia/include/utils/SkProxyCanvas.h" + +namespace skia { + +class AutoStamper { +public: + AutoStamper(TimingCanvas* timing_canvas); + ~AutoStamper(); + +private: + TimingCanvas* timing_canvas_; + base::TimeTicks start_ticks_; +}; + +class TimingCanvas : public SkProxyCanvas { +public: + TimingCanvas(int width, int height, const BenchmarkingCanvas* track_canvas) + : tracking_canvas_(track_canvas) { + skia::RefPtr<SkDevice> device = skia::AdoptRef( + SkNEW_ARGS(SkDevice, (SkBitmap::kARGB_8888_Config, width, height))); + canvas_ = skia::AdoptRef(SkNEW_ARGS(SkCanvas, (device.get()))); + + setProxy(canvas_.get()); + } + + virtual ~TimingCanvas() { + } + + 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; + } + + // SkCanvas overrides. + virtual int save(SaveFlags flags = kMatrixClip_SaveFlag) OVERRIDE { + AutoStamper stamper(this); + return SkProxyCanvas::save(flags); + } + + virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, + SaveFlags flags = kARGB_ClipLayer_SaveFlag) OVERRIDE { + AutoStamper stamper(this); + return SkProxyCanvas::saveLayer(bounds, paint, flags); + } + + virtual void restore() OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::restore(); + } + + virtual bool clipRect(const SkRect& rect, SkRegion::Op op, + bool doAa) OVERRIDE { + AutoStamper stamper(this); + return SkProxyCanvas::clipRect(rect, op, doAa); + } + + virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op, + bool doAa) OVERRIDE { + AutoStamper stamper(this); + return SkProxyCanvas::clipRRect(rrect, op, doAa); + } + + virtual bool clipPath(const SkPath& path, SkRegion::Op op, + bool doAa) OVERRIDE { + AutoStamper stamper(this); + return SkProxyCanvas::clipPath(path, op, doAa); + } + + virtual bool clipRegion(const SkRegion& region, + SkRegion::Op op = SkRegion::kIntersect_Op) OVERRIDE { + AutoStamper stamper(this); + return SkProxyCanvas::clipRegion(region, op); + } + + virtual void drawPaint(const SkPaint& paint) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawPaint(paint); + } + + virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawPoints(mode, count, pts, paint); + } + + virtual void drawOval(const SkRect& rect, const SkPaint& paint) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawOval(rect, paint); + } + + virtual void drawRect(const SkRect& rect, const SkPaint& paint) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawRect(rect, paint); + } + + virtual void drawRRect(const SkRRect& rrect, const SkPaint& paint) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawRRect(rrect, paint); + } + + virtual void drawPath(const SkPath& path, const SkPaint& paint) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawPath(path, paint); + } + + virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, + const SkPaint* paint = NULL) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawBitmap(bitmap, left, top, paint); + } + + virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, + const SkRect& dst, + const SkPaint* paint = NULL) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawBitmapRectToRect(bitmap, src, dst, paint); + } + + virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, + const SkPaint* paint = NULL) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawBitmapMatrix(bitmap, m, paint); + } + + virtual void drawSprite(const SkBitmap& bitmap, int left, int top, + const SkPaint* paint = NULL) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawSprite(bitmap, left, top, paint); + } + + virtual void drawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint& paint) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawText(text, byteLength, x, y, paint); + } + + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], + const SkPaint& paint) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawPosText(text, byteLength, pos, paint); + } + + virtual void drawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, + const SkPaint& paint) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawPosTextH(text, byteLength, xpos, constY, paint); + } + + virtual void drawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawTextOnPath(text, byteLength, path, matrix, paint); + } + + virtual void drawPicture(SkPicture& picture) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawPicture(picture); + } + + virtual void drawVertices(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); + SkProxyCanvas::drawVertices(vmode, vertexCount, vertices, texs, colors, + xmode, indices, indexCount, paint); + } + + virtual void drawData(const void* data, size_t length) OVERRIDE { + AutoStamper stamper(this); + SkProxyCanvas::drawData(data, length); + } + +private: + typedef base::hash_map<size_t, base::TimeDelta> TimingsMap; + TimingsMap timings_map_; + + skia::RefPtr<SkCanvas> canvas_; + + friend class AutoStamper; + const BenchmarkingCanvas* tracking_canvas_; +}; + +AutoStamper::AutoStamper(TimingCanvas *timing_canvas) + : timing_canvas_(timing_canvas) { + start_ticks_ = base::TimeTicks::HighResNow(); +} + +AutoStamper::~AutoStamper() { + base::TimeDelta delta = base::TimeTicks::HighResNow() - start_ticks_; + int command_index = timing_canvas_->tracking_canvas_->CommandCount(); + timing_canvas_->timings_map_[command_index] = delta; +} + +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))); + + addCanvas(debug_canvas_.get()); + addCanvas(timing_canvas_.get()); +} + +BenchmarkingCanvas::~BenchmarkingCanvas() { + removeAll(); +} + +size_t BenchmarkingCanvas::CommandCount() const { + return debug_canvas_->getSize(); +} + +SkDrawCommand* BenchmarkingCanvas::GetCommand(size_t index) { + DCHECK_LT(index, static_cast<size_t>(debug_canvas_->getSize())); + return debug_canvas_->getDrawCommandAt(index); +} + +double BenchmarkingCanvas::GetTime(size_t index) { + DCHECK_LT(index, static_cast<size_t>(debug_canvas_->getSize())); + return timing_canvas_->GetTime(index); +} + +} // namespace skia diff --git a/skia/ext/benchmarking_canvas.h b/skia/ext/benchmarking_canvas.h new file mode 100644 index 0000000..7ef8204 --- /dev/null +++ b/skia/ext/benchmarking_canvas.h @@ -0,0 +1,50 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SKIA_EXT_BENCHMARKING_CANVAS_H_ +#define SKIA_EXT_BENCHMARKING_CANVAS_H_ + +#include "base/compiler_specific.h" +#include "skia/ext/refptr.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); + virtual ~BenchmarkingCanvas(); + + // 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); + + // Return the recorded render time (milliseconds) for a draw command index. + double GetTime(size_t index); + +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_; +}; + +} +#endif // SKIA_EXT_BENCHMARKING_CANVAS_H diff --git a/skia/skia_chrome.gypi b/skia/skia_chrome.gypi index d47fc10..ecd9b47 100644 --- a/skia/skia_chrome.gypi +++ b/skia/skia_chrome.gypi @@ -27,6 +27,8 @@ 'sources': [ 'ext/analysis_canvas.cc', 'ext/analysis_canvas.h', + 'ext/benchmarking_canvas.cc', + 'ext/benchmarking_canvas.h', 'ext/bitmap_platform_device.h', 'ext/bitmap_platform_device_android.cc', 'ext/bitmap_platform_device_android.h', diff --git a/skia/skia_library.gypi b/skia/skia_library.gypi index 986efe4..299feb19 100644 --- a/skia/skia_library.gypi +++ b/skia/skia_library.gypi @@ -150,6 +150,7 @@ '../third_party/skia/include/utils/SkNWayCanvas.h', '../third_party/skia/src/utils/SkNWayCanvas.cpp', '../third_party/skia/src/utils/SkPictureUtils.cpp', + '../third_party/skia/src/utils/SkProxyCanvas.cpp', '../third_party/skia/src/utils/SkRTConf.cpp', '../third_party/skia/include/utils/SkRTConf.h', '../third_party/skia/include/pdf/SkPDFDevice.h', @@ -164,6 +165,7 @@ '../third_party/skia/include/utils/SkNullCanvas.h', '../third_party/skia/include/utils/SkPictureUtils.h', + '../third_party/skia/include/utils/SkProxyCanvas.h', ], 'include_dirs': [ '..', |