Update function names in BrowserContextKeyedServiceFactory::GetServiceForBrowserConte...
[chromium-blink-merge.git] / content / renderer / gpu / gpu_benchmarking_extension.cc
blob9066d55a895430e8208e9b87930aaac6b538c983
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/gpu/gpu_benchmarking_extension.h"
7 #include <string>
9 #include "base/base64.h"
10 #include "base/file_util.h"
11 #include "base/files/file_path.h"
12 #include "base/memory/scoped_vector.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "content/common/browser_rendering_stats.h"
15 #include "content/common/gpu/gpu_rendering_stats.h"
16 #include "content/public/renderer/render_thread.h"
17 #include "content/renderer/all_rendering_benchmarks.h"
18 #include "content/renderer/gpu/render_widget_compositor.h"
19 #include "content/renderer/render_view_impl.h"
20 #include "content/renderer/rendering_benchmark.h"
21 #include "content/renderer/skia_benchmarking_extension.h"
22 #include "third_party/WebKit/public/web/WebFrame.h"
23 #include "third_party/WebKit/public/web/WebImageCache.h"
24 #include "third_party/WebKit/public/web/WebView.h"
25 #include "third_party/WebKit/public/web/WebViewBenchmarkSupport.h"
26 #include "third_party/skia/include/core/SkData.h"
27 #include "third_party/skia/include/core/SkGraphics.h"
28 #include "third_party/skia/include/core/SkPicture.h"
29 #include "third_party/skia/include/core/SkPixelRef.h"
30 #include "third_party/skia/include/core/SkStream.h"
31 #include "ui/gfx/codec/png_codec.h"
32 #include "v8/include/v8.h"
33 #include "webkit/renderer/compositor_bindings/web_rendering_stats_impl.h"
35 using WebKit::WebCanvas;
36 using WebKit::WebFrame;
37 using WebKit::WebImageCache;
38 using WebKit::WebPrivatePtr;
39 using WebKit::WebRenderingStatsImpl;
40 using WebKit::WebSize;
41 using WebKit::WebView;
42 using WebKit::WebViewBenchmarkSupport;
44 const char kGpuBenchmarkingExtensionName[] = "v8/GpuBenchmarking";
46 static SkData* EncodeBitmapToData(size_t* offset, const SkBitmap& bm) {
47 SkPixelRef* pr = bm.pixelRef();
48 if (pr != NULL) {
49 SkData* data = pr->refEncodedData();
50 if (data != NULL) {
51 *offset = bm.pixelRefOffset();
52 return data;
55 std::vector<unsigned char> vector;
56 if (gfx::PNGCodec::EncodeBGRASkBitmap(bm, true, &vector)) {
57 return SkData::NewWithCopy(&vector.front() , vector.size());
59 return NULL;
62 namespace {
64 class SkPictureRecorder : public WebViewBenchmarkSupport::PaintClient {
65 public:
66 explicit SkPictureRecorder(const base::FilePath& dirpath)
67 : dirpath_(dirpath),
68 layer_id_(0) {
69 // Let skia register known effect subclasses. This basically enables
70 // reflection on those subclasses required for picture serialization.
71 content::SkiaBenchmarkingExtension::InitSkGraphics();
74 virtual WebCanvas* willPaint(const WebSize& size) {
75 return picture_.beginRecording(size.width, size.height);
78 virtual void didPaint(WebCanvas* canvas) {
79 DCHECK(canvas == picture_.getRecordingCanvas());
80 picture_.endRecording();
81 // Serialize picture to file.
82 // TODO(alokp): Note that for this to work Chrome needs to be launched with
83 // --no-sandbox command-line flag. Get rid of this limitation.
84 // CRBUG: 139640.
85 std::string filename = "layer_" + base::IntToString(layer_id_++) + ".skp";
86 std::string filepath = dirpath_.AppendASCII(filename).MaybeAsASCII();
87 DCHECK(!filepath.empty());
88 SkFILEWStream file(filepath.c_str());
89 DCHECK(file.isValid());
90 picture_.serialize(&file, &EncodeBitmapToData);
93 private:
94 base::FilePath dirpath_;
95 int layer_id_;
96 SkPicture picture_;
99 class RenderingStatsEnumerator : public cc::RenderingStats::Enumerator {
100 public:
101 RenderingStatsEnumerator(v8::Handle<v8::Object> stats_object)
102 : stats_object(stats_object) { }
104 virtual void AddInt64(const char* name, int64 value) OVERRIDE {
105 stats_object->Set(v8::String::New(name), v8::Number::New(value));
108 virtual void AddDouble(const char* name, double value) OVERRIDE {
109 stats_object->Set(v8::String::New(name), v8::Number::New(value));
112 virtual void AddInt(const char* name, int value) OVERRIDE {
113 stats_object->Set(v8::String::New(name), v8::Integer::New(value));
116 virtual void AddTimeDeltaInSecondsF(const char* name,
117 const base::TimeDelta& value) OVERRIDE {
118 stats_object->Set(v8::String::New(name),
119 v8::Number::New(value.InSecondsF()));
122 private:
123 v8::Handle<v8::Object> stats_object;
126 } // namespace
128 namespace content {
130 namespace {
132 class CallbackAndContext : public base::RefCounted<CallbackAndContext> {
133 public:
134 CallbackAndContext(v8::Isolate* isolate,
135 v8::Handle<v8::Function> callback,
136 v8::Handle<v8::Context> context)
137 : isolate_(isolate) {
138 callback_.Reset(isolate_, callback);
139 context_.Reset(isolate_, context);
142 v8::Isolate* isolate() {
143 return isolate_;
146 v8::Handle<v8::Function> GetCallback() {
147 return v8::Local<v8::Function>::New(isolate_, callback_);
150 v8::Handle<v8::Context> GetContext() {
151 return v8::Local<v8::Context>::New(isolate_, context_);
154 private:
155 friend class base::RefCounted<CallbackAndContext>;
157 virtual ~CallbackAndContext() {
158 callback_.Dispose();
159 context_.Dispose();
162 v8::Isolate* isolate_;
163 v8::Persistent<v8::Function> callback_;
164 v8::Persistent<v8::Context> context_;
165 DISALLOW_COPY_AND_ASSIGN(CallbackAndContext);
168 } // namespace
170 class GpuBenchmarkingWrapper : public v8::Extension {
171 public:
172 GpuBenchmarkingWrapper() :
173 v8::Extension(kGpuBenchmarkingExtensionName,
174 "if (typeof(chrome) == 'undefined') {"
175 " chrome = {};"
176 "};"
177 "if (typeof(chrome.gpuBenchmarking) == 'undefined') {"
178 " chrome.gpuBenchmarking = {};"
179 "};"
180 "chrome.gpuBenchmarking.setNeedsDisplayOnAllLayers = function() {"
181 " native function SetNeedsDisplayOnAllLayers();"
182 " return SetNeedsDisplayOnAllLayers();"
183 "};"
184 "chrome.gpuBenchmarking.setRasterizeOnlyVisibleContent = function() {"
185 " native function SetRasterizeOnlyVisibleContent();"
186 " return SetRasterizeOnlyVisibleContent();"
187 "};"
188 "chrome.gpuBenchmarking.renderingStats = function() {"
189 " native function GetRenderingStats();"
190 " return GetRenderingStats();"
191 "};"
192 "chrome.gpuBenchmarking.printToSkPicture = function(dirname) {"
193 " native function PrintToSkPicture();"
194 " return PrintToSkPicture(dirname);"
195 "};"
196 "chrome.gpuBenchmarking.smoothScrollBy = "
197 " function(pixels_to_scroll, opt_callback, opt_mouse_event_x,"
198 " opt_mouse_event_y) {"
199 " pixels_to_scroll = pixels_to_scroll || 0;"
200 " callback = opt_callback || function() { };"
201 " native function BeginSmoothScroll();"
202 " if (typeof opt_mouse_event_x !== 'undefined' &&"
203 " typeof opt_mouse_event_y !== 'undefined') {"
204 " return BeginSmoothScroll(pixels_to_scroll >= 0, callback,"
205 " Math.abs(pixels_to_scroll),"
206 " opt_mouse_event_x, opt_mouse_event_y);"
207 " } else {"
208 " return BeginSmoothScroll(pixels_to_scroll >= 0, callback,"
209 " Math.abs(pixels_to_scroll));"
210 " }"
211 "};"
212 "chrome.gpuBenchmarking.runRenderingBenchmarks = function(filter) {"
213 " native function RunRenderingBenchmarks();"
214 " return RunRenderingBenchmarks(filter);"
215 "};"
216 "chrome.gpuBenchmarking.beginWindowSnapshotPNG = function(callback) {"
217 " native function BeginWindowSnapshotPNG();"
218 " BeginWindowSnapshotPNG(callback);"
219 "};"
220 "chrome.gpuBenchmarking.clearImageCache = function() {"
221 " native function ClearImageCache();"
222 " ClearImageCache();"
223 "};") {}
225 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
226 v8::Handle<v8::String> name) OVERRIDE {
227 if (name->Equals(v8::String::New("SetNeedsDisplayOnAllLayers")))
228 return v8::FunctionTemplate::New(SetNeedsDisplayOnAllLayers);
229 if (name->Equals(v8::String::New("SetRasterizeOnlyVisibleContent")))
230 return v8::FunctionTemplate::New(SetRasterizeOnlyVisibleContent);
231 if (name->Equals(v8::String::New("GetRenderingStats")))
232 return v8::FunctionTemplate::New(GetRenderingStats);
233 if (name->Equals(v8::String::New("PrintToSkPicture")))
234 return v8::FunctionTemplate::New(PrintToSkPicture);
235 if (name->Equals(v8::String::New("BeginSmoothScroll")))
236 return v8::FunctionTemplate::New(BeginSmoothScroll);
237 if (name->Equals(v8::String::New("RunRenderingBenchmarks")))
238 return v8::FunctionTemplate::New(RunRenderingBenchmarks);
239 if (name->Equals(v8::String::New("BeginWindowSnapshotPNG")))
240 return v8::FunctionTemplate::New(BeginWindowSnapshotPNG);
241 if (name->Equals(v8::String::New("ClearImageCache")))
242 return v8::FunctionTemplate::New(ClearImageCache);
244 return v8::Handle<v8::FunctionTemplate>();
247 static void SetNeedsDisplayOnAllLayers(
248 const v8::FunctionCallbackInfo<v8::Value>& args) {
249 WebFrame* web_frame = WebFrame::frameForCurrentContext();
250 if (!web_frame)
251 return;
253 WebView* web_view = web_frame->view();
254 if (!web_view)
255 return;
257 RenderViewImpl* render_view_impl = RenderViewImpl::FromWebView(web_view);
258 if (!render_view_impl)
259 return;
261 RenderWidgetCompositor* compositor = render_view_impl->compositor();
262 if (!compositor)
263 return;
265 compositor->SetNeedsDisplayOnAllLayers();
268 static void SetRasterizeOnlyVisibleContent(
269 const v8::FunctionCallbackInfo<v8::Value>& args) {
270 WebFrame* web_frame = WebFrame::frameForCurrentContext();
271 if (!web_frame)
272 return;
274 WebView* web_view = web_frame->view();
275 if (!web_view)
276 return;
278 RenderViewImpl* render_view_impl = RenderViewImpl::FromWebView(web_view);
279 if (!render_view_impl)
280 return;
282 RenderWidgetCompositor* compositor = render_view_impl->compositor();
283 if (!compositor)
284 return;
286 compositor->SetRasterizeOnlyVisibleContent();
289 static void GetRenderingStats(
290 const v8::FunctionCallbackInfo<v8::Value>& args) {
292 WebFrame* web_frame = WebFrame::frameForCurrentContext();
293 if (!web_frame)
294 return;
296 WebView* web_view = web_frame->view();
297 if (!web_view)
298 return;
300 RenderViewImpl* render_view_impl = RenderViewImpl::FromWebView(web_view);
301 if (!render_view_impl)
302 return;
304 WebRenderingStatsImpl stats;
305 render_view_impl->GetRenderingStats(stats);
307 content::GpuRenderingStats gpu_stats;
308 render_view_impl->GetGpuRenderingStats(&gpu_stats);
309 BrowserRenderingStats browser_stats;
310 render_view_impl->GetBrowserRenderingStats(&browser_stats);
311 v8::Handle<v8::Object> stats_object = v8::Object::New();
313 RenderingStatsEnumerator enumerator(stats_object);
314 stats.rendering_stats.EnumerateFields(&enumerator);
315 gpu_stats.EnumerateFields(&enumerator);
316 browser_stats.EnumerateFields(&enumerator);
318 args.GetReturnValue().Set(stats_object);
321 static void PrintToSkPicture(
322 const v8::FunctionCallbackInfo<v8::Value>& args) {
323 if (args.Length() != 1)
324 return;
326 v8::String::AsciiValue dirname(args[0]);
327 if (dirname.length() == 0)
328 return;
330 WebFrame* web_frame = WebFrame::frameForCurrentContext();
331 if (!web_frame)
332 return;
334 WebView* web_view = web_frame->view();
335 if (!web_view)
336 return;
338 WebViewBenchmarkSupport* benchmark_support = web_view->benchmarkSupport();
339 if (!benchmark_support)
340 return;
342 base::FilePath dirpath(
343 base::FilePath::StringType(*dirname, *dirname + dirname.length()));
344 if (!file_util::CreateDirectory(dirpath) ||
345 !file_util::PathIsWritable(dirpath)) {
346 std::string msg("Path is not writable: ");
347 msg.append(dirpath.MaybeAsASCII());
348 v8::ThrowException(v8::Exception::Error(
349 v8::String::New(msg.c_str(), msg.length())));
350 return;
353 SkPictureRecorder recorder(dirpath);
354 benchmark_support->paint(&recorder,
355 WebViewBenchmarkSupport::PaintModeEverything);
358 static void OnSmoothScrollCompleted(
359 CallbackAndContext* callback_and_context) {
360 v8::HandleScope scope(callback_and_context->isolate());
361 v8::Handle<v8::Context> context = callback_and_context->GetContext();
362 v8::Context::Scope context_scope(context);
363 WebFrame* frame = WebFrame::frameForContext(context);
364 if (frame) {
365 frame->callFunctionEvenIfScriptDisabled(
366 callback_and_context->GetCallback(), v8::Object::New(), 0, NULL);
370 static void BeginSmoothScroll(
371 const v8::FunctionCallbackInfo<v8::Value>& args) {
372 WebFrame* web_frame = WebFrame::frameForCurrentContext();
373 if (!web_frame)
374 return;
376 WebView* web_view = web_frame->view();
377 if (!web_view)
378 return;
380 RenderViewImpl* render_view_impl = RenderViewImpl::FromWebView(web_view);
381 if (!render_view_impl)
382 return;
384 // Account for the 2 optional arguments, mouse_event_x and mouse_event_y.
385 int arglen = args.Length();
386 if (arglen < 3 ||
387 !args[0]->IsBoolean() ||
388 !args[1]->IsFunction() ||
389 !args[2]->IsNumber()) {
390 args.GetReturnValue().Set(false);
391 return;
394 bool scroll_down = args[0]->BooleanValue();
395 v8::Local<v8::Function> callback_local =
396 v8::Local<v8::Function>::Cast(args[1]);
398 scoped_refptr<CallbackAndContext> callback_and_context =
399 new CallbackAndContext(args.GetIsolate(),
400 callback_local,
401 web_frame->mainWorldScriptContext());
403 int pixels_to_scroll = args[2]->IntegerValue();
405 int mouse_event_x = 0;
406 int mouse_event_y = 0;
408 if (arglen == 3) {
409 WebKit::WebRect rect = render_view_impl->windowRect();
410 mouse_event_x = rect.x + rect.width / 2;
411 mouse_event_y = rect.y + rect.height / 2;
412 } else {
413 if (arglen != 5 ||
414 !args[3]->IsNumber() ||
415 !args[4]->IsNumber()) {
416 args.GetReturnValue().Set(false);
417 return;
420 mouse_event_x = args[3]->IntegerValue() * web_view->pageScaleFactor();
421 mouse_event_y = args[4]->IntegerValue() * web_view->pageScaleFactor();
424 // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
425 // progress, we will leak the callback and context. This needs to be fixed,
426 // somehow.
427 render_view_impl->BeginSmoothScroll(
428 scroll_down,
429 base::Bind(&OnSmoothScrollCompleted,
430 callback_and_context),
431 pixels_to_scroll,
432 mouse_event_x,
433 mouse_event_y);
435 args.GetReturnValue().Set(true);
438 static void RunRenderingBenchmarks(
439 const v8::FunctionCallbackInfo<v8::Value>& args) {
440 // For our name filter, the argument can be undefined or null to run
441 // all benchmarks, or a string for filtering by name.
442 if (!args.Length() ||
443 (!args[0]->IsString() &&
444 !(args[0]->IsNull() || args[0]->IsUndefined()))) {
445 return;
448 std::string name_filter;
449 if (args[0]->IsNull() || args[0]->IsUndefined()) {
450 name_filter = "";
451 } else {
452 char filter[256];
453 args[0]->ToString()->WriteUtf8(filter, sizeof(filter)-1);
454 name_filter = std::string(filter);
457 WebFrame* web_frame = WebFrame::frameForCurrentContext();
458 if (!web_frame)
459 return;
461 WebView* web_view = web_frame->view();
462 if (!web_view)
463 return;
465 WebViewBenchmarkSupport* support = web_view->benchmarkSupport();
466 if (!support)
467 return;
469 ScopedVector<RenderingBenchmark> benchmarks = AllRenderingBenchmarks();
471 v8::Handle<v8::Array> results = v8::Array::New(0);
472 ScopedVector<RenderingBenchmark>::const_iterator it;
473 for (it = benchmarks.begin(); it != benchmarks.end(); it++) {
474 RenderingBenchmark* benchmark = *it;
475 const std::string& name = benchmark->name();
476 if (name_filter != "" &&
477 std::string::npos == name.find(name_filter)) {
478 continue;
480 benchmark->SetUp(support);
481 double result = benchmark->Run(support);
482 benchmark->TearDown(support);
484 v8::Handle<v8::Object> result_object = v8::Object::New();
485 result_object->Set(v8::String::New("benchmark", 9),
486 v8::String::New(name.c_str(), -1));
487 result_object->Set(v8::String::New("result", 6), v8::Number::New(result));
488 results->Set(results->Length(), result_object);
491 args.GetReturnValue().Set(results);
494 static void OnSnapshotCompleted(CallbackAndContext* callback_and_context,
495 const gfx::Size& size,
496 const std::vector<unsigned char>& png) {
497 v8::HandleScope scope(callback_and_context->isolate());
498 v8::Handle<v8::Context> context = callback_and_context->GetContext();
499 v8::Context::Scope context_scope(context);
500 WebFrame* frame = WebFrame::frameForContext(context);
501 if (frame) {
503 v8::Handle<v8::Value> result;
505 if(!size.IsEmpty()) {
506 v8::Handle<v8::Object> result_object;
507 result_object = v8::Object::New();
509 result_object->Set(v8::String::New("width"),
510 v8::Number::New(size.width()));
511 result_object->Set(v8::String::New("height"),
512 v8::Number::New(size.height()));
514 std::string base64_png;
515 base::Base64Encode(base::StringPiece(
516 reinterpret_cast<const char*>(&*png.begin()), png.size()),
517 &base64_png);
519 result_object->Set(v8::String::New("data"),
520 v8::String::New(base64_png.c_str(), base64_png.size()));
522 result = result_object;
523 } else {
524 result = v8::Null();
527 v8::Handle<v8::Value> argv[] = { result };
529 frame->callFunctionEvenIfScriptDisabled(
530 callback_and_context->GetCallback(), v8::Object::New(), 1, argv);
534 static void BeginWindowSnapshotPNG(
535 const v8::FunctionCallbackInfo<v8::Value>& args) {
536 WebFrame* web_frame = WebFrame::frameForCurrentContext();
537 if (!web_frame)
538 return;
540 WebView* web_view = web_frame->view();
541 if (!web_view)
542 return;
544 RenderViewImpl* render_view_impl = RenderViewImpl::FromWebView(web_view);
545 if (!render_view_impl)
546 return;
548 if (!args[0]->IsFunction())
549 return;
551 v8::Local<v8::Function> callback_local =
552 v8::Local<v8::Function>::Cast(args[0]);
554 scoped_refptr<CallbackAndContext> callback_and_context =
555 new CallbackAndContext(args.GetIsolate(),
556 callback_local,
557 web_frame->mainWorldScriptContext());
559 render_view_impl->GetWindowSnapshot(
560 base::Bind(&OnSnapshotCompleted, callback_and_context));
563 static void ClearImageCache(
564 const v8::FunctionCallbackInfo<v8::Value>& args) {
565 WebImageCache::clear();
569 v8::Extension* GpuBenchmarkingExtension::Get() {
570 return new GpuBenchmarkingWrapper();
573 } // namespace content