File: xr_view.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (254 lines) | stat: -rw-r--r-- 8,609 bytes parent folder | download | duplicates (5)
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/modules/xr/xr_view.h"

#include <algorithm>

#include "base/containers/contains.h"
#include "base/trace_event/trace_event.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_eye.h"
#include "third_party/blink/renderer/modules/xr/xr_camera.h"
#include "third_party/blink/renderer/modules/xr/xr_depth_manager.h"
#include "third_party/blink/renderer/modules/xr/xr_frame.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
#include "third_party/blink/renderer/modules/xr/xr_utils.h"
#include "third_party/blink/renderer/modules/xr/xr_view_geometry.h"
#include "ui/gfx/geometry/point3_f.h"

namespace blink {

namespace {

// Arbitrary minimum size multiplier for dynamic viewport scaling,
// where 1.0 is full framebuffer size (which may in turn be adjusted
// by framebufferScaleFactor). This should be less than or equal to
// kMinScale in xr_session_viewport_scaler.cc to allow use of the full
// dynamic viewport scaling range.
constexpr double kMinViewportScale = 0.125;

}  // namespace

XRView::XRView(XRFrame* frame,
               XRViewData* view_data,
               const gfx::Transform& ref_space_from_mojo)
    : eye_(view_data->Eye()),
      ref_space_from_mojo_(ref_space_from_mojo),
      frame_(frame),
      view_data_(view_data) {
  ref_space_from_view_ = MakeGarbageCollected<XRRigidTransform>(
      ref_space_from_mojo_ * view_data->MojoFromView());
  projection_matrix_ =
      transformationMatrixToDOMFloat32Array(view_data->ProjectionMatrix());
}

XRViewport* XRView::Viewport(double framebuffer_scale) {
  if (!viewport_) {
    const gfx::Rect& viewport = view_data_->Viewport();
    double scale = framebuffer_scale * view_data_->CurrentViewportScale();

    viewport_ = MakeGarbageCollected<XRViewport>(
        viewport.x() * scale, viewport.y() * scale, viewport.width() * scale,
        viewport.height() * scale);
  }

  return viewport_.Get();
}

V8XREye XRView::eye() const {
  switch (eye_) {
    case device::mojom::blink::XREye::kLeft:
      return V8XREye(V8XREye::Enum::kLeft);
    case device::mojom::blink::XREye::kRight:
      return V8XREye(V8XREye::Enum::kRight);
    case device::mojom::blink::XREye::kNone:
      return V8XREye(V8XREye::Enum::kNone);
  }
  NOTREACHED();
}

XRFrame* XRView::frame() const {
  return frame_.Get();
}

XRSession* XRView::session() const {
  return frame_->session();
}

NotShared<DOMFloat32Array> XRView::projectionMatrix() const {
  if (!projection_matrix_ || !projection_matrix_->Data()) {
    // A page may take the projection matrix value and detach it so
    // projection_matrix_ is a detached array buffer.  This breaks the
    // inspector, so return an empty array instead.
    return NotShared<DOMFloat32Array>(DOMFloat32Array::Create(0));
  }

  return projection_matrix_;
}

XRCPUDepthInformation* XRView::GetCpuDepthInformation(
    ExceptionState& exception_state) const {
  return view_data_->GetCpuDepthInformation(this, exception_state);
}

XRWebGLDepthInformation* XRView::GetWebGLDepthInformation(
    ExceptionState& exception_state) const {
  return view_data_->GetWebGLDepthInformation(this, exception_state);
}

XRRigidTransform* XRView::viewGeometryTransform() const {
  // The viewGeometryTransform for XRView is `ref_space_from_view`.
  // https://immersive-web.github.io/webxr/#ref-for-dom-xrviewgeometry-transform%E2%91%A2
  return ref_space_from_view_.Get();
}

std::optional<double> XRView::recommendedViewportScale() const {
  return view_data_->recommendedViewportScale();
}

void XRView::requestViewportScale(std::optional<double> scale) {
  view_data_->requestViewportScale(scale);
}

XRCamera* XRView::camera() const {
  const bool camera_access_enabled = frame_->session()->IsFeatureEnabled(
      device::mojom::XRSessionFeature::CAMERA_ACCESS);
  const bool is_immersive_ar_session =
      frame_->session()->mode() ==
      device::mojom::blink::XRSessionMode::kImmersiveAr;

  DVLOG(3) << __func__ << ": camera_access_enabled=" << camera_access_enabled
           << ", is_immersive_ar_session=" << is_immersive_ar_session;

  if (camera_access_enabled && is_immersive_ar_session) {
    // The feature is enabled and we're in immersive-ar session, so let's return
    // a camera object if the camera image was received in the current frame.
    // Note: currently our only implementation of AR sessions is provided by
    // ARCore device, which should *not* return a frame data with camera image
    // that is not set in case the raw camera access is enabled, so we could
    // DCHECK that the camera image size has value. Since there may be other AR
    // devices that implement raw camera access via a different mechanism that's
    // not neccessarily frame-aligned, a DCHECK here would affect them.
    if (frame_->session()->CameraImageSize().has_value()) {
      return MakeGarbageCollected<XRCamera>(frame_);
    }
  }

  return nullptr;
}

bool XRView::isFirstPersonObserver() const {
  return view_data_->IsFirstPersonObserver();
}

void XRView::Trace(Visitor* visitor) const {
  visitor->Trace(frame_);
  visitor->Trace(projection_matrix_);
  visitor->Trace(ref_space_from_view_);
  visitor->Trace(view_data_);
  visitor->Trace(viewport_);
  ScriptWrappable::Trace(visitor);
}

// XRViewData
XRViewData::XRViewData(
    wtf_size_t index,
    device::mojom::blink::XRViewPtr view,
    double depth_near,
    double depth_far,
    const device::mojom::blink::XRSessionDeviceConfig& device_config,
    const HashSet<device::mojom::XRSessionFeature>& enabled_feature_set,
    XRGraphicsBinding::Api graphics_api)
    : XRViewGeometry(graphics_api),
      index_(index),
      eye_(view->eye),
      viewport_(view->viewport) {
  if (base::Contains(enabled_feature_set,
                     device::mojom::XRSessionFeature::DEPTH)) {
    if (!device_config.depth_configuration) {
      DCHECK(false)
          << "The session reports that depth sensing is supported but "
             "did not report depth sensing API configuration!";
    }
    depth_manager_ = MakeGarbageCollected<XRDepthManager>(
        base::PassKey<XRViewData>{}, *device_config.depth_configuration);
  }

  UpdateView(std::move(view), depth_near, depth_far);
}

void XRViewData::UpdateView(device::mojom::blink::XRViewPtr view,
                            double depth_near,
                            double depth_far) {
  DCHECK_EQ(eye_, view->eye);

  UpdateViewGeometry(view->geometry, depth_near, depth_far);

  viewport_ = view->viewport;
  is_first_person_observer_ = view->is_first_person_observer;
  if (depth_manager_) {
    depth_manager_->ProcessDepthInformation(std::move(view->depth_data));
  }
}

XRCPUDepthInformation* XRViewData::GetCpuDepthInformation(
    const XRView* xr_view,
    ExceptionState& exception_state) const {
  if (!depth_manager_) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kInvalidStateError,
        XRSession::kDepthSensingFeatureNotSupported);
    return nullptr;
  }

  return depth_manager_->GetCpuDepthInformation(xr_view, exception_state);
}

