File: overlay_state_service.cc

package info (click to toggle)
chromium 139.0.7258.138-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,120,676 kB
  • sloc: cpp: 35,100,869; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (197 lines) | stat: -rw-r--r-- 8,460 bytes parent folder | download | duplicates (3)
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