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