blob: 50f29b2dd92f779caeba11cb36105bcccd116a28 [file] [log] [blame]
// Copyright 2017 Google Inc. 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 <string>
#include <vector>
#include "base/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 (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(text_builder.Pass());
// 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,
scoped_ptr<render_tree::Brush>(
new render_tree::SolidColorBrush(kBackgroundColor))));
text_with_background_builder.AddChild(text);
return new render_tree::CompositionNode(text_with_background_builder.Pass());
}
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_, 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(builder.Pass());
}
}
} // namespace renderer
} // namespace cobalt