Commit 2336dd21 authored by Stefan Zager's avatar Stefan Zager Committed by Commit Bot

Invalidate hit test data when a surface becomes active

viz::HitTestManager::submit_hit_test_region_list_index_ is used to avoid
sending hit test information to the browser if the underlying hit test
data hasn't changed. It increments the index every time a new batch of
hit test data arrives from a renderer process. However, there is another
way that hit test data can be invalidated, requiring hit test data to
be re-aggregated and sent to the browser:

HitTestAggregator::Aggregate is not a simple pass-through for the data
collected by HitTestManager. It also modifies flags on the hit test
regions, based on whether or not a surface is active (see
HitTestRegionFlags::kHitTestNotActive). "Active", in this case, does
*not* mean that the surface has submitted a compositor frame. Rather,
it means that the surface has submitted a compositor frame *and* the
frame was included in the output of SurfaceAggregator::Aggregate. It is
possible for a surface to change from inactive to active without
triggering the re-aggregation of hit test data. In particular:

- child surface submits a compositor frame with hit test data
- SurfaceAggregator omits the child surface, because the parent surface
  has not yet reported bounds for the child surface.
- HitTestAggregator marks the child surface's hit test regions as
  kHitTestNotActive.
- parent surface submits a compositor frame with bounds for the child
  surface, but without new hit test data.

In this situation, HitTestAggregator will never send new hit test data
to the browser with updated flags for the child surface's regions.

I have not seen this fail in the wild, but then again I don't generally
pay attention to viz bugs. For the bug in question, I have a separate
fix in blink; but that fix causes some changes in the order of data
sent from the renderer to viz, which exacerbates this hit test data
problem, causing failures in SitePerProcessHitTestBrowsertest.

BUG=1033746

