OLD | NEW |
| (Empty) |
1 // Copyright 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. | |
4 | |
5 #include "cc/layers/heads_up_display_layer_impl.h" | |
6 | |
7 #include <algorithm> | |
8 #include <vector> | |
9 | |
10 #include "base/strings/stringprintf.h" | |
11 #include "base/trace_event/trace_event.h" | |
12 #include "base/trace_event/trace_event_argument.h" | |
13 #include "cc/debug/debug_colors.h" | |
14 #include "cc/debug/frame_rate_counter.h" | |
15 #include "cc/debug/paint_time_counter.h" | |
16 #include "cc/output/begin_frame_args.h" | |
17 #include "cc/output/renderer.h" | |
18 #include "cc/quads/texture_draw_quad.h" | |
19 #include "cc/resources/memory_history.h" | |
20 #include "cc/trees/layer_tree_host_impl.h" | |
21 #include "cc/trees/layer_tree_impl.h" | |
22 #include "skia/ext/platform_canvas.h" | |
23 #include "third_party/skia/include/core/SkPaint.h" | |
24 #include "third_party/skia/include/core/SkTypeface.h" | |
25 #include "third_party/skia/include/effects/SkColorMatrixFilter.h" | |
26 #include "ui/gfx/geometry/point.h" | |
27 #include "ui/gfx/geometry/size.h" | |
28 #include "ui/gfx/geometry/size_conversions.h" | |
29 #include "ui/gfx/hud_font.h" | |
30 | |
31 namespace cc { | |
32 | |
33 static inline SkPaint CreatePaint() { | |
34 SkPaint paint; | |
35 #if (SK_R32_SHIFT || SK_B32_SHIFT != 16) | |
36 // The SkCanvas is in RGBA but the shader is expecting BGRA, so we need to | |
37 // swizzle our colors when drawing to the SkCanvas. | |
38 SkColorMatrix swizzle_matrix; | |
39 for (int i = 0; i < 20; ++i) | |
40 swizzle_matrix.fMat[i] = 0; | |
41 swizzle_matrix.fMat[0 + 5 * 2] = 1; | |
42 swizzle_matrix.fMat[1 + 5 * 1] = 1; | |
43 swizzle_matrix.fMat[2 + 5 * 0] = 1; | |
44 swizzle_matrix.fMat[3 + 5 * 3] = 1; | |
45 | |
46 skia::RefPtr<SkColorMatrixFilter> filter = | |
47 skia::AdoptRef(SkColorMatrixFilter::Create(swizzle_matrix)); | |
48 paint.setColorFilter(filter.get()); | |
49 #endif | |
50 return paint; | |
51 } | |
52 | |
53 HeadsUpDisplayLayerImpl::Graph::Graph(double indicator_value, | |
54 double start_upper_bound) | |
55 : value(0.0), | |
56 min(0.0), | |
57 max(0.0), | |
58 current_upper_bound(start_upper_bound), | |
59 default_upper_bound(start_upper_bound), | |
60 indicator(indicator_value) {} | |
61 | |
62 double HeadsUpDisplayLayerImpl::Graph::UpdateUpperBound() { | |
63 double target_upper_bound = std::max(max, default_upper_bound); | |
64 current_upper_bound += (target_upper_bound - current_upper_bound) * 0.5; | |
65 return current_upper_bound; | |
66 } | |
67 | |
68 HeadsUpDisplayLayerImpl::HeadsUpDisplayLayerImpl(LayerTreeImpl* tree_impl, | |
69 int id) | |
70 : LayerImpl(tree_impl, id), | |
71 typeface_(gfx::GetHudTypeface()), | |
72 internal_contents_scale_(1.f), | |
73 fps_graph_(60.0, 80.0), | |
74 paint_time_graph_(16.0, 48.0), | |
75 fade_step_(0) { | |
76 if (!typeface_) { | |
77 typeface_ = skia::AdoptRef( | |
78 SkTypeface::CreateFromName("monospace", SkTypeface::kBold)); | |
79 } | |
80 } | |
81 | |
82 HeadsUpDisplayLayerImpl::~HeadsUpDisplayLayerImpl() {} | |
83 | |
84 scoped_ptr<LayerImpl> HeadsUpDisplayLayerImpl::CreateLayerImpl( | |
85 LayerTreeImpl* tree_impl) { | |
86 return HeadsUpDisplayLayerImpl::Create(tree_impl, id()); | |
87 } | |
88 | |
89 void HeadsUpDisplayLayerImpl::AcquireResource( | |
90 ResourceProvider* resource_provider) { | |
91 for (ScopedPtrVector<ScopedResource>::iterator it = resources_.begin(); | |
92 it != resources_.end(); | |
93 ++it) { | |
94 if (!resource_provider->InUseByConsumer((*it)->id())) { | |
95 resources_.swap(it, resources_.end() - 1); | |
96 return; | |
97 } | |
98 } | |
99 | |
100 scoped_ptr<ScopedResource> resource = | |
101 ScopedResource::Create(resource_provider); | |
102 resource->Allocate(internal_content_bounds_, | |
103 ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888); | |
104 resources_.push_back(resource.Pass()); | |
105 } | |
106 | |
107 class ResourceSizeIsEqualTo { | |
108 public: | |
109 explicit ResourceSizeIsEqualTo(const gfx::Size& size_) | |
110 : compare_size_(size_) {} | |
111 | |
112 bool operator()(const ScopedResource* resource) { | |
113 return resource->size() == compare_size_; | |
114 } | |
115 | |
116 private: | |
117 const gfx::Size compare_size_; | |
118 }; | |
119 | |
120 void HeadsUpDisplayLayerImpl::ReleaseUnmatchedSizeResources( | |
121 ResourceProvider* resource_provider) { | |
122 ScopedPtrVector<ScopedResource>::iterator it_erase = | |
123 resources_.partition(ResourceSizeIsEqualTo(internal_content_bounds_)); | |
124 resources_.erase(it_erase, resources_.end()); | |
125 } | |
126 | |
127 bool HeadsUpDisplayLayerImpl::WillDraw(DrawMode draw_mode, | |
128 ResourceProvider* resource_provider) { | |
129 if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE) | |
130 return false; | |
131 | |
132 internal_contents_scale_ = draw_properties().ideal_contents_scale; | |
133 internal_content_bounds_ = | |
134 gfx::ToCeiledSize(gfx::ScaleSize(bounds(), internal_contents_scale_)); | |
135 | |
136 ReleaseUnmatchedSizeResources(resource_provider); | |
137 AcquireResource(resource_provider); | |
138 return LayerImpl::WillDraw(draw_mode, resource_provider); | |
139 } | |
140 | |
141 void HeadsUpDisplayLayerImpl::AppendQuads( | |
142 RenderPass* render_pass, | |
143 AppendQuadsData* append_quads_data) { | |
144 if (!resources_.back()->id()) | |
145 return; | |
146 | |
147 SharedQuadState* shared_quad_state = | |
148 render_pass->CreateAndAppendSharedQuadState(); | |
149 PopulateScaledSharedQuadState(shared_quad_state, internal_contents_scale_); | |
150 | |
151 gfx::Rect quad_rect(internal_content_bounds_); | |
152 gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect()); | |
153 gfx::Rect visible_quad_rect(quad_rect); | |
154 bool premultiplied_alpha = true; | |
155 gfx::PointF uv_top_left(0.f, 0.f); | |
156 gfx::PointF uv_bottom_right(1.f, 1.f); | |
157 const float vertex_opacity[] = { 1.f, 1.f, 1.f, 1.f }; | |
158 bool flipped = false; | |
159 bool nearest_neighbor = false; | |
160 TextureDrawQuad* quad = | |
161 render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); | |
162 quad->SetNew(shared_quad_state, | |
163 quad_rect, | |
164 opaque_rect, | |
165 visible_quad_rect, | |
166 resources_.back()->id(), | |
167 premultiplied_alpha, | |
168 uv_top_left, | |
169 uv_bottom_right, | |
170 SK_ColorTRANSPARENT, | |
171 vertex_opacity, | |
172 flipped, | |
173 nearest_neighbor); | |
174 } | |
175 | |
176 void HeadsUpDisplayLayerImpl::UpdateHudTexture( | |
177 DrawMode draw_mode, | |
178 ResourceProvider* resource_provider) { | |
179 if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE || !resources_.back()->id()) | |
180 return; | |
181 | |
182 SkISize canvas_size; | |
183 if (hud_surface_) | |
184 canvas_size = hud_surface_->getCanvas()->getDeviceSize(); | |
185 else | |
186 canvas_size.set(0, 0); | |
187 | |
188 if (canvas_size.width() != internal_content_bounds_.width() || | |
189 canvas_size.height() != internal_content_bounds_.height() || | |
190 !hud_surface_) { | |
191 TRACE_EVENT0("cc", "ResizeHudCanvas"); | |
192 | |
193 hud_surface_ = skia::AdoptRef(SkSurface::NewRasterN32Premul( | |
194 internal_content_bounds_.width(), internal_content_bounds_.height())); | |
195 } | |
196 | |
197 UpdateHudContents(); | |
198 | |
199 { | |
200 TRACE_EVENT0("cc", "DrawHudContents"); | |
201 hud_surface_->getCanvas()->clear(SkColorSetARGB(0, 0, 0, 0)); | |
202 hud_surface_->getCanvas()->save(); | |
203 hud_surface_->getCanvas()->scale(internal_contents_scale_, | |
204 internal_contents_scale_); | |
205 | |
206 DrawHudContents(hud_surface_->getCanvas()); | |
207 | |
208 hud_surface_->getCanvas()->restore(); | |
209 } | |
210 | |
211 TRACE_EVENT0("cc", "UploadHudTexture"); | |
212 SkImageInfo info; | |
213 size_t row_bytes = 0; | |
214 const void* pixels = hud_surface_->getCanvas()->peekPixels(&info, &row_bytes); | |
215 DCHECK(pixels); | |
216 DCHECK(info.colorType() == kN32_SkColorType); | |
217 resource_provider->CopyToResource(resources_.back()->id(), | |
218 static_cast<const uint8_t*>(pixels), | |
219 internal_content_bounds_); | |
220 } | |
221 | |
222 void HeadsUpDisplayLayerImpl::ReleaseResources() { | |
223 resources_.clear(); | |
224 } | |
225 | |
226 gfx::Rect HeadsUpDisplayLayerImpl::GetEnclosingRectInTargetSpace() const { | |
227 return GetScaledEnclosingRectInTargetSpace(internal_contents_scale_); | |
228 } | |
229 | |
230 void HeadsUpDisplayLayerImpl::UpdateHudContents() { | |
231 const LayerTreeDebugState& debug_state = layer_tree_impl()->debug_state(); | |
232 | |
233 // Don't update numbers every frame so text is readable. | |
234 base::TimeTicks now = layer_tree_impl()->CurrentBeginFrameArgs().frame_time; | |
235 if (base::TimeDelta(now - time_of_last_graph_update_).InSecondsF() > 0.25f) { | |
236 time_of_last_graph_update_ = now; | |
237 | |
238 if (debug_state.show_fps_counter) { | |
239 FrameRateCounter* fps_counter = layer_tree_impl()->frame_rate_counter(); | |
240 fps_graph_.value = fps_counter->GetAverageFPS(); | |
241 fps_counter->GetMinAndMaxFPS(&fps_graph_.min, &fps_graph_.max); | |
242 } | |
243 | |
244 if (debug_state.continuous_painting) { | |
245 PaintTimeCounter* paint_time_counter = | |
246 layer_tree_impl()->paint_time_counter(); | |
247 base::TimeDelta latest, min, max; | |
248 | |
249 if (paint_time_counter->End()) | |
250 latest = **paint_time_counter->End(); | |
251 paint_time_counter->GetMinAndMaxPaintTime(&min, &max); | |
252 | |
253 paint_time_graph_.value = latest.InMillisecondsF(); | |
254 paint_time_graph_.min = min.InMillisecondsF(); | |
255 paint_time_graph_.max = max.InMillisecondsF(); | |
256 } | |
257 | |
258 if (debug_state.ShowMemoryStats()) { | |
259 MemoryHistory* memory_history = layer_tree_impl()->memory_history(); | |
260 if (memory_history->End()) | |
261 memory_entry_ = **memory_history->End(); | |
262 else | |
263 memory_entry_ = MemoryHistory::Entry(); | |
264 } | |
265 } | |
266 | |
267 fps_graph_.UpdateUpperBound(); | |
268 paint_time_graph_.UpdateUpperBound(); | |
269 } | |
270 | |
271 void HeadsUpDisplayLayerImpl::DrawHudContents(SkCanvas* canvas) { | |
272 const LayerTreeDebugState& debug_state = layer_tree_impl()->debug_state(); | |
273 | |
274 if (debug_state.ShowHudRects()) { | |
275 DrawDebugRects(canvas, layer_tree_impl()->debug_rect_history()); | |
276 if (IsAnimatingHUDContents()) { | |
277 layer_tree_impl()->SetNeedsRedraw(); | |
278 } | |
279 } | |
280 | |
281 SkRect area = SkRect::MakeEmpty(); | |
282 if (debug_state.continuous_painting) { | |
283 area = DrawPaintTimeDisplay( | |
284 canvas, layer_tree_impl()->paint_time_counter(), 0, 0); | |
285 } else if (debug_state.show_fps_counter) { | |
286 // Don't show the FPS display when continuous painting is enabled, because | |
287 // it would show misleading numbers. | |
288 area = | |
289 DrawFPSDisplay(canvas, layer_tree_impl()->frame_rate_counter(), 0, 0); | |
290 } | |
291 | |
292 if (debug_state.show_fps_counter || debug_state.continuous_painting) { | |
293 area = DrawGpuRasterizationStatus(canvas, 0, area.bottom(), | |
294 SkMaxScalar(area.width(), 150)); | |
295 } | |
296 | |
297 if (debug_state.ShowMemoryStats()) | |
298 DrawMemoryDisplay(canvas, 0, area.bottom(), SkMaxScalar(area.width(), 150)); | |
299 } | |
300 | |
301 void HeadsUpDisplayLayerImpl::DrawText(SkCanvas* canvas, | |
302 SkPaint* paint, | |
303 const std::string& text, | |
304 SkPaint::Align align, | |
305 int size, | |
306 int x, | |
307 int y) const { | |
308 const bool anti_alias = paint->isAntiAlias(); | |
309 paint->setAntiAlias(true); | |
310 | |
311 paint->setTextSize(size); | |
312 paint->setTextAlign(align); | |
313 paint->setTypeface(typeface_.get()); | |
314 canvas->drawText(text.c_str(), text.length(), x, y, *paint); | |
315 | |
316 paint->setAntiAlias(anti_alias); | |
317 } | |
318 | |
319 void HeadsUpDisplayLayerImpl::DrawText(SkCanvas* canvas, | |
320 SkPaint* paint, | |
321 const std::string& text, | |
322 SkPaint::Align align, | |
323 int size, | |
324 const SkPoint& pos) const { | |
325 DrawText(canvas, paint, text, align, size, pos.x(), pos.y()); | |
326 } | |
327 | |
328 void HeadsUpDisplayLayerImpl::DrawGraphBackground(SkCanvas* canvas, | |
329 SkPaint* paint, | |
330 const SkRect& bounds) const { | |
331 paint->setColor(DebugColors::HUDBackgroundColor()); | |
332 canvas->drawRect(bounds, *paint); | |
333 } | |
334 | |
335 void HeadsUpDisplayLayerImpl::DrawGraphLines(SkCanvas* canvas, | |
336 SkPaint* paint, | |
337 const SkRect& bounds, | |
338 const Graph& graph) const { | |
339 // Draw top and bottom line. | |
340 paint->setColor(DebugColors::HUDSeparatorLineColor()); | |
341 canvas->drawLine(bounds.left(), | |
342 bounds.top() - 1, | |
343 bounds.right(), | |
344 bounds.top() - 1, | |
345 *paint); | |
346 canvas->drawLine( | |
347 bounds.left(), bounds.bottom(), bounds.right(), bounds.bottom(), *paint); | |
348 | |
349 // Draw indicator line (additive blend mode to increase contrast when drawn on | |
350 // top of graph). | |
351 paint->setColor(DebugColors::HUDIndicatorLineColor()); | |
352 paint->setXfermodeMode(SkXfermode::kPlus_Mode); | |
353 const double indicator_top = | |
354 bounds.height() * (1.0 - graph.indicator / graph.current_upper_bound) - | |
355 1.0; | |
356 canvas->drawLine(bounds.left(), | |
357 bounds.top() + indicator_top, | |
358 bounds.right(), | |
359 bounds.top() + indicator_top, | |
360 *paint); | |
361 paint->setXfermode(nullptr); | |
362 } | |
363 | |
364 SkRect HeadsUpDisplayLayerImpl::DrawFPSDisplay( | |
365 SkCanvas* canvas, | |
366 const FrameRateCounter* fps_counter, | |
367 int right, | |
368 int top) const { | |
369 const int kPadding = 4; | |
370 const int kGap = 6; | |
371 | |
372 const int kFontHeight = 15; | |
373 | |
374 const int kGraphWidth = fps_counter->time_stamp_history_size() - 2; | |
375 const int kGraphHeight = 40; | |
376 | |
377 const int kHistogramWidth = 37; | |
378 | |
379 int width = kGraphWidth + kHistogramWidth + 4 * kPadding; | |
380 int height = kFontHeight + kGraphHeight + 4 * kPadding + 2; | |
381 int left = bounds().width() - width - right; | |
382 SkRect area = SkRect::MakeXYWH(left, top, width, height); | |
383 | |
384 SkPaint paint = CreatePaint(); | |
385 DrawGraphBackground(canvas, &paint, area); | |
386 | |
387 SkRect text_bounds = | |
388 SkRect::MakeXYWH(left + kPadding, | |
389 top + kPadding, | |
390 kGraphWidth + kHistogramWidth + kGap + 2, | |
391 kFontHeight); | |
392 SkRect graph_bounds = SkRect::MakeXYWH(left + kPadding, | |
393 text_bounds.bottom() + 2 * kPadding, | |
394 kGraphWidth, | |
395 kGraphHeight); | |
396 SkRect histogram_bounds = SkRect::MakeXYWH(graph_bounds.right() + kGap, | |
397 graph_bounds.top(), | |
398 kHistogramWidth, | |
399 kGraphHeight); | |
400 | |
401 const std::string value_text = | |
402 base::StringPrintf("FPS:%5.1f", fps_graph_.value); | |
403 const std::string min_max_text = | |
404 base::StringPrintf("%.0f-%.0f", fps_graph_.min, fps_graph_.max); | |
405 | |
406 VLOG(1) << value_text; | |
407 | |
408 paint.setColor(DebugColors::FPSDisplayTextAndGraphColor()); | |
409 DrawText(canvas, | |
410 &paint, | |
411 value_text, | |
412 SkPaint::kLeft_Align, | |
413 kFontHeight, | |
414 text_bounds.left(), | |
415 text_bounds.bottom()); | |
416 DrawText(canvas, | |
417 &paint, | |
418 min_max_text, | |
419 SkPaint::kRight_Align, | |
420 kFontHeight, | |
421 text_bounds.right(), | |
422 text_bounds.bottom()); | |
423 | |
424 DrawGraphLines(canvas, &paint, graph_bounds, fps_graph_); | |
425 | |
426 // Collect graph and histogram data. | |
427 SkPath path; | |
428 | |
429 const int kHistogramSize = 20; | |
430 double histogram[kHistogramSize] = { 1.0 }; | |
431 double max_bucket_value = 1.0; | |
432 | |
433 for (FrameRateCounter::RingBufferType::Iterator it = --fps_counter->end(); it; | |
434 --it) { | |
435 base::TimeDelta delta = fps_counter->RecentFrameInterval(it.index() + 1); | |
436 | |
437 // Skip this particular instantaneous frame rate if it is not likely to have | |
438 // been valid. | |
439 if (!fps_counter->IsBadFrameInterval(delta)) { | |
440 double fps = 1.0 / delta.InSecondsF(); | |
441 | |
442 // Clamp the FPS to the range we want to plot visually. | |
443 double p = fps / fps_graph_.current_upper_bound; | |
444 if (p > 1.0) | |
445 p = 1.0; | |
446 | |
447 // Plot this data point. | |
448 SkPoint cur = | |
449 SkPoint::Make(graph_bounds.left() + it.index(), | |
450 graph_bounds.bottom() - p * graph_bounds.height()); | |
451 if (path.isEmpty()) | |
452 path.moveTo(cur); | |
453 else | |
454 path.lineTo(cur); | |
455 | |
456 // Use the fps value to find the right bucket in the histogram. | |
457 int bucket_index = floor(p * (kHistogramSize - 1)); | |
458 | |
459 // Add the delta time to take the time spent at that fps rate into | |
460 // account. | |
461 histogram[bucket_index] += delta.InSecondsF(); | |
462 max_bucket_value = std::max(histogram[bucket_index], max_bucket_value); | |
463 } | |
464 } | |
465 | |
466 // Draw FPS histogram. | |
467 paint.setColor(DebugColors::HUDSeparatorLineColor()); | |
468 canvas->drawLine(histogram_bounds.left() - 1, | |
469 histogram_bounds.top() - 1, | |
470 histogram_bounds.left() - 1, | |
471 histogram_bounds.bottom() + 1, | |
472 paint); | |
473 canvas->drawLine(histogram_bounds.right() + 1, | |
474 histogram_bounds.top() - 1, | |
475 histogram_bounds.right() + 1, | |
476 histogram_bounds.bottom() + 1, | |
477 paint); | |
478 | |
479 paint.setColor(DebugColors::FPSDisplayTextAndGraphColor()); | |
480 const double bar_height = histogram_bounds.height() / kHistogramSize; | |
481 | |
482 for (int i = kHistogramSize - 1; i >= 0; --i) { | |
483 if (histogram[i] > 0) { | |
484 double bar_width = | |
485 histogram[i] / max_bucket_value * histogram_bounds.width(); | |
486 canvas->drawRect( | |
487 SkRect::MakeXYWH(histogram_bounds.left(), | |
488 histogram_bounds.bottom() - (i + 1) * bar_height, | |
489 bar_width, | |
490 1), | |
491 paint); | |
492 } | |
493 } | |
494 | |
495 // Draw FPS graph. | |
496 paint.setAntiAlias(true); | |
497 paint.setStyle(SkPaint::kStroke_Style); | |
498 paint.setStrokeWidth(1); | |
499 canvas->drawPath(path, paint); | |
500 | |
501 return area; | |
502 } | |
503 | |
504 SkRect HeadsUpDisplayLayerImpl::DrawMemoryDisplay(SkCanvas* canvas, | |
505 int right, | |
506 int top, | |
507 int width) const { | |
508 if (!memory_entry_.total_bytes_used) | |
509 return SkRect::MakeEmpty(); | |
510 | |
511 const int kPadding = 4; | |
512 const int kFontHeight = 13; | |
513 | |
514 const int height = 3 * kFontHeight + 4 * kPadding; | |
515 const int left = bounds().width() - width - right; | |
516 const SkRect area = SkRect::MakeXYWH(left, top, width, height); | |
517 | |
518 const double kMegabyte = 1024.0 * 1024.0; | |
519 | |
520 SkPaint paint = CreatePaint(); | |
521 DrawGraphBackground(canvas, &paint, area); | |
522 | |
523 SkPoint title_pos = SkPoint::Make(left + kPadding, top + kFontHeight); | |
524 SkPoint stat1_pos = SkPoint::Make(left + width - kPadding - 1, | |
525 top + kPadding + 2 * kFontHeight); | |
526 SkPoint stat2_pos = SkPoint::Make(left + width - kPadding - 1, | |
527 top + 2 * kPadding + 3 * kFontHeight); | |
528 | |
529 paint.setColor(DebugColors::MemoryDisplayTextColor()); | |
530 DrawText(canvas, | |
531 &paint, | |
532 "GPU memory", | |
533 SkPaint::kLeft_Align, | |
534 kFontHeight, | |
535 title_pos); | |
536 | |
537 std::string text = base::StringPrintf( | |
538 "%6.1f MB used", memory_entry_.total_bytes_used / kMegabyte); | |
539 DrawText(canvas, &paint, text, SkPaint::kRight_Align, kFontHeight, stat1_pos); | |
540 | |
541 if (!memory_entry_.had_enough_memory) | |
542 paint.setColor(SK_ColorRED); | |
543 text = base::StringPrintf("%6.1f MB max ", | |
544 memory_entry_.total_budget_in_bytes / kMegabyte); | |
545 DrawText(canvas, &paint, text, SkPaint::kRight_Align, kFontHeight, stat2_pos); | |
546 | |
547 return area; | |
548 } | |
549 | |
550 SkRect HeadsUpDisplayLayerImpl::DrawGpuRasterizationStatus(SkCanvas* canvas, | |
551 int right, | |
552 int top, | |
553 int width) const { | |
554 std::string status; | |
555 SkColor color = SK_ColorRED; | |
556 switch (layer_tree_impl()->GetGpuRasterizationStatus()) { | |
557 case GpuRasterizationStatus::ON: | |
558 status = "on"; | |
559 color = SK_ColorGREEN; | |
560 break; | |
561 case GpuRasterizationStatus::ON_FORCED: | |
562 status = "on (forced)"; | |
563 color = SK_ColorGREEN; | |
564 break; | |
565 case GpuRasterizationStatus::OFF_DEVICE: | |
566 status = "off (device)"; | |
567 color = SK_ColorRED; | |
568 break; | |
569 case GpuRasterizationStatus::OFF_VIEWPORT: | |
570 status = "off (viewport)"; | |
571 color = SK_ColorYELLOW; | |
572 break; | |
573 case GpuRasterizationStatus::OFF_CONTENT: | |
574 status = "off (content)"; | |
575 color = SK_ColorYELLOW; | |
576 break; | |
577 } | |
578 | |
579 if (status.empty()) | |
580 return SkRect::MakeEmpty(); | |
581 | |
582 const int kPadding = 4; | |
583 const int kFontHeight = 13; | |
584 | |
585 const int height = 2 * kFontHeight + 3 * kPadding; | |
586 const int left = bounds().width() - width - right; | |
587 const SkRect area = SkRect::MakeXYWH(left, top, width, height); | |
588 | |
589 SkPaint paint = CreatePaint(); | |
590 DrawGraphBackground(canvas, &paint, area); | |
591 | |
592 SkPoint gpu_status_pos = SkPoint::Make(left + width - kPadding, | |
593 top + 2 * kFontHeight + 2 * kPadding); | |
594 | |
595 paint.setColor(color); | |
596 DrawText(canvas, &paint, "GPU raster: ", SkPaint::kLeft_Align, kFontHeight, | |
597 left + kPadding, top + kFontHeight + kPadding); | |
598 DrawText(canvas, &paint, status, SkPaint::kRight_Align, kFontHeight, | |
599 gpu_status_pos); | |
600 | |
601 return area; | |
602 } | |
603 | |
604 SkRect HeadsUpDisplayLayerImpl::DrawPaintTimeDisplay( | |
605 SkCanvas* canvas, | |
606 const PaintTimeCounter* paint_time_counter, | |
607 int right, | |
608 int top) const { | |
609 const int kPadding = 4; | |
610 const int kFontHeight = 14; | |
611 | |
612 const int kGraphWidth = paint_time_counter->HistorySize(); | |
613 const int kGraphHeight = 40; | |
614 | |
615 const int width = kGraphWidth + 2 * kPadding; | |
616 const int height = | |
617 kFontHeight + kGraphHeight + 4 * kPadding + 2 + kFontHeight + kPadding; | |
618 const int left = bounds().width() - width - right; | |
619 | |
620 const SkRect area = SkRect::MakeXYWH(left, top, width, height); | |
621 | |
622 SkPaint paint = CreatePaint(); | |
623 DrawGraphBackground(canvas, &paint, area); | |
624 | |
625 SkRect text_bounds = SkRect::MakeXYWH( | |
626 left + kPadding, top + kPadding, kGraphWidth, kFontHeight); | |
627 SkRect text_bounds2 = SkRect::MakeXYWH(left + kPadding, | |
628 text_bounds.bottom() + kPadding, | |
629 kGraphWidth, | |
630 kFontHeight); | |
631 SkRect graph_bounds = SkRect::MakeXYWH(left + kPadding, | |
632 text_bounds2.bottom() + 2 * kPadding, | |
633 kGraphWidth, | |
634 kGraphHeight); | |
635 | |
636 const std::string value_text = | |
637 base::StringPrintf("%.1f", paint_time_graph_.value); | |
638 const std::string min_max_text = base::StringPrintf( | |
639 "%.1f-%.1f", paint_time_graph_.min, paint_time_graph_.max); | |
640 | |
641 paint.setColor(DebugColors::PaintTimeDisplayTextAndGraphColor()); | |
642 DrawText(canvas, &paint, "Compositor frame time(ms)", SkPaint::kLeft_Align, | |
643 kFontHeight, text_bounds.left(), text_bounds.bottom()); | |
644 DrawText(canvas, | |
645 &paint, | |
646 value_text, | |
647 SkPaint::kLeft_Align, | |
648 kFontHeight, | |
649 text_bounds2.left(), | |
650 text_bounds2.bottom()); | |
651 DrawText(canvas, | |
652 &paint, | |
653 min_max_text, | |
654 SkPaint::kRight_Align, | |
655 kFontHeight, | |
656 text_bounds2.right(), | |
657 text_bounds2.bottom()); | |
658 | |
659 paint.setColor(DebugColors::PaintTimeDisplayTextAndGraphColor()); | |
660 for (PaintTimeCounter::RingBufferType::Iterator it = | |
661 paint_time_counter->End(); | |
662 it; | |
663 --it) { | |
664 double pt = it->InMillisecondsF(); | |
665 | |
666 if (pt == 0.0) | |
667 continue; | |
668 | |
669 double p = pt / paint_time_graph_.current_upper_bound; | |
670 if (p > 1.0) | |
671 p = 1.0; | |
672 | |
673 canvas->drawRect( | |
674 SkRect::MakeXYWH(graph_bounds.left() + it.index(), | |
675 graph_bounds.bottom() - p * graph_bounds.height(), | |
676 1, | |
677 p * graph_bounds.height()), | |
678 paint); | |
679 } | |
680 | |
681 DrawGraphLines(canvas, &paint, graph_bounds, paint_time_graph_); | |
682 | |
683 return area; | |
684 } | |
685 | |
686 void HeadsUpDisplayLayerImpl::DrawDebugRect( | |
687 SkCanvas* canvas, | |
688 SkPaint* paint, | |
689 const DebugRect& rect, | |
690 SkColor stroke_color, | |
691 SkColor fill_color, | |
692 float stroke_width, | |
693 const std::string& label_text) const { | |
694 gfx::Rect debug_layer_rect = | |
695 gfx::ScaleToEnclosingRect(rect.rect, 1.0 / internal_contents_scale_, | |
696 1.0 / internal_contents_scale_); | |
697 SkIRect sk_rect = RectToSkIRect(debug_layer_rect); | |
698 paint->setColor(fill_color); | |
699 paint->setStyle(SkPaint::kFill_Style); | |
700 canvas->drawIRect(sk_rect, *paint); | |
701 | |
702 paint->setColor(stroke_color); | |
703 paint->setStyle(SkPaint::kStroke_Style); | |
704 paint->setStrokeWidth(SkFloatToScalar(stroke_width)); | |
705 canvas->drawIRect(sk_rect, *paint); | |
706 | |
707 if (label_text.length()) { | |
708 const int kFontHeight = 12; | |
709 const int kPadding = 3; | |
710 | |
711 // The debug_layer_rect may be huge, and converting to a floating point may | |
712 // be lossy, so intersect with the HUD layer bounds first to prevent that. | |
713 gfx::Rect clip_rect = debug_layer_rect; | |
714 clip_rect.Intersect(gfx::Rect(internal_content_bounds_)); | |
715 SkRect sk_clip_rect = RectToSkRect(clip_rect); | |
716 | |
717 canvas->save(); | |
718 canvas->clipRect(sk_clip_rect); | |
719 canvas->translate(sk_clip_rect.x(), sk_clip_rect.y()); | |
720 | |
721 SkPaint label_paint = CreatePaint(); | |
722 label_paint.setTextSize(kFontHeight); | |
723 label_paint.setTypeface(typeface_.get()); | |
724 label_paint.setColor(stroke_color); | |
725 | |
726 const SkScalar label_text_width = | |
727 label_paint.measureText(label_text.c_str(), label_text.length()); | |
728 canvas->drawRect(SkRect::MakeWH(label_text_width + 2 * kPadding, | |
729 kFontHeight + 2 * kPadding), | |
730 label_paint); | |
731 | |
732 label_paint.setAntiAlias(true); | |
733 label_paint.setColor(SkColorSetARGB(255, 50, 50, 50)); | |
734 canvas->drawText(label_text.c_str(), | |
735 label_text.length(), | |
736 kPadding, | |
737 kFontHeight * 0.8f + kPadding, | |
738 label_paint); | |
739 | |
740 canvas->restore(); | |
741 } | |
742 } | |
743 | |
744 void HeadsUpDisplayLayerImpl::DrawDebugRects( | |
745 SkCanvas* canvas, | |
746 DebugRectHistory* debug_rect_history) { | |
747 SkPaint paint = CreatePaint(); | |
748 | |
749 const std::vector<DebugRect>& debug_rects = debug_rect_history->debug_rects(); | |
750 std::vector<DebugRect> new_paint_rects; | |
751 | |
752 for (size_t i = 0; i < debug_rects.size(); ++i) { | |
753 SkColor stroke_color = 0; | |
754 SkColor fill_color = 0; | |
755 float stroke_width = 0.f; | |
756 std::string label_text; | |
757 | |
758 switch (debug_rects[i].type) { | |
759 case PAINT_RECT_TYPE: | |
760 new_paint_rects.push_back(debug_rects[i]); | |
761 continue; | |
762 case PROPERTY_CHANGED_RECT_TYPE: | |
763 stroke_color = DebugColors::PropertyChangedRectBorderColor(); | |
764 fill_color = DebugColors::PropertyChangedRectFillColor(); | |
765 stroke_width = DebugColors::PropertyChangedRectBorderWidth(); | |
766 break; | |
767 case SURFACE_DAMAGE_RECT_TYPE: | |
768 stroke_color = DebugColors::SurfaceDamageRectBorderColor(); | |
769 fill_color = DebugColors::SurfaceDamageRectFillColor(); | |
770 stroke_width = DebugColors::SurfaceDamageRectBorderWidth(); | |
771 break; | |
772 case REPLICA_SCREEN_SPACE_RECT_TYPE: | |
773 stroke_color = DebugColors::ScreenSpaceSurfaceReplicaRectBorderColor(); | |
774 fill_color = DebugColors::ScreenSpaceSurfaceReplicaRectFillColor(); | |
775 stroke_width = DebugColors::ScreenSpaceSurfaceReplicaRectBorderWidth(); | |
776 break; | |
777 case SCREEN_SPACE_RECT_TYPE: | |
778 stroke_color = DebugColors::ScreenSpaceLayerRectBorderColor(); | |
779 fill_color = DebugColors::ScreenSpaceLayerRectFillColor(); | |
780 stroke_width = DebugColors::ScreenSpaceLayerRectBorderWidth(); | |
781 break; | |
782 case TOUCH_EVENT_HANDLER_RECT_TYPE: | |
783 stroke_color = DebugColors::TouchEventHandlerRectBorderColor(); | |
784 fill_color = DebugColors::TouchEventHandlerRectFillColor(); | |
785 stroke_width = DebugColors::TouchEventHandlerRectBorderWidth(); | |
786 label_text = "touch event listener"; | |
787 break; | |
788 case WHEEL_EVENT_HANDLER_RECT_TYPE: | |
789 stroke_color = DebugColors::WheelEventHandlerRectBorderColor(); | |
790 fill_color = DebugColors::WheelEventHandlerRectFillColor(); | |
791 stroke_width = DebugColors::WheelEventHandlerRectBorderWidth(); | |
792 label_text = "mousewheel event listener"; | |
793 break; | |
794 case SCROLL_EVENT_HANDLER_RECT_TYPE: | |
795 stroke_color = DebugColors::ScrollEventHandlerRectBorderColor(); | |
796 fill_color = DebugColors::ScrollEventHandlerRectFillColor(); | |
797 stroke_width = DebugColors::ScrollEventHandlerRectBorderWidth(); | |
798 label_text = "scroll event listener"; | |
799 break; | |
800 case NON_FAST_SCROLLABLE_RECT_TYPE: | |
801 stroke_color = DebugColors::NonFastScrollableRectBorderColor(); | |
802 fill_color = DebugColors::NonFastScrollableRectFillColor(); | |
803 stroke_width = DebugColors::NonFastScrollableRectBorderWidth(); | |
804 label_text = "repaints on scroll"; | |
805 break; | |
806 case ANIMATION_BOUNDS_RECT_TYPE: | |
807 stroke_color = DebugColors::LayerAnimationBoundsBorderColor(); | |
808 fill_color = DebugColors::LayerAnimationBoundsFillColor(); | |
809 stroke_width = DebugColors::LayerAnimationBoundsBorderWidth(); | |
810 label_text = "animation bounds"; | |
811 break; | |
812 } | |
813 | |
814 DrawDebugRect(canvas, | |
815 &paint, | |
816 debug_rects[i], | |
817 stroke_color, | |
818 fill_color, | |
819 stroke_width, | |
820 label_text); | |
821 } | |
822 | |
823 if (new_paint_rects.size()) { | |
824 paint_rects_.swap(new_paint_rects); | |
825 fade_step_ = DebugColors::kFadeSteps; | |
826 } | |
827 if (fade_step_ > 0) { | |
828 fade_step_--; | |
829 for (size_t i = 0; i < paint_rects_.size(); ++i) { | |
830 DrawDebugRect(canvas, | |
831 &paint, | |
832 paint_rects_[i], | |
833 DebugColors::PaintRectBorderColor(fade_step_), | |
834 DebugColors::PaintRectFillColor(fade_step_), | |
835 DebugColors::PaintRectBorderWidth(), | |
836 ""); | |
837 } | |
838 } | |
839 } | |
840 | |
841 const char* HeadsUpDisplayLayerImpl::LayerTypeAsString() const { | |
842 return "cc::HeadsUpDisplayLayerImpl"; | |
843 } | |
844 | |
845 void HeadsUpDisplayLayerImpl::AsValueInto( | |
846 base::trace_event::TracedValue* dict) const { | |
847 LayerImpl::AsValueInto(dict); | |
848 dict->SetString("layer_name", "Heads Up Display Layer"); | |
849 } | |
850 | |
851 } // namespace cc | |
OLD | NEW |