Commit 0b60f14d authored by Kramer Ge's avatar Kramer Ge Committed by Commit Bot

[exo] Pending surface states are cached for synced wl_subsurface

If the surface is a synchronized subsurface, wl_surface.commit on
a sub-surface will accumulate the committed state in a cache, but
the state will not be applied until a parent surface commit.

Reference: https://github.com/wayland-project/wayland/blob/master/protocol/wayland.xml#L2834

Bug: 1123921
Change-Id: I32396bb087db1e06262deca2611615d9f89c930e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2382057Reviewed-by: default avatarDaniele Castagna <dcastagna@chromium.org>
Commit-Queue: Kramer Ge <fangzhoug@chromium.org>
Cr-Commit-Position: refs/heads/master@{#821318}
parent c9d9423e
This diff is collapsed.
...@@ -287,7 +287,7 @@ class Surface final : public ui::PropertyHandler { ...@@ -287,7 +287,7 @@ class Surface final : public ui::PropertyHandler {
bool FillsBoundsOpaquely() const; bool FillsBoundsOpaquely() const;
bool HasPendingDamageForTesting(const gfx::Rect& damage) const { bool HasPendingDamageForTesting(const gfx::Rect& damage) const {
return pending_damage_.Contains(damage); return pending_state_.damage.Contains(damage);
} }
// Set occlusion tracking region for surface. // Set occlusion tracking region for surface.
...@@ -346,6 +346,26 @@ class Surface final : public ui::PropertyHandler { ...@@ -346,6 +346,26 @@ class Surface final : public ui::PropertyHandler {
DISALLOW_COPY_AND_ASSIGN(BufferAttachment); DISALLOW_COPY_AND_ASSIGN(BufferAttachment);
}; };
struct ExtendedState {
ExtendedState();
~ExtendedState();
State basic_state;
// The buffer that will become the content of surface.
BufferAttachment buffer;
// The damage region to schedule paint for.
cc::Region damage;
// These lists contain the callbacks to notify the client when it is a good
// time to start producing a new frame.
std::list<FrameCallback> frame_callbacks;
// These lists contain the callbacks to notify the client when surface
// contents have been presented.
std::list<PresentationCallback> presentation_callbacks;
// The acquire gpu fence to associate with the surface buffer.
std::unique_ptr<gfx::GpuFence> acquire_fence;
};
friend class subtle::PropertyHelper; friend class subtle::PropertyHelper;
// Updates current_resource_ with a new resource id corresponding to the // Updates current_resource_ with a new resource id corresponding to the
...@@ -367,7 +387,7 @@ class Surface final : public ui::PropertyHandler { ...@@ -367,7 +387,7 @@ class Surface final : public ui::PropertyHandler {
void UpdateContentSize(); void UpdateContentSize();
// This returns true when the surface has some contents assigned to it. // This returns true when the surface has some contents assigned to it.
bool has_contents() const { return !current_buffer_.size().IsEmpty(); } bool has_contents() const { return !state_.buffer.size().IsEmpty(); }
// This window has the layer which contains the Surface contents. // This window has the layer which contains the Surface contents.
std::unique_ptr<aura::Window> window_; std::unique_ptr<aura::Window> window_;
...@@ -381,43 +401,19 @@ class Surface final : public ui::PropertyHandler { ...@@ -381,43 +401,19 @@ class Surface final : public ui::PropertyHandler {
// This is the bounds of the last committed surface hierarchy contents. // This is the bounds of the last committed surface hierarchy contents.
gfx::Rect surface_hierarchy_content_bounds_; gfx::Rect surface_hierarchy_content_bounds_;
// This is true when Attach() has been called and new contents should take // This is true when Attach() has been called and new contents should be
// effect next time Commit() is called. // cached next time Commit() is called.
bool has_pending_contents_ = false; bool has_pending_contents_ = false;
// This is true when new contents are cached and should take effect next time
// synchronized CommitSurfaceHierarchy() is called.
bool has_cached_contents_ = false;
// The buffer that will become the content of surface when Commit() is called. // This is the state that has yet to be cached.
BufferAttachment pending_buffer_; ExtendedState pending_state_;
// The damage region to schedule paint for when Commit() is called.
cc::Region pending_damage_;
// The damage region which will be used by
// AppendSurfaceHierarchyContentsToFrame() to generate frame.
cc::Region damage_;
// These lists contains the callbacks to notify the client when it is a good
// time to start producing a new frame. These callbacks move to
// |frame_callbacks_| when Commit() is called. Later they are moved to
// |active_frame_callbacks_| when the effect of the Commit() is scheduled to
// be drawn. They fire at the first begin frame notification after this.
std::list<FrameCallback> pending_frame_callbacks_;
std::list<FrameCallback> frame_callbacks_;
// These lists contains the callbacks to notify the client when surface
// contents have been presented. These callbacks move to
// |presentation_callbacks_| when Commit() is called. Later they are moved to
// |swapping_presentation_callbacks_| when the effect of the Commit() is
// scheduled to be drawn and then moved to |swapped_presentation_callbacks_|
// after receiving VSync parameters update for the previous frame. They fire
// at the next VSync parameters update after that.
std::list<PresentationCallback> pending_presentation_callbacks_;
std::list<PresentationCallback> presentation_callbacks_;
// This is the state that has yet to be committed. // This is the state that has yet to be committed.
State pending_state_; ExtendedState cached_state_;
// This is the state that has been committed. // This is the state that has been committed.
State state_; ExtendedState state_;
// Cumulative input region of surface and its sub-surfaces. // Cumulative input region of surface and its sub-surfaces.
cc::Region hit_test_region_; cc::Region hit_test_region_;
...@@ -430,21 +426,12 @@ class Surface final : public ui::PropertyHandler { ...@@ -430,21 +426,12 @@ class Surface final : public ui::PropertyHandler {
SubSurfaceEntryList pending_sub_surfaces_; SubSurfaceEntryList pending_sub_surfaces_;
SubSurfaceEntryList sub_surfaces_; SubSurfaceEntryList sub_surfaces_;
// The buffer that is currently set as content of surface.
BufferAttachment current_buffer_;
// The last resource that was sent to a surface. // The last resource that was sent to a surface.
viz::TransferableResource current_resource_; viz::TransferableResource current_resource_;
// Whether the last resource that was sent to a surface has an alpha channel. // Whether the last resource that was sent to a surface has an alpha channel.
bool current_resource_has_alpha_ = false; bool current_resource_has_alpha_ = false;
// The acquire gpu fence to associate with the surface buffer when Commit()
// is called.
std::unique_ptr<gfx::GpuFence> pending_acquire_fence_;
// The acquire gpu fence that is currently associated with the surface buffer.
std::unique_ptr<gfx::GpuFence> acquire_fence_;
// This is true if a call to Commit() as been made but // This is true if a call to Commit() as been made but
// CommitSurfaceHierarchy() has not yet been called. // CommitSurfaceHierarchy() has not yet been called.
bool needs_commit_surface_ = false; bool needs_commit_surface_ = false;
......
...@@ -260,6 +260,128 @@ TEST_P(SurfaceTest, SubsurfaceDamageAggregation) { ...@@ -260,6 +260,128 @@ TEST_P(SurfaceTest, SubsurfaceDamageAggregation) {
} }
} }
TEST_P(SurfaceTest, SubsurfaceDamageSynchronizedCommitBehavior) {
gfx::Size buffer_size(256, 512);
auto buffer = std::make_unique<Buffer>(
exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
auto surface = std::make_unique<Surface>();
auto shell_surface = std::make_unique<ShellSurface>(surface.get());
surface->Attach(buffer.get());
gfx::Size child_buffer_size(64, 128);
auto child_buffer = std::make_unique<Buffer>(
exo_test_helper()->CreateGpuMemoryBuffer(child_buffer_size));
auto child_surface = std::make_unique<Surface>();
auto sub_surface =
std::make_unique<SubSurface>(child_surface.get(), surface.get());
// Set commit behavior to synchronized.
sub_surface->SetCommitBehavior(true);
child_surface->Attach(child_buffer.get());
child_surface->Commit();
surface->Commit();
base::RunLoop().RunUntilIdle();
{
// Initial frame has full damage.
const viz::CompositorFrame& frame =
GetFrameFromSurface(shell_surface.get());
const gfx::Rect scaled_damage = gfx::ToNearestRect(gfx::ScaleRect(
gfx::RectF(gfx::Rect(buffer_size)), device_scale_factor()));
EXPECT_EQ(scaled_damage, frame.render_pass_list.back()->damage_rect);
}
const gfx::RectF subsurface_damage(32, 32, 16, 16);
const gfx::RectF subsurface_damage2(0, 0, 16, 16);
int margin = ceil(device_scale_factor());
child_surface->Damage(gfx::ToNearestRect(subsurface_damage));
EXPECT_TRUE(child_surface->HasPendingDamageForTesting(
gfx::ToNearestRect(subsurface_damage)));
// Subsurface damage is cached.
child_surface->Commit();
EXPECT_FALSE(child_surface->HasPendingDamageForTesting(
gfx::ToNearestRect(subsurface_damage)));
base::RunLoop().RunUntilIdle();
{
// Subsurface damage should not be propagated at all.
const viz::CompositorFrame& frame =
GetFrameFromSurface(shell_surface.get());
const gfx::Rect scaled_damage = gfx::ToNearestRect(gfx::ScaleRect(
gfx::RectF(gfx::Rect(buffer_size)), device_scale_factor()));
EXPECT_EQ(scaled_damage, frame.render_pass_list.back()->damage_rect);
}
// Damage but do not commit.
child_surface->Damage(gfx::ToNearestRect(subsurface_damage2));
EXPECT_TRUE(child_surface->HasPendingDamageForTesting(
gfx::ToNearestRect(subsurface_damage2)));
// Apply subsurface damage from cached state, not pending state.
surface->Commit();
base::RunLoop().RunUntilIdle();
{
// Subsurface damage in cached state should be propagated.
const viz::CompositorFrame& frame =
GetFrameFromSurface(shell_surface.get());
const gfx::Rect scaled_damage = gfx::ToNearestRect(
gfx::ScaleRect(subsurface_damage, device_scale_factor()));
EXPECT_TRUE(scaled_damage.ApproximatelyEqual(
frame.render_pass_list.back()->damage_rect, margin));
}
}
TEST_P(SurfaceTest, SubsurfaceDamageDesynchronizedCommitBehavior) {
gfx::Size buffer_size(256, 512);
auto buffer = std::make_unique<Buffer>(
exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
auto surface = std::make_unique<Surface>();
auto shell_surface = std::make_unique<ShellSurface>(surface.get());
surface->Attach(buffer.get());
gfx::Size child_buffer_size(64, 128);
auto child_buffer = std::make_unique<Buffer>(
exo_test_helper()->CreateGpuMemoryBuffer(child_buffer_size));
auto child_surface = std::make_unique<Surface>();
auto sub_surface =
std::make_unique<SubSurface>(child_surface.get(), surface.get());
// Set commit behavior to desynchronized.
sub_surface->SetCommitBehavior(false);
child_surface->Attach(child_buffer.get());
child_surface->Commit();
surface->Commit();
base::RunLoop().RunUntilIdle();
{
// Initial frame has full damage.
const viz::CompositorFrame& frame =
GetFrameFromSurface(shell_surface.get());
const gfx::Rect scaled_damage = gfx::ToNearestRect(gfx::ScaleRect(
gfx::RectF(gfx::Rect(buffer_size)), device_scale_factor()));
EXPECT_EQ(scaled_damage, frame.render_pass_list.back()->damage_rect);
}
const gfx::RectF subsurface_damage(32, 32, 16, 16);
int margin = ceil(device_scale_factor());
child_surface->Damage(gfx::ToNearestRect(subsurface_damage));
EXPECT_TRUE(child_surface->HasPendingDamageForTesting(
gfx::ToNearestRect(subsurface_damage)));
// Subsurface damage is applied.
child_surface->Commit();
EXPECT_FALSE(child_surface->HasPendingDamageForTesting(
gfx::ToNearestRect(subsurface_damage)));
base::RunLoop().RunUntilIdle();
{
// Subsurface damage should be propagated.
const viz::CompositorFrame& frame =
GetFrameFromSurface(shell_surface.get());
const gfx::Rect scaled_damage = gfx::ToNearestRect(
gfx::ScaleRect(subsurface_damage, device_scale_factor()));
EXPECT_TRUE(scaled_damage.ApproximatelyEqual(
frame.render_pass_list.back()->damage_rect, margin));
}
}
void SetFrameTime(base::TimeTicks* result, base::TimeTicks frame_time) { void SetFrameTime(base::TimeTicks* result, base::TimeTicks frame_time) {
*result = frame_time; *result = frame_time;
} }
......
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