Commit a4a3af77 authored by yiyix's avatar yiyix Committed by Commit Bot

viz: Optimize transform usage in draw occlusion

The most common transform used in rendering are simple transforms,
such as translation and scaling. This patch is aimed to optimize the
usage of these simple transforms.

We used to transform every draw quad to the target space and verify
that if the draw quad is behind a occlusion region or not. Since these
simple transforms are invertible, we can transform the occlusion
region from the target space to the coordinate space so that we can
do the verification without applying transform on draw quad. The
traversal speed is increased by 8 times as shown here:
https://docs.google.com/document/d/1gM4h1ca2jDWdXbYa9yjC53m0sJzaT9skqbPGnfDsdyI/edit#heading=h.7y9syhsnunpw

Before:
98.26% viz::Display::RemoveOverdrawQuads(CompositorFrame)
  95.58% viz::Display::RemoveOverdrawQuads(CompositorFrame)
  53.17% cc::MathUtil::MapEnclosingClippedRect(gfx::Transform, Rect)
  9.36% cc::ListContainer::viz::DrawQuad::Iterator
  9.07% cc::ListContainer::viz::SharedQuadState::end
  6.77% cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(gfx::Transform, Rect)
  5.20% cc::SimpleEnclosedRegion::Union(gfx::Rect)
  4.46% cc::SimpleEnclosedRegion::Contains(gfx::Rect)
  2.28% cc::ListContainerHelper::PositionInCharAllocator

After applying this patch,
https://chromium-review.googlesource.com/c/chromium/src/+/783799
and https://chromium-review.googlesource.com/c/chromium/src/+/782063:
97.37% viz::Display::RemoveOverdrawQuads(CompositorFrame)
  1.23% cc::LapTimer::NextLap()
  0.48% cc::ListContainer::viz::SharedQuadState::ReverseIterator
  0.21% gfx::Rect::IsEmpty()
  0.17% gfx::Transform(SkMatrix44)
  0.09% cc::LapTimer::HasTimeLimitExpired()
  0.08% cc::ListContainerHelper::PositionInCharAllocator


