|  | // Copyright 2013 The Flutter Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef FML_SHELL_COMMON_TASK_RUNNER_MERGER_H_ | 
|  | #define FML_SHELL_COMMON_TASK_RUNNER_MERGER_H_ | 
|  |  | 
|  | #include <condition_variable> | 
|  | #include <mutex> | 
|  |  | 
|  | #include "flutter/fml/macros.h" | 
|  | #include "flutter/fml/memory/ref_counted.h" | 
|  | #include "flutter/fml/message_loop_task_queues.h" | 
|  | #include "flutter/fml/shared_thread_merger.h" | 
|  |  | 
|  | namespace fml { | 
|  |  | 
|  | class MessageLoopImpl; | 
|  |  | 
|  | enum class RasterThreadStatus { | 
|  | kRemainsMerged, | 
|  | kRemainsUnmerged, | 
|  | kUnmergedNow | 
|  | }; | 
|  |  | 
|  | /// This class is a client and proxy between the rasterizer and | 
|  | /// |SharedThreadMerger|. The multiple |RasterThreadMerger| instances with same | 
|  | /// owner_queue_id and same subsumed_queue_id share the same | 
|  | /// |SharedThreadMerger| instance. Whether they share the same inner instance is | 
|  | /// determined by |RasterThreadMerger::CreateOrShareThreadMerger| method. | 
|  | class RasterThreadMerger | 
|  | : public fml::RefCountedThreadSafe<RasterThreadMerger> { | 
|  | public: | 
|  | // Merges the raster thread into platform thread for the duration of | 
|  | // the lease term. Lease is managed by the caller by either calling | 
|  | // |ExtendLeaseTo| or |DecrementLease|. | 
|  | // When the caller merges with a lease term of say 2. The threads | 
|  | // are going to remain merged until 2 invocations of |DecreaseLease|, | 
|  | // unless an |ExtendLeaseTo| gets called. | 
|  | // | 
|  | // If the task queues are the same, we consider them statically merged. | 
|  | // When task queues are statically merged this method becomes no-op. | 
|  | void MergeWithLease(size_t lease_term); | 
|  |  | 
|  | // Gets the shared merger from current merger object | 
|  | const fml::RefPtr<SharedThreadMerger>& GetSharedRasterThreadMerger() const; | 
|  |  | 
|  | /// Creates a new merger from parent, share the inside shared_merger member | 
|  | /// when the platform_queue_id and raster_queue_id are same, otherwise create | 
|  | /// a new shared_merger instance | 
|  | static fml::RefPtr<fml::RasterThreadMerger> CreateOrShareThreadMerger( | 
|  | const fml::RefPtr<fml::RasterThreadMerger>& parent_merger, | 
|  | TaskQueueId platform_id, | 
|  | TaskQueueId raster_id); | 
|  |  | 
|  | // Un-merges the threads now if current caller is the last merge caller, | 
|  | // and it resets the lease term to 0, otherwise it will remove the caller | 
|  | // record and return. The multiple caller records were recorded after | 
|  | // |MergeWithLease| or |ExtendLeaseTo| method. | 
|  | // | 
|  | // Must be executed on the raster task runner. | 
|  | // | 
|  | // If the task queues are the same, we consider them statically merged. | 
|  | // When task queues are statically merged, we never unmerge them and | 
|  | // this method becomes no-op. | 
|  | void UnMergeNowIfLastOne(); | 
|  |  | 
|  | // If the task queues are the same, we consider them statically merged. | 
|  | // When task queues are statically merged this method becomes no-op. | 
|  | void ExtendLeaseTo(size_t lease_term); | 
|  |  | 
|  | // Returns |RasterThreadStatus::kUnmergedNow| if this call resulted in | 
|  | // splitting the raster and platform threads. Reduces the lease term by 1. | 
|  | // | 
|  | // If the task queues are the same, we consider them statically merged. | 
|  | // When task queues are statically merged this method becomes no-op. | 
|  | RasterThreadStatus DecrementLease(); | 
|  |  | 
|  | // The method is locked by current instance, and asks the shared instance of | 
|  | // SharedThreadMerger and the merging state is determined by the | 
|  | // lease_term_ counter. | 
|  | bool IsMerged(); | 
|  |  | 
|  | // Waits until the threads are merged. | 
|  | // | 
|  | // Must run on the platform task runner. | 
|  | void WaitUntilMerged(); | 
|  |  | 
|  | // Returns true if the current thread owns rasterizing. | 
|  | // When the threads are merged, platform thread owns rasterizing. | 
|  | // When un-merged, raster thread owns rasterizing. | 
|  | bool IsOnRasterizingThread(); | 
|  |  | 
|  | // Returns true if the current thread is the platform thread. | 
|  | bool IsOnPlatformThread() const; | 
|  |  | 
|  | // Enables the thread merger. | 
|  | void Enable(); | 
|  |  | 
|  | // Disables the thread merger. Once disabled, any call to | 
|  | // |MergeWithLease| or |UnMergeNowIfLastOne| results in a noop. | 
|  | void Disable(); | 
|  |  | 
|  | // Whether the thread merger is enabled. By default, the thread merger is | 
|  | // enabled. If false, calls to |MergeWithLease| or |UnMergeNowIfLastOne| | 
|  | // or |ExtendLeaseTo| or |DecrementLease| results in a noop. | 
|  | bool IsEnabled(); | 
|  |  | 
|  | // Registers a callback that can be used to clean up global state right after | 
|  | // the thread configuration has changed. | 
|  | // | 
|  | // For example, it can be used to clear the GL context so it can be used in | 
|  | // the next task from a different thread. | 
|  | void SetMergeUnmergeCallback(const fml::closure& callback); | 
|  |  | 
|  | private: | 
|  | fml::TaskQueueId platform_queue_id_; | 
|  | fml::TaskQueueId gpu_queue_id_; | 
|  |  | 
|  | RasterThreadMerger(fml::TaskQueueId platform_queue_id, | 
|  | fml::TaskQueueId gpu_queue_id); | 
|  | RasterThreadMerger(fml::RefPtr<fml::SharedThreadMerger> shared_merger, | 
|  | fml::TaskQueueId platform_queue_id, | 
|  | fml::TaskQueueId gpu_queue_id); | 
|  |  | 
|  | const fml::RefPtr<fml::SharedThreadMerger> shared_merger_; | 
|  | std::condition_variable merged_condition_; | 
|  | std::mutex mutex_; | 
|  | fml::closure merge_unmerge_callback_; | 
|  |  | 
|  | bool IsMergedUnSafe() const; | 
|  |  | 
|  | bool IsEnabledUnSafe() const; | 
|  |  | 
|  | // The platform_queue_id and gpu_queue_id are exactly the same. | 
|  | // We consider the threads are always merged and cannot be unmerged. | 
|  | bool TaskQueuesAreSame() const; | 
|  |  | 
|  | FML_FRIEND_REF_COUNTED_THREAD_SAFE(RasterThreadMerger); | 
|  | FML_FRIEND_MAKE_REF_COUNTED(RasterThreadMerger); | 
|  | FML_DISALLOW_COPY_AND_ASSIGN(RasterThreadMerger); | 
|  | }; | 
|  |  | 
|  | }  // namespace fml | 
|  |  | 
|  | #endif  // FML_SHELL_COMMON_TASK_RUNNER_MERGER_H_ |