Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: content/renderer/skia_benchmarking_extension.cc

Issue 19266015: [SkiaBenchmarkingExtension] Add draw command timing info. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased. Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 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.
4
5 #include "content/renderer/skia_benchmarking_extension.h"
6
7 #include "base/values.h"
8 #include "cc/base/math_util.h"
9 #include "cc/resources/picture.h"
10 #include "content/public/renderer/v8_value_converter.h"
11 #include "third_party/WebKit/public/platform/WebArrayBuffer.h"
12 #include "third_party/WebKit/public/web/WebFrame.h"
13 #include "third_party/skia/include/core/SkCanvas.h"
14 #include "third_party/skia/include/core/SkColorPriv.h"
15 #include "third_party/skia/include/core/SkGraphics.h"
16 #include "third_party/skia/src/utils/debugger/SkDebugCanvas.h"
17 #include "third_party/skia/src/utils/debugger/SkDrawCommand.h"
18 #include "ui/gfx/rect_conversions.h"
19 #include "ui/gfx/skia_util.h"
20 #include "v8/include/v8.h"
21
22 using WebKit::WebFrame;
23
24 namespace {
25
26 const char kSkiaBenchmarkingExtensionName[] = "v8/SkiaBenchmarking";
27
28 static scoped_refptr<cc::Picture> ParsePictureArg(v8::Handle<v8::Value> arg) {
29 scoped_ptr<content::V8ValueConverter> converter(
30 content::V8ValueConverter::create());
31
32 v8::String::Value v8_picture(arg);
33 scoped_ptr<base::Value> picture_value(
34 converter->FromV8Value(arg, v8::Context::GetCurrent()));
35 if (!picture_value)
36 return NULL;
37
38 return cc::Picture::CreateFromValue(picture_value.get());
39 }
40
41 class SkiaBenchmarkingWrapper : public v8::Extension {
42 public:
43 SkiaBenchmarkingWrapper() :
44 v8::Extension(kSkiaBenchmarkingExtensionName,
45 "if (typeof(chrome) == 'undefined') {"
46 " chrome = {};"
47 "};"
48 "if (typeof(chrome.skiaBenchmarking) == 'undefined') {"
49 " chrome.skiaBenchmarking = {};"
50 "};"
51 "chrome.skiaBenchmarking.rasterize = function(picture, params) {"
52 " /* "
53 " Rasterizes a Picture JSON-encoded by cc::Picture::AsValue()."
54 " @param {Object} picture A json-encoded cc::Picture."
55 " @param {"
56 " 'scale': {Number},"
57 " 'stop': {Number},"
58 " 'clip': [Number, Number, Number, Number]"
59 " } (optional) Rasterization parameters."
60 " @returns {"
61 " 'width': {Number},"
62 " 'height': {Number},"
63 " 'data': {ArrayBuffer}"
64 " }"
65 " @returns undefined if the arguments are invalid or the picture"
66 " version is not supported."
67 " */"
68 " native function Rasterize();"
69 " return Rasterize(picture, params);"
70 "};"
71 "chrome.skiaBenchmarking.getOps = function(picture) {"
72 " /* "
73 " Extracts the Skia draw commands from a JSON-encoded cc::Picture"
74 " @param {Object} picture A json-encoded cc::Picture."
75 " @returns [{ 'cmd': {String}, 'info': [String, ...] }, ...]"
76 " @returns undefined if the arguments are invalid or the picture"
77 " version is not supported."
78 " */"
79 " native function GetOps();"
80 " return GetOps(picture);"
81 "};"
82 ) {
83 content::SkiaBenchmarkingExtension::InitSkGraphics();
84 }
85
86 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
87 v8::Handle<v8::String> name) OVERRIDE {
88 if (name->Equals(v8::String::New("Rasterize")))
89 return v8::FunctionTemplate::New(Rasterize);
90 if (name->Equals(v8::String::New("GetOps")))
91 return v8::FunctionTemplate::New(GetOps);
92
93 return v8::Handle<v8::FunctionTemplate>();
94 }
95
96 static void Rasterize(const v8::FunctionCallbackInfo<v8::Value>& args) {
97 if (args.Length() < 1)
98 return;
99
100 scoped_refptr<cc::Picture> picture = ParsePictureArg(args[0]);
101 if (!picture.get())
102 return;
103
104 double scale = 1.0;
105 gfx::Rect clip_rect(picture->LayerRect());
106 int stop_index = -1;
107
108 if (args.Length() > 1) {
109 scoped_ptr<content::V8ValueConverter> converter(
110 content::V8ValueConverter::create());
111 scoped_ptr<base::Value> params_value(
112 converter->FromV8Value(args[1], v8::Context::GetCurrent()));
113
114 const base::DictionaryValue* params_dict = NULL;
115 if (params_value.get() && params_value->GetAsDictionary(&params_dict)) {
116 params_dict->GetDouble("scale", &scale);
117 params_dict->GetInteger("stop", &stop_index);
118
119 const base::Value* clip_value = NULL;
120 if (params_dict->Get("clip", &clip_value))
121 cc::MathUtil::FromValue(clip_value, &clip_rect);
122 }
123 }
124
125 gfx::RectF clip(clip_rect);
126 clip.Intersect(picture->LayerRect());
127 clip.Scale(scale);
128 gfx::Rect snapped_clip = gfx::ToEnclosingRect(clip);
129
130 const int kMaxBitmapSize = 4096;
131 if (snapped_clip.width() > kMaxBitmapSize
132 || snapped_clip.height() > kMaxBitmapSize)
133 return;
134
135 SkBitmap bitmap;
136 bitmap.setConfig(SkBitmap::kARGB_8888_Config, snapped_clip.width(),
137 snapped_clip.height());
138 if (!bitmap.allocPixels())
139 return;
140 bitmap.eraseARGB(0, 0, 0, 0);
141
142 SkCanvas canvas(bitmap);
143 canvas.translate(SkFloatToScalar(-clip.x()),
144 SkFloatToScalar(-clip.y()));
145 canvas.clipRect(gfx::RectToSkRect(snapped_clip));
146 canvas.scale(scale, scale);
147 canvas.translate(picture->LayerRect().x(),
148 picture->LayerRect().y());
149
150 // First, build a debug canvas for the given picture.
151 SkDebugCanvas debug_canvas(picture->LayerRect().width(),
152 picture->LayerRect().height());
153 picture->Replay(&debug_canvas);
154
155 // Raster the requested command subset into the bitmap-backed canvas.
156 int last_index = debug_canvas.getSize() - 1;
157 debug_canvas.drawTo(&canvas, stop_index < 0
158 ? last_index
159 : std::min(last_index, stop_index));
160
161 WebKit::WebArrayBuffer buffer =
162 WebKit::WebArrayBuffer::create(bitmap.getSize(), 1);
163 uint32* packed_pixels = reinterpret_cast<uint32*>(bitmap.getPixels());
164 uint8* buffer_pixels = reinterpret_cast<uint8*>(buffer.data());
165 // Swizzle from native Skia format to RGBA as we copy out.
166 for (size_t i = 0; i < bitmap.getSize(); i += 4) {
167 uint32 c = packed_pixels[i >> 2];
168 buffer_pixels[i] = SkGetPackedR32(c);
169 buffer_pixels[i + 1] = SkGetPackedG32(c);
170 buffer_pixels[i + 2] = SkGetPackedB32(c);
171 buffer_pixels[i + 3] = SkGetPackedA32(c);
172 }
173
174 v8::Handle<v8::Object> result = v8::Object::New();
175 result->Set(v8::String::New("width"),
176 v8::Number::New(snapped_clip.width()));
177 result->Set(v8::String::New("height"),
178 v8::Number::New(snapped_clip.height()));
179 result->Set(v8::String::New("data"), buffer.toV8Value());
180
181 args.GetReturnValue().Set(result);
182 }
183
184 static void GetOps(const v8::FunctionCallbackInfo<v8::Value>& args) {
185 if (args.Length() != 1)
186 return;
187
188 scoped_refptr<cc::Picture> picture = ParsePictureArg(args[0]);
189 if (!picture.get())
190 return;
191
192 gfx::Rect bounds = picture->LayerRect();
193 SkDebugCanvas canvas(bounds.width(), bounds.height());
194 picture->Replay(&canvas);
195
196 v8::Local<v8::Array> result = v8::Array::New(canvas.getSize());
197 for (int i = 0; i < canvas.getSize(); ++i) {
198 DrawType cmd_type = canvas.getDrawCommandAt(i)->getType();
199 v8::Handle<v8::Object> cmd = v8::Object::New();
200 cmd->Set(v8::String::New("cmd_type"), v8::Integer::New(cmd_type));
201 cmd->Set(v8::String::New("cmd_string"), v8::String::New(
202 SkDrawCommand::GetCommandString(cmd_type)));
203
204 SkTDArray<SkString*>* info = canvas.getCommandInfo(i);
205 DCHECK(info);
206
207 v8::Local<v8::Array> v8_info = v8::Array::New(info->count());
208 for (int j = 0; j < info->count(); ++j) {
209 const SkString* info_str = (*info)[j];
210 DCHECK(info_str);
211 v8_info->Set(j, v8::String::New(info_str->c_str()));
212 }
213
214 cmd->Set(v8::String::New("info"), v8_info);
215
216 result->Set(i, cmd);
217 }
218
219 args.GetReturnValue().Set(result);
220 }
221 };
222
223 } // namespace
224
225 namespace content {
226
227 v8::Extension* SkiaBenchmarkingExtension::Get() {
228 return new SkiaBenchmarkingWrapper();
229 }
230
231 void SkiaBenchmarkingExtension::InitSkGraphics() {
232 // Always call on the main render thread.
233 // Does not need to be thread-safe, as long as the above holds.
234 // FIXME: remove this after Skia updates SkGraphics::Init() to be
235 // thread-safe and idempotent.
236 static bool skia_initialized = false;
237 if (!skia_initialized) {
238 SkGraphics::Init();
239 skia_initialized = true;
240 }
241 }
242
243 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698