Bug: 
Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel
Change-Id: Iee7fb16e44637489a155101e4cc39e128e45acc4
Reviewed-on: https://chromium-review.googlesource.com/788283
Commit-Queue: Yi Xu <yiyix@chromium.org>
Reviewed-by: default avatardanakj <danakj@chromium.org>
Cr-Commit-Position: refs/heads/master@{#521380}
parent ad2869c0
...@@ -520,7 +520,7 @@ void Display::RemoveOverdrawQuads(CompositorFrame* frame) { ...@@ -520,7 +520,7 @@ void Display::RemoveOverdrawQuads(CompositorFrame* frame) {
return; return;
const SharedQuadState* last_sqs = nullptr; const SharedQuadState* last_sqs = nullptr;
cc::SimpleEnclosedRegion occlusion_region; cc::SimpleEnclosedRegion occlusion_in_target_space;
bool current_sqs_intersects_occlusion = false; bool current_sqs_intersects_occlusion = false;
for (const auto& pass : frame->render_pass_list) { for (const auto& pass : frame->render_pass_list) {
// TODO(yiyix): Add filter effects to draw occlusion calculation and perform // TODO(yiyix): Add filter effects to draw occlusion calculation and perform
...@@ -533,8 +533,9 @@ void Display::RemoveOverdrawQuads(CompositorFrame* frame) { ...@@ -533,8 +533,9 @@ void Display::RemoveOverdrawQuads(CompositorFrame* frame) {
if (pass != frame->render_pass_list.back()) if (pass != frame->render_pass_list.back())
continue; continue;
auto last_quad = pass->quad_list.end(); auto quad_list_end = pass->quad_list.end();
for (auto quad = pass->quad_list.begin(); quad != last_quad;) { gfx::Rect occlusion_in_quad_content_space;
for (auto quad = pass->quad_list.begin(); quad != quad_list_end;) {
// RenderPassDrawQuad is a special type of DrawQuad where the visible_rect // RenderPassDrawQuad is a special type of DrawQuad where the visible_rect
// of shared quad state is not entirely covered by draw quads in it. // of shared quad state is not entirely covered by draw quads in it.
if (quad->material == ContentDrawQuadBase::Material::RENDER_PASS) { if (quad->material == ContentDrawQuadBase::Material::RENDER_PASS) {
...@@ -560,15 +561,43 @@ void Display::RemoveOverdrawQuads(CompositorFrame* frame) { ...@@ -560,15 +561,43 @@ void Display::RemoveOverdrawQuads(CompositorFrame* frame) {
if (last_sqs->is_clipped) if (last_sqs->is_clipped)
sqs_rect_in_target.Intersect(last_sqs->clip_rect); sqs_rect_in_target.Intersect(last_sqs->clip_rect);
occlusion_region.Union(sqs_rect_in_target); occlusion_in_target_space.Union(sqs_rect_in_target);
} }
// If the visible_rect of the current shared quad state does not // If the visible_rect of the current shared quad state does not
// intersect with the occlusion rect, we can skip draw occlusion checks // intersect with the occlusion rect, we can skip draw occlusion checks
// for quads in the current SharedQuadState. // for quads in the current SharedQuadState.
last_sqs = quad->shared_quad_state; last_sqs = quad->shared_quad_state;
current_sqs_intersects_occlusion = current_sqs_intersects_occlusion = occlusion_in_target_space.Intersects(
occlusion_region.Intersects(cc::MathUtil::MapEnclosingClippedRect( cc::MathUtil::MapEnclosingClippedRect(
transform, last_sqs->visible_quad_layer_rect)); transform, last_sqs->visible_quad_layer_rect));
// Compute the occlusion region in the quad content space for scale and
// translation transforms. Note that 0 scale transform will fail the
// positive scale check.
if (current_sqs_intersects_occlusion &&
transform.IsPositiveScaleOrTranslation()) {
gfx::Transform reverse_transform;
bool is_invertible = transform.GetInverse(&reverse_transform);
// Scale transform can be inverted by multiplying 1/scale (given
// scale > 0) and translation transform can be inverted by applying
// the reversed directional translation. Therefore, |transform| is
// always invertible.
DCHECK(is_invertible);
// TODO(yiyix): Make |occlusion_coordinate_space| to work with
// occlusion region consists multiple rect.
DCHECK_EQ(occlusion_in_target_space.GetRegionComplexity(), 1u);
// Since transform can only be a scale or a translation matrix, it is
// safe to use function MapEnclosedRectWith2dAxisAlignedTransform to
// define occluded region in the quad content space with inverted
// transform.
occlusion_in_quad_content_space =
cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
reverse_transform, occlusion_in_target_space.bounds());
} else {
occlusion_in_quad_content_space = gfx::Rect();
}
} }
if (!current_sqs_intersects_occlusion) { if (!current_sqs_intersects_occlusion) {
...@@ -576,13 +605,23 @@ void Display::RemoveOverdrawQuads(CompositorFrame* frame) { ...@@ -576,13 +605,23 @@ void Display::RemoveOverdrawQuads(CompositorFrame* frame) {
continue; continue;
} }
// TODO(yiyix): Using profile tools to analyze bottleneck of this // If the |quad| is not shown on the screen, i.e., covered by the occluded
// algorithm. // region, then remove |quad| from the compositor frame.
if (occlusion_region.Contains(cc::MathUtil::MapEnclosingClippedRect( if (occlusion_in_quad_content_space.Contains(quad->visible_rect)) {
transform, quad->visible_rect))) // Case 1: for simple transforms (scale or translation), the occlusion
// region is defined in the quad content space.
quad = pass->quad_list.EraseAndInvalidateAllPointers(quad); quad = pass->quad_list.EraseAndInvalidateAllPointers(quad);
else
} else if (occlusion_in_quad_content_space.IsEmpty() &&
occlusion_in_target_space.Contains(
cc::MathUtil::MapEnclosingClippedRect(
transform, quad->visible_rect))) {
// Case 2: for non-simple transforms, the occlusion region is defined in
// the target space.
quad = pass->quad_list.EraseAndInvalidateAllPointers(quad);
} else {
++quad; ++quad;
}
} }
} }
} }
......
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