| Index: ui/android/window_android.cc
|
| diff --git a/ui/android/window_android.cc b/ui/android/window_android.cc
|
| index cff32ba6f571def1c787cd219296027d86f1cbc8..8fc03c5e33fa65a902020468aff4fb2cce87f77c 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,104 @@ 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_(1), 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 +172,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 +214,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 +252,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);
|
|
|