Index: ui/android/window_android.cc |
diff --git a/ui/android/window_android.cc b/ui/android/window_android.cc |
index cff32ba6f571def1c787cd219296027d86f1cbc8..49374511ecf588155ad3268ad07d14bfe1729f0d 100644 |
--- a/ui/android/window_android.cc |
+++ b/ui/android/window_android.cc |
@@ -4,12 +4,19 @@ |
#include "ui/android/window_android.h" |
+#include <stdint.h> |
+#include <unordered_set> |
+ |
#include "base/android/context_utils.h" |
#include "base/android/jni_android.h" |
#include "base/android/jni_array.h" |
#include "base/android/jni_string.h" |
#include "base/android/jni_weak_ref.h" |
#include "base/android/scoped_java_ref.h" |
+#include "base/auto_reset.h" |
+#include "base/stl_util.h" |
+#include "cc/output/begin_frame_args.h" |
+#include "cc/scheduler/begin_frame_source.h" |
#include "jni/WindowAndroid_jni.h" |
#include "ui/android/window_android_compositor.h" |
#include "ui/android/window_android_observer.h" |
@@ -21,8 +28,106 @@ using base::android::JavaParamRef; |
using base::android::JavaRef; |
using base::android::ScopedJavaLocalRef; |
+class WindowAndroid::WindowBeginFrameSource : public cc::BeginFrameSource { |
+ public: |
+ explicit WindowBeginFrameSource(WindowAndroid* window) |
+ : window_(window), |
+ next_sequence_number_(cc::BeginFrameArgs::kStartingFrameNumber), |
+ in_on_vsync_(false) {} |
+ ~WindowBeginFrameSource() override {} |
+ |
+ // cc::BeginFrameSource implementation. |
+ void AddObserver(cc::BeginFrameObserver* obs) override; |
+ void RemoveObserver(cc::BeginFrameObserver* obs) override; |
+ void DidFinishFrame(cc::BeginFrameObserver* obs, |
+ const cc::BeginFrameAck& ack) override {} |
+ bool IsThrottled() const override { return true; } |
+ |
+ void OnVSync(base::TimeTicks frame_time, |
+ base::TimeDelta vsync_period); |
+ |
+ private: |
+ WindowAndroid* const window_; |
+ std::unordered_set<cc::BeginFrameObserver*> observers_; |
+ cc::BeginFrameArgs last_begin_frame_args_; |
+ uint64_t next_sequence_number_; |
+ bool in_on_vsync_; |
+}; |
+ |
+void WindowAndroid::WindowBeginFrameSource::AddObserver( |
+ cc::BeginFrameObserver* obs) { |
+ DCHECK(obs); |
+ DCHECK(observers_.find(obs) == observers_.end()); |
+ |
+ observers_.insert(obs); |
+ obs->OnBeginFrameSourcePausedChanged(false); |
+ window_->OnNeedsBeginFramesChange(true); |
+ |
+ // Send a MISSED BeginFrame if possible and necessary. If an observer is added |
+ // during OnVSync(), it will get a NORMAL BeginFrame from OnVSync() instead. |
+ if (!in_on_vsync_ && last_begin_frame_args_.IsValid()) { |
+ cc::BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs(); |
+ if (!last_args.IsValid() || |
+ last_args.sequence_number < last_begin_frame_args_.sequence_number) { |
+ last_begin_frame_args_.type = cc::BeginFrameArgs::MISSED; |
+ // TODO(crbug.com/602485): A deadline doesn't make too much sense |
+ // for a missed BeginFrame (the intention rather is 'immediately'), |
+ // but currently the retro frame logic is very strict in discarding |
+ // BeginFrames. |
+ last_begin_frame_args_.deadline = |
+ base::TimeTicks::Now() + last_begin_frame_args_.interval; |
+ obs->OnBeginFrame(last_begin_frame_args_); |
+ } |
+ } |
+} |
+ |
+void WindowAndroid::WindowBeginFrameSource::RemoveObserver( |
+ cc::BeginFrameObserver* obs) { |
+ DCHECK(obs); |
+ DCHECK(observers_.find(obs) != observers_.end()); |
+ |
+ observers_.erase(obs); |
+ if (observers_.empty()) |
+ window_->OnNeedsBeginFramesChange(false); |
+} |
+ |
+void WindowAndroid::WindowBeginFrameSource::OnVSync( |
+ base::TimeTicks frame_time, |
+ base::TimeDelta vsync_period) { |
+ base::AutoReset<bool> auto_reset(&in_on_vsync_, true); |
+ |
+ // frame time is in the past, so give the next vsync period as the deadline. |
+ base::TimeTicks deadline = frame_time + vsync_period; |
+ last_begin_frame_args_ = cc::BeginFrameArgs::Create( |
+ BEGINFRAME_FROM_HERE, source_id(), next_sequence_number_++, frame_time, |
+ deadline, vsync_period, cc::BeginFrameArgs::NORMAL); |
+ DCHECK(last_begin_frame_args_.IsValid()); |
+ |
+ // Support SynchronousCompositorBrowserFilter: Observers added during vsync |
+ // distribution receive a NORMAL args in addition to the missed ones, after |
+ // all current observers were notified. We also have to support observers |
+ // removing themselves during OnBeginFrame, so we iterate on set copies until |
+ // all observers were notified once. |
+ std::unordered_set<cc::BeginFrameObserver*> notified_observers; |
+ bool observer_was_notified = true; |
+ while (observer_was_notified) { |
+ observer_was_notified = false; |
+ std::unordered_set<cc::BeginFrameObserver*> observers(observers_); |
+ for (auto* obs : observers) { |
+ if (notified_observers.find(obs) == notified_observers.end()) { |
+ obs->OnBeginFrame(last_begin_frame_args_); |
+ notified_observers.insert(obs); |
+ observer_was_notified = true; |
+ } |
+ } |
+ } |
+} |
+ |
WindowAndroid::WindowAndroid(JNIEnv* env, jobject obj, int display_id) |
- : display_id_(display_id), compositor_(NULL) { |
+ : display_id_(display_id), |
+ compositor_(NULL), |
+ begin_frame_source_(new WindowBeginFrameSource(this)), |
+ needs_begin_frames_(false) { |
java_window_.Reset(env, obj); |
} |
@@ -69,6 +174,10 @@ void WindowAndroid::RemoveObserver(WindowAndroidObserver* observer) { |
observer_list_.RemoveObserver(observer); |
} |
+cc::BeginFrameSource* WindowAndroid::GetBeginFrameSource() { |
+ return begin_frame_source_.get(); |
+} |
+ |
void WindowAndroid::AttachCompositor(WindowAndroidCompositor* compositor) { |
if (compositor_ && compositor != compositor_) |
DetachCompositor(); |
@@ -107,10 +216,9 @@ void WindowAndroid::OnVSync(JNIEnv* env, |
base::TimeTicks frame_time(base::TimeTicks::FromInternalValue(time_micros)); |
base::TimeDelta vsync_period( |
base::TimeDelta::FromMicroseconds(period_micros)); |
- for (WindowAndroidObserver& observer : observer_list_) |
- observer.OnVSync(frame_time, vsync_period); |
- if (compositor_) |
- compositor_->OnVSync(frame_time, vsync_period); |
+ begin_frame_source_->OnVSync(frame_time, vsync_period); |
+ if (needs_begin_frames_) |
+ RequestVSyncUpdate(); |
} |
void WindowAndroid::OnVisibilityChanged(JNIEnv* env, |
@@ -146,6 +254,15 @@ bool WindowAndroid::CanRequestPermission(const std::string& permission) { |
base::android::ConvertUTF8ToJavaString(env, permission)); |
} |
+void WindowAndroid::OnNeedsBeginFramesChange(bool needs_begin_frames) { |
+ if (needs_begin_frames_ == needs_begin_frames) |
+ return; |
+ |
+ needs_begin_frames_ = needs_begin_frames; |
+ if (needs_begin_frames_) |
+ RequestVSyncUpdate(); |
+} |
+ |
WindowAndroid* WindowAndroid::GetWindowAndroid() const { |
DCHECK(parent_ == nullptr); |
return const_cast<WindowAndroid*>(this); |