Commit 5c2e137d authored by Sadrul Habib Chowdhury's avatar Sadrul Habib Chowdhury Committed by Commit Bot

viz: Throttle begin-frames when gpu is busy.

Throttle begin-frames to clients until gpu is done processing the
earlier swaps. This helps with reducing work when the gpu has a high
load, by not sending begin-frames to clients.

The clients always keep receiving the compositor-frame-ack messages
when a surface becomes activated (or replaces an older pending frame),
even if the gpu is busy doing work from earlier frames. So this change
introduces the back pressure by way of withholding begin-frames so
clients have to do less work.

BUG=877906

Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel
Change-Id: If34eb5c5af03961e17932c8f57caf352d0362bab
Reviewed-on: https://chromium-review.googlesource.com/c/1282219Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Commit-Queue: Sadrul Chowdhury <sadrul@chromium.org>
Cr-Commit-Position: refs/heads/master@{#601383}
parent 369947b4
...@@ -90,6 +90,25 @@ BeginFrameSource::BeginFrameSource(uint32_t restart_id) ...@@ -90,6 +90,25 @@ BeginFrameSource::BeginFrameSource(uint32_t restart_id)
BeginFrameSource::~BeginFrameSource() = default; BeginFrameSource::~BeginFrameSource() = default;
void BeginFrameSource::SetIsGpuBusy(bool busy) {
if (is_gpu_busy_ == busy)
return;
is_gpu_busy_ = busy;
if (is_gpu_busy_) {
DCHECK(!request_notification_on_gpu_availability_);
} else if (request_notification_on_gpu_availability_) {
request_notification_on_gpu_availability_ = false;
OnGpuNoLongerBusy();
}
}
bool BeginFrameSource::RequestCallbackOnGpuAvailable() {
if (!is_gpu_busy_)
return false;
request_notification_on_gpu_availability_ = true;
return true;
}
void BeginFrameSource::AsValueInto( void BeginFrameSource::AsValueInto(
base::trace_event::TracedValue* state) const { base::trace_event::TracedValue* state) const {
// The lower 32 bits of source_id are the interesting piece of |source_id_|. // The lower 32 bits of source_id are the interesting piece of |source_id_|.
...@@ -154,7 +173,13 @@ bool BackToBackBeginFrameSource::IsThrottled() const { ...@@ -154,7 +173,13 @@ bool BackToBackBeginFrameSource::IsThrottled() const {
return false; return false;
} }
void BackToBackBeginFrameSource::OnGpuNoLongerBusy() {
OnTimerTick();
}
void BackToBackBeginFrameSource::OnTimerTick() { void BackToBackBeginFrameSource::OnTimerTick() {
if (RequestCallbackOnGpuAvailable())
return;
base::TimeTicks frame_time = time_source_->LastTickTime(); base::TimeTicks frame_time = time_source_->LastTickTime();
base::TimeDelta default_interval = BeginFrameArgs::DefaultInterval(); base::TimeDelta default_interval = BeginFrameArgs::DefaultInterval();
BeginFrameArgs args = BeginFrameArgs::Create( BeginFrameArgs args = BeginFrameArgs::Create(
...@@ -229,17 +254,7 @@ void DelayBasedBeginFrameSource::AddObserver(BeginFrameObserver* obs) { ...@@ -229,17 +254,7 @@ void DelayBasedBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
} }
BeginFrameArgs missed_args = last_begin_frame_args_; BeginFrameArgs missed_args = last_begin_frame_args_;
missed_args.type = BeginFrameArgs::MISSED; missed_args.type = BeginFrameArgs::MISSED;
IssueBeginFrameToObserver(obs, missed_args);
BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs();
if (!last_args.IsValid() ||
(missed_args.frame_time >
last_args.frame_time + missed_args.interval / kDoubleTickDivisor)) {
DCHECK(missed_args.sequence_number > last_args.sequence_number ||
missed_args.source_id != last_args.source_id)
<< "missed " << missed_args.AsValue()->ToString() << ", last "
<< last_args.AsValue()->ToString();
FilterAndIssueBeginFrame(obs, missed_args);
}
} }
void DelayBasedBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) { void DelayBasedBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
...@@ -255,17 +270,33 @@ bool DelayBasedBeginFrameSource::IsThrottled() const { ...@@ -255,17 +270,33 @@ bool DelayBasedBeginFrameSource::IsThrottled() const {
return true; return true;
} }
void DelayBasedBeginFrameSource::OnGpuNoLongerBusy() {
OnTimerTick();
}
void DelayBasedBeginFrameSource::OnTimerTick() { void DelayBasedBeginFrameSource::OnTimerTick() {
if (RequestCallbackOnGpuAvailable())
return;
last_begin_frame_args_ = CreateBeginFrameArgs(time_source_->LastTickTime()); last_begin_frame_args_ = CreateBeginFrameArgs(time_source_->LastTickTime());
std::unordered_set<BeginFrameObserver*> observers(observers_); std::unordered_set<BeginFrameObserver*> observers(observers_);
for (auto* obs : observers) { for (auto* obs : observers)
BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs(); IssueBeginFrameToObserver(obs, last_begin_frame_args_);
if (!last_args.IsValid() || }
(last_begin_frame_args_.frame_time >
last_args.frame_time + void DelayBasedBeginFrameSource::IssueBeginFrameToObserver(
last_begin_frame_args_.interval / kDoubleTickDivisor)) { BeginFrameObserver* obs,
FilterAndIssueBeginFrame(obs, last_begin_frame_args_); const BeginFrameArgs& args) {
BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs();
if (!last_args.IsValid() ||
(args.frame_time >
last_args.frame_time + args.interval / kDoubleTickDivisor)) {
if (args.type == BeginFrameArgs::MISSED) {
DCHECK(args.sequence_number > last_args.sequence_number ||
args.source_id != last_args.source_id)
<< "missed " << args.AsValue()->ToString() << ", last "
<< last_args.AsValue()->ToString();
} }
FilterAndIssueBeginFrame(obs, args);
} }
} }
...@@ -324,6 +355,11 @@ bool ExternalBeginFrameSource::IsThrottled() const { ...@@ -324,6 +355,11 @@ bool ExternalBeginFrameSource::IsThrottled() const {
return true; return true;
} }
void ExternalBeginFrameSource::OnGpuNoLongerBusy() {
OnBeginFrame(pending_begin_frame_args_);
pending_begin_frame_args_ = BeginFrameArgs();
}
void ExternalBeginFrameSource::OnSetBeginFrameSourcePaused(bool paused) { void ExternalBeginFrameSource::OnSetBeginFrameSourcePaused(bool paused) {
if (paused_ == paused) if (paused_ == paused)
return; return;
...@@ -342,6 +378,11 @@ void ExternalBeginFrameSource::OnBeginFrame(const BeginFrameArgs& args) { ...@@ -342,6 +378,11 @@ void ExternalBeginFrameSource::OnBeginFrame(const BeginFrameArgs& args) {
args.sequence_number <= last_begin_frame_args_.sequence_number))) args.sequence_number <= last_begin_frame_args_.sequence_number)))
return; return;
if (RequestCallbackOnGpuAvailable()) {
pending_begin_frame_args_ = args;
return;
}
last_begin_frame_args_ = args; last_begin_frame_args_ = args;
std::unordered_set<BeginFrameObserver*> observers(observers_); std::unordered_set<BeginFrameObserver*> observers(observers_);
for (auto* obs : observers) { for (auto* obs : observers) {
......
...@@ -130,6 +130,10 @@ class VIZ_COMMON_EXPORT BeginFrameSource { ...@@ -130,6 +130,10 @@ class VIZ_COMMON_EXPORT BeginFrameSource {
// BeginFrames created by other sources, with different IDs. // BeginFrames created by other sources, with different IDs.
uint64_t source_id() const { return source_id_; } uint64_t source_id() const { return source_id_; }
// Sets whether the gpu is busy or not. See below the documentation for
// RequestCallbackOnGpuAvailable() for more details.
void SetIsGpuBusy(bool busy);
// BeginFrameObservers use DidFinishFrame to provide back pressure to a frame // BeginFrameObservers use DidFinishFrame to provide back pressure to a frame
// source about frame processing (rather than toggling SetNeedsBeginFrames // source about frame processing (rather than toggling SetNeedsBeginFrames
// every frame). For example, the BackToBackFrameSource uses them to make sure // every frame). For example, the BackToBackFrameSource uses them to make sure
...@@ -147,12 +151,27 @@ class VIZ_COMMON_EXPORT BeginFrameSource { ...@@ -147,12 +151,27 @@ class VIZ_COMMON_EXPORT BeginFrameSource {
virtual void AsValueInto(base::trace_event::TracedValue* state) const; virtual void AsValueInto(base::trace_event::TracedValue* state) const;
protected:
// Returns whether begin-frames to clients should be withheld (because the gpu
// is still busy, for example). If this returns true, then OnGpuNoLongerBusy()
// will be called once the gpu becomes available and the begin-frames can be
// dispatched to clients again.
bool RequestCallbackOnGpuAvailable();
virtual void OnGpuNoLongerBusy() = 0;
private: private:
// The higher 32 bits are used for a process restart id that changes if a // The higher 32 bits are used for a process restart id that changes if a
// process allocating BeginFrameSources has been restarted. The lower 32 bits // process allocating BeginFrameSources has been restarted. The lower 32 bits
// are allocated from an atomic sequence. // are allocated from an atomic sequence.
const uint64_t source_id_; const uint64_t source_id_;
// The BeginFrameSource should not send the begin-frame messages to clients if
// gpu is busy.
bool is_gpu_busy_ = false;
// Keeps track of whether a begin-frame was paused, and whether
// OnGpuNoLongerBusy() should be invoked when the gpu is no longer busy.
bool request_notification_on_gpu_availability_ = false;
DISALLOW_COPY_AND_ASSIGN(BeginFrameSource); DISALLOW_COPY_AND_ASSIGN(BeginFrameSource);
}; };
...@@ -165,6 +184,7 @@ class VIZ_COMMON_EXPORT StubBeginFrameSource : public BeginFrameSource { ...@@ -165,6 +184,7 @@ class VIZ_COMMON_EXPORT StubBeginFrameSource : public BeginFrameSource {
void AddObserver(BeginFrameObserver* obs) override {} void AddObserver(BeginFrameObserver* obs) override {}
void RemoveObserver(BeginFrameObserver* obs) override {} void RemoveObserver(BeginFrameObserver* obs) override {}
bool IsThrottled() const override; bool IsThrottled() const override;
void OnGpuNoLongerBusy() override {}
}; };
// A frame source which ticks itself independently. // A frame source which ticks itself independently.
...@@ -192,6 +212,7 @@ class VIZ_COMMON_EXPORT BackToBackBeginFrameSource ...@@ -192,6 +212,7 @@ class VIZ_COMMON_EXPORT BackToBackBeginFrameSource
void RemoveObserver(BeginFrameObserver* obs) override; void RemoveObserver(BeginFrameObserver* obs) override;
void DidFinishFrame(BeginFrameObserver* obs) override; void DidFinishFrame(BeginFrameObserver* obs) override;
bool IsThrottled() const override; bool IsThrottled() const override;
void OnGpuNoLongerBusy() override;
// SyntheticBeginFrameSource implementation. // SyntheticBeginFrameSource implementation.
void OnUpdateVSyncParameters(base::TimeTicks timebase, void OnUpdateVSyncParameters(base::TimeTicks timebase,
...@@ -225,6 +246,7 @@ class VIZ_COMMON_EXPORT DelayBasedBeginFrameSource ...@@ -225,6 +246,7 @@ class VIZ_COMMON_EXPORT DelayBasedBeginFrameSource
void RemoveObserver(BeginFrameObserver* obs) override; void RemoveObserver(BeginFrameObserver* obs) override;
void DidFinishFrame(BeginFrameObserver* obs) override {} void DidFinishFrame(BeginFrameObserver* obs) override {}
bool IsThrottled() const override; bool IsThrottled() const override;
void OnGpuNoLongerBusy() override;
// SyntheticBeginFrameSource implementation. // SyntheticBeginFrameSource implementation.
void OnUpdateVSyncParameters(base::TimeTicks timebase, void OnUpdateVSyncParameters(base::TimeTicks timebase,
...@@ -235,6 +257,8 @@ class VIZ_COMMON_EXPORT DelayBasedBeginFrameSource ...@@ -235,6 +257,8 @@ class VIZ_COMMON_EXPORT DelayBasedBeginFrameSource
private: private:
BeginFrameArgs CreateBeginFrameArgs(base::TimeTicks frame_time); BeginFrameArgs CreateBeginFrameArgs(base::TimeTicks frame_time);
void IssueBeginFrameToObserver(BeginFrameObserver* obs,
const BeginFrameArgs& args);
std::unique_ptr<DelayBasedTimeSource> time_source_; std::unique_ptr<DelayBasedTimeSource> time_source_;
std::unordered_set<BeginFrameObserver*> observers_; std::unordered_set<BeginFrameObserver*> observers_;
...@@ -270,6 +294,7 @@ class VIZ_COMMON_EXPORT ExternalBeginFrameSource : public BeginFrameSource { ...@@ -270,6 +294,7 @@ class VIZ_COMMON_EXPORT ExternalBeginFrameSource : public BeginFrameSource {
void DidFinishFrame(BeginFrameObserver* obs) override {} void DidFinishFrame(BeginFrameObserver* obs) override {}
bool IsThrottled() const override; bool IsThrottled() const override;
void AsValueInto(base::trace_event::TracedValue* state) const override; void AsValueInto(base::trace_event::TracedValue* state) const override;
void OnGpuNoLongerBusy() override;
void OnSetBeginFrameSourcePaused(bool paused); void OnSetBeginFrameSourcePaused(bool paused);
void OnBeginFrame(const BeginFrameArgs& args); void OnBeginFrame(const BeginFrameArgs& args);
...@@ -286,6 +311,8 @@ class VIZ_COMMON_EXPORT ExternalBeginFrameSource : public BeginFrameSource { ...@@ -286,6 +311,8 @@ class VIZ_COMMON_EXPORT ExternalBeginFrameSource : public BeginFrameSource {
bool paused_ = false; bool paused_ = false;
private: private:
BeginFrameArgs pending_begin_frame_args_;
DISALLOW_COPY_AND_ASSIGN(ExternalBeginFrameSource); DISALLOW_COPY_AND_ASSIGN(ExternalBeginFrameSource);
}; };
......
...@@ -504,18 +504,22 @@ void DisplayScheduler::OnBeginFrameDeadline() { ...@@ -504,18 +504,22 @@ void DisplayScheduler::OnBeginFrameDeadline() {
void DisplayScheduler::DidFinishFrame(bool did_draw) { void DisplayScheduler::DidFinishFrame(bool did_draw) {
DCHECK(begin_frame_source_); DCHECK(begin_frame_source_);
begin_frame_source_->DidFinishFrame(this); begin_frame_source_->DidFinishFrame(this);
BeginFrameAck ack(current_begin_frame_args_, did_draw); BeginFrameAck ack(current_begin_frame_args_, did_draw);
client_->DidFinishFrame(ack); client_->DidFinishFrame(ack);
} }
void DisplayScheduler::DidSwapBuffers() { void DisplayScheduler::DidSwapBuffers() {
pending_swaps_++; pending_swaps_++;
if (pending_swaps_ == max_pending_swaps_)
begin_frame_source_->SetIsGpuBusy(true);
uint32_t swap_id = next_swap_id_++; uint32_t swap_id = next_swap_id_++;
TRACE_EVENT_ASYNC_BEGIN0("viz", "DisplayScheduler:pending_swaps", swap_id); TRACE_EVENT_ASYNC_BEGIN0("viz", "DisplayScheduler:pending_swaps", swap_id);
} }
void DisplayScheduler::DidReceiveSwapBuffersAck() { void DisplayScheduler::DidReceiveSwapBuffersAck() {
begin_frame_source_->SetIsGpuBusy(false);
uint32_t swap_id = next_swap_id_ - pending_swaps_; uint32_t swap_id = next_swap_id_ - pending_swaps_;
pending_swaps_--; pending_swaps_--;
TRACE_EVENT_ASYNC_END0("viz", "DisplayScheduler:pending_swaps", swap_id); TRACE_EVENT_ASYNC_END0("viz", "DisplayScheduler:pending_swaps", swap_id);
......
...@@ -75,6 +75,11 @@ bool PrimaryBeginFrameSource::IsThrottled() const { ...@@ -75,6 +75,11 @@ bool PrimaryBeginFrameSource::IsThrottled() const {
: true; : true;
} }
void PrimaryBeginFrameSource::OnGpuNoLongerBusy() {
// PrimaryBeginFrameSource does not hold back the begin frames. So it doesn't
// need to do anything here.
}
void PrimaryBeginFrameSource::OnNeedsBeginFrames(bool needs_begin_frames) { void PrimaryBeginFrameSource::OnNeedsBeginFrames(bool needs_begin_frames) {
if (needs_begin_frames_ == needs_begin_frames) if (needs_begin_frames_ == needs_begin_frames)
return; return;
......
...@@ -36,6 +36,7 @@ class VIZ_SERVICE_EXPORT PrimaryBeginFrameSource ...@@ -36,6 +36,7 @@ class VIZ_SERVICE_EXPORT PrimaryBeginFrameSource
void AddObserver(BeginFrameObserver* obs) override; void AddObserver(BeginFrameObserver* obs) override;
void RemoveObserver(BeginFrameObserver* obs) override; void RemoveObserver(BeginFrameObserver* obs) override;
bool IsThrottled() const override; bool IsThrottled() const override;
void OnGpuNoLongerBusy() override;
// ExternalBeginFrameSourceClient implementation. // ExternalBeginFrameSourceClient implementation.
void OnNeedsBeginFrames(bool needs_begin_frames) override; void OnNeedsBeginFrames(bool needs_begin_frames) override;
......
...@@ -39,6 +39,7 @@ class FakeExternalBeginFrameSource : public BeginFrameSource { ...@@ -39,6 +39,7 @@ class FakeExternalBeginFrameSource : public BeginFrameSource {
void RemoveObserver(BeginFrameObserver* obs) override; void RemoveObserver(BeginFrameObserver* obs) override;
void DidFinishFrame(BeginFrameObserver* obs) override; void DidFinishFrame(BeginFrameObserver* obs) override;
bool IsThrottled() const override; bool IsThrottled() const override;
void OnGpuNoLongerBusy() override {}
BeginFrameArgs CreateBeginFrameArgs( BeginFrameArgs CreateBeginFrameArgs(
BeginFrameArgs::CreationLocation location); BeginFrameArgs::CreationLocation location);
......
...@@ -42,6 +42,7 @@ class WindowAndroid::WindowBeginFrameSource : public viz::BeginFrameSource { ...@@ -42,6 +42,7 @@ class WindowAndroid::WindowBeginFrameSource : public viz::BeginFrameSource {
void RemoveObserver(viz::BeginFrameObserver* obs) override; void RemoveObserver(viz::BeginFrameObserver* obs) override;
void DidFinishFrame(viz::BeginFrameObserver* obs) override {} void DidFinishFrame(viz::BeginFrameObserver* obs) override {}
bool IsThrottled() const override { return true; } bool IsThrottled() const override { return true; }
void OnGpuNoLongerBusy() override;
void OnVSync(base::TimeTicks frame_time, base::TimeDelta vsync_period); void OnVSync(base::TimeTicks frame_time, base::TimeDelta vsync_period);
void OnPauseChanged(bool paused); void OnPauseChanged(bool paused);
...@@ -96,6 +97,11 @@ void WindowAndroid::WindowBeginFrameSource::RemoveObserver( ...@@ -96,6 +97,11 @@ void WindowAndroid::WindowBeginFrameSource::RemoveObserver(
window_->SetNeedsBeginFrames(false); window_->SetNeedsBeginFrames(false);
} }
void WindowAndroid::WindowBeginFrameSource::OnGpuNoLongerBusy() {
for (auto& obs : observers_)
obs.OnBeginFrame(last_begin_frame_args_);
}
void WindowAndroid::WindowBeginFrameSource::OnVSync( void WindowAndroid::WindowBeginFrameSource::OnVSync(
base::TimeTicks frame_time, base::TimeTicks frame_time,
base::TimeDelta vsync_period) { base::TimeDelta vsync_period) {
...@@ -106,9 +112,9 @@ void WindowAndroid::WindowBeginFrameSource::OnVSync( ...@@ -106,9 +112,9 @@ void WindowAndroid::WindowBeginFrameSource::OnVSync(
deadline, vsync_period, viz::BeginFrameArgs::NORMAL); deadline, vsync_period, viz::BeginFrameArgs::NORMAL);
DCHECK(last_begin_frame_args_.IsValid()); DCHECK(last_begin_frame_args_.IsValid());
next_sequence_number_++; next_sequence_number_++;
if (RequestCallbackOnGpuAvailable())
for (auto& obs : observers_) return;
obs.OnBeginFrame(last_begin_frame_args_); OnGpuNoLongerBusy();
} }
void WindowAndroid::WindowBeginFrameSource::OnPauseChanged(bool paused) { void WindowAndroid::WindowBeginFrameSource::OnPauseChanged(bool paused) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment