| 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 |