Change-Id: Ic338ad64465a1427ed29017b20370b54ed747d76
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2044435
Commit-Queue: Stefan Zager <szager@chromium.org>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Reviewed-by: default avatarYi Gu <yigu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#743307}
parent 276dd144
...@@ -51,6 +51,7 @@ class FrameRateDeciderTest : public testing::Test, ...@@ -51,6 +51,7 @@ class FrameRateDeciderTest : public testing::Test,
const FrameSinkId& frame_sink_id) const override { const FrameSinkId& frame_sink_id) const override {
return base::StringPiece(); return base::StringPiece();
} }
void AggregatedFrameSinksChanged() override {}
protected: protected:
base::WeakPtr<SurfaceClient> surface_client() { base::WeakPtr<SurfaceClient> surface_client() {
......
...@@ -93,6 +93,7 @@ struct SurfaceAggregator::PrewalkResult { ...@@ -93,6 +93,7 @@ struct SurfaceAggregator::PrewalkResult {
// not included in a SurfaceDrawQuad. // not included in a SurfaceDrawQuad.
base::flat_set<SurfaceId> undrawn_surfaces; base::flat_set<SurfaceId> undrawn_surfaces;
bool may_contain_video = false; bool may_contain_video = false;
bool frame_sinks_changed = false;
gfx::ContentColorUsage content_color_usage = gfx::ContentColorUsage::kSRGB; gfx::ContentColorUsage content_color_usage = gfx::ContentColorUsage::kSRGB;
}; };
...@@ -1318,6 +1319,8 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface, ...@@ -1318,6 +1319,8 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
contained_surfaces_[surface->surface_id()] = surface->GetActiveFrameIndex(); contained_surfaces_[surface->surface_id()] = surface->GetActiveFrameIndex();
LocalSurfaceId& local_surface_id = LocalSurfaceId& local_surface_id =
contained_frame_sinks_[surface->surface_id().frame_sink_id()]; contained_frame_sinks_[surface->surface_id().frame_sink_id()];
result->frame_sinks_changed |= (!previous_contained_frame_sinks_.contains(
surface->surface_id().frame_sink_id()));
local_surface_id = local_surface_id =
std::max(surface->surface_id().local_surface_id(), local_surface_id); std::max(surface->surface_id().local_surface_id(), local_surface_id);
...@@ -1677,6 +1680,9 @@ CompositorFrame SurfaceAggregator::Aggregate( ...@@ -1677,6 +1680,9 @@ CompositorFrame SurfaceAggregator::Aggregate(
PrewalkTree(surface, false, 0, true /* will_draw */, &prewalk_result); PrewalkTree(surface, false, 0, true /* will_draw */, &prewalk_result);
root_content_color_usage_ = prewalk_result.content_color_usage; root_content_color_usage_ = prewalk_result.content_color_usage;
if (prewalk_result.frame_sinks_changed)
manager_->AggregatedFrameSinksChanged();
PropagateCopyRequestPasses(); PropagateCopyRequestPasses();
has_copy_requests_ = !copy_request_passes_.empty(); has_copy_requests_ = !copy_request_passes_.empty();
frame.metadata.may_contain_video = prewalk_result.may_contain_video; frame.metadata.may_contain_video = prewalk_result.may_contain_video;
......
...@@ -6221,5 +6221,63 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, ...@@ -6221,5 +6221,63 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
aggregated_frame.render_pass_list[4]->damage_rect.ToString()); aggregated_frame.render_pass_list[4]->damage_rect.ToString());
} }
TEST_F(SurfaceAggregatorValidSurfaceTest,
ContainedFrameSinkChangeInvalidatesHitTestData) {
auto embedded_support = std::make_unique<CompositorFrameSinkSupport>(
nullptr, &manager_, kArbitraryFrameSinkId1, kRootIsRoot);
ParentLocalSurfaceIdAllocator embedded_allocator;
embedded_allocator.GenerateId();
LocalSurfaceId embedded_local_surface_id =
embedded_allocator.GetCurrentLocalSurfaceIdAllocation()
.local_surface_id();
SurfaceId embedded_surface_id(embedded_support->frame_sink_id(),
embedded_local_surface_id);
SurfaceId root_surface_id(root_sink_->frame_sink_id(),
root_local_surface_id_);
// First submit a root frame which doesn't reference the embedded frame and
// aggregate.
{
std::vector<Quad> embedded_quads = {
Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5)),
Quad::SolidColorQuad(SK_ColorGRAY, gfx::Rect(5, 5))};
std::vector<Pass> embedded_passes = {Pass(embedded_quads, SurfaceSize())};
SubmitCompositorFrame(embedded_support.get(), embedded_passes,
embedded_local_surface_id, 1.0f);
std::vector<Quad> root_quads = {
Quad::SolidColorQuad(SK_ColorRED, gfx::Rect(5, 5)),
Quad::SolidColorQuad(SK_ColorBLUE, gfx::Rect(5, 5))};
std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
SubmitCompositorFrame(root_sink_.get(), root_passes, root_local_surface_id_,
1.0f);
AggregateFrame(root_surface_id);
}
const HitTestManager* hit_test_manager = manager_.hit_test_manager();
uint64_t hit_test_region_index =
hit_test_manager->submit_hit_test_region_list_index();
// Now submit a root frame that *does* reference the embedded frame, and
// aggregate.
{
std::vector<Quad> root_quads = {
Quad::SurfaceQuad(SurfaceRange(base::nullopt, embedded_surface_id),
SK_ColorWHITE, gfx::Rect(5, 5), false),
Quad::SolidColorQuad(SK_ColorRED, gfx::Rect(5, 5)),
Quad::SolidColorQuad(SK_ColorBLUE, gfx::Rect(5, 5))};
std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
SubmitCompositorFrame(root_sink_.get(), root_passes, root_local_surface_id_,
1.0);
AggregateFrame(root_surface_id);
}
// Check that the HitTestManager was marked as needing to re-aggregate hit
// test data.
EXPECT_GT(hit_test_manager->submit_hit_test_region_list_index(),
hit_test_region_index);
}
} // namespace } // namespace
} // namespace viz } // namespace viz
...@@ -339,6 +339,10 @@ base::StringPiece FrameSinkManagerImpl::GetFrameSinkDebugLabel( ...@@ -339,6 +339,10 @@ base::StringPiece FrameSinkManagerImpl::GetFrameSinkDebugLabel(
return base::StringPiece(); return base::StringPiece();
} }
void FrameSinkManagerImpl::AggregatedFrameSinksChanged() {
hit_test_manager_.SetNeedsSubmit();
}
void FrameSinkManagerImpl::RegisterCompositorFrameSinkSupport( void FrameSinkManagerImpl::RegisterCompositorFrameSinkSupport(
const FrameSinkId& frame_sink_id, const FrameSinkId& frame_sink_id,
CompositorFrameSinkSupport* support) { CompositorFrameSinkSupport* support) {
......
...@@ -145,6 +145,7 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl ...@@ -145,6 +145,7 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
// SurfaceManagerDelegate implementation: // SurfaceManagerDelegate implementation:
base::StringPiece GetFrameSinkDebugLabel( base::StringPiece GetFrameSinkDebugLabel(
const FrameSinkId& frame_sink_id) const override; const FrameSinkId& frame_sink_id) const override;
void AggregatedFrameSinksChanged() override;
// CompositorFrameSinkSupport, hierarchy, and BeginFrameSource can be // CompositorFrameSinkSupport, hierarchy, and BeginFrameSource can be
// registered and unregistered in any order with respect to each other. // registered and unregistered in any order with respect to each other.
......
...@@ -64,6 +64,7 @@ class VIZ_SERVICE_EXPORT HitTestManager : public SurfaceObserver { ...@@ -64,6 +64,7 @@ class VIZ_SERVICE_EXPORT HitTestManager : public SurfaceObserver {
uint64_t submit_hit_test_region_list_index() const { uint64_t submit_hit_test_region_list_index() const {
return submit_hit_test_region_list_index_; return submit_hit_test_region_list_index_;
} }
void SetNeedsSubmit() { submit_hit_test_region_list_index_++; }
private: private:
bool ValidateHitTestRegionList(const SurfaceId& surface_id, bool ValidateHitTestRegionList(const SurfaceId& surface_id,
......
...@@ -641,4 +641,9 @@ bool SurfaceManager::HasBlockedEmbedder( ...@@ -641,4 +641,9 @@ bool SurfaceManager::HasBlockedEmbedder(
return false; return false;
} }
void SurfaceManager::AggregatedFrameSinksChanged() {
if (delegate_)
delegate_->AggregatedFrameSinksChanged();
}
} // namespace viz } // namespace viz
...@@ -193,6 +193,10 @@ class VIZ_SERVICE_EXPORT SurfaceManager { ...@@ -193,6 +193,10 @@ class VIZ_SERVICE_EXPORT SurfaceManager {
// |frame_sink_id|. // |frame_sink_id|.
bool HasBlockedEmbedder(const FrameSinkId& frame_sink_id) const; bool HasBlockedEmbedder(const FrameSinkId& frame_sink_id) const;
// Indicates that the set of frame sinks being aggregated for display has
// changed since the previous aggregation.
void AggregatedFrameSinksChanged();
private: private:
friend class CompositorFrameSinkSupportTest; friend class CompositorFrameSinkSupportTest;
friend class FrameSinkManagerTest; friend class FrameSinkManagerTest;
......
...@@ -17,6 +17,10 @@ class VIZ_SERVICE_EXPORT SurfaceManagerDelegate { ...@@ -17,6 +17,10 @@ class VIZ_SERVICE_EXPORT SurfaceManagerDelegate {
// Returns the debug label associated with |frame_sink_id| if any. // Returns the debug label associated with |frame_sink_id| if any.
virtual base::StringPiece GetFrameSinkDebugLabel( virtual base::StringPiece GetFrameSinkDebugLabel(
const FrameSinkId& frame_sink_id) const = 0; const FrameSinkId& frame_sink_id) const = 0;
// Indicates that the set of frame sinks being aggregated for display has
// changed since the previous aggregation.
virtual void AggregatedFrameSinksChanged() = 0;
}; };
} // namespace viz } // namespace viz
......
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