chromium/android_webview/browser/gfx/display_scheduler_webview.cc

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

#include "android_webview/browser/gfx/display_scheduler_webview.h"

#include "android_webview/browser/gfx/root_frame_sink.h"
#include "android_webview/browser/gfx/viz_compositor_thread_runner_webview.h"
#include "base/trace_event/trace_event.h"
#include "components/viz/common/features.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"

namespace android_webview {
DisplaySchedulerWebView::DisplaySchedulerWebView(
    RootFrameSink* root_frame_sink,
    OverlaysInfoProvider* overlays_info_provider)
    : root_frame_sink_(root_frame_sink),
      overlays_info_provider_(overlays_info_provider),
      use_new_invalidate_heuristic_(
          features::UseWebViewNewInvalidateHeuristic()) {
  auto* frame_sink_manager =
      VizCompositorThreadRunnerWebView::GetInstance()->GetFrameSinkManager();

  surface_manager_observation_.Observe(frame_sink_manager->surface_manager());
  frame_sink_manager_observation_.Observe(frame_sink_manager);
}

DisplaySchedulerWebView::~DisplaySchedulerWebView() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}

void DisplaySchedulerWebView::ForceImmediateSwapIfPossible() {
  // We can't swap immediately
  NOTREACHED();
}
void DisplaySchedulerWebView::SetNeedsOneBeginFrame(bool needs_draw) {
  NOTREACHED();
}
void DisplaySchedulerWebView::DidSwapBuffers() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);

  // Code below is part of old invalidation heuristic.
  if (use_new_invalidate_heuristic_)
    return;

  bool needs_draw = false;
  for (auto it = damaged_frames_.begin(); it != damaged_frames_.end();) {
    DCHECK_GT(it->second, 0);
    if (!--it->second) {
      it = damaged_frames_.erase(it);
    } else {
      if (!needs_draw) {
        TRACE_EVENT_INSTANT2(
            "android_webview",
            "DisplaySchedulerWebView::DidSwapBuffers first needs_draw",
            TRACE_EVENT_SCOPE_THREAD, "frame_sink_id", it->first.ToString(),
            "damage_count", it->second);
      }
      needs_draw = true;
      ++it;
    }
  }

  root_frame_sink_->SetNeedsDraw(needs_draw);
}
void DisplaySchedulerWebView::OutputSurfaceLost() {
}

bool DisplaySchedulerWebView::IsFrameSinkOverlayed(
    viz::FrameSinkId frame_sink_id) {
  return overlays_info_provider_ &&
         overlays_info_provider_->IsFrameSinkOverlayed(frame_sink_id);
}

void DisplaySchedulerWebView::OnDisplayDamaged(viz::SurfaceId surface_id) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);

  // Code below is part of old invalidation heuristic.
  if (use_new_invalidate_heuristic_)
    return;

  // We don't need to track damage of root frame sink as we submit frame to it
  // at DrawAndSwap and Root Renderer sink because Android View.Invalidation is
  // handled by SynchronousCompositorHost.

  if (surface_id.frame_sink_id() != root_frame_sink_->root_frame_sink_id() &&
      !root_frame_sink_->IsChildSurface(surface_id.frame_sink_id()) &&
      !IsFrameSinkOverlayed(surface_id.frame_sink_id())) {
    int count = damaged_frames_[surface_id.frame_sink_id()] + 1;

    TRACE_EVENT_INSTANT2(
        "android_webview", "DisplaySchedulerWebView::OnDisplayDamaged",
        TRACE_EVENT_SCOPE_THREAD, "frame_sink_id",
        surface_id.frame_sink_id().ToString(), "damage_count", count);

    // Clamp value to max two frames. Two is enough to keep invalidation
    // working, but will prevent number going too high in case if kModeDraw
    // doesn't happen for some time.
    damaged_frames_[surface_id.frame_sink_id()] = std::min(2, count);

    root_frame_sink_->SetNeedsDraw(true);
  }
}

void DisplaySchedulerWebView::OnSurfaceHasNewUncommittedFrame(
    const viz::SurfaceId& surface_id) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);

  // We don't need to track damage of root frame sink as we submit frame to it
  // at DrawAndSwap and Root Renderer sink because Android View.Invalidation is
  // handled by SynchronousCompositorHost.
  const bool is_root =
      surface_id.frame_sink_id() == root_frame_sink_->root_frame_sink_id();
  const bool is_root_renderer =
      root_frame_sink_->IsChildSurface(surface_id.frame_sink_id());
  const bool is_overlay = IsFrameSinkOverlayed(surface_id.frame_sink_id());

  if (!is_root && !is_root_renderer && !is_overlay &&
      damage_tracker_->CheckForDisplayDamage(surface_id)) {
    root_frame_sink_->OnNewUncommittedFrame(surface_id);
  }
}

void DisplaySchedulerWebView::OnCaptureStarted(
    const viz::FrameSinkId& frame_sink_id) {
  root_frame_sink_->OnCaptureStarted(frame_sink_id);
}

}  // namespace android_webview