XRWebGLDepthInformation* XRViewData::GetWebGLDepthInformation(
    const XRView* xr_view,
    ExceptionState& exception_state) const {
  if (!depth_manager_) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kInvalidStateError,
        XRSession::kDepthSensingFeatureNotSupported);
    return nullptr;
  }

  return depth_manager_->GetWebGLDepthInformation(xr_view, exception_state);
}

std::optional<double> XRViewData::recommendedViewportScale() const {
  return recommended_viewport_scale_;
}

void XRViewData::requestViewportScale(std::optional<double> scale) {
  if (!scale)
    return;

  requested_viewport_scale_ = std::clamp(*scale, kMinViewportScale, 1.0);
}

bool XRViewData::ApplyViewportScaleForFrame() {
  bool changed = false;

  // Dynamic viewport scaling, see steps 6 and 7 in
  // https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport
  if (ViewportModifiable() &&
      CurrentViewportScale() != RequestedViewportScale()) {
    DVLOG(2) << __func__
             << ": apply ViewportScale=" << RequestedViewportScale();
    SetCurrentViewportScale(RequestedViewportScale());
    changed = true;
  }
  TRACE_COUNTER1("xr", "XR viewport scale (%)", CurrentViewportScale() * 100);
  SetViewportModifiable(false);

  return changed;
}

void XRViewData::Trace(Visitor* visitor) const {
  visitor->Trace(depth_manager_);
}

}  // namespace blink