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
content / browser / xr / service / xr_frame_sink_client_impl.cc [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/xr/service/xr_frame_sink_client_impl.h"
#include <memory>
#include "base/functional/callback.h"
#include "build/build_config.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "services/viz/privileged/mojom/compositing/frame_sink_manager.mojom.h"
#if BUILDFLAG(IS_ANDROID)
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#endif
namespace content {
XrFrameSinkClientImpl::XrFrameSinkClientImpl(int32_t render_process_id,
int32_t render_frame_id)
: ui_thread_task_runner_(GetUIThreadTaskRunner({})),
render_process_id_(render_process_id),
render_frame_id_(render_frame_id) {
DCHECK(IsOnUiThread())
<< "XrFrameSinkClientImpl must be constructed on the UI thread.";
}
XrFrameSinkClientImpl::~XrFrameSinkClientImpl() {
DCHECK(IsOnUiThread())
<< "XrFrameSinkClientImpl must be destructed on the UI thread.";
if (!initialized_)
return;
SurfaceDestroyed();
}
bool XrFrameSinkClientImpl::IsOnUiThread() const {
return ui_thread_task_runner_->BelongsToCurrentThread();
}
void XrFrameSinkClientImpl::SurfaceDestroyed() {
DCHECK(IsOnUiThread());
if (!initialized_)
return;
auto* frame_sink_manager = GetHostFrameSinkManager();
// Since this code can be run during destruction, it's theoretically possible,
// though unlikely, that the FrameSinkManager no longer exists.
if (frame_sink_manager)
frame_sink_manager->InvalidateFrameSinkId(root_frame_sink_id_, this);
// Reset the initialized state and the root FrameSinkId to an invalid value.
initialized_ = false;
root_frame_sink_id_ = viz::FrameSinkId();
}
std::optional<viz::SurfaceId> XrFrameSinkClientImpl::GetDOMSurface() {
base::AutoLock lock(dom_surface_lock_);
return dom_surface_id_;
}
viz::FrameSinkId XrFrameSinkClientImpl::FrameSinkId() {
return root_frame_sink_id_;
}
void XrFrameSinkClientImpl::InitializeRootCompositorFrameSink(
viz::mojom::RootCompositorFrameSinkParamsPtr root_params,
device::DomOverlaySetup dom_setup,
base::OnceClosure on_initialized) {
DCHECK(!initialized_);
DVLOG(1) << __func__;
ui_thread_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&XrFrameSinkClientImpl::InitializeOnUiThread,
weak_ptr_factory_.GetWeakPtr(), std::move(root_params),
dom_setup, std::move(on_initialized)));
}
void XrFrameSinkClientImpl::InitializeOnUiThread(
viz::mojom::RootCompositorFrameSinkParamsPtr root_params,
device::DomOverlaySetup dom_setup,
base::OnceClosure on_initialized) {
// AllocateFrameSinkId needs to be called from the UI thread.
DCHECK(IsOnUiThread());
DVLOG(1) << __func__;
root_frame_sink_id_ = AllocateFrameSinkId();
root_params->frame_sink_id = root_frame_sink_id_;
GetHostFrameSinkManager()->RegisterFrameSinkId(
root_params->frame_sink_id, this, viz::ReportFirstSurfaceActivation::kNo);
GetHostFrameSinkManager()->CreateRootCompositorFrameSink(
std::move(root_params));
if (dom_setup != device::DomOverlaySetup::kNone) {
ConfigureDOMOverlay();
}
initialized_ = true;
std::move(on_initialized).Run();
}
void XrFrameSinkClientImpl::ConfigureDOMOverlay() {
DCHECK(IsOnUiThread());
base::AutoLock lock(dom_surface_lock_);
// This is left outside of the OS_ANDROID ifdef to prevent warnings about the
// render_process_id and render_frame_id from being unused. Since we check
// the render_frame_host for an early return, it is in fact used.
RenderFrameHostImpl* render_frame_host =
RenderFrameHostImpl::FromID(render_process_id_, render_frame_id_);
if (!render_frame_host)
return;
RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
render_frame_host->GetOutermostMainFrameOrEmbedder()->GetView());
CHECK(!root_view || !root_view->IsRenderWidgetHostViewChildFrame());
// Since we don't have the ability to get updates to the surface id on non-
// Android OS's, we let it stay null, which callers can use to as a signal that
// DOMOverlay will not work.
#if BUILDFLAG(IS_ANDROID)
RenderWidgetHostViewAndroid* view =
static_cast<RenderWidgetHostViewAndroid*>(root_view);
if (!view)
return;
// The returned CallbackListSubscription manages the lifetime of this callback
// and thus makes Unretained safe.
surface_id_changed_subscription_ =
view->SubscribeToSurfaceIdChanges(base::BindRepeating(
&XrFrameSinkClientImpl::OnSurfaceIdUpdated, base::Unretained(this)));
dom_surface_id_ = view->GetCurrentSurfaceId();
#endif
if (dom_surface_id_ && dom_surface_id_->is_valid()) {
GetHostFrameSinkManager()->RegisterFrameSinkHierarchy(
root_frame_sink_id_, dom_surface_id_->frame_sink_id());
}
}
void XrFrameSinkClientImpl::OnSurfaceIdUpdated(
const viz::SurfaceId& dom_surface_id) {
base::AutoLock lock(dom_surface_lock_);
dom_surface_id_ = dom_surface_id;
}
} // namespace content