diff options
author | bajones <bajones@chromium.org> | 2015-06-18 09:39:07 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-18 16:39:47 +0000 |
commit | 4ab52def6d1861a55fd9864b47f56c16e4b423a0 (patch) | |
tree | 264d5754c3cae805c8f19959f30e04dd88d5ed63 | |
parent | 5d1fef66183dbe232abef3144bef2db8bf5dd7b8 (diff) | |
download | chromium_src-4ab52def6d1861a55fd9864b47f56c16e4b423a0.zip chromium_src-4ab52def6d1861a55fd9864b47f56c16e4b423a0.tar.gz chromium_src-4ab52def6d1861a55fd9864b47f56c16e4b423a0.tar.bz2 |
Adding Chrome-side WebVR interface and Cardboard implementation
WebVR Spec: http://mozvr.github.io/webvr-spec/webvr.html
For the Blink half of this CL, see https://codereview.chromium.org/848053002
Provides an Android-only, Cardboard-SDK-based implementation of the initial WebVR interface, as well as the basic plumbing required to get data from Javascript to the right place in the browser process and back.
BUG=389343
Review URL: https://codereview.chromium.org/829803003
Cr-Commit-Position: refs/heads/master@{#335062}
47 files changed, 1514 insertions, 2 deletions
diff --git a/build/common.gypi b/build/common.gypi index 04368e7..6d77eaa 100644 --- a/build/common.gypi +++ b/build/common.gypi @@ -1016,6 +1016,14 @@ }, { 'pkg-config': 'pkg-config' }], + + # Enable WebVR support by default on Android + # Still requires command line flag to access API + ['OS=="android"', { + 'enable_webvr%': 1, + }, { + 'enable_webvr%': 0, + }], ], # Setting this to '0' will cause V8's startup snapshot to be @@ -1232,6 +1240,7 @@ 'mac_views_browser%': '<(mac_views_browser)', 'android_app_version_name%': '<(android_app_version_name)', 'android_app_version_code%': '<(android_app_version_code)', + 'enable_webvr%': '<(enable_webvr)', # Use system protobuf instead of bundled one. 'use_system_protobuf%': 0, @@ -3030,6 +3039,9 @@ ['v8_use_external_startup_data==1', { 'defines': ['V8_USE_EXTERNAL_STARTUP_DATA'], }], + ['enable_webvr==1', { + 'defines': ['ENABLE_WEBVR'], + }], # SAFE_BROWSING_SERVICE - browser manages a safe-browsing service. # SAFE_BROWSING_DB_LOCAL - service manages a local database. diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index d1e6ee7..9fc86fd 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn @@ -269,6 +269,9 @@ config("feature_flags") { if (enable_media_router) { defines += [ "ENABLE_MEDIA_ROUTER=1" ] } + if (enable_webvr) { + defines += [ "ENABLE_WEBVR" ] + } } # Debug/release ---------------------------------------------------------------- diff --git a/build/config/features.gni b/build/config/features.gni index daf5177..8ef35f8 100644 --- a/build/config/features.gni +++ b/build/config/features.gni @@ -195,3 +195,7 @@ enable_hangout_services_extension = false # Whether to back up data before sync. enable_pre_sync_backup = is_win || is_mac || (is_linux && !is_chromeos) + +# Enable WebVR support by default on Android +# Still requires command line flag to access API +enable_webvr = is_android diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index fe443dd..5710807 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -5950,6 +5950,12 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_FLAGS_ENABLE_WEBRTC_STUN_ORIGIN_DESCRIPTION" desc="Description of chrome:flags option to turn on Origin header for WebRTC STUN messages"> When enabled, Stun messages generated by WebRTC will contain the Origin header. </message> + <message name="IDS_FLAGS_ENABLE_WEBVR_NAME" desc="Name of the 'Enable WebVR' flag."> + Enable WebVR + </message> + <message name="IDS_FLAGS_ENABLE_WEBVR_DESCRIPTION" desc="Description for the flag to enable WebVR APIs."> + Enabling this option allows web applications to access experimental Virtual Reality APIs. + </message> <if expr="is_android"> <message name="IDS_FLAGS_DISABLE_WEBAUDIO_NAME" desc="Name of the 'Disable WebAudio' lab."> Disable WebAudio diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 6b26f7f..2da2f56 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc @@ -1992,6 +1992,13 @@ const Experiment kExperiments[] = { ENABLE_DISABLE_VALUE_TYPE(switches::kEnableMacViewsNativeAppWindows, switches::kDisableMacViewsNativeAppWindows)}, #endif +#if defined(ENABLE_WEBVR) + {"enable-webvr", + IDS_FLAGS_ENABLE_WEBVR_NAME, + IDS_FLAGS_ENABLE_WEBVR_DESCRIPTION, + kOsAll, + SINGLE_VALUE_TYPE(switches::kEnableWebVR)}, +#endif // NOTE: Adding new command-line switches requires adding corresponding // entries to enum "LoginCustomFlags" in histograms.xml. See note in // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test. diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc index 16b433d..9e77998 100644 --- a/chrome/browser/chromeos/login/chrome_restart_request.cc +++ b/chrome/browser/chromeos/login/chrome_restart_request.cc @@ -158,6 +158,7 @@ std::string DeriveCommandLine(const GURL& start_url, ::switches::kVModule, ::switches::kEnableWebGLDraftExtensions, ::switches::kEnableWebGLImageChromium, + ::switches::kEnableWebVR, #if defined(ENABLE_WEBRTC) ::switches::kDisableWebRtcHWDecoding, ::switches::kDisableWebRtcHWEncoding, diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 3cdfc88..d71883c 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn @@ -479,4 +479,23 @@ source_set("browser") { if (enable_media_mojo_renderer) { deps += [ "//media/mojo/services:renderer_service" ] } + + if (enable_webvr) { + sources += [ + "vr/vr_device.cc", + "vr/vr_device.h", + "vr/vr_device_manager.cc", + "vr/vr_device_manager.h", + "vr/vr_device_provider.h", + ] + } + + if (enable_webvr && is_android) { + sources += [ + "vr/android/cardboard/cardboard_vr_device.cc", + "vr/android/cardboard/cardboard_vr_device.h", + "vr/android/cardboard/cardboard_vr_device_provider.cc", + "vr/android/cardboard/cardboard_vr_device_provider.h", + ] + } } diff --git a/content/browser/DEPS b/content/browser/DEPS index 2ed7e5c..092903f 100644 --- a/content/browser/DEPS +++ b/content/browser/DEPS @@ -63,6 +63,7 @@ include_rules = [ "+third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h", "+third_party/WebKit/public/platform/modules/notifications/WebNotificationPermission.h", "+third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h", + "+third_party/WebKit/public/platform/modules/vr/WebVR.h", "+third_party/WebKit/public/web/mac/WebScrollbarTheme.h", "+third_party/WebKit/public/web/WebAXEnums.h", "+third_party/WebKit/public/web/WebCompositionUnderline.h", diff --git a/content/browser/android/browser_jni_registrar.cc b/content/browser/android/browser_jni_registrar.cc index 808e3f3..43adba8 100644 --- a/content/browser/android/browser_jni_registrar.cc +++ b/content/browser/android/browser_jni_registrar.cc @@ -40,6 +40,7 @@ #include "content/browser/screen_orientation/screen_orientation_delegate_android.h" #include "content/browser/speech/speech_recognizer_impl_android.h" #include "content/browser/time_zone_monitor_android.h" +#include "content/browser/vr/android/cardboard/cardboard_vr_device.h" #include "content/browser/web_contents/web_contents_android.h" #include "mojo/android/system/core_impl.h" @@ -52,6 +53,10 @@ base::android::RegistrationMethod kContentRegisteredMethods[] = { {"BrowserAccessibilityManager", content::RegisterBrowserAccessibilityManager}, {"BrowserStartupController", content::RegisterBrowserStartupController}, +#if defined(ENABLE_WEBVR) + {"CardboardVRDevice", + content::CardboardVRDevice::RegisterCardboardVRDevice}, +#endif {"ChildProcessLauncher", content::RegisterChildProcessLauncher}, {"ContentReadbackHandler", content::ContentReadbackHandler::RegisterContentReadbackHandler}, diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 74ac164..11ae65a 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc @@ -81,6 +81,10 @@ #include "media/mojo/services/mojo_renderer_service.h" #endif +#if defined(ENABLE_WEBVR) +#include "content/browser/vr/vr_device_manager.h" +#endif + using base::TimeDelta; namespace content { @@ -1579,6 +1583,16 @@ void RenderFrameHostImpl::RegisterMojoServices() { GetServiceRegistry()->AddService<mojo::Shell>(base::Bind( &FrameMojoShell::BindRequest, base::Unretained(frame_mojo_shell_.get()))); +#if defined(ENABLE_WEBVR) + const base::CommandLine& browser_command_line = + *base::CommandLine::ForCurrentProcess(); + + if (browser_command_line.HasSwitch(switches::kEnableWebVR)) { + GetServiceRegistry()->AddService<VRService>( + base::Bind(&VRDeviceManager::BindRequest)); + } +#endif + GetContentClient()->browser()->OverrideRenderFrameMojoServices( GetServiceRegistry(), this); } diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index aa2cee4..4754ddb 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -1306,6 +1306,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( switches::kEnableWebBluetooth, switches::kEnableWebGLDraftExtensions, switches::kEnableWebGLImageChromium, + switches::kEnableWebVR, switches::kExplicitlyAllowedPorts, switches::kForceDeviceScaleFactor, switches::kForceDisplayList2dCanvas, diff --git a/content/browser/vr/OWNERS b/content/browser/vr/OWNERS new file mode 100644 index 0000000..1c724a6 --- /dev/null +++ b/content/browser/vr/OWNERS @@ -0,0 +1,2 @@ +bajones@chromium.org +kbr@chromium.org diff --git a/content/browser/vr/android/cardboard/cardboard_vr_device.cc b/content/browser/vr/android/cardboard/cardboard_vr_device.cc new file mode 100644 index 0000000..11f8505 --- /dev/null +++ b/content/browser/vr/android/cardboard/cardboard_vr_device.cc @@ -0,0 +1,188 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/vr/android/cardboard/cardboard_vr_device.h" + +#include <math.h> +#include <algorithm> + +#include "base/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" +#include "jni/CardboardVRDevice_jni.h" + +using base::android::AttachCurrentThread; + +namespace content { + +namespace { + +// Source: +// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/ +VRVector4Ptr MatrixToOrientationQuat(const float m[16]) { + VRVector4Ptr out = VRVector4::New(); + float trace = m[0] + m[5] + m[10]; + float root; + if (trace > 0.0f) { + root = sqrtf(1.0f + trace) * 2.0f; + out->x = (m[9] - m[6]) / root; + out->y = (m[2] - m[8]) / root; + out->z = (m[4] - m[1]) / root; + out->w = 0.25f * root; + } else if ((m[0] > m[5]) && (m[0] > m[10])) { + root = sqrtf(1.0f + m[0] - m[5] - m[10]) * 2.0f; + out->x = 0.25f * root; + out->y = (m[1] + m[4]) / root; + out->z = (m[2] + m[8]) / root; + out->w = (m[9] - m[6]) / root; + } else if (m[5] > m[10]) { + root = sqrtf(1.0f + m[5] - m[0] - m[10]) * 2.0f; + out->x = (m[1] + m[4]) / root; + out->y = 0.25f * root; + out->z = (m[6] + m[9]) / root; + out->w = (m[2] - m[8]) / root; + } else { + root = sqrtf(1.0f + m[10] - m[0] - m[5]) * 2.0f; + out->x = (m[2] + m[8]) / root; + out->y = (m[6] + m[9]) / root; + out->z = 0.25f * root; + out->w = (m[4] - m[1]) / root; + } + + return out.Pass(); +} + +} // namespace + +bool CardboardVRDevice::RegisterCardboardVRDevice(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +CardboardVRDevice::CardboardVRDevice(VRDeviceProvider* provider) + : VRDevice(provider), frame_index_(0) { + j_cardboard_device_.Reset(Java_CardboardVRDevice_create( + AttachCurrentThread(), base::android::GetApplicationContext())); +} + +CardboardVRDevice::~CardboardVRDevice() { + Java_CardboardVRDevice_stopTracking(AttachCurrentThread(), + j_cardboard_device_.obj()); +} + +VRDeviceInfoPtr CardboardVRDevice::GetVRDevice() { + VRDeviceInfoPtr device = VRDeviceInfo::New(); + + JNIEnv* env = AttachCurrentThread(); + + ScopedJavaLocalRef<jstring> j_device_name = + Java_CardboardVRDevice_getDeviceName(env, j_cardboard_device_.obj()); + device->deviceName = + base::android::ConvertJavaStringToUTF8(env, j_device_name.obj()); + + ScopedJavaLocalRef<jfloatArray> j_fov(env, env->NewFloatArray(4)); + Java_CardboardVRDevice_getFieldOfView(env, j_cardboard_device_.obj(), + j_fov.obj()); + + std::vector<float> fov; + base::android::JavaFloatArrayToFloatVector(env, j_fov.obj(), &fov); + + device->hmdInfo = VRHMDInfo::New(); + VRHMDInfoPtr& hmdInfo = device->hmdInfo; + + hmdInfo->leftEye = VREyeParameters::New(); + hmdInfo->rightEye = VREyeParameters::New(); + VREyeParametersPtr& leftEye = hmdInfo->leftEye; + VREyeParametersPtr& rightEye = hmdInfo->rightEye; + + leftEye->recommendedFieldOfView = VRFieldOfView::New(); + leftEye->recommendedFieldOfView->upDegrees = fov[0]; + leftEye->recommendedFieldOfView->downDegrees = fov[1]; + leftEye->recommendedFieldOfView->leftDegrees = fov[2]; + leftEye->recommendedFieldOfView->rightDegrees = fov[3]; + + // Cardboard devices always assume a mirrored FOV, so this is just the left + // eye FOV with the left and right degrees swapped. + rightEye->recommendedFieldOfView = VRFieldOfView::New(); + rightEye->recommendedFieldOfView->upDegrees = fov[0]; + rightEye->recommendedFieldOfView->downDegrees = fov[1]; + rightEye->recommendedFieldOfView->leftDegrees = fov[3]; + rightEye->recommendedFieldOfView->rightDegrees = fov[2]; + + // Cardboard does not support configurable FOV. + leftEye->maximumFieldOfView = leftEye->recommendedFieldOfView.Clone(); + rightEye->maximumFieldOfView = rightEye->recommendedFieldOfView.Clone(); + leftEye->minimumFieldOfView = leftEye->recommendedFieldOfView.Clone(); + rightEye->minimumFieldOfView = rightEye->recommendedFieldOfView.Clone(); + + float ipd = Java_CardboardVRDevice_getIpd(env, j_cardboard_device_.obj()); + + leftEye->eyeTranslation = VRVector3::New(); + leftEye->eyeTranslation->x = ipd * -0.5f; + leftEye->eyeTranslation->y = 0.0f; + leftEye->eyeTranslation->z = 0.0f; + + rightEye->eyeTranslation = VRVector3::New(); + rightEye->eyeTranslation->x = ipd * 0.5f; + rightEye->eyeTranslation->y = 0.0f; + rightEye->eyeTranslation->z = 0.0f; + + ScopedJavaLocalRef<jintArray> j_screen_size(env, env->NewIntArray(2)); + Java_CardboardVRDevice_getScreenSize(env, j_cardboard_device_.obj(), + j_screen_size.obj()); + + std::vector<int> screen_size; + base::android::JavaIntArrayToIntVector(env, j_screen_size.obj(), + &screen_size); + + leftEye->renderRect = VRRect::New(); + leftEye->renderRect->x = 0; + leftEye->renderRect->y = 0; + leftEye->renderRect->width = screen_size[0] / 2.0; + leftEye->renderRect->height = screen_size[1]; + + rightEye->renderRect = VRRect::New(); + rightEye->renderRect->x = screen_size[0] / 2.0; + rightEye->renderRect->y = 0; + rightEye->renderRect->width = screen_size[0] / 2.0; + rightEye->renderRect->height = screen_size[1]; + + return device.Pass(); +} + +VRSensorStatePtr CardboardVRDevice::GetSensorState() { + VRSensorStatePtr state = VRSensorState::New(); + + state->timestamp = base::Time::Now().ToJsTime(); + state->frameIndex = frame_index_; + + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jfloatArray> j_head_matrix(env, env->NewFloatArray(16)); + Java_CardboardVRDevice_getSensorState(env, j_cardboard_device_.obj(), + j_head_matrix.obj()); + + std::vector<float> head_matrix; + base::android::JavaFloatArrayToFloatVector(env, j_head_matrix.obj(), + &head_matrix); + + state->orientation = MatrixToOrientationQuat(&head_matrix[0]); + + state->position = VRVector3::New(); + state->position->x = -head_matrix[12]; + state->position->y = head_matrix[13]; + state->position->z = head_matrix[14]; + + frame_index_++; + + return state.Pass(); +} + +void CardboardVRDevice::ResetSensor() { + Java_CardboardVRDevice_resetSensor(AttachCurrentThread(), + j_cardboard_device_.obj()); +} + +} // namespace content diff --git a/content/browser/vr/android/cardboard/cardboard_vr_device.h b/content/browser/vr/android/cardboard/cardboard_vr_device.h new file mode 100644 index 0000000..5d7baa9 --- /dev/null +++ b/content/browser/vr/android/cardboard/cardboard_vr_device.h @@ -0,0 +1,37 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_VR_CARDBOARD_VR_DEVICE_H +#define CONTENT_BROWSER_VR_CARDBOARD_VR_DEVICE_H + +#include <jni.h> + +#include "base/android/jni_android.h" +#include "base/basictypes.h" +#include "content/browser/vr/vr_device.h" + +namespace content { + +class CardboardVRDevice : public VRDevice { + public: + static bool RegisterCardboardVRDevice(JNIEnv* env); + + explicit CardboardVRDevice(VRDeviceProvider* provider); + ~CardboardVRDevice() override; + + VRDeviceInfoPtr GetVRDevice() override; + VRSensorStatePtr GetSensorState() override; + void ResetSensor() override; + + private: + base::android::ScopedJavaGlobalRef<jobject> j_cardboard_device_; + + unsigned int frame_index_; + + DISALLOW_COPY_AND_ASSIGN(CardboardVRDevice); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_VR_CARDBOARD_VR_DEVICE_H diff --git a/content/browser/vr/android/cardboard/cardboard_vr_device_provider.cc b/content/browser/vr/android/cardboard/cardboard_vr_device_provider.cc new file mode 100644 index 0000000..eeb5baf --- /dev/null +++ b/content/browser/vr/android/cardboard/cardboard_vr_device_provider.cc @@ -0,0 +1,29 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/vr/android/cardboard/cardboard_vr_device_provider.h" + +#include "content/browser/vr/android/cardboard/cardboard_vr_device.h" + +namespace content { + +CardboardVRDeviceProvider::CardboardVRDeviceProvider() : VRDeviceProvider() { +} + +CardboardVRDeviceProvider::~CardboardVRDeviceProvider() { +} + +void CardboardVRDeviceProvider::GetDevices(std::vector<VRDevice*>& devices) { + if (!cardboard_device_) { + cardboard_device_.reset(new CardboardVRDevice(this)); + } + + devices.push_back(cardboard_device_.get()); +} + +void CardboardVRDeviceProvider::Initialize() { + // No initialization needed for Cardboard devices. +} + +} // namespace content diff --git a/content/browser/vr/android/cardboard/cardboard_vr_device_provider.h b/content/browser/vr/android/cardboard/cardboard_vr_device_provider.h new file mode 100644 index 0000000..18efa5c --- /dev/null +++ b/content/browser/vr/android/cardboard/cardboard_vr_device_provider.h @@ -0,0 +1,33 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_VR_CARDBOARD_VR_DEVICE_PROVIDER_H +#define CONTENT_BROWSER_VR_CARDBOARD_VR_DEVICE_PROVIDER_H + +#include <map> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "content/browser/vr/vr_device.h" +#include "content/browser/vr/vr_device_provider.h" + +namespace content { + +class CardboardVRDeviceProvider : public VRDeviceProvider { + public: + CardboardVRDeviceProvider(); + ~CardboardVRDeviceProvider() override; + + void GetDevices(std::vector<VRDevice*>& devices) override; + void Initialize() override; + + private: + scoped_ptr<VRDevice> cardboard_device_; + + DISALLOW_COPY_AND_ASSIGN(CardboardVRDeviceProvider); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_VR_CARDBOARD_VR_DEVICE_PROVIDER_H diff --git a/content/browser/vr/test/fake_vr_device.cc b/content/browser/vr/test/fake_vr_device.cc new file mode 100644 index 0000000..7ee5e06 --- /dev/null +++ b/content/browser/vr/test/fake_vr_device.cc @@ -0,0 +1,33 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/vr/test/fake_vr_device.h" + +namespace content { + +FakeVRDevice::FakeVRDevice(VRDeviceProvider* provider) : VRDevice(provider) { + device_ = VRDeviceInfo::New(); + state_ = VRSensorState::New(); +} + +FakeVRDevice::~FakeVRDevice() { +} + +void FakeVRDevice::SetVRDevice(const VRDeviceInfoPtr& device) { + device_ = device.Clone(); +} + +void FakeVRDevice::SetSensorState(const VRSensorStatePtr& state) { + state_ = state.Clone(); +} + +VRDeviceInfoPtr FakeVRDevice::GetVRDevice() { + return device_.Clone(); +} + +VRSensorStatePtr FakeVRDevice::GetSensorState() { + return state_.Clone(); +} + +} // namespace content
\ No newline at end of file diff --git a/content/browser/vr/test/fake_vr_device.h b/content/browser/vr/test/fake_vr_device.h new file mode 100644 index 0000000..2cb7384 --- /dev/null +++ b/content/browser/vr/test/fake_vr_device.h @@ -0,0 +1,34 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_VR_TEST_FAKE_VR_DEVICE_H_ +#define CONTENT_BROWSER_VR_TEST_FAKE_VR_DEVICE_H_ + +#include "content/browser/vr/vr_device.h" +#include "content/browser/vr/vr_device_provider.h" + +namespace content { + +class FakeVRDevice : public VRDevice { + public: + explicit FakeVRDevice(VRDeviceProvider* provider); + ~FakeVRDevice() override; + + void SetVRDevice(const VRDeviceInfoPtr& device); + void SetSensorState(const VRSensorStatePtr& state); + + VRDeviceInfoPtr GetVRDevice() override; + VRSensorStatePtr GetSensorState() override; + void ResetSensor() override{}; + + private: + VRDeviceInfoPtr device_; + VRSensorStatePtr state_; + + DISALLOW_COPY_AND_ASSIGN(FakeVRDevice); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_VR_TEST_FAKE_VR_DEVICE_H_ diff --git a/content/browser/vr/test/fake_vr_device_provider.cc b/content/browser/vr/test/fake_vr_device_provider.cc new file mode 100644 index 0000000..d69802b --- /dev/null +++ b/content/browser/vr/test/fake_vr_device_provider.cc @@ -0,0 +1,43 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/vr/test/fake_vr_device_provider.h" + +namespace content { + +FakeVRDeviceProvider::FakeVRDeviceProvider() : VRDeviceProvider() { + initialized_ = false; +} + +FakeVRDeviceProvider::~FakeVRDeviceProvider() { +} + +void FakeVRDeviceProvider::AddDevice(VRDevice* device) { + devices_.push_back(device); +} + +void FakeVRDeviceProvider::RemoveDevice(VRDevice* device) { + std::vector<VRDevice*>::iterator iter = devices_.begin(); + while (iter != devices_.end()) { + if (device == *iter) { + iter = devices_.erase(iter); + } else { + ++iter; + } + } +} + +void FakeVRDeviceProvider::GetDevices(std::vector<VRDevice*>& devices) { + std::vector<VRDevice*>::iterator iter; + + for (auto device : devices_) { + devices.push_back(device); + } +} + +void FakeVRDeviceProvider::Initialize() { + initialized_ = true; +} + +} // namespace content
\ No newline at end of file diff --git a/content/browser/vr/test/fake_vr_device_provider.h b/content/browser/vr/test/fake_vr_device_provider.h new file mode 100644 index 0000000..e5877a3 --- /dev/null +++ b/content/browser/vr/test/fake_vr_device_provider.h @@ -0,0 +1,35 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_VR_TEST_FAKE_VR_DEVICE_PROVIDER_H_ +#define CONTENT_BROWSER_VR_TEST_FAKE_VR_DEVICE_PROVIDER_H_ + +#include <vector> +#include "content/browser/vr/vr_device.h" +#include "content/browser/vr/vr_device_provider.h" + +namespace content { + +class FakeVRDeviceProvider : public VRDeviceProvider { + public: + FakeVRDeviceProvider(); + ~FakeVRDeviceProvider() override; + + // Adds devices to the provider with the given device, which will be + // returned when GetDevices is queried. + void AddDevice(VRDevice* device); + void RemoveDevice(VRDevice* device); + bool IsInitialized() { return initialized_; } + + void GetDevices(std::vector<VRDevice*>& devices) override; + void Initialize() override; + + private: + std::vector<VRDevice*> devices_; + bool initialized_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_VR_TEST_FAKE_VR_DEVICE_PROVIDER_H_ diff --git a/content/browser/vr/vr_device.cc b/content/browser/vr/vr_device.cc new file mode 100644 index 0000000..ab7a7bc --- /dev/null +++ b/content/browser/vr/vr_device.cc @@ -0,0 +1,22 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/vr/vr_device.h" +#include "content/browser/vr/vr_device_provider.h" + +namespace content { + +unsigned int VRDevice::next_id_ = 1; + +VRDevice::VRDevice(VRDeviceProvider* provider) + : provider_(provider), id_(next_id_) { + // Prevent wraparound. Devices with this ID will be treated as invalid. + if (next_id_ != VR_DEVICE_LAST_ID) + next_id_++; +} + +VRDevice::~VRDevice() { +} + +} // namespace content diff --git a/content/browser/vr/vr_device.h b/content/browser/vr/vr_device.h new file mode 100644 index 0000000..e3026d7 --- /dev/null +++ b/content/browser/vr/vr_device.h @@ -0,0 +1,48 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_VR_VR_DEVICE_H +#define CONTENT_BROWSER_VR_VR_DEVICE_H + +#include "base/macros.h" +#include "content/common/vr_service.mojom.h" + +namespace blink { +struct WebHMDSensorState; +} + +namespace ui { +class BaseWindow; +} + +namespace content { + +class VRDeviceProvider; + +const unsigned int VR_DEVICE_LAST_ID = 0xFFFFFFFF; + +class VRDevice { + public: + explicit VRDevice(VRDeviceProvider* provider); + virtual ~VRDevice(); + + VRDeviceProvider* provider() const { return provider_; } + unsigned int id() const { return id_; } + + virtual VRDeviceInfoPtr GetVRDevice() = 0; + virtual VRSensorStatePtr GetSensorState() = 0; + virtual void ResetSensor() = 0; + + private: + VRDeviceProvider* provider_; + unsigned int id_; + + static unsigned int next_id_; + + DISALLOW_COPY_AND_ASSIGN(VRDevice); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_VR_VR_DEVICE_H diff --git a/content/browser/vr/vr_device_manager.cc b/content/browser/vr/vr_device_manager.cc new file mode 100644 index 0000000..1451056 --- /dev/null +++ b/content/browser/vr/vr_device_manager.cc @@ -0,0 +1,148 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/vr/vr_device_manager.h" + +#include "base/memory/singleton.h" +#include "third_party/WebKit/public/platform/modules/vr/WebVR.h" + +#if defined(OS_ANDROID) +#include "content/browser/vr/android/cardboard/cardboard_vr_device_provider.h" +#endif + +namespace content { + +namespace { +VRDeviceManager* g_vr_device_manager = nullptr; +} + +VRDeviceManager::VRDeviceManager() + : vr_initialized_(false), keep_alive_(false) { + bindings_.set_error_handler(this); + +#if defined(OS_ANDROID) + scoped_ptr<VRDeviceProvider> cardboard_provider( + new CardboardVRDeviceProvider()); + RegisterProvider(cardboard_provider.Pass()); +#endif +} + +VRDeviceManager::VRDeviceManager(scoped_ptr<VRDeviceProvider> provider) + : vr_initialized_(false), keep_alive_(true) { + thread_checker_.DetachFromThread(); + RegisterProvider(provider.Pass()); + SetInstance(this); +} + +VRDeviceManager::~VRDeviceManager() { + DCHECK(thread_checker_.CalledOnValidThread()); + g_vr_device_manager = nullptr; +} + +void VRDeviceManager::BindRequest(mojo::InterfaceRequest<VRService> request) { + VRDeviceManager* device_manager = GetInstance(); + device_manager->bindings_.AddBinding(device_manager, request.Pass()); +} + +void VRDeviceManager::OnConnectionError() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (bindings_.empty() && !keep_alive_) { + // Delete the device manager when it has no active connections. + delete g_vr_device_manager; + } +} + +VRDeviceManager* VRDeviceManager::GetInstance() { + if (!g_vr_device_manager) + g_vr_device_manager = new VRDeviceManager(); + return g_vr_device_manager; +} + +void VRDeviceManager::SetInstance(VRDeviceManager* instance) { + // Unit tests can create multiple instances but only one should exist at any + // given time so g_vr_device_manager should only go from nullptr to + // non-nullptr and vica versa. + CHECK_NE(!!instance, !!g_vr_device_manager); + g_vr_device_manager = instance; +} + +bool VRDeviceManager::HasInstance() { + // For testing. Checks to see if a VRDeviceManager instance is active. + return !!g_vr_device_manager; +} + +mojo::Array<VRDeviceInfoPtr> VRDeviceManager::GetVRDevices() { + DCHECK(thread_checker_.CalledOnValidThread()); + + InitializeProviders(); + + std::vector<VRDevice*> devices; + for (const auto& provider : providers_) + provider->GetDevices(devices); + + mojo::Array<VRDeviceInfoPtr> out_devices(0); + for (const auto& device : devices) { + if (device->id() == VR_DEVICE_LAST_ID) + continue; + + if (devices_.find(device->id()) == devices_.end()) + devices_[device->id()] = device; + + VRDeviceInfoPtr vr_device_info = device->GetVRDevice(); + if (vr_device_info.is_null()) + continue; + + vr_device_info->index = device->id(); + out_devices.push_back(vr_device_info.Pass()); + } + + return out_devices; +} + +VRDevice* VRDeviceManager::GetDevice(unsigned int index) { + DCHECK(thread_checker_.CalledOnValidThread()); + + DeviceMap::iterator iter = devices_.find(index); + if (iter == devices_.end()) { + return nullptr; + } + return iter->second; +} + +void VRDeviceManager::InitializeProviders() { + if (vr_initialized_) { + return; + } + + for (const auto& provider : providers_) + provider->Initialize(); + + vr_initialized_ = true; +} + +void VRDeviceManager::RegisterProvider(scoped_ptr<VRDeviceProvider> provider) { + providers_.push_back(make_linked_ptr(provider.release())); +} + +void VRDeviceManager::GetDevices(const GetDevicesCallback& callback) { + callback.Run(GetVRDevices()); +} + +void VRDeviceManager::GetSensorState(uint32_t index, + const GetSensorStateCallback& callback) { + VRDevice* device = GetDevice(index); + if (device) { + callback.Run(device->GetSensorState()); + } else { + callback.Run(nullptr); + } +} + +void VRDeviceManager::ResetSensor(uint32_t index) { + VRDevice* device = GetDevice(index); + if (device) + device->ResetSensor(); +} + +} // namespace content diff --git a/content/browser/vr/vr_device_manager.h b/content/browser/vr/vr_device_manager.h new file mode 100644 index 0000000..6c8dc96 --- /dev/null +++ b/content/browser/vr/vr_device_manager.h @@ -0,0 +1,78 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_VR_VR_DEVICE_MANAGER_H +#define CONTENT_BROWSER_VR_VR_DEVICE_MANAGER_H + +#include <map> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/linked_ptr.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/thread_checker.h" +#include "content/browser/vr/vr_device.h" +#include "content/browser/vr/vr_device_provider.h" +#include "content/common/content_export.h" +#include "content/common/vr_service.mojom.h" +#include "mojo/common/weak_binding_set.h" + +namespace content { + +class VRDeviceManager : public VRService, public mojo::ErrorHandler { + public: + ~VRDeviceManager() override; + + static void BindRequest(mojo::InterfaceRequest<VRService> request); + + // Returns the VRDeviceManager singleton. + static VRDeviceManager* GetInstance(); + + mojo::Array<VRDeviceInfoPtr> GetVRDevices(); + VRDevice* GetDevice(unsigned int index); + + private: + friend class VRDeviceManagerTest; + + VRDeviceManager(); + // Constructor for testing. + explicit VRDeviceManager(scoped_ptr<VRDeviceProvider> provider); + + static void SetInstance(VRDeviceManager* service); + static bool HasInstance(); + + void InitializeProviders(); + void RegisterProvider(scoped_ptr<VRDeviceProvider> provider); + + // VRService implementation + void GetDevices(const GetDevicesCallback& callback) override; + void GetSensorState(uint32_t index, + const GetSensorStateCallback& callback) override; + void ResetSensor(uint32_t index) override; + + // mojo::ErrorHandler implementation + void OnConnectionError() override; + + using ProviderList = std::vector<linked_ptr<VRDeviceProvider>>; + ProviderList providers_; + + // Devices are owned by their providers. + using DeviceMap = std::map<unsigned int, VRDevice*>; + DeviceMap devices_; + + bool vr_initialized_; + + mojo::WeakBindingSet<VRService> bindings_; + + // For testing. If true will not delete self when consumer count reaches 0. + bool keep_alive_; + + base::ThreadChecker thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(VRDeviceManager); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_VR_VR_DEVICE_MANAGER_H diff --git a/content/browser/vr/vr_device_manager_unittest.cc b/content/browser/vr/vr_device_manager_unittest.cc new file mode 100644 index 0000000..873a296 --- /dev/null +++ b/content/browser/vr/vr_device_manager_unittest.cc @@ -0,0 +1,96 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/linked_ptr.h" +#include "base/memory/scoped_ptr.h" +#include "content/browser/vr/test/fake_vr_device.h" +#include "content/browser/vr/test/fake_vr_device_provider.h" +#include "content/browser/vr/vr_device_manager.h" +#include "content/browser/vr/vr_device_provider.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { + +class VRDeviceManagerTest : public testing::Test { + protected: + VRDeviceManagerTest(); + ~VRDeviceManagerTest() override; + + void SetUp() override; + + bool HasServiceInstance() { return VRDeviceManager::HasInstance(); } + + protected: + FakeVRDeviceProvider* provider_; + scoped_ptr<VRDeviceManager> device_manager_; + + DISALLOW_COPY_AND_ASSIGN(VRDeviceManagerTest); +}; + +VRDeviceManagerTest::VRDeviceManagerTest() { +} + +VRDeviceManagerTest::~VRDeviceManagerTest() { +} + +void VRDeviceManagerTest::SetUp() { + scoped_ptr<FakeVRDeviceProvider> provider(new FakeVRDeviceProvider()); + provider_ = provider.get(); + device_manager_.reset(new VRDeviceManager(provider.Pass())); +} + +TEST_F(VRDeviceManagerTest, InitializationTest) { + EXPECT_FALSE(provider_->IsInitialized()); + + // Calling GetDevices should initialize the service if it hasn't been + // initialized yet or the providesr have been released. + // The VRService should initialize each of it's providers upon it's own + // initialization. + mojo::Array<VRDeviceInfoPtr> webvr_devices; + webvr_devices = device_manager_->GetVRDevices(); + EXPECT_TRUE(provider_->IsInitialized()); +} + +TEST_F(VRDeviceManagerTest, GetDevicesBasicTest) { + mojo::Array<VRDeviceInfoPtr> webvr_devices; + webvr_devices = device_manager_->GetVRDevices(); + // Calling GetVRDevices should initialize the providers. + EXPECT_TRUE(provider_->IsInitialized()); + // Should successfully return zero devices when none are available. + EXPECT_EQ(0u, webvr_devices.size()); + + // GetDeviceByIndex should return nullptr if an invalid index in queried. + VRDevice* queried_device = device_manager_->GetDevice(1); + EXPECT_EQ(nullptr, queried_device); + + scoped_ptr<FakeVRDevice> device1(new FakeVRDevice(provider_)); + provider_->AddDevice(device1.get()); + webvr_devices = device_manager_->GetVRDevices(); + // Should have successfully returned one device. + EXPECT_EQ(1u, webvr_devices.size()); + // The WebVRDevice index should match the device id. + EXPECT_EQ(webvr_devices[0]->index, device1->id()); + + scoped_ptr<FakeVRDevice> device2(new FakeVRDevice(provider_)); + provider_->AddDevice(device2.get()); + webvr_devices = device_manager_->GetVRDevices(); + // Should have successfully returned two devices. + EXPECT_EQ(2u, webvr_devices.size()); + // NOTE: Returned WebVRDevices are not required to be in any particular order. + + // Querying the WebVRDevice index should return the correct device. + queried_device = device_manager_->GetDevice(device1->id()); + EXPECT_EQ(device1.get(), queried_device); + queried_device = device_manager_->GetDevice(device2->id()); + EXPECT_EQ(device2.get(), queried_device); + + provider_->RemoveDevice(device1.get()); + webvr_devices = device_manager_->GetVRDevices(); + // Should have successfully returned one device. + EXPECT_EQ(1u, webvr_devices.size()); + // The WebVRDevice index should match the only remaining device id. + EXPECT_EQ(webvr_devices[0]->index, device2->id()); +} + +} // namespace content diff --git a/content/browser/vr/vr_device_provider.h b/content/browser/vr/vr_device_provider.h new file mode 100644 index 0000000..7a0207c --- /dev/null +++ b/content/browser/vr/vr_device_provider.h @@ -0,0 +1,27 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_VR_VR_DEVICE_PROVIDER_H +#define CONTENT_BROWSER_VR_VR_DEVICE_PROVIDER_H + +#include <vector> + +namespace content { + +class VRDevice; + +class VRDeviceProvider { + public: + VRDeviceProvider() {} + virtual ~VRDeviceProvider() {} + + virtual void GetDevices(std::vector<VRDevice*>& devices) = 0; + + // If the VR API requires initialization that should happen here. + virtual void Initialize() = 0; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_VR_VR_DEVICE_PROVIDER_H diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 5ce09de..8309415 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc @@ -203,6 +203,11 @@ void SetRuntimeFeaturesDefaultsAndUpdateFromArgs( if (command_line.HasSwitch(switches::kEnableUnsafeES3APIs)) WebRuntimeFeatures::enableUnsafeES3APIs(true); + if (command_line.HasSwitch(switches::kEnableWebVR)) { + WebRuntimeFeatures::enableWebVR(true); + WebRuntimeFeatures::enableFeatureFromString("GeometryInterfaces", true); + } + // Enable explicitly enabled features, and then disable explicitly disabled // ones. if (command_line.HasSwitch(switches::kEnableBlinkFeatures)) { diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index 2e82056..9f9c1e9 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn @@ -492,6 +492,7 @@ mojom("mojo_bindings") { "presentation/presentation_service.mojom", "process_control.mojom", "render_frame_setup.mojom", + "vr_service.mojom", ] import_dirs = [ "//mojo/services" ] diff --git a/content/common/vr_service.mojom b/content/common/vr_service.mojom new file mode 100644 index 0000000..2d81ec7 --- /dev/null +++ b/content/common/vr_service.mojom @@ -0,0 +1,73 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module content; + +struct VRVector3 { + float x; + float y; + float z; +}; + +struct VRVector4 { + float x; + float y; + float z; + float w; +}; + +struct VRRect { + int32 x; + int32 y; + int32 width; + int32 height; +}; + +// A field of view, given by 4 degrees describing the view from a center point. +struct VRFieldOfView { + float upDegrees; + float downDegrees; + float leftDegrees; + float rightDegrees; +}; + +// A sensor's position, orientation, velocity, and acceleration state at the +// given timestamp. +struct VRSensorState { + double timestamp; + uint32 frameIndex; + VRVector4? orientation; + VRVector3? position; + VRVector3? angularVelocity; + VRVector3? linearVelocity; + VRVector3? angularAcceleration; + VRVector3? linearAcceleration; +}; + +// Information about the optical properties for an eye in an HMD. +struct VREyeParameters { + VRFieldOfView minimumFieldOfView; + VRFieldOfView maximumFieldOfView; + VRFieldOfView recommendedFieldOfView; + VRVector3 eyeTranslation; + VRRect renderRect; +}; + +// Information pertaining to Head Mounted Displays. +struct VRHMDInfo { + VREyeParameters leftEye; + VREyeParameters rightEye; +}; + +struct VRDeviceInfo { + uint32 index; + string deviceName; + VRHMDInfo? hmdInfo; +}; + +interface VRService { + GetDevices() => (array<VRDeviceInfo> devices); + GetSensorState(uint32 index) => (VRSensorState state); + ResetSensor(uint32 index); +}; diff --git a/content/content.gyp b/content/content.gyp index 13a8385..beffec2 100644 --- a/content/content.gyp +++ b/content/content.gyp @@ -589,6 +589,16 @@ 'motionevent_jni_headers' ], 'includes': [ 'content_jni.gypi' ], + 'conditions': [ + ['enable_webvr==1', { + 'sources': [ + 'public/android/java/src/org/chromium/content/browser/input/CardboardVRDevice.java', + ], + 'dependencies': [ + '../third_party/cardboard-java/cardboard.gyp:cardboard_jar', + ], + }], + ], }, { 'target_name': 'content_icudata', diff --git a/content/content_browser.gypi b/content/content_browser.gypi index b406173..1ac6bb2 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -2091,5 +2091,22 @@ '../third_party/boringssl/boringssl.gyp:boringssl', ], }], + ['enable_webvr==1', { + 'sources': [ + 'browser/vr/vr_device.cc', + 'browser/vr/vr_device.h', + 'browser/vr/vr_device_manager.cc', + 'browser/vr/vr_device_manager.h', + 'browser/vr/vr_device_provider.h', + ] + }], + ['enable_webvr==1 and OS=="android"', { + 'sources': [ + 'browser/vr/android/cardboard/cardboard_vr_device.cc', + 'browser/vr/android/cardboard/cardboard_vr_device.h', + 'browser/vr/android/cardboard/cardboard_vr_device_provider.cc', + 'browser/vr/android/cardboard/cardboard_vr_device_provider.h', + ], + }], ], } diff --git a/content/content_common_mojo_bindings.gyp b/content/content_common_mojo_bindings.gyp index 4f01043..528fa67 100644 --- a/content/content_common_mojo_bindings.gyp +++ b/content/content_common_mojo_bindings.gyp @@ -18,6 +18,7 @@ 'common/presentation/presentation_service.mojom', 'common/process_control.mojom', 'common/render_frame_setup.mojom', + 'common/vr_service.mojom', # NOTE: Sources duplicated in # //content/public/common/BUILD.gn:mojo_bindings. diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index aaf0c40..1089688 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -837,6 +837,14 @@ ['use_seccomp_bpf==1', { 'defines': ['USE_SECCOMP_BPF'], }], + ['enable_webvr==1', { + 'sources': [ + 'renderer/vr/vr_dispatcher.cc', + 'renderer/vr/vr_dispatcher.h', + 'renderer/vr/vr_type_converters.cc', + 'renderer/vr/vr_type_converters.h', + ] + }], ], 'target_conditions': [ ['OS=="android"', { diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index 988a87a..b4ce419 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn @@ -57,6 +57,10 @@ android_library("content_java") { ] DEPRECATED_java_in_dir = "java/src" + + if (enable_webvr) { + deps += [ "//third_party/cardboard-java:cardboard-java" ] + } } java_strings_grd("content_strings_grd") { @@ -151,6 +155,13 @@ generate_jar_jni("jar_jni") { generate_jni("content_jni_headers") { sources = rebase_path(content_jni_gypi_values.sources, "", "../..") jni_package = "content" + + if (enable_webvr) { + sources += [ "//content/public/android/java/src/org/chromium/content/browser/input/CardboardVRDevice.java" ] + deps = [ + "//third_party/cardboard-java:cardboard-java", + ] + } } group("jni") { diff --git a/content/public/android/java/src/org/chromium/content/browser/input/CardboardVRDevice.java b/content/public/android/java/src/org/chromium/content/browser/input/CardboardVRDevice.java new file mode 100644 index 0000000..280e3bf --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/browser/input/CardboardVRDevice.java @@ -0,0 +1,88 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.content.browser.input; + +import android.content.Context; + +import com.google.vrtoolkit.cardboard.CardboardDeviceParams; +import com.google.vrtoolkit.cardboard.FieldOfView; +import com.google.vrtoolkit.cardboard.HeadMountedDisplay; +import com.google.vrtoolkit.cardboard.HeadMountedDisplayManager; +import com.google.vrtoolkit.cardboard.ScreenParams; +import com.google.vrtoolkit.cardboard.sensors.HeadTracker; + +import org.chromium.base.CalledByNative; +import org.chromium.base.JNINamespace; + +/** + * This is the implementation of the C++ counterpart CardboardVRDevice. + */ +@JNINamespace("content") +class CardboardVRDevice { + private static final String TAG = "CardboardVRDevice"; + private final HeadMountedDisplayManager mHMDManager; + private final HeadTracker mHeadTracker; + + @CalledByNative + private static CardboardVRDevice create(Context context) { + return new CardboardVRDevice(context); + } + + private CardboardVRDevice(Context context) { + mHMDManager = new HeadMountedDisplayManager(context); + + mHeadTracker = HeadTracker.createFromContext(context); + mHeadTracker.setNeckModelEnabled(true); + mHeadTracker.startTracking(); + } + + @CalledByNative + private void getFieldOfView(float[] outFov) { + HeadMountedDisplay hmd = mHMDManager.getHeadMountedDisplay(); + CardboardDeviceParams deviceParams = hmd.getCardboardDeviceParams(); + FieldOfView fov = deviceParams.getLeftEyeMaxFov(); + outFov[0] = fov.getTop(); + outFov[1] = fov.getBottom(); + outFov[2] = fov.getLeft(); + outFov[3] = fov.getRight(); + } + + @CalledByNative + private float getIpd() { + HeadMountedDisplay hmd = mHMDManager.getHeadMountedDisplay(); + CardboardDeviceParams deviceParams = hmd.getCardboardDeviceParams(); + return deviceParams.getInterLensDistance(); + } + + @CalledByNative + private String getDeviceName() { + HeadMountedDisplay hmd = mHMDManager.getHeadMountedDisplay(); + CardboardDeviceParams deviceParams = hmd.getCardboardDeviceParams(); + return deviceParams.getVendor() + " " + deviceParams.getModel(); + } + + @CalledByNative + private void getScreenSize(int[] outSize) { + HeadMountedDisplay hmd = mHMDManager.getHeadMountedDisplay(); + ScreenParams screenParams = hmd.getScreenParams(); + outSize[0] = screenParams.getWidth(); + outSize[1] = screenParams.getHeight(); + } + + @CalledByNative + private void getSensorState(float[] outMatrix) { + mHeadTracker.getLastHeadView(outMatrix, 0); + } + + @CalledByNative + private void stopTracking() { + mHeadTracker.stopTracking(); + } + + @CalledByNative + private void resetSensor() { + mHeadTracker.resetTracker(); + } +} diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index 1f7e4b0..5c8efcd 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc @@ -477,6 +477,9 @@ const char kEnableWebGLDraftExtensions[] = "enable-webgl-draft-extensions"; // Enables WebGL rendering into a scanout buffer for overlay support. const char kEnableWebGLImageChromium[] = "enable-webgl-image-chromium"; +// Enables interaction with virtual reality devices. +const char kEnableWebVR[] = "enable-webvr"; + // Enable rasterizer that writes directly to GPU memory associated with tiles. const char kEnableZeroCopy[] = "enable-zero-copy"; diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index aead5ac..4b45d2e 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h @@ -142,6 +142,7 @@ CONTENT_EXPORT extern const char kInvertViewportScrollOrder[]; CONTENT_EXPORT extern const char kEnableVtune[]; CONTENT_EXPORT extern const char kEnableWebGLDraftExtensions[]; CONTENT_EXPORT extern const char kEnableWebGLImageChromium[]; +CONTENT_EXPORT extern const char kEnableWebVR[]; CONTENT_EXPORT extern const char kEnableZeroCopy[]; CONTENT_EXPORT extern const char kExplicitlyAllowedPorts[]; CONTENT_EXPORT extern const char kExtraPluginDir[]; diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index 9287ccb..9c078e4 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn @@ -199,4 +199,13 @@ source_set("renderer") { ] deps += [ "//media/mojo/services:proxy" ] } + + if (enable_webvr) { + sources += [ + "vr/vr_dispatcher.cc", + "vr/vr_dispatcher.h", + "vr/vr_type_converters.cc", + "vr/vr_type_converters.h", + ] + } } diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 8060019..92603ba 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -186,6 +186,10 @@ #include "media/renderers/default_renderer_factory.h" #endif +#if defined(ENABLE_WEBVR) +#include "content/renderer/vr/vr_dispatcher.h" +#endif + using blink::WebContextMenuData; using blink::WebData; using blink::WebDataSource; @@ -3738,6 +3742,15 @@ blink::WebAppBannerClient* RenderFrameImpl::appBannerClient() { return app_banner_client_.get(); } +#if defined(ENABLE_WEBVR) +blink::WebVRClient* RenderFrameImpl::webVRClient() { + if (!vr_dispatcher_) + vr_dispatcher_.reset(new VRDispatcher(GetServiceRegistry())); + + return vr_dispatcher_.get(); +} +#endif + void RenderFrameImpl::DidPlay(blink::WebMediaPlayer* player) { Send(new FrameHostMsg_MediaPlayingNotification( routing_id_, reinterpret_cast<int64>(player), player->hasVideo(), diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 281dd86..6af9e99 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h @@ -114,6 +114,7 @@ struct RequestNavigationParams; struct ResourceResponseHead; struct StartNavigationParams; struct StreamOverrideParameters; +class VRDispatcher; class CONTENT_EXPORT RenderFrameImpl : public RenderFrame, @@ -530,6 +531,10 @@ class CONTENT_EXPORT RenderFrameImpl virtual blink::WebPermissionClient* permissionClient(); virtual blink::WebAppBannerClient* appBannerClient(); +#if defined(ENABLE_WEBVR) + blink::WebVRClient* webVRClient() override; +#endif + // WebMediaPlayerDelegate implementation: void DidPlay(blink::WebMediaPlayer* player) override; void DidPause(blink::WebMediaPlayer* player) override; @@ -973,6 +978,11 @@ class CONTENT_EXPORT RenderFrameImpl scoped_ptr<blink::WebAppBannerClient> app_banner_client_; +#if defined(ENABLE_WEBVR) + // The VR dispatcher attached to the frame, lazily initialized. + scoped_ptr<VRDispatcher> vr_dispatcher_; +#endif + #if defined(OS_MACOSX) || defined(OS_ANDROID) // The external popup for the currently showing select popup. scoped_ptr<ExternalPopupMenu> external_popup_menu_; diff --git a/content/renderer/vr/vr_dispatcher.cc b/content/renderer/vr/vr_dispatcher.cc new file mode 100644 index 0000000..43e2572 --- /dev/null +++ b/content/renderer/vr/vr_dispatcher.cc @@ -0,0 +1,69 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/vr/vr_dispatcher.h" + +#include "content/public/common/service_registry.h" +#include "content/renderer/vr/vr_type_converters.h" + +namespace content { + +VRDispatcher::VRDispatcher(ServiceRegistry* service_registry) + : service_registry_(service_registry) { +} + +VRDispatcher::~VRDispatcher() { +} + +VRServicePtr& VRDispatcher::GetVRServicePtr() { + if (!vr_service_) { + service_registry_->ConnectToRemoteService(mojo::GetProxy(&vr_service_)); + } + return vr_service_; +} + +void VRDispatcher::getDevices(blink::WebVRGetDevicesCallback* callback) { + int request_id = pending_requests_.Add(callback); + GetVRServicePtr()->GetDevices(base::Bind(&VRDispatcher::OnGetDevices, + base::Unretained(this), request_id)); +} + +void VRDispatcher::getSensorState(unsigned int index, + blink::WebHMDSensorState& state) { + GetVRServicePtr()->GetSensorState( + index, + base::Bind(&VRDispatcher::OnGetSensorState, base::Unretained(&state))); + + // This call needs to return results synchronously in order to be useful and + // provide the lowest latency results possible. + GetVRServicePtr().WaitForIncomingResponse(); +} + +void VRDispatcher::resetSensor(unsigned int index) { + GetVRServicePtr()->ResetSensor(index); +} + +void VRDispatcher::OnGetDevices(int request_id, + const mojo::Array<VRDeviceInfoPtr>& devices) { + blink::WebVector<blink::WebVRDevice> web_devices(devices.size()); + + blink::WebVRGetDevicesCallback* callback = + pending_requests_.Lookup(request_id); + if (!callback) + return; + + for (size_t i = 0; i < devices.size(); ++i) { + web_devices[i] = devices[i].To<blink::WebVRDevice>(); + } + + callback->onSuccess(&web_devices); + pending_requests_.Remove(request_id); +} + +void VRDispatcher::OnGetSensorState(blink::WebHMDSensorState* state, + const VRSensorStatePtr& mojo_state) { + *state = mojo_state.To<blink::WebHMDSensorState>(); +} + +} // namespace content diff --git a/content/renderer/vr/vr_dispatcher.h b/content/renderer/vr/vr_dispatcher.h new file mode 100644 index 0000000..7e5d56b --- /dev/null +++ b/content/renderer/vr/vr_dispatcher.h @@ -0,0 +1,55 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_VR_DISPATCHER_H_ +#define CONTENT_RENDERER_VR_DISPATCHER_H_ + +#include <vector> + +#include "base/id_map.h" +#include "content/common/vr_service.mojom.h" +#include "third_party/WebKit/public/platform/WebVector.h" +#include "third_party/WebKit/public/platform/modules/vr/WebVR.h" +#include "third_party/WebKit/public/platform/modules/vr/WebVRClient.h" + +namespace content { + +class ServiceRegistry; + +class VRDispatcher : NON_EXPORTED_BASE(public blink::WebVRClient) { + public: + explicit VRDispatcher(ServiceRegistry* service_registry); + ~VRDispatcher(); + + // blink::WebVRClient implementation. + void getDevices(blink::WebVRGetDevicesCallback* callback) override; + + void getSensorState(unsigned int index, + blink::WebHMDSensorState& state) override; + + void resetSensor(unsigned int index) override; + + private: + // Helper method that returns an initialized PermissionServicePtr. + VRServicePtr& GetVRServicePtr(); + + // Callback handlers + void OnGetDevices(int request_id, + const mojo::Array<VRDeviceInfoPtr>& devices); + static void OnGetSensorState(blink::WebHMDSensorState* state, + const VRSensorStatePtr& mojo_state); + + // Tracks requests sent to browser to match replies with callbacks. + // Owns callback objects. + IDMap<blink::WebVRGetDevicesCallback, IDMapOwnPointer> pending_requests_; + + ServiceRegistry* service_registry_; + VRServicePtr vr_service_; + + DISALLOW_COPY_AND_ASSIGN(VRDispatcher); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_VR_DISPATCHER_H_ diff --git a/content/renderer/vr/vr_type_converters.cc b/content/renderer/vr/vr_type_converters.cc new file mode 100644 index 0000000..68d686c --- /dev/null +++ b/content/renderer/vr/vr_type_converters.cc @@ -0,0 +1,147 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/vr/vr_type_converters.h" + +#include <algorithm> + +using content::VRVector3Ptr; +using content::VRVector4Ptr; +using content::VRRectPtr; +using content::VRFieldOfViewPtr; +using content::VREyeParametersPtr; +using content::VRHMDInfoPtr; +using content::VRDeviceInfoPtr; +using content::VRSensorStatePtr; + +namespace mojo { + +// static +blink::WebVRVector3 TypeConverter<blink::WebVRVector3, VRVector3Ptr>::Convert( + const VRVector3Ptr& input) { + blink::WebVRVector3 output; + output.x = input->x; + output.y = input->y; + output.z = input->z; + return output; +} + +// static +blink::WebVRVector4 TypeConverter<blink::WebVRVector4, VRVector4Ptr>::Convert( + const VRVector4Ptr& input) { + blink::WebVRVector4 output; + output.x = input->x; + output.y = input->y; + output.z = input->z; + output.w = input->w; + return output; +} + +// static +blink::WebVRRect TypeConverter<blink::WebVRRect, VRRectPtr>::Convert( + const VRRectPtr& input) { + blink::WebVRRect output; + output.x = input->x; + output.y = input->y; + output.width = input->width; + output.height = input->height; + return output; +} + +// static +blink::WebVRFieldOfView +TypeConverter<blink::WebVRFieldOfView, VRFieldOfViewPtr>::Convert( + const VRFieldOfViewPtr& input) { + blink::WebVRFieldOfView output; + output.upDegrees = input->upDegrees; + output.downDegrees = input->downDegrees; + output.leftDegrees = input->leftDegrees; + output.rightDegrees = input->rightDegrees; + return output; +} + +// static +blink::WebVREyeParameters +TypeConverter<blink::WebVREyeParameters, VREyeParametersPtr>::Convert( + const VREyeParametersPtr& input) { + blink::WebVREyeParameters output; + output.minimumFieldOfView = + input->minimumFieldOfView.To<blink::WebVRFieldOfView>(); + output.maximumFieldOfView = + input->maximumFieldOfView.To<blink::WebVRFieldOfView>(); + output.recommendedFieldOfView = + input->recommendedFieldOfView.To<blink::WebVRFieldOfView>(); + output.eyeTranslation = input->eyeTranslation.To<blink::WebVRVector3>(); + output.renderRect = input->renderRect.To<blink::WebVRRect>(); + return output; +} + +// static +blink::WebVRHMDInfo TypeConverter<blink::WebVRHMDInfo, VRHMDInfoPtr>::Convert( + const VRHMDInfoPtr& input) { + blink::WebVRHMDInfo output; + output.leftEye = input->leftEye.To<blink::WebVREyeParameters>(); + output.rightEye = input->rightEye.To<blink::WebVREyeParameters>(); + return output; +} + +// static +blink::WebVRDevice TypeConverter<blink::WebVRDevice, VRDeviceInfoPtr>::Convert( + const VRDeviceInfoPtr& input) { + blink::WebVRDevice output; + memset(&output, 0, sizeof(blink::WebVRDevice)); + + output.index = input->index; + output.flags = blink::WebVRDeviceTypePosition; + output.deviceName = blink::WebString::fromUTF8(input->deviceName.data(), + input->deviceName.size()); + + if (!input->hmdInfo.is_null()) { + output.flags |= blink::WebVRDeviceTypeHMD; + output.hmdInfo = input->hmdInfo.To<blink::WebVRHMDInfo>(); + } + + return output; +} + +// static +blink::WebHMDSensorState +TypeConverter<blink::WebHMDSensorState, VRSensorStatePtr>::Convert( + const VRSensorStatePtr& input) { + blink::WebHMDSensorState output; + output.timestamp = input->timestamp; + output.frameIndex = input->frameIndex; + output.flags = 0; + + if (!input->orientation.is_null()) { + output.flags |= blink::WebVRSensorStateOrientation; + output.orientation = input->orientation.To<blink::WebVRVector4>(); + } + if (!input->position.is_null()) { + output.flags |= blink::WebVRSensorStatePosition; + output.position = input->position.To<blink::WebVRVector3>(); + } + if (!input->angularVelocity.is_null()) { + output.flags |= blink::WebVRSensorStateAngularVelocity; + output.angularVelocity = input->angularVelocity.To<blink::WebVRVector3>(); + } + if (!input->linearVelocity.is_null()) { + output.flags |= blink::WebVRSensorStateLinearVelocity; + output.linearVelocity = input->linearVelocity.To<blink::WebVRVector3>(); + } + if (!input->angularAcceleration.is_null()) { + output.flags |= blink::WebVRSensorStateAngularAcceleration; + output.angularAcceleration = + input->angularAcceleration.To<blink::WebVRVector3>(); + } + if (!input->linearAcceleration.is_null()) { + output.flags |= blink::WebVRSensorStateLinearAcceleration; + output.linearAcceleration = + input->linearAcceleration.To<blink::WebVRVector3>(); + } + + return output; +} + +} // namespace mojo diff --git a/content/renderer/vr/vr_type_converters.h b/content/renderer/vr/vr_type_converters.h new file mode 100644 index 0000000..8902cd5 --- /dev/null +++ b/content/renderer/vr/vr_type_converters.h @@ -0,0 +1,62 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_CONTENT_RENDERER_VR_VR_TYPE_CONVERTERS_H_ +#define CHROME_CONTENT_RENDERER_VR_VR_TYPE_CONVERTERS_H_ + +#include "content/common/vr_service.mojom.h" +#include "mojo/common/common_type_converters.h" +#include "third_party/WebKit/public/platform/modules/vr/WebVR.h" + +namespace mojo { + +// Type/enum conversions from WebVR data types to Mojo data types +// and vice versa. + +template <> +struct TypeConverter<blink::WebVRVector3, content::VRVector3Ptr> { + static blink::WebVRVector3 Convert(const content::VRVector3Ptr& input); +}; + +template <> +struct TypeConverter<blink::WebVRVector4, content::VRVector4Ptr> { + static blink::WebVRVector4 Convert(const content::VRVector4Ptr& input); +}; + +template <> +struct TypeConverter<blink::WebVRRect, content::VRRectPtr> { + static blink::WebVRRect Convert(const content::VRRectPtr& input); +}; + +template <> +struct TypeConverter<blink::WebVRFieldOfView, content::VRFieldOfViewPtr> { + static blink::WebVRFieldOfView Convert( + const content::VRFieldOfViewPtr& input); +}; + +template <> +struct TypeConverter<blink::WebVREyeParameters, content::VREyeParametersPtr> { + static blink::WebVREyeParameters Convert( + const content::VREyeParametersPtr& input); +}; + +template <> +struct TypeConverter<blink::WebVRHMDInfo, content::VRHMDInfoPtr> { + static blink::WebVRHMDInfo Convert(const content::VRHMDInfoPtr& input); +}; + +template <> +struct TypeConverter<blink::WebVRDevice, content::VRDeviceInfoPtr> { + static blink::WebVRDevice Convert(const content::VRDeviceInfoPtr& input); +}; + +template <> +struct TypeConverter<blink::WebHMDSensorState, content::VRSensorStatePtr> { + static blink::WebHMDSensorState Convert( + const content::VRSensorStatePtr& input); +}; + +} // namespace mojo + +#endif // CHROME_CONTENT_RENDERER_VR_VR_TYPE_CONVERTERS_H_
\ No newline at end of file diff --git a/mojo/common/weak_binding_set.h b/mojo/common/weak_binding_set.h index 8738388..aeeefe9 100644 --- a/mojo/common/weak_binding_set.h +++ b/mojo/common/weak_binding_set.h @@ -42,6 +42,8 @@ class WeakBindingSet : public ErrorHandler { bindings_.clear(); } + bool empty() const { return bindings_.empty(); } + private: // ErrorHandler implementation. void OnConnectionError() override { diff --git a/third_party/cardboard-java/BUILD.gn b/third_party/cardboard-java/BUILD.gn index a6ff1b6c..4effd70 100644 --- a/third_party/cardboard-java/BUILD.gn +++ b/third_party/cardboard-java/BUILD.gn @@ -5,9 +5,9 @@ import("//build/config/android/rules.gni") # GYP: //third_party/cardboard-java/cardboard.gyp:cardboard_jar -java_prebuilt("cardboard-java") { +android_java_prebuilt("cardboard-java") { jar_path = "src/CardboardSample/libs/cardboard.jar" deps = [ - "//third_party/android_protobuf/android_protobuf.gyp:protobuf_nano_javalib", + "//third_party/android_protobuf:protobuf_nano_javalib", ] } diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index d149cc7..3172332 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -58895,6 +58895,7 @@ To add a new entry, add it with any value and run test to compute valid value. <int value="-1346722635" label="gesture-selection"/> <int value="-1341092934" label="enable-accelerated-overflow-scroll"/> <int value="-1340055960" label="enable-streamlined-hosted-apps"/> + <int value="-1337185440" label="enable-webvr"/> <int value="-1334327410" label="ash-enable-touch-view-testing"/> <int value="-1322882747" label="disable-datasaver-prompt"/> <int value="-1319688939" label="ignore-gpu-blacklist"/> |