Commit 6a449226 authored by David Reveman's avatar David Reveman Committed by Commit Bot

exo: Improve frame callbacks.

Use the compositor frame ack instead of begin-frame callback to
trigger these callbacks. The frame ack is sufficient to prevent
frames from being dropped, and provides minimal latency
back-pressure for clients that implement more advanced
scheduling.

This makes it possible to improve scheduling of frames for
Linux apps significantly. Sommelier can have the next frame
prepared as a dmabuf and ready to commit when we receive the
callback. This minimizes the chance that we'll miss a frame.

BUG=845659
TEST=exo_unittests --gtest_filter=SurfaceTest.RequestFrameCallback
TEST=sommelier /usr/lib/weston/weston-simple-shm
TEST=sommelier -X glxgears

Change-Id: I20f06618d9d550ab501f3945b3d25d4a5c20c218
Reviewed-on: https://chromium-review.googlesource.com/1097776Reviewed-by: default avatarDaniele Castagna <dcastagna@chromium.org>
Commit-Queue: David Reveman <reveman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#567301}
parent 4a5c3582
...@@ -114,12 +114,6 @@ base::WeakPtr<LayerTreeFrameSinkHolder> LayerTreeFrameSinkHolder::GetWeakPtr() { ...@@ -114,12 +114,6 @@ base::WeakPtr<LayerTreeFrameSinkHolder> LayerTreeFrameSinkHolder::GetWeakPtr() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cc::LayerTreeFrameSinkClient overrides: // cc::LayerTreeFrameSinkClient overrides:
void LayerTreeFrameSinkHolder::SetBeginFrameSource(
viz::BeginFrameSource* source) {
if (surface_tree_host_)
surface_tree_host_->SetBeginFrameSource(source);
}
base::Optional<viz::HitTestRegionList> base::Optional<viz::HitTestRegionList>
LayerTreeFrameSinkHolder::BuildHitTestData() { LayerTreeFrameSinkHolder::BuildHitTestData() {
return {}; return {};
......
...@@ -50,7 +50,7 @@ class LayerTreeFrameSinkHolder : public cc::LayerTreeFrameSinkClient, ...@@ -50,7 +50,7 @@ class LayerTreeFrameSinkHolder : public cc::LayerTreeFrameSinkClient,
base::WeakPtr<LayerTreeFrameSinkHolder> GetWeakPtr(); base::WeakPtr<LayerTreeFrameSinkHolder> GetWeakPtr();
// Overridden from cc::LayerTreeFrameSinkClient: // Overridden from cc::LayerTreeFrameSinkClient:
void SetBeginFrameSource(viz::BeginFrameSource* source) override; void SetBeginFrameSource(viz::BeginFrameSource* source) override {}
base::Optional<viz::HitTestRegionList> BuildHitTestData() override; base::Optional<viz::HitTestRegionList> BuildHitTestData() override;
void ReclaimResources( void ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) override; const std::vector<viz::ReturnedResource>& resources) override;
......
...@@ -121,13 +121,11 @@ void SurfaceTreeHost::SetRootSurface(Surface* root_surface) { ...@@ -121,13 +121,11 @@ void SurfaceTreeHost::SetRootSurface(Surface* root_surface) {
root_surface_->SurfaceHierarchyResourcesLost(); root_surface_->SurfaceHierarchyResourcesLost();
root_surface_ = nullptr; root_surface_ = nullptr;
active_frame_callbacks_.splice(active_frame_callbacks_.end(),
frame_callbacks_);
// Call all frame callbacks with a null frame time to indicate that they // Call all frame callbacks with a null frame time to indicate that they
// have been cancelled. // have been cancelled.
while (!active_frame_callbacks_.empty()) { while (!frame_callbacks_.empty()) {
active_frame_callbacks_.front().Run(base::TimeTicks()); frame_callbacks_.front().Run(base::TimeTicks());
active_frame_callbacks_.pop_front(); frame_callbacks_.pop_front();
} }
DCHECK(presentation_callbacks_.empty()); DCHECK(presentation_callbacks_.empty());
...@@ -159,9 +157,10 @@ void SurfaceTreeHost::GetHitTestMask(gfx::Path* mask) const { ...@@ -159,9 +157,10 @@ void SurfaceTreeHost::GetHitTestMask(gfx::Path* mask) const {
} }
void SurfaceTreeHost::DidReceiveCompositorFrameAck() { void SurfaceTreeHost::DidReceiveCompositorFrameAck() {
active_frame_callbacks_.splice(active_frame_callbacks_.end(), while (!frame_callbacks_.empty()) {
frame_callbacks_); frame_callbacks_.front().Run(base::TimeTicks::Now());
UpdateNeedsBeginFrame(); frame_callbacks_.pop_front();
}
} }
void SurfaceTreeHost::DidPresentCompositorFrame( void SurfaceTreeHost::DidPresentCompositorFrame(
...@@ -174,30 +173,6 @@ void SurfaceTreeHost::DidPresentCompositorFrame( ...@@ -174,30 +173,6 @@ void SurfaceTreeHost::DidPresentCompositorFrame(
active_presentation_callbacks_.erase(it); active_presentation_callbacks_.erase(it);
} }
void SurfaceTreeHost::SetBeginFrameSource(
viz::BeginFrameSource* begin_frame_source) {
if (needs_begin_frame_) {
DCHECK(begin_frame_source_);
begin_frame_source_->RemoveObserver(this);
needs_begin_frame_ = false;
}
begin_frame_source_ = begin_frame_source;
UpdateNeedsBeginFrame();
}
void SurfaceTreeHost::UpdateNeedsBeginFrame() {
if (!begin_frame_source_)
return;
bool needs_begin_frame = !active_frame_callbacks_.empty();
if (needs_begin_frame == needs_begin_frame_)
return;
needs_begin_frame_ = needs_begin_frame;
if (needs_begin_frame_)
begin_frame_source_->AddObserver(this);
else
begin_frame_source_->RemoveObserver(this);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// SurfaceDelegate overrides: // SurfaceDelegate overrides:
...@@ -217,31 +192,6 @@ bool SurfaceTreeHost::IsInputEnabled(Surface*) const { ...@@ -217,31 +192,6 @@ bool SurfaceTreeHost::IsInputEnabled(Surface*) const {
return true; return true;
} }
////////////////////////////////////////////////////////////////////////////////
// cc::BeginFrameObserverBase overrides:
bool SurfaceTreeHost::OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) {
current_begin_frame_ack_ =
viz::BeginFrameAck(args.source_id, args.sequence_number, false);
if (!frame_callbacks_.empty()) {
// In this case, the begin frame arrives just before
// |DidReceivedCompositorFrameAck()|, we need more begin frames to run
// |frame_callbacks_| which will be moved to |active_frame_callbacks_| by
// |DidReceivedCompositorFrameAck()| shortly.
layer_tree_frame_sink_holder_->DidNotProduceFrame(current_begin_frame_ack_);
current_begin_frame_ack_.sequence_number =
viz::BeginFrameArgs::kInvalidFrameNumber;
begin_frame_source_->DidFinishFrame(this);
}
while (!active_frame_callbacks_.empty()) {
active_frame_callbacks_.front().Run(args.frame_time);
active_frame_callbacks_.pop_front();
}
return true;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// ui::ContextFactoryObserver overrides: // ui::ContextFactoryObserver overrides:
...@@ -258,15 +208,8 @@ void SurfaceTreeHost::OnLostResources() { ...@@ -258,15 +208,8 @@ void SurfaceTreeHost::OnLostResources() {
void SurfaceTreeHost::SubmitCompositorFrame() { void SurfaceTreeHost::SubmitCompositorFrame() {
DCHECK(root_surface_); DCHECK(root_surface_);
viz::CompositorFrame frame; viz::CompositorFrame frame;
// If we commit while we don't have an active BeginFrame, we acknowledge a frame.metadata.begin_frame_ack =
// manual one. viz::BeginFrameAck::CreateManualAckWithDamage();
if (current_begin_frame_ack_.sequence_number ==
viz::BeginFrameArgs::kInvalidFrameNumber) {
current_begin_frame_ack_ = viz::BeginFrameAck::CreateManualAckWithDamage();
} else {
current_begin_frame_ack_.has_damage = true;
}
frame.metadata.begin_frame_ack = current_begin_frame_ack_;
root_surface_->AppendSurfaceHierarchyCallbacks(&frame_callbacks_, root_surface_->AppendSurfaceHierarchyCallbacks(&frame_callbacks_,
&presentation_callbacks_); &presentation_callbacks_);
if (!presentation_callbacks_.empty()) { if (!presentation_callbacks_.empty()) {
...@@ -315,18 +258,6 @@ void SurfaceTreeHost::SubmitCompositorFrame() { ...@@ -315,18 +258,6 @@ void SurfaceTreeHost::SubmitCompositorFrame() {
} }
layer_tree_frame_sink_holder_->SubmitCompositorFrame(std::move(frame)); layer_tree_frame_sink_holder_->SubmitCompositorFrame(std::move(frame));
if (current_begin_frame_ack_.sequence_number !=
viz::BeginFrameArgs::kInvalidFrameNumber) {
if (!current_begin_frame_ack_.has_damage) {
layer_tree_frame_sink_holder_->DidNotProduceFrame(
current_begin_frame_ack_);
}
current_begin_frame_ack_.sequence_number =
viz::BeginFrameArgs::kInvalidFrameNumber;
if (begin_frame_source_)
begin_frame_source_->DidFinishFrame(this);
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "components/exo/layer_tree_frame_sink_holder.h" #include "components/exo/layer_tree_frame_sink_holder.h"
#include "components/exo/surface.h" #include "components/exo/surface.h"
#include "components/exo/surface_delegate.h" #include "components/exo/surface_delegate.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
namespace aura { namespace aura {
...@@ -22,17 +21,12 @@ namespace gfx { ...@@ -22,17 +21,12 @@ namespace gfx {
class Path; class Path;
} // namespace gfx } // namespace gfx
namespace viz {
class BeginFrameSource;
} // namespace viz
namespace exo { namespace exo {
class LayerTreeFrameSinkHolder; class LayerTreeFrameSinkHolder;
// This class provides functionality for hosting a surface tree. The surface // This class provides functionality for hosting a surface tree. The surface
// tree is hosted in the |host_window_|. // tree is hosted in the |host_window_|.
class SurfaceTreeHost : public SurfaceDelegate, class SurfaceTreeHost : public SurfaceDelegate,
public viz::BeginFrameObserverBase,
public ui::ContextFactoryObserver { public ui::ContextFactoryObserver {
public: public:
explicit SurfaceTreeHost(const std::string& window_name); explicit SurfaceTreeHost(const std::string& window_name);
...@@ -58,12 +52,6 @@ class SurfaceTreeHost : public SurfaceDelegate, ...@@ -58,12 +52,6 @@ class SurfaceTreeHost : public SurfaceDelegate,
void DidPresentCompositorFrame(uint32_t presentation_token, void DidPresentCompositorFrame(uint32_t presentation_token,
const gfx::PresentationFeedback& feedback); const gfx::PresentationFeedback& feedback);
// Called when the begin frame source has changed.
void SetBeginFrameSource(viz::BeginFrameSource* begin_frame_source);
// Adds/Removes begin frame observer based on state.
void UpdateNeedsBeginFrame();
aura::Window* host_window() { return host_window_.get(); } aura::Window* host_window() { return host_window_.get(); }
const aura::Window* host_window() const { return host_window_.get(); } const aura::Window* host_window() const { return host_window_.get(); }
...@@ -87,10 +75,6 @@ class SurfaceTreeHost : public SurfaceDelegate, ...@@ -87,10 +75,6 @@ class SurfaceTreeHost : public SurfaceDelegate,
void OnSetStartupId(const char* startup_id) override {} void OnSetStartupId(const char* startup_id) override {}
void OnSetApplicationId(const char* application_id) override {} void OnSetApplicationId(const char* application_id) override {}
// Overridden from cc::BeginFrameObserverBase:
bool OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) override;
void OnBeginFrameSourcePausedChanged(bool paused) override {}
// Overridden from ui::ContextFactoryObserver: // Overridden from ui::ContextFactoryObserver:
void OnLostResources() override; void OnLostResources() override;
...@@ -110,18 +94,11 @@ class SurfaceTreeHost : public SurfaceDelegate, ...@@ -110,18 +94,11 @@ class SurfaceTreeHost : public SurfaceDelegate,
std::unique_ptr<aura::Window> host_window_; std::unique_ptr<aura::Window> host_window_;
std::unique_ptr<LayerTreeFrameSinkHolder> layer_tree_frame_sink_holder_; std::unique_ptr<LayerTreeFrameSinkHolder> layer_tree_frame_sink_holder_;
// The begin frame source being observed. // This list contains the callbacks to notify the client when it is a good
viz::BeginFrameSource* begin_frame_source_ = nullptr;
bool needs_begin_frame_ = false;
viz::BeginFrameAck current_begin_frame_ack_;
// These lists contain the callbacks to notify the client when it is a good
// time to start producing a new frame. These callbacks move to // time to start producing a new frame. These callbacks move to
// |frame_callbacks_| when Commit() is called. Later they are moved to // |frame_callbacks_| when Commit() is called. They fire when the effect
// |active_frame_callbacks_| when the effect of the Commit() is scheduled to // of the Commit() is scheduled to be drawn.
// be drawn. They fire at the first begin frame notification after this.
std::list<Surface::FrameCallback> frame_callbacks_; std::list<Surface::FrameCallback> frame_callbacks_;
std::list<Surface::FrameCallback> active_frame_callbacks_;
// These lists contains the callbacks to notify the client when surface // These lists contains the callbacks to notify the client when surface
// contents have been presented. // contents have been presented.
......
...@@ -812,44 +812,6 @@ TEST_P(SurfaceTest, Commit) { ...@@ -812,44 +812,6 @@ TEST_P(SurfaceTest, Commit) {
surface->Commit(); surface->Commit();
} }
TEST_P(SurfaceTest, SendsBeginFrameAcks) {
viz::FakeExternalBeginFrameSource source(0.f, false);
gfx::Size buffer_size(1, 1);
auto buffer = std::make_unique<Buffer>(
exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D, 0,
true, true);
auto surface = std::make_unique<Surface>();
auto shell_surface = std::make_unique<ShellSurface>(surface.get());
shell_surface->SetBeginFrameSource(&source);
surface->Attach(buffer.get());
// Request a frame callback so that Surface now needs BeginFrames.
base::TimeTicks frame_time;
surface->RequestFrameCallback(
base::Bind(&SetFrameTime, base::Unretained(&frame_time)));
surface->Commit(); // Move callback from pending callbacks to current ones.
RunAllPendingInMessageLoop();
// Surface should add itself as observer during
// DidReceiveCompositorFrameAck().
shell_surface->DidReceiveCompositorFrameAck();
EXPECT_EQ(1u, source.num_observers());
viz::BeginFrameArgs args(source.CreateBeginFrameArgs(BEGINFRAME_FROM_HERE));
args.frame_time = base::TimeTicks::FromInternalValue(100);
source.TestOnBeginFrame(args); // Runs the frame callback.
EXPECT_EQ(args.frame_time, frame_time);
surface->Commit(); // Acknowledges the BeginFrame via CompositorFrame.
RunAllPendingInMessageLoop();
const viz::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
viz::BeginFrameAck expected_ack(args.source_id, args.sequence_number, true);
EXPECT_EQ(expected_ack, frame.metadata.begin_frame_ack);
// TODO(eseckler): Add test for DidNotProduceFrame plumbing.
}
TEST_P(SurfaceTest, RemoveSubSurface) { TEST_P(SurfaceTest, RemoveSubSurface) {
gfx::Size buffer_size(256, 256); gfx::Size buffer_size(256, 256);
std::unique_ptr<Buffer> buffer( std::unique_ptr<Buffer> buffer(
......
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