blob: bbb96587fa1956c8fae94fe0c0607bcea874e3a7 [file] [log] [blame]
// Copyright 2014 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
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
#include <memory>
#include <string>
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "cobalt/base/c_val_collection_timer_stats.h"
#include "cobalt/math/rect.h"
#include "cobalt/render_tree/animations/animate_node.h"
#include "cobalt/render_tree/node.h"
#include "cobalt/renderer/backend/graphics_context.h"
#include "cobalt/renderer/fps_overlay.h"
#include "cobalt/renderer/rasterizer/rasterizer.h"
#include "cobalt/renderer/submission.h"
#include "cobalt/renderer/submission_queue.h"
#if defined(ENABLE_DEBUGGER)
#include "cobalt/debug/console/command_manager.h"
#endif // defined(ENABLE_DEBUGGER)
namespace cobalt {
namespace renderer {
// Pipeline is a thread-safe class that setups up a rendering pipeline
// for processing render trees through a rasterizer. New render trees are
// submitted to the pipeline, from any thread, by calling Submit(). This
// pushes the submitted render tree through a rendering pipeline that eventually
// results in the render tree being submitted to the passed in rasterizer which
// can output the render tree to the display. A new thread is created which
// hosts the rasterizer submit calls. Render trees are rasterized as fast
// as the rasterizer will accept them, which is likely to be the display's
// refresh rate.
class Pipeline {
typedef base::Callback<std::unique_ptr<rasterizer::Rasterizer>()>
typedef base::Callback<void(std::unique_ptr<uint8[]>, const math::Size&)>
enum ShutdownClearMode {
struct Options {
Options() : enable_fps_stdout(false), enable_fps_overlay(false) {}
bool enable_fps_stdout;
bool enable_fps_overlay;
// Using the provided rasterizer creation function, a rasterizer will be
// created within the Pipeline on a separate rasterizer thread. Thus,
// the rasterizer created by the provided function should only reference
// thread safe objects. If |clear_to_black_on_shutdown| is specified,
// the provided render_target_ (if not NULL) will be cleared to black when
// the pipeline is destroyed.
Pipeline(const CreateRasterizerFunction& create_rasterizer_function,
const scoped_refptr<backend::RenderTarget>& render_target,
backend::GraphicsContext* graphics_context,
bool submit_even_if_render_tree_is_unchanged,
ShutdownClearMode clear_on_shutdown_mode,
const Options& options = Options());
// Submit a new render tree to the renderer pipeline. After calling this
// method, the submitted render tree will be the one that is continuously
// animated and rendered by the rasterizer.
void Submit(const Submission& render_tree_submission);
// Clears the currently submitted render tree submission and waits for the
// pipeline to be flushed before returning.
void Clear();
// |render_tree_submission| will be rasterized into a new offscreen surface.
// The RGBA pixel data will be extracted from this surface, and |complete|
// will be called with the pixel data and the dimensions of the image.
void RasterizeToRGBAPixels(
const scoped_refptr<render_tree::Node>& render_tree_root,
const base::Optional<math::Rect>& clip_rect,
const RasterizationCompleteCallback& complete);
// Inserts a fence that ensures the rasterizer rasterizes up until the
// submission time proceeding queuing additional submissions. This is useful
// when switching timelines in order to ensure that an old timeline plays out
// completely before resetting the submission queue for a timeline change.
// Upon passing the fence, we will immediately queue the latest submission
// submitted after TimeFence() was called. If a time fence is set while
// an existing time fence already exists, the new time fence is ignored (and
// an error is logged).
void TimeFence(base::TimeDelta time_fence);
// Returns a thread-safe object from which one can produce renderer resources
// like images and fonts which can be referenced by render trees that are
// subsequently submitted to this pipeline.
render_tree::ResourceProvider* GetResourceProvider();
static bool IsMapToMeshEnabled(const Pipeline* pipeline);
// All private data members should be accessed only on the rasterizer thread,
// with the exception of rasterizer_thread_ itself through which messages
// are posted.
// Called by Submit() to do the work of actually setting the newly submitted
// render tree. This method will be called on the rasterizer thread.
void SetNewRenderTree(const Submission& render_tree_submission);
// Clears the current render tree and calls the callback when this is done.
void ClearCurrentRenderTree();
// Called repeatedly (the rate is limited by the rasterizer, so likely it
// will be called every 1/60th of a second) on the rasterizer thread and
// results in the rasterization of the current tree and submission of it to
// the render target.
void RasterizeCurrentTree();
// Rasterize the animated |render_tree_submission| to |render_target|,
// applying the time_offset in the submission to the animations.
// Returns true only if a rasterization actually took place.
bool RasterizeSubmissionToRenderTarget(
const Submission& render_tree_submission,
const scoped_refptr<backend::RenderTarget>& render_target,
bool force_rasterize);
// Updates the rasterizer timer stats according to the |start_time| and
// |end_time| of the most recent rasterize call.
void UpdateRasterizeStats(bool did_rasterize,
bool are_stat_tracked_animations_expired,
bool is_new_render_tree, base::TimeTicks start_time,
base::TimeTicks end_time);
// This method is executed on the rasterizer thread and is responsible for
// constructing the rasterizer.
void InitializeRasterizerThread(
const CreateRasterizerFunction& create_rasterizer_function);
// Shuts down the submission queue. This is done on the rasterizer thread
// and is separate from general shutdown because clearing out the submission
// queue may result in tasks being posted to the rasterizer thread (e.g.
// texture deletions).
void ShutdownSubmissionQueue();
// This method is executed on the rasterizer thread to shutdown anything that
// needs to be shutdown from there.
void ShutdownRasterizerThread();
// This method releases the rasterizer. This is exposed separately from
// ShutdownRasterizerThread() so it can be executed after tasks that may
// be posted by ShutdownRasterizerThread().
void ShutdownRasterizer() { rasterizer_.reset(); }
#if defined(ENABLE_DEBUGGER)
void OnDumpCurrentRenderTree(const std::string&);
void OnToggleFpsStdout(const std::string&);
void OnToggleFpsOverlay(const std::string&);
#endif // defined(ENABLE_DEBUGGER)
// Render trees may contain a number of AnimateNodes (or none). In order
// to optimize for applying the animations on the rasterizer thread, this
// function searches the tree for AnimateNodes and collects all of their
// information into a single AnimateNode at the root of the returned
// render tree.
Submission CollectAnimations(const Submission& render_tree_submission);
void FrameStatsOnFlushCallback(
const base::CValCollectionTimerStatsFlushResults& flush_results);
// Resets the submission queue, effecitvely emptying it and restarting it
// with the configuration specified by |current_timeline_info_| applied to it.
void ResetSubmissionQueue();
// Pushes the specified submission into the submission queue, where it will
// then be picked up by subsequent rasterizations. If the submission's
// timeline id is different from the current timeline id (in
// |current_timeline_info_|), then the submission queue will be reset.
void QueueSubmission(const Submission& submission,
base::TimeTicks receipt_time);
base::WaitableEvent rasterizer_created_event_;
// The render_target that all submitted render trees will be rasterized to.
scoped_refptr<backend::RenderTarget> render_target_;
backend::GraphicsContext* graphics_context_;
// A timer that signals to the rasterizer to rasterize the next frame.
// The timer is setup with a period of 0ms so that it will submit as fast
// as possible, it is up to the rasterizer to pace the pipeline. The timer
// is used to manage the repeated posting of the rasterize task call and
// to make proper shutdown easier.
base::Optional<base::RepeatingTimer> rasterize_timer_;
// ThreadChecker for use by the rasterizer_thread_ defined below.
// The thread that all rasterization will take place within.
base::Thread rasterizer_thread_;
// The rasterizer object that will run on the rasterizer_thread_ and is
// effectively the last stage of the pipeline, responsible for rasterizing
// the final render tree and submitting it to the render target.
std::unique_ptr<rasterizer::Rasterizer> rasterizer_;
// A thread whose only purpose is to destroy submissions/render trees.
// This is important because destroying a render tree can take some time,
// and we would like to avoid spending this time on the renderer thread.
base::Thread submission_disposal_thread_;
// Manages a queue of render tree submissions that are to be rendered in
// the future.
base::Optional<SubmissionQueue> submission_queue_;
// If true, we will submit the current render tree to the rasterizer every
// frame, even if it hasn't changed.
const bool submit_even_if_render_tree_is_unchanged_;
// Keeps track of the last rendered animated render tree.
scoped_refptr<render_tree::Node> last_render_tree_;
// Keeps track of the area of the screen that animations previously existed
// within, so that we can know which regions of the screens would be dirty
// next frame.
base::Optional<math::Rect> previous_animated_area_;
// The submission time used during the last render tree render.
base::Optional<base::TimeDelta> last_render_time_;
// Keep track of whether the last rendered tree had active animations. This
// allows us to skip rasterizing that render tree if we see it again and it
// did have expired animations.
bool last_animations_expired_;
// Keep track of whether the last rendered tree had animations that we're
// tracking stats on.
bool last_stat_tracked_animations_expired_;
// Did a rasterization take place in the last frame?
bool last_did_rasterize_;
// Timer tracking the amount of time spent in
// |RasterizeSubmissionToRenderTarget| while animations are active. The
// tracking is flushed when the animations expire.
base::CValCollectionTimerStats<base::CValPublic> rasterize_animations_timer_;
// Accumulates render tree rasterization interval times but does not flush
// them until the maximum number of samples is gathered.
// Timer tracking the amount of time between calls to
// |RasterizeSubmissionToRenderTarget| while animations are active. The
// tracking is flushed when the animations expire.
// The total number of times Skia was used to render
// a non-text render tree node.
base::CVal<int64, base::CValPublic> fallback_rasterize_count_;
// The total number of new render trees that have been rasterized.
base::CVal<int, base::CValPublic> new_render_tree_rasterize_count_;
// The last time that a newly encountered render tree was first rasterized.
base::CVal<int64, base::CValPublic> new_render_tree_rasterize_time_;
// Whether or not animations are currently playing.
base::CVal<bool, base::CValPublic> has_active_animations_c_val_;
// The most recent time animations started playing.
base::CVal<int64, base::CValPublic> animations_start_time_;
// The most recent time animations ended playing.
base::CVal<int64, base::CValPublic> animations_end_time_;
#if defined(ENABLE_DEBUGGER)
// Dumps the current render tree to the console.
#endif // defined(ENABLE_DEBUGGER)
// If true, Pipeline's destructor will clear its render target to black on
// shutdown.
const ShutdownClearMode clear_on_shutdown_mode_;
// If true, we will print framerate statistics to stdout upon completion
// of each animation (or after a maximum number of frames has been issued).
bool enable_fps_stdout_;
// If true, an overlay will be displayed over the UI output that shows the
// FPS statistics from the last animation.
bool enable_fps_overlay_;
base::Optional<FpsOverlay> fps_overlay_;
// True if the overlay has been updated and it needs to be re-rasterized.
bool fps_overlay_update_pending_;
// Time fence data that records if a time fence is active, at what time, and
// what submission if any is waiting to be queued once we pass the time fence.
base::Optional<base::TimeDelta> time_fence_;
base::Optional<Submission> post_fence_submission_;
base::Optional<base::TimeTicks> post_fence_receipt_time_;
// Information about the current timeline. Each incoming submission
// identifies with a particular timeline, and if that ever changes, we assume
// a discontinuity in animations and reset our submission queue, possibly
// with new configuration parameters specified in the new |TimelineInfo|.
Submission::TimelineInfo current_timeline_info_;
// This timestamp represents the last time the pipeline rasterized a
// render tree to render_target_. This is different from last_render_time_
// which is specific to the current submission and is reset whenever a new
// render tree is submitted.
base::TimeTicks last_rasterize_time_;
} // namespace renderer
} // namespace cobalt