1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119

cc / trees / occlusion_tracker.h [blame]

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CC_TREES_OCCLUSION_TRACKER_H_
#define CC_TREES_OCCLUSION_TRACKER_H_

#include <vector>

#include "base/memory/raw_ptr_exclusion.h"
#include "cc/base/simple_enclosed_region.h"
#include "cc/cc_export.h"
#include "cc/layers/effect_tree_layer_list_iterator.h"
#include "cc/trees/occlusion.h"
#include "ui/gfx/geometry/rect.h"

namespace cc {
class LayerImpl;
class Region;
class RenderSurfaceImpl;

// This class is used to track occlusion of layers while traversing them in a
// front-to-back order. As each layer is visited, one of the methods in this
// class is called to notify it about the current target surface. Then,
// occlusion in the content space of the current layer may be queried, via
// Occlusion from GetCurrentOcclusionForLayer(). If the current layer owns a
// RenderSurfaceImpl, then occlusion on that RenderSurfaceImpl may also be
// queried via surfaceOccluded() and surfaceUnoccludedContentRect(). Finally,
// once finished with the layer, occlusion behind the layer should be marked by
// calling MarkOccludedBehindLayer().
class CC_EXPORT OcclusionTracker {
 public:
  explicit OcclusionTracker(const gfx::Rect& screen_space_clip_rect);
  OcclusionTracker(const OcclusionTracker&) = delete;
  ~OcclusionTracker();

  OcclusionTracker& operator=(const OcclusionTracker&) = delete;

  // Return an occlusion that retains the current state of the tracker
  // and can be used outside of a layer walk to check occlusion.
  Occlusion GetCurrentOcclusionForLayer(
      const gfx::Transform& draw_transform) const;
  Occlusion GetCurrentOcclusionForContributingSurface(
      const gfx::Transform& draw_transform) const;

  const RenderSurfaceImpl* OcclusionSurfaceForContributingSurface() const;
  // Called at the beginning of each step in EffectTreeLayerListIterator's
  // front-to-back traversal.
  void EnterLayer(const EffectTreeLayerListIterator::Position& iterator);
  // Called at the end of each step in EffectTreeLayerListIterator's
  // front-to-back traversal.
  void LeaveLayer(const EffectTreeLayerListIterator::Position& iterator);

  // Gives the region of the screen that is not occluded by something opaque.
  Region ComputeVisibleRegionInScreen(const LayerTreeImpl* layer_tree) const;

  void set_minimum_tracking_size(const gfx::Size& size) {
    minimum_tracking_size_ = size;
  }

 protected:
  struct StackObject {
    StackObject() : target(nullptr) {}
    explicit StackObject(const RenderSurfaceImpl* target) : target(target) {}
    // RAW_PTR_EXCLUSION: Performance reasons: on-stack (temporary) vector +
    // based on analysis of sampling profiler data
    // (LayerTreeImpl::UpdateDrawProperties -> OcclusionTracker::EnterLayer ->
    // OcclusionTracker::EnterRenderTarget -> emplaces StackObject in a vector;
    // ... -> OcclusionTracker::LeaveLayer ->
    // OcclusionTracker::LeaveToRenderTarget -> pops StackObject from a vector).
    RAW_PTR_EXCLUSION const RenderSurfaceImpl* target;
    SimpleEnclosedRegion occlusion_from_outside_target;
    SimpleEnclosedRegion occlusion_from_inside_target;
    bool ignores_parent_occlusion = false;
  };

  // The stack holds occluded regions for subtrees in the
  // RenderSurfaceImpl-Layer tree, so that when we leave a subtree we may apply
  // a mask to it, but not to the parts outside the subtree.
  // - The first time we see a new subtree under a target, we add that target to
  // the top of the stack. This can happen as a layer representing itself, or as
  // a target surface.
  // - When we visit a target surface, we apply its mask to its subtree, which
  // is at the top of the stack.
  // - When we visit a layer representing itself, we add its occlusion to the
  // current subtree, which is at the top of the stack.
  // - When we visit a layer representing a contributing surface, the current
  // target will never be the top of the stack since we just came from the
  // contributing surface.
  // We merge the occlusion at the top of the stack with the new current
  // subtree. This new target is pushed onto the stack if not already there.
  std::vector<StackObject> stack_;

 private:
  // Called when visiting a layer. If the target was not already current, then
  // this indicates we have entered a new surface subtree.
  void EnterRenderTarget(const RenderSurfaceImpl* new_target_surface);

  // Called when visiting a target surface. This indicates we have visited all
  // the layers within the surface, and we may perform any surface-wide
  // operations.
  void FinishedRenderTarget(const RenderSurfaceImpl* finished_target_surface);

  // Called when visiting a contributing surface. This indicates that we are
  // leaving our current surface, and entering the new one. We then perform any
  // operations required for merging results from the child subtree into its
  // parent.
  void LeaveToRenderTarget(const RenderSurfaceImpl* new_target_surface);

  // Add the layer's occlusion to the tracked state.
  void MarkOccludedBehindLayer(const LayerImpl* layer);

  gfx::Rect screen_space_clip_rect_;
  gfx::Size minimum_tracking_size_;
};

}  // namespace cc

#endif  // CC_TREES_OCCLUSION_TRACKER_H_