blob: 4ec862c0825dea9d4a9be98b1c888222b4ab6378 [file]
// Copyright 2025 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/display/mac/vsync_provider_mac.h"
#include "base/logging.h"
#include "base/task/bind_post_task.h"
#include "base/trace_event/trace_event.h"
namespace ui {
// static
VSyncProviderMac* VSyncProviderMac::GetInstance() {
static base::NoDestructor<VSyncProviderMac> provider;
return provider.get();
}
VSyncProviderMac::VSyncProviderMac()
: task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {}
VSyncProviderMac::~VSyncProviderMac() = default;
void VSyncProviderMac::SetSupportedDisplayLinkId(int64_t display_id,
bool is_supported) {
if (is_supported) {
AddSupportedDisplayLinkId(display_id);
} else {
RemoveSupportedDisplayLinkId(display_id);
}
}
void VSyncProviderMac::AddSupportedDisplayLinkId(int64_t display_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(vsync_sequence_checker_);
base::AutoLock lock(id_lock_);
auto found = callback_lists_.find(display_id);
if (found == callback_lists_.end()) {
std::list<VSyncCallbackMac::Callback> callbacks;
// Insert an empty callback list
auto result = callback_lists_.insert(
std::make_pair(display_id, std::move(callbacks)));
bool inserted = result.second;
DCHECK(inserted);
}
}
void VSyncProviderMac::RemoveSupportedDisplayLinkId(int64_t display_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(vsync_sequence_checker_);
base::AutoLock lock(id_lock_);
auto found = callback_lists_.find(display_id);
if (found != callback_lists_.end()) {
callback_lists_.erase(display_id);
}
}
void VSyncProviderMac::RegisterCallback(VSyncCallbackMac::Callback callback,
int64_t display_id) {
if (!task_runner_->BelongsToCurrentThread()) {
task_runner_->PostTask(FROM_HERE,
base::BindOnce(&VSyncProviderMac::RegisterCallback,
weak_factory_.GetWeakPtr(),
std::move(callback), display_id));
return;
}
auto found = callback_lists_.find(display_id);
if (found == callback_lists_.end()) {
return;
}
std::list<VSyncCallbackMac::Callback>& callbacks = found->second;
bool should_request_begin_frame = callbacks.empty();
callbacks.push_back(std::move(callback));
// Request BeginFrame in browser via IPC.
if (should_request_begin_frame) {
needs_begin_frame_callback_.Run(display_id,
/*needs_begin_frames=*/true);
}
}
void VSyncProviderMac::UnregisterCallback(VSyncCallbackMac::Callback callback,
int64_t display_id) {
if (!task_runner_->BelongsToCurrentThread()) {
task_runner_->PostTask(FROM_HERE,
base::BindOnce(&VSyncProviderMac::UnregisterCallback,
weak_factory_.GetWeakPtr(),
std::move(callback), display_id));
return;
}
auto found = callback_lists_.find(display_id);
if (found == callback_lists_.end()) {
return;
}
std::list<VSyncCallbackMac::Callback>& callbacks = found->second;
callbacks.remove(callback);
// Stop BeginFrame in browser via IPC.
if (callbacks.empty()) {
needs_begin_frame_callback_.Run(display_id,
/*needs_begin_frames=*/false);
}
}
void VSyncProviderMac::OnVSync(const VSyncParamsMac& params,
int64_t display_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(vsync_sequence_checker_);
TRACE_EVENT0("gpu", "VSyncProviderMac::OnVSync");
// DisplayLink entry might no longer exist.
auto found = callback_lists_.find(display_id);
if (found == callback_lists_.end()) {
return;
}
// Unregister() might be called inside the loop and
// |callback_lists_.[display_id]| size changes while callbacks are called. Get
// a local copy here.
std::list<VSyncCallbackMac::Callback> local_callbacks = found->second;
// Run callbacks
for (auto& cb : local_callbacks) {
cb.Run(params);
}
}
void VSyncProviderMac::SetCallbackForRemoteNeedsBeginFrame(
NeedsBeginFrameCB callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(vsync_sequence_checker_);
needs_begin_frame_callback_ = std::move(callback);
}
bool VSyncProviderMac::IsDisplayLinkSupported(int64_t display_id) {
if (!needs_begin_frame_callback_) {
return false;
}
// |callback_lists_| is updated on Viz thread. A lock is needed when this
// function is called on CrGpuMain or CompositorGpuThread (DrDC).
base::AutoLock lock(id_lock_);
return callback_lists_.find(display_id) != callback_lists_.end();
}
bool VSyncProviderMac::BelongsToCurrentThread() {
return task_runner_->BelongsToCurrentThread();
}
} // namespace ui