chromium/ui/compositor/recyclable_compositor_mac.cc

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

#include "ui/compositor/recyclable_compositor_mac.h"

#include "base/functional/bind.h"
#include "base/no_destructor.h"
#include "base/task/single_thread_task_runner.h"
#include "components/viz/common/features.h"
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_observer.h"
#include "ui/compositor/compositor_switches.h"
#include "ui/display/types/display_constants.h"

namespace ui {

namespace {

// Returns a task runner for creating a ui::Compositor. This allows compositor
// tasks to be funneled through ui::WindowResizeHelper's task runner to allow
// resize operations to coordinate with frames provided by the GPU process.
scoped_refptr<base::SingleThreadTaskRunner> GetCompositorTaskRunner() {
  // If the WindowResizeHelper's pumpable task runner is set, it means the GPU
  // process is directing messages there, and the compositor can synchronize
  // with it. Otherwise, just use the UI thread.
  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
      ui::WindowResizeHelperMac::Get()->task_runner();
  return task_runner ? task_runner
                     : base::SingleThreadTaskRunner::GetCurrentDefault();
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// RecyclableCompositorMac

RecyclableCompositorMac::RecyclableCompositorMac(
    ui::ContextFactory* context_factory)
    : accelerated_widget_mac_(new ui::AcceleratedWidgetMac()),
      compositor_(context_factory->AllocateFrameSinkId(),
                  context_factory,
                  GetCompositorTaskRunner(),
                  ui::IsPixelCanvasRecordingEnabled()) {
  compositor_.SetAcceleratedWidget(
      accelerated_widget_mac_->accelerated_widget());
  Suspend();
  compositor_.AddObserver(this);
}

RecyclableCompositorMac::~RecyclableCompositorMac() {
  compositor_.RemoveObserver(this);
}

void RecyclableCompositorMac::Suspend() {
  // Requests a compositor lock without a timeout.
  compositor_suspended_lock_ =
      compositor_.GetCompositorLock(nullptr, base::TimeDelta());
}

void RecyclableCompositorMac::Unsuspend() {
  compositor_suspended_lock_ = nullptr;
}

void RecyclableCompositorMac::UpdateSurface(
    const gfx::Size& size_pixels,
    float scale_factor,
    const gfx::DisplayColorSpaces& display_color_spaces,
    int64_t display_id) {
  if (size_pixels != size_pixels_ || scale_factor != scale_factor_) {
    size_pixels_ = size_pixels;
    scale_factor_ = scale_factor;
    local_surface_id_allocator_.GenerateId();
    viz::LocalSurfaceId local_surface_id =
        local_surface_id_allocator_.GetCurrentLocalSurfaceId();
    compositor()->SetScaleAndSize(scale_factor_, size_pixels_,
                                  local_surface_id);
  }
  compositor()->SetDisplayColorSpaces(display_color_spaces);
  compositor()->SetVSyncDisplayID(display_id);
}

void RecyclableCompositorMac::InvalidateSurface() {
  size_pixels_ = gfx::Size();
  scale_factor_ = 1.f;
  local_surface_id_allocator_.Invalidate();
  compositor()->SetScaleAndSize(
      scale_factor_, size_pixels_,
      local_surface_id_allocator_.GetCurrentLocalSurfaceId());
  compositor()->SetDisplayColorSpaces(gfx::DisplayColorSpaces());
  compositor()->SetVSyncDisplayID(display::kInvalidDisplayId);
}

void RecyclableCompositorMac::OnCompositingDidCommit(
    ui::Compositor* compositor_that_did_commit) {
  DCHECK_EQ(compositor_that_did_commit, compositor());
  accelerated_widget_mac_->SetSuspended(false);
}

}  // namespace ui