| // Copyright 2017 The Cobalt Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "cobalt/renderer/fps_overlay.h" |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/strings/stringprintf.h" |
| #include "cobalt/render_tree/brush.h" |
| #include "cobalt/render_tree/color_rgba.h" |
| #include "cobalt/render_tree/composition_node.h" |
| #include "cobalt/render_tree/font.h" |
| #include "cobalt/render_tree/glyph_buffer.h" |
| #include "cobalt/render_tree/rect_node.h" |
| #include "cobalt/render_tree/resource_provider.h" |
| #include "cobalt/render_tree/text_node.h" |
| |
| namespace cobalt { |
| namespace renderer { |
| |
| namespace { |
| const render_tree::ColorRGBA kTextColor(1.0f, 1.0f, 1.0f, 1.0f); |
| const render_tree::ColorRGBA kBackgroundColor(1.0f, 0.6f, 0.6f, 1.0f); |
| const char* kTypefaceName = "Roboto"; |
| const float kFontSize = 14.0f; |
| |
| // Distance between the text bounds and the background bounds. |
| const int kTextMarginInPixels = 5; |
| |
| // Spacing between each line of text. |
| const int kTextVerticalSpacingInPixels = 5; |
| |
| scoped_refptr<render_tree::Node> ConvertLinesToOverlay( |
| render_tree::ResourceProvider* resource_provider, render_tree::Font* font, |
| const std::vector<std::string>& lines) { |
| // First create a composition node that composes all the lines of text |
| // together. |
| float y_offset = kTextMarginInPixels; |
| render_tree::CompositionNode::Builder text_builder; |
| for (const auto& line : lines) { |
| scoped_refptr<render_tree::GlyphBuffer> glyph_buffer = |
| resource_provider->CreateGlyphBuffer(line, font); |
| math::RectF bounds(glyph_buffer->GetBounds()); |
| |
| text_builder.AddChild(new render_tree::TextNode( |
| math::Vector2dF(-bounds.x() + kTextMarginInPixels, |
| -bounds.y() + y_offset), |
| glyph_buffer, kTextColor)); |
| |
| y_offset += bounds.height() + kTextVerticalSpacingInPixels; |
| } |
| |
| scoped_refptr<render_tree::CompositionNode> text = |
| new render_tree::CompositionNode(std::move(text_builder)); |
| |
| // Now compose that onto a solid background. |
| math::RectF background_bounds = text->GetBounds(); |
| background_bounds.set_height(background_bounds.height() + |
| 2 * kTextMarginInPixels); |
| background_bounds.set_y(0); |
| background_bounds.set_width(background_bounds.width() + |
| 2 * kTextMarginInPixels); |
| background_bounds.set_x(0); |
| |
| render_tree::CompositionNode::Builder text_with_background_builder; |
| text_with_background_builder.AddChild(new render_tree::RectNode( |
| background_bounds, |
| std::unique_ptr<render_tree::Brush>( |
| new render_tree::SolidColorBrush(kBackgroundColor)))); |
| text_with_background_builder.AddChild(text); |
| |
| return new render_tree::CompositionNode( |
| std::move(text_with_background_builder)); |
| } |
| |
| scoped_refptr<render_tree::Node> ConvertFPSStatsToOverlay( |
| render_tree::ResourceProvider* resource_provider, render_tree::Font* font, |
| const base::CValCollectionTimerStatsFlushResults& fps_stats) { |
| std::vector<std::string> lines; |
| lines.push_back(base::StringPrintf( |
| "Samples: %d", static_cast<unsigned int>(fps_stats.sample_count))); |
| lines.push_back(base::StringPrintf("Average: %.1fms", |
| fps_stats.average.InMillisecondsF())); |
| lines.push_back( |
| base::StringPrintf("Min: %.1fms", fps_stats.minimum.InMillisecondsF())); |
| lines.push_back( |
| base::StringPrintf("Max: %.1fms", fps_stats.maximum.InMillisecondsF())); |
| lines.push_back(base::StringPrintf( |
| "25th Pct: %.1fms", fps_stats.percentile_25th.InMillisecondsF())); |
| lines.push_back(base::StringPrintf( |
| "50th Pct: %.1fms", fps_stats.percentile_50th.InMillisecondsF())); |
| lines.push_back(base::StringPrintf( |
| "75th Pct: %.1fms", fps_stats.percentile_75th.InMillisecondsF())); |
| lines.push_back(base::StringPrintf( |
| "95th Pct: %.1fms", fps_stats.percentile_95th.InMillisecondsF())); |
| |
| return ConvertLinesToOverlay(resource_provider, font, lines); |
| } |
| } // namespace |
| |
| FpsOverlay::FpsOverlay(render_tree::ResourceProvider* resource_provider) |
| : resource_provider_(resource_provider) { |
| font_ = resource_provider_ |
| ->GetLocalTypeface(kTypefaceName, render_tree::FontStyle()) |
| ->CreateFontWithSize(kFontSize); |
| } |
| |
| void FpsOverlay::UpdateOverlay( |
| const base::CValCollectionTimerStatsFlushResults& fps_stats) { |
| cached_overlay_ = |
| ConvertFPSStatsToOverlay(resource_provider_, font_.get(), fps_stats); |
| } |
| |
| scoped_refptr<render_tree::Node> FpsOverlay::AnnotateRenderTreeWithOverlay( |
| render_tree::Node* original_tree) { |
| if (!cached_overlay_) { |
| return original_tree; |
| } else { |
| // Compose the overlay onto the top left corner of the original render tree. |
| render_tree::CompositionNode::Builder builder; |
| builder.AddChild(original_tree); |
| builder.AddChild(cached_overlay_); |
| return new render_tree::CompositionNode(std::move(builder)); |
| } |
| } |
| |
| } // namespace renderer |
| } // namespace cobalt |