diff options
Diffstat (limited to 'chromium/content/browser/xr')
9 files changed, 205 insertions, 154 deletions
diff --git a/chromium/content/browser/xr/metrics/webxr_session_tracker.cc b/chromium/content/browser/xr/metrics/webxr_session_tracker.cc index 1914e7e1289..8bf301013b0 100644 --- a/chromium/content/browser/xr/metrics/webxr_session_tracker.cc +++ b/chromium/content/browser/xr/metrics/webxr_session_tracker.cc @@ -73,6 +73,7 @@ void WebXRSessionTracker::ReportFeatureUsed( case XRSessionFeature::HIT_TEST: case XRSessionFeature::LIGHT_ESTIMATION: case XRSessionFeature::ANCHORS: + case XRSessionFeature::CAMERA_ACCESS: // Not recording metrics for these features currently. // TODO(https://crbug.com/965729): Add metrics for the AR-related features // that are enabled by default. @@ -110,6 +111,7 @@ void WebXRSessionTracker::SetFeatureRequest( case XRSessionFeature::HIT_TEST: case XRSessionFeature::LIGHT_ESTIMATION: case XRSessionFeature::ANCHORS: + case XRSessionFeature::CAMERA_ACCESS: // Not recording metrics for these features currently. // TODO(https://crbug.com/965729): Add metrics for the AR-related features // that are enabled by default. diff --git a/chromium/content/browser/xr/service/browser_xr_runtime_impl.cc b/chromium/content/browser/xr/service/browser_xr_runtime_impl.cc index 59394d2d92d..03827f97e5d 100644 --- a/chromium/content/browser/xr/service/browser_xr_runtime_impl.cc +++ b/chromium/content/browser/xr/service/browser_xr_runtime_impl.cc @@ -163,6 +163,7 @@ constexpr device::mojom::XRSessionFeature kARCoreDeviceFeatures[] = { device::mojom::XRSessionFeature::DOM_OVERLAY, device::mojom::XRSessionFeature::LIGHT_ESTIMATION, device::mojom::XRSessionFeature::ANCHORS, + device::mojom::XRSessionFeature::CAMERA_ACCESS, }; #if BUILDFLAG(ENABLE_OPENVR) @@ -212,9 +213,11 @@ bool ContainsFeature( BrowserXRRuntimeImpl::BrowserXRRuntimeImpl( device::mojom::XRDeviceId id, + device::mojom::XRDeviceDataPtr device_data, mojo::PendingRemote<device::mojom::XRRuntime> runtime, device::mojom::VRDisplayInfoPtr display_info) : id_(id), + device_data_(std::move(device_data)), runtime_(std::move(runtime)), display_info_(ValidateVRDisplayInfo(display_info.get(), id)) { DVLOG(2) << __func__ << ": id=" << id; @@ -231,7 +234,6 @@ BrowserXRRuntimeImpl::BrowserXRRuntimeImpl( if (integration_client) { install_helper_ = integration_client->GetInstallHelper(id_); - consent_helper_ = integration_client->GetConsentHelper(id_); } } @@ -493,22 +495,6 @@ void BrowserXRRuntimeImpl::OnRequestSessionResult( } } -void BrowserXRRuntimeImpl::ShowConsentPrompt( - int render_process_id, - int render_frame_id, - content::XrConsentPromptLevel consent_level, - content::OnXrUserConsentCallback consent_callback) { - // It is the responsibility of the consent prompt to ensure that the callback - // is run in the event that we get removed (and it gets destroyed). - if (consent_helper_) { - consent_helper_->ShowConsentPrompt(render_process_id, render_frame_id, - consent_level, - std::move(consent_callback)); - } else { - std::move(consent_callback).Run(consent_level, false); - } -} - void BrowserXRRuntimeImpl::EnsureInstalled( int render_process_id, int render_frame_id, @@ -574,4 +560,10 @@ void BrowserXRRuntimeImpl::BeforeRuntimeRemoved() { StopImmersiveSession(base::DoNothing()); } +#if defined(OS_WIN) +base::Optional<LUID> BrowserXRRuntimeImpl::GetLuid() const { + return device_data_->luid; +} +#endif + } // namespace content diff --git a/chromium/content/browser/xr/service/browser_xr_runtime_impl.h b/chromium/content/browser/xr/service/browser_xr_runtime_impl.h index 8f96a0d04a1..23a4ed19733 100644 --- a/chromium/content/browser/xr/service/browser_xr_runtime_impl.h +++ b/chromium/content/browser/xr/service/browser_xr_runtime_impl.h @@ -10,10 +10,10 @@ #include "base/observer_list.h" #include "base/observer_list_types.h" +#include "build/build_config.h" #include "content/browser/xr/service/vr_service_impl.h" #include "content/public/browser/browser_xr_runtime.h" #include "content/public/browser/render_frame_host.h" -#include "content/public/browser/xr_consent_helper.h" #include "device/vr/public/mojom/isolated_xr_service.mojom.h" #include "device/vr/public/mojom/vr_service.mojom-forward.h" #include "mojo/public/cpp/bindings/associated_receiver.h" @@ -36,6 +36,7 @@ class BrowserXRRuntimeImpl : public content::BrowserXRRuntime, base::OnceCallback<void(device::mojom::XRSessionPtr)>; explicit BrowserXRRuntimeImpl( device::mojom::XRDeviceId id, + device::mojom::XRDeviceDataPtr device_data, mojo::PendingRemote<device::mojom::XRRuntime> runtime, device::mojom::VRDisplayInfoPtr info); ~BrowserXRRuntimeImpl() override; @@ -59,10 +60,6 @@ class BrowserXRRuntimeImpl : public content::BrowserXRRuntime, void RequestSession(VRServiceImpl* service, const device::mojom::XRRuntimeSessionOptionsPtr& options, RequestSessionCallback callback); - void ShowConsentPrompt(int render_process_id, - int render_frame_id, - content::XrConsentPromptLevel consent_level, - content::OnXrUserConsentCallback consent_callback); void EnsureInstalled(int render_process_id, int render_frame_id, base::OnceCallback<void(bool)> install_callback); @@ -76,6 +73,10 @@ class BrowserXRRuntimeImpl : public content::BrowserXRRuntime, device::mojom::XRDeviceId GetId() const { return id_; } +#if defined(OS_WIN) + base::Optional<LUID> GetLuid() const; +#endif + // BrowserXRRuntime void AddObserver(Observer* observer) override; void RemoveObserver(Observer* observer) override; @@ -105,6 +106,7 @@ class BrowserXRRuntimeImpl : public content::BrowserXRRuntime, void OnInstallFinished(bool succeeded); device::mojom::XRDeviceId id_; + device::mojom::XRDeviceDataPtr device_data_; mojo::Remote<device::mojom::XRRuntime> runtime_; mojo::Remote<device::mojom::XRSessionController> immersive_session_controller_; @@ -118,7 +120,6 @@ class BrowserXRRuntimeImpl : public content::BrowserXRRuntime, this}; base::ObserverList<Observer> observers_; - std::unique_ptr<content::XrConsentHelper> consent_helper_; std::unique_ptr<content::XrInstallHelper> install_helper_; base::OnceCallback<void(bool)> install_finished_callback_; diff --git a/chromium/content/browser/xr/service/isolated_device_provider.cc b/chromium/content/browser/xr/service/isolated_device_provider.cc index aae1ae6c654..650a86614e1 100644 --- a/chromium/content/browser/xr/service/isolated_device_provider.cc +++ b/chromium/content/browser/xr/service/isolated_device_provider.cc @@ -18,6 +18,7 @@ namespace content { void IsolatedVRDeviceProvider::Initialize( base::RepeatingCallback<void(device::mojom::XRDeviceId, device::mojom::VRDisplayInfoPtr, + device::mojom::XRDeviceDataPtr, mojo::PendingRemote<device::mojom::XRRuntime>)> add_device_callback, base::RepeatingCallback<void(device::mojom::XRDeviceId)> @@ -37,8 +38,10 @@ bool IsolatedVRDeviceProvider::Initialized() { void IsolatedVRDeviceProvider::OnDeviceAdded( mojo::PendingRemote<device::mojom::XRRuntime> device, mojo::PendingRemote<device::mojom::XRCompositorHost> compositor_host, + device::mojom::XRDeviceDataPtr device_data, device::mojom::XRDeviceId device_id) { - add_device_callback_.Run(device_id, nullptr, std::move(device)); + add_device_callback_.Run(device_id, nullptr, std::move(device_data), + std::move(device)); auto* integration_client = GetXrIntegrationClient(); if (!integration_client) diff --git a/chromium/content/browser/xr/service/isolated_device_provider.h b/chromium/content/browser/xr/service/isolated_device_provider.h index e362f18f59c..6495c377198 100644 --- a/chromium/content/browser/xr/service/isolated_device_provider.h +++ b/chromium/content/browser/xr/service/isolated_device_provider.h @@ -30,6 +30,7 @@ class IsolatedVRDeviceProvider base::RepeatingCallback<void( device::mojom::XRDeviceId, device::mojom::VRDisplayInfoPtr, + device::mojom::XRDeviceDataPtr, mojo::PendingRemote<device::mojom::XRRuntime>)> add_device_callback, base::RepeatingCallback<void(device::mojom::XRDeviceId)> remove_device_callback, @@ -43,6 +44,7 @@ class IsolatedVRDeviceProvider void OnDeviceAdded( mojo::PendingRemote<device::mojom::XRRuntime> device, mojo::PendingRemote<device::mojom::XRCompositorHost> compositor_host, + device::mojom::XRDeviceDataPtr device_data, device::mojom::XRDeviceId device_id) override; void OnDeviceRemoved(device::mojom::XRDeviceId id) override; void OnDevicesEnumerated() override; @@ -53,8 +55,10 @@ class IsolatedVRDeviceProvider int retry_count_ = 0; mojo::Remote<device::mojom::IsolatedXRRuntimeProvider> device_provider_; + // TODO(crbug.com/1090029): Wrap XRDeviceId + VRDisplayInfo into XRDeviceData base::RepeatingCallback<void(device::mojom::XRDeviceId, device::mojom::VRDisplayInfoPtr, + device::mojom::XRDeviceDataPtr, mojo::PendingRemote<device::mojom::XRRuntime>)> add_device_callback_; base::RepeatingCallback<void(device::mojom::XRDeviceId)> diff --git a/chromium/content/browser/xr/service/vr_service_impl.cc b/chromium/content/browser/xr/service/vr_service_impl.cc index e01fc6f8494..6dce9c2ff5f 100644 --- a/chromium/content/browser/xr/service/vr_service_impl.cc +++ b/chromium/content/browser/xr/service/vr_service_impl.cc @@ -22,8 +22,6 @@ #include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/content_features.h" -#include "content/public/common/content_switches.h" #include "content/public/common/origin_util.h" #include "device/vr/buildflags/buildflags.h" #include "device/vr/public/cpp/session_mode.h" @@ -38,42 +36,6 @@ device::mojom::XRRuntimeSessionOptionsPtr GetRuntimeOptions( return runtime_options; } -content::XrConsentPromptLevel GetRequiredConsentLevel( - device::mojom::XRSessionMode mode, - const content::BrowserXRRuntimeImpl* runtime, - const std::set<device::mojom::XRSessionFeature>& requested_features) { - if (base::Contains( - requested_features, - device::mojom::XRSessionFeature::REF_SPACE_BOUNDED_FLOOR)) { - return content::XrConsentPromptLevel::kVRFloorPlan; - } - - // If the device supports a custom IPD and it will be exposed (via immersive), - // we need to warn about physical features Being exposed. - if (runtime->SupportsCustomIPD() && - device::XRSessionModeUtils::IsImmersive(mode)) { - return content::XrConsentPromptLevel::kVRFeatures; - } - - // If local-floor is requested and the device supports a user inputted or real - // height, we need to warn about physical features being exposed. - // Note that while this is also the case for bounded-floor, that is covered - // by the stricter kVRFloorPlan Prompt set above. - if (base::Contains(requested_features, - device::mojom::XRSessionFeature::REF_SPACE_LOCAL_FLOOR) && - runtime->SupportsNonEmulatedHeight()) { - return content::XrConsentPromptLevel::kVRFeatures; - } - - // In the absence of other items that need to be consented, inline does not - // require consent. - if (mode == device::mojom::XRSessionMode::kInline) { - return content::XrConsentPromptLevel::kNone; - } - - return content::XrConsentPromptLevel::kDefault; -} - content::PermissionType GetRequiredPermission( device::mojom::XRSessionMode mode) { switch (mode) { @@ -115,6 +77,20 @@ VRServiceImpl::SessionRequestData::~SessionRequestData() { VRServiceImpl::SessionRequestData::SessionRequestData(SessionRequestData&&) = default; +VRServiceImpl::XrCompatibleCallback::XrCompatibleCallback( + device::mojom::VRService::MakeXrCompatibleCallback callback) + : callback(std::move(callback)) {} + +VRServiceImpl::XrCompatibleCallback::XrCompatibleCallback( + XrCompatibleCallback&& wrapper) { + this->callback = std::move(wrapper.callback); +} + +VRServiceImpl::XrCompatibleCallback::~XrCompatibleCallback() { + if (!callback.is_null()) + std::move(callback).Run(device::mojom::XrCompatibleResult::kNotCompatible); +} + VRServiceImpl::VRServiceImpl(content::RenderFrameHost* render_frame_host) : WebContentsObserver( content::WebContents::FromRenderFrameHost(render_frame_host)), @@ -399,11 +375,11 @@ void VRServiceImpl::RequestSession( SessionRequestData request(std::move(options), std::move(callback), std::move(requested_features), runtime->GetId()); - ShowConsentPrompt(std::move(request), runtime); + GetPermissionStatus(std::move(request), runtime); } -void VRServiceImpl::ShowConsentPrompt(SessionRequestData request, - BrowserXRRuntimeImpl* runtime) { +void VRServiceImpl::GetPermissionStatus(SessionRequestData request, + BrowserXRRuntimeImpl* runtime) { DVLOG(2) << __func__; DCHECK(request.options); DCHECK(runtime); @@ -413,61 +389,28 @@ void VRServiceImpl::ShowConsentPrompt(SessionRequestData request, DCHECK_NE(request.options->mode, device::mojom::XRSessionMode::kImmersiveAr); #endif - bool consent_granted = false; - content::XrConsentPromptLevel consent_level = GetRequiredConsentLevel( - request.options->mode, runtime, request.enabled_features); - if (!base::FeatureList::IsEnabled(features::kWebXrPermissionsApi)) { - consent_granted = - ((consent_level == content::XrConsentPromptLevel::kNone) || - IsConsentGrantedForDevice(request.runtime_id, consent_level)); - } - - // Skip the consent prompt if the user has already consented for this device, - // or if consent is not needed. - if (consent_granted) { - EnsureRuntimeInstalled(std::move(request), runtime); - return; - } - - if (base::FeatureList::IsEnabled(features::kWebXrPermissionsApi)) { - PermissionControllerImpl* permission_controller = - PermissionControllerImpl::FromBrowserContext( - GetWebContents()->GetBrowserContext()); - DCHECK(permission_controller); - - // Need to calculate the permission before the call below, as otherwise - // std::move nulls options out before GetRequiredPermission runs. - PermissionType permission = GetRequiredPermission(request.options->mode); - permission_controller->RequestPermission( - permission, render_frame_host_, - render_frame_host_->GetLastCommittedURL(), true, - base::BindOnce(&VRServiceImpl::OnPermissionResult, - weak_ptr_factory_.GetWeakPtr(), std::move(request), - consent_level)); - return; - } - - runtime->ShowConsentPrompt( - render_frame_host_->GetProcess()->GetID(), - render_frame_host_->GetRoutingID(), consent_level, - base::BindOnce(&VRServiceImpl::OnConsentResult, + PermissionControllerImpl* permission_controller = + PermissionControllerImpl::FromBrowserContext( + GetWebContents()->GetBrowserContext()); + DCHECK(permission_controller); + + // Need to calculate the permission before the call below, as otherwise + // std::move nulls options out before GetRequiredPermission runs. + PermissionType permission = GetRequiredPermission(request.options->mode); + permission_controller->RequestPermission( + permission, render_frame_host_, render_frame_host_->GetLastCommittedURL(), + true, + base::BindOnce(&VRServiceImpl::OnPermissionResult, weak_ptr_factory_.GetWeakPtr(), std::move(request))); } -// TODO(alcooper): Once the ConsentFlow can be removed expected_runtime_id and -// consent_level shouldn't be needed. void VRServiceImpl::OnPermissionResult( SessionRequestData request, - content::XrConsentPromptLevel consent_level, blink::mojom::PermissionStatus permission_status) { - OnConsentResult(std::move(request), consent_level, - permission_status == blink::mojom::PermissionStatus::GRANTED); -} - -void VRServiceImpl::OnConsentResult(SessionRequestData request, - content::XrConsentPromptLevel consent_level, - bool is_consent_granted) { DVLOG(2) << __func__; + bool is_consent_granted = + (permission_status == blink::mojom::PermissionStatus::GRANTED); + if (!is_consent_granted) { std::move(request.callback) .Run(device::mojom::RequestSessionResult::NewFailureReason( @@ -475,8 +418,6 @@ void VRServiceImpl::OnConsentResult(SessionRequestData request, return; } - AddConsentGrantedDevice(request.runtime_id, consent_level); - // Re-check for another client instance after a potential user consent. if (runtime_manager_->IsOtherClientPresenting(this)) { // Can't create sessions while an immersive session exists. @@ -608,6 +549,31 @@ void VRServiceImpl::SetFramesThrottled(bool throttled) { } } +void VRServiceImpl::MakeXrCompatible( + device::mojom::VRService::MakeXrCompatibleCallback callback) { + if (!initialization_complete_) { + pending_requests_.push_back(base::BindOnce(&VRServiceImpl::MakeXrCompatible, + base::Unretained(this), + std::move(callback))); + return; + } + + xr_compatible_callbacks_.emplace_back(std::move(callback)); + + // Only request compatibility if there aren't any pending calls. + // OnMakeXrCompatibleComplete will run all callbacks. + if (xr_compatible_callbacks_.size() == 1) + runtime_manager_->MakeXrCompatible(); +} + +void VRServiceImpl::OnMakeXrCompatibleComplete( + device::mojom::XrCompatibleResult result) { + for (XrCompatibleCallback& wrapper : xr_compatible_callbacks_) + std::move(wrapper.callback).Run(result); + + xr_compatible_callbacks_.clear(); +} + void VRServiceImpl::OnExitPresent() { DVLOG(2) << __func__; @@ -632,20 +598,4 @@ content::WebContents* VRServiceImpl::GetWebContents() { return content::WebContents::FromRenderFrameHost(render_frame_host_); } -bool VRServiceImpl::IsConsentGrantedForDevice( - device::mojom::XRDeviceId device_id, - content::XrConsentPromptLevel consent_level) { - auto it = consent_granted_devices_.find(device_id); - return it != consent_granted_devices_.end() && it->second >= consent_level; -} - -void VRServiceImpl::AddConsentGrantedDevice( - device::mojom::XRDeviceId device_id, - content::XrConsentPromptLevel consent_level) { - auto it = consent_granted_devices_.find(device_id); - if (it == consent_granted_devices_.end() || it->second < consent_level) { - consent_granted_devices_[device_id] = consent_level; - } -} - } // namespace content diff --git a/chromium/content/browser/xr/service/vr_service_impl.h b/chromium/content/browser/xr/service/vr_service_impl.h index 70251655801..9932a0c3cea 100644 --- a/chromium/content/browser/xr/service/vr_service_impl.h +++ b/chromium/content/browser/xr/service/vr_service_impl.h @@ -16,8 +16,6 @@ #include "content/browser/xr/metrics/session_metrics_helper.h" #include "content/common/content_export.h" #include "content/public/browser/web_contents_observer.h" -#include "content/public/browser/xr_consent_helper.h" -#include "content/public/browser/xr_consent_prompt_level.h" #include "device/vr/public/mojom/isolated_xr_service.mojom-forward.h" #include "device/vr/public/mojom/vr_service.mojom.h" #include "mojo/public/cpp/bindings/pending_receiver.h" @@ -64,6 +62,8 @@ class CONTENT_EXPORT VRServiceImpl : public device::mojom::VRService, device::mojom::VRService::SupportsSessionCallback callback) override; void ExitPresent(ExitPresentCallback on_exited) override; void SetFramesThrottled(bool throttled) override; + void MakeXrCompatible( + device::mojom::VRService::MakeXrCompatibleCallback callback) override; void InitializationComplete(); @@ -78,6 +78,7 @@ class CONTENT_EXPORT VRServiceImpl : public device::mojom::VRService, device::mojom::XRVisibilityState visibility_state); void OnDisplayInfoChanged(); void RuntimesChanged(); + void OnMakeXrCompatibleComplete(device::mojom::XrCompatibleResult result); base::WeakPtr<VRServiceImpl> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); @@ -105,6 +106,18 @@ class CONTENT_EXPORT VRServiceImpl : public device::mojom::VRService, SessionRequestData& operator=(const SessionRequestData&) = delete; }; + // Wrapper around MakeXrCompatibleCallback so that the callback gets executed + // on destruction if it hasn't already. Otherwise, mojom throws a DCHECK if + // the callback is not executed before being destroyed. + struct XrCompatibleCallback { + device::mojom::VRService::MakeXrCompatibleCallback callback; + + explicit XrCompatibleCallback( + device::mojom::VRService::MakeXrCompatibleCallback callback); + XrCompatibleCallback(XrCompatibleCallback&& wrapper); + ~XrCompatibleCallback(); + }; + // content::WebContentsObserver implementation void OnWebContentsFocused(content::RenderWidgetHost* host) override; void OnWebContentsLostFocus(content::RenderWidgetHost* host) override; @@ -121,26 +134,15 @@ class CONTENT_EXPORT VRServiceImpl : public device::mojom::VRService, bool InternalSupportsSession(device::mojom::XRSessionOptions* options); - bool IsConsentGrantedForDevice(device::mojom::XRDeviceId device_id, - content::XrConsentPromptLevel consent_level); - void AddConsentGrantedDevice(device::mojom::XRDeviceId device_id, - content::XrConsentPromptLevel consent_level); - // The following steps are ordered in the general flow for "RequestSession" - // If the WebXrPermissionsAPI is enabled ShowConsentPrompt will result in a - // call to OnPermissionResult which feeds into OnConsentResult. - // If ShowConsentPrompt determines that no consent/permission is needed (or - // has already been granted), then it will directly call - // EnsureRuntimeInstalled. DoRequestSession will continue with OnInline or + // GetPermissionStatus will result in a call to OnPermissionResult which then + // calls EnsureRuntimeInstalled (with a callback to OnInstallResult), which + // then feeds into DoRequestSession, which will continue with OnInline or // OnImmersive SessionCreated depending on the type of session created. - void ShowConsentPrompt(SessionRequestData request, - BrowserXRRuntimeImpl* runtime); + void GetPermissionStatus(SessionRequestData request, + BrowserXRRuntimeImpl* runtime); - void OnConsentResult(SessionRequestData request, - content::XrConsentPromptLevel consent_level, - bool is_consent_granted); void OnPermissionResult(SessionRequestData request, - content::XrConsentPromptLevel consent_level, blink::mojom::PermissionStatus permission_status); void EnsureRuntimeInstalled(SessionRequestData request, @@ -177,8 +179,7 @@ class CONTENT_EXPORT VRServiceImpl : public device::mojom::VRService, bool in_focused_frame_ = false; bool frames_throttled_ = false; - std::map<device::mojom::XRDeviceId, content::XrConsentPromptLevel> - consent_granted_devices_; + std::vector<XrCompatibleCallback> xr_compatible_callbacks_; base::WeakPtrFactory<VRServiceImpl> weak_ptr_factory_{this}; diff --git a/chromium/content/browser/xr/service/xr_runtime_manager_impl.cc b/chromium/content/browser/xr/service/xr_runtime_manager_impl.cc index bb096ac8a53..9cfddf411ef 100644 --- a/chromium/content/browser/xr/service/xr_runtime_manager_impl.cc +++ b/chromium/content/browser/xr/service/xr_runtime_manager_impl.cc @@ -9,21 +9,27 @@ #include <utility> #include "base/bind.h" +#include "base/command_line.h" #include "base/feature_list.h" #include "base/lazy_instance.h" #include "base/memory/singleton.h" +#include "base/strings/string_number_conversions.h" #include "base/trace_event/common/trace_event_common.h" #include "build/build_config.h" #include "content/browser/xr/xr_utils.h" #include "content/public/browser/device_service.h" +#include "content/public/browser/gpu_data_manager.h" +#include "content/public/browser/gpu_utils.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "device/base/features.h" #include "device/vr/buildflags/buildflags.h" #include "device/vr/orientation/orientation_device_provider.h" #include "device/vr/public/cpp/vr_device_provider.h" +#include "gpu/config/gpu_info.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "services/device/public/mojom/sensor_provider.mojom.h" +#include "ui/gl/gl_switches.h" #if !defined(OS_ANDROID) #include "content/browser/xr/service/isolated_device_provider.h" @@ -310,6 +316,87 @@ void XRRuntimeManagerImpl::SupportsSession( std::move(callback).Run(true); } +void XRRuntimeManagerImpl::MakeXrCompatible() { + auto* runtime = GetImmersiveVrRuntime(); + if (!runtime) { + // WebXR spec: if there's no device, xr compatible is false. + for (VRServiceImpl* service : services_) + service->OnMakeXrCompatibleComplete( + device::mojom::XrCompatibleResult::kNotCompatible); + return; + } + + if (!IsInitializedOnCompatibleAdapter(runtime)) { +#if defined(OS_WIN) + base::Optional<LUID> luid = runtime->GetLuid(); + // IsInitializedOnCompatibleAdapter should have returned true if the + // runtime doesn't specify a LUID. + DCHECK(luid && (luid->HighPart != 0 || luid->LowPart != 0)); + + // Add the XR compatible adapter LUID to the browser command line. + // GpuProcessHost::LaunchGpuProcess passes this to the GPU process. + std::string luid_string = base::NumberToString(luid->HighPart) + "," + + base::NumberToString(luid->LowPart); + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kUseAdapterLuid, luid_string); + + // Get notified when the new GPU process sends back its GPUInfo. This + // indicates that the GPU process has finished initializing and the GPUInfo + // contains the LUID of the active adapter. + content::GpuDataManager::GetInstance()->AddObserver(this); + + content::KillGpuProcess(); + return; +#else + // MakeXrCompatible is not yet supported on other platforms so + // IsInitializedOnCompatibleAdapter should have returned true. + NOTREACHED(); +#endif + } + + for (VRServiceImpl* service : services_) + service->OnMakeXrCompatibleComplete( + device::mojom::XrCompatibleResult::kAlreadyCompatible); +} + +bool XRRuntimeManagerImpl::IsInitializedOnCompatibleAdapter( + BrowserXRRuntimeImpl* runtime) { +#if defined(OS_WIN) + base::Optional<LUID> luid = runtime->GetLuid(); + if (luid && (luid->HighPart != 0 || luid->LowPart != 0)) { + LUID active_luid = + content::GpuDataManager::GetInstance()->GetGPUInfo().active_gpu().luid; + return active_luid.HighPart == luid->HighPart && + active_luid.LowPart == luid->LowPart; + } +#endif + + return true; +} + +void XRRuntimeManagerImpl::OnGpuInfoUpdate() { + content::GpuDataManager::GetInstance()->RemoveObserver(this); + + device::mojom::XrCompatibleResult xr_compatible_result; + auto* runtime = GetImmersiveVrRuntime(); + + if (runtime && IsInitializedOnCompatibleAdapter(runtime)) { + xr_compatible_result = + device::mojom::XrCompatibleResult::kCompatibleAfterRestart; + } else { + // We can still be incompatible after restarting if either: + // 1. The runtime has been removed (usually means the VR headset was + // unplugged) since the GPU process restart was triggered. Per the WebXR + // spec, if there is no device, xr compatible is false. + // 2. The GPU process is still not using the correct GPU after restarting. + xr_compatible_result = + device::mojom::XrCompatibleResult::kNotCompatibleAfterRestart; + } + + for (VRServiceImpl* service : services_) + service->OnMakeXrCompatibleComplete(xr_compatible_result); +} + XRRuntimeManagerImpl::XRRuntimeManagerImpl(XRProviderList providers) : providers_(std::move(providers)) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -385,14 +472,15 @@ bool XRRuntimeManagerImpl::AreAllProvidersInitialized() { void XRRuntimeManagerImpl::AddRuntime( device::mojom::XRDeviceId id, device::mojom::VRDisplayInfoPtr info, + device::mojom::XRDeviceDataPtr device_data, mojo::PendingRemote<device::mojom::XRRuntime> runtime) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(runtimes_.find(id) == runtimes_.end()); TRACE_EVENT_INSTANT1("xr", "AddRuntime", TRACE_EVENT_SCOPE_THREAD, "id", id); - runtimes_[id] = std::make_unique<BrowserXRRuntimeImpl>(id, std::move(runtime), - std::move(info)); + runtimes_[id] = std::make_unique<BrowserXRRuntimeImpl>( + id, std::move(device_data), std::move(runtime), std::move(info)); for (Observer& obs : g_xr_runtime_manager_observers.Get()) obs.OnRuntimeAdded(runtimes_[id].get()); diff --git a/chromium/content/browser/xr/service/xr_runtime_manager_impl.h b/chromium/content/browser/xr/service/xr_runtime_manager_impl.h index 57e5494a3d9..0445b05fb3e 100644 --- a/chromium/content/browser/xr/service/xr_runtime_manager_impl.h +++ b/chromium/content/browser/xr/service/xr_runtime_manager_impl.h @@ -21,6 +21,7 @@ #include "content/browser/xr/service/browser_xr_runtime_impl.h" #include "content/browser/xr/service/vr_service_impl.h" #include "content/common/content_export.h" +#include "content/public/browser/gpu_data_manager_observer.h" #include "content/public/browser/xr_integration_client.h" #include "content/public/browser/xr_runtime_manager.h" #include "device/vr/public/mojom/vr_service.mojom-forward.h" @@ -33,7 +34,8 @@ class XRRuntimeManagerTest; // instances. class CONTENT_EXPORT XRRuntimeManagerImpl : public XRRuntimeManager, - public base::RefCounted<XRRuntimeManagerImpl> { + public base::RefCounted<XRRuntimeManagerImpl>, + public content::GpuDataManagerObserver { public: friend base::RefCounted<XRRuntimeManagerImpl>; static constexpr auto kRefCountPreference = @@ -73,6 +75,11 @@ class CONTENT_EXPORT XRRuntimeManagerImpl device::mojom::XRSessionOptionsPtr options, device::mojom::VRService::SupportsSessionCallback callback); + void MakeXrCompatible(); + + // content::GpuDataManagerObserver + void OnGpuInfoUpdate() override; + // XRRuntimeManager implementation BrowserXRRuntimeImpl* GetRuntime(device::mojom::XRDeviceId id) override; void ForEachRuntime( @@ -99,9 +106,12 @@ class CONTENT_EXPORT XRRuntimeManagerImpl void AddRuntime(device::mojom::XRDeviceId id, device::mojom::VRDisplayInfoPtr info, + device::mojom::XRDeviceDataPtr device_data, mojo::PendingRemote<device::mojom::XRRuntime> runtime); void RemoveRuntime(device::mojom::XRDeviceId id); + bool IsInitializedOnCompatibleAdapter(BrowserXRRuntimeImpl* runtime); + // Gets the system default immersive-vr runtime if available. BrowserXRRuntimeImpl* GetImmersiveVrRuntime(); |