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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/common/overlay_state/win/overlay_state_service.h"
#include <memory>
#include <utility>
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "base/trace_event/trace_event.h"
namespace viz {
OverlayStateService::MailboxState::MailboxState() = default;
OverlayStateService::MailboxState::~MailboxState() = default;
OverlayStateService::OverlayStateService() = default;
OverlayStateService::~OverlayStateService() = default;
OverlayStateService* OverlayStateService::GetInstance() {
// TODO(wicarr, crbug.com/1316009): Ideally the OverlayStateService should be
// a singleton. Instead the GpuServiceImpl should be responsible for creating
// the OverlayStateService and injecting it into dependent GpuChannel(s) and
// the DCLayerOverlayProcessor. Further the OverlayStateService should live
// in gpu to avoid gpu needing to take a dependency on viz.
static base::NoDestructor<OverlayStateService> service_wrapper;
return service_wrapper.get();
}
void OverlayStateService::Initialize(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
// GpuServiceImpl is expected to initialize the OverlayStateService and
// OverlayStateService will operate on the GpuMain sequenced task runner.
// RegisterObserver is expected to be called by GpuChannel and should operate
// on the same GpuMain sequence as GpuServiceImpl.
// SetPromotionHint is called by DCLayerOverlayProcessor which operates on a
// separate task sequence, VizCompositorThread, so calls are posted to
// 'task_runner_' to allow mojo'ing back out to bound PromotionHintObserver
// clients on the proper sequence.
DCHECK(!initialized_);
task_runner_ = std::move(task_runner);
initialized_ = true;
}
bool OverlayStateService::IsInitialized() {
return initialized_;
}
void OverlayStateService::RegisterObserver(
mojo::PendingRemote<gpu::mojom::OverlayStateObserver>
overlay_state_observer,
const gpu::Mailbox& mailbox) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
TRACE_EVENT1("gpu", "OverlayStateService::RegisterObserver", "mailbox",
mailbox.ToDebugString());
auto [mailbox_iterator, insert] =
mailboxes_.try_emplace(mailbox, std::make_unique<MailboxState>());
MailboxState* mailbox_state = mailbox_iterator->second.get();
DCHECK(mailbox_state != nullptr);
if (insert) {
mailbox_state->observer_set_.set_disconnect_handler(
base::BindRepeating(&OverlayStateService::OnBoundObserverDisconnect,
base::Unretained(this), mailbox));
}
// Add observer to the RemoteSet
mojo::RemoteSetElementId id =
mailbox_state->observer_set_.Add(std::move(overlay_state_observer));
// It's possible that the overlay processor has already set promotion hint
// information for this mailbox. If this is the case then we send a Hint
// Changed event to the observer to inform them of the current promotion
// state.
OverlayStateAggregator::PromotionState promotion_state =
mailbox_state->aggregator_.GetPromotionState();
// If promotion state is unset there is no further work to do. If it is set
// then inform the new observer of the current state.
if (promotion_state != OverlayStateAggregator::PromotionState::kUnset) {
bool promoted =
promotion_state == OverlayStateAggregator::PromotionState::kPromoted;
mailbox_state->observer_set_.Get(id)->OnStateChanged(promoted);
}
}
void OverlayStateService::OnBoundObserverDisconnect(const gpu::Mailbox& mailbox,
mojo::RemoteSetElementId) {
TRACE_EVENT1("gpu", "OverlayStateService::OnBoundObserverDisconnect",
"mailbox", mailbox.ToDebugString());
auto mailbox_iterator = mailboxes_.find(mailbox);
if (mailbox_iterator != mailboxes_.end() &&
mailbox_iterator->second->observer_set_.empty()) {
// When the last observer has been disconnected, stop tracking mailbox.
mailboxes_.erase(mailbox_iterator);
}
}
void OverlayStateService::OnStateChanged(
const gpu::Mailbox& mailbox,
OverlayStateAggregator::PromotionState promotion_state) {
// If promotion state is unset there is no further work to do.
if (promotion_state == OverlayStateAggregator::PromotionState::kUnset)
return;
if (!task_runner_->RunsTasksInCurrentSequence()) {
// Use of base::Unretained is safe as OverlayStateService is a singleton
// service bound to the lifetime of the GPU process.
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&OverlayStateService::OnStateChangedOnTaskRunnerSequence,
base::Unretained(this), mailbox, promotion_state));
} else {
OnStateChangedOnTaskRunnerSequence(mailbox, promotion_state);
}
}
void OverlayStateService::OnStateChangedOnTaskRunnerSequence(
const gpu::Mailbox& mailbox,
OverlayStateAggregator::PromotionState promotion_state) {
// Notify all observers of the new hint state.
bool promoted =
promotion_state == OverlayStateAggregator::PromotionState::kPromoted;
TRACE_EVENT2("gpu", "OverlayStateService::OnStateChangedOnTaskRunnerSequence",
"mailbox", mailbox.ToDebugString(), "promoted", promoted);
auto mailbox_iterator = mailboxes_.find(mailbox);
DCHECK(mailbox_iterator != mailboxes_.end());
for (auto& observer : mailbox_iterator->second->observer_set_) {
observer->OnStateChanged(promoted);
}
}
void OverlayStateService::SetPromotionHint(const gpu::Mailbox& mailbox,
bool promoted) {
DCHECK(!task_runner_->RunsTasksInCurrentSequence());
// Use of base::Unretained is safe as OverlayStateService is a singleton
// service bound to the lifetime of the GPU process.
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&OverlayStateService::SetPromotionHintOnTaskRunnerSequence,
base::Unretained(this), mailbox, promoted));
}
void OverlayStateService::SetPromotionHintOnTaskRunnerSequence(
const gpu::Mailbox& mailbox,
bool promoted) {
TRACE_EVENT2("gpu",
"OverlayStateService::SetPromotionHintOnTaskRunnerSequence",
"mailbox", mailbox.ToDebugString(), "promoted", promoted);
// The OverlayStateService is made aware of mailboxes of interest through two
// channels:
// 1.) The registration of an observer for a mailbox.
// 2.) The setting of a promotion hint for a mailbox (the overlay processor
// will only send hints for mailboxes which are tagged as
// 'wants_promotion_hint' on their TransferResource).
//
// If this is the first promotion hint associated with a mailbox which has
// not had an observer registered yet, then we will not have an existing
// entry in 'mailboxes_' tracking it. Since there is no guarantee when we'll
// receive another promotion hint for the mailbox we'll store the result so
// any future observer can be informed of the current promotion state.
auto [mailbox_iterator, insert] =
mailboxes_.try_emplace(mailbox, std::make_unique<MailboxState>());
MailboxState* mailbox_state = mailbox_iterator->second.get();
DCHECK(mailbox_state != nullptr);
bool state_change = mailbox_state->aggregator_.SetPromotionHint(promoted);
if (!insert & state_change) {
// Notifying observers requires an IPC so we only send an update when
// the underlying state changes.
OnStateChanged(mailbox, mailbox_state->aggregator_.GetPromotionState());
}
}
void OverlayStateService::MailboxDestroyed(const gpu::Mailbox& mailbox) {
DCHECK(!task_runner_->RunsTasksInCurrentSequence());
// Use of base::Unretained is safe as OverlayStateService is a singleton
// service bound to the lifetime of the GPU process.
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&OverlayStateService::MailboxDestroyedOnTaskRunnerSequence,
base::Unretained(this), mailbox));
}
void OverlayStateService::MailboxDestroyedOnTaskRunnerSequence(
const gpu::Mailbox& mailbox) {
TRACE_EVENT1("gpu",
"OverlayStateService::MailboxDestroyedOnTaskRunnerSequence",
"mailbox", mailbox.ToDebugString());
mailboxes_.erase(mailbox);
}
} // namespace viz
|