gecko-dev/gfx/vr/gfxVRGVR.cpp

816 строки
24 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <math.h>
#include "GLBlitHelper.h"
#include "GLContextEGL.h"
#include "GLContextProvider.h"
#include "GLContextTypes.h"
#include "GLImages.h"
#include "GLLibraryEGL.h"
#include "gfxPrefs.h"
#include "gfxVRGVRAPI.h"
#include "gfxVRGVR.h"
#include "mozilla/dom/GamepadEventTypes.h"
#include "mozilla/dom/GamepadBinding.h"
#include "mozilla/gfx/Matrix.h"
#include "mozilla/gfx/Quaternion.h"
#include "mozilla/jni/Utils.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/TextureHostOGL.h"
#include "mozilla/Preferences.h"
#include "GeckoVRManager.h"
#include "nsString.h"
#include "SurfaceTypes.h"
#include "VRManager.h"
#define MOZ_CHECK_GVR_ERRORS
#if defined(MOZ_CHECK_GVR_ERRORS)
#define GVR_LOGTAG "GeckoWebVR"
#include <android/log.h>
#define GVR_CHECK(X) X; \
{ \
gvr_context* context = (mPresentingContext ? mPresentingContext : GetNonPresentingContext()); \
if (context && (gvr_get_error(context) != GVR_ERROR_NONE)) { \
__android_log_print(ANDROID_LOG_ERROR, GVR_LOGTAG, \
"GVR ERROR: %s at:%s:%s:%d", \
gvr_get_error_string(gvr_get_error(context)), \
__FILE__, __FUNCTION__, __LINE__); \
gvr_clear_error(context); \
} else if (!context) { \
__android_log_print(ANDROID_LOG_ERROR, GVR_LOGTAG, \
"UNABLE TO CHECK GVR ERROR: NO CONTEXT"); \
} \
}
#define GVR_LOG(format, ...) __android_log_print(ANDROID_LOG_INFO, GVR_LOGTAG, format, ##__VA_ARGS__);
#else
#define GVR_CHECK(X) X
#define GVR_LOG(...)
#endif
using namespace mozilla;
using namespace mozilla::gl;
using namespace mozilla::gfx;
using namespace mozilla::gfx::impl;
using namespace mozilla::layers;
using namespace mozilla::dom;
namespace {
static VRDisplayGVR* sContextObserver;
static RefPtr<GLContextEGL> sGLContextEGL;
static gvr_context* sNonPresentingContext;
gvr_context*
GetNonPresentingContext() {
if (!sNonPresentingContext) {
// Try and restore if it has been lost
sNonPresentingContext = (gvr_context*)GeckoVRManager::CreateGVRNonPresentingContext();
}
return sNonPresentingContext;
}
class SynchronousRunnable : public nsIRunnable {
public:
enum class Type {
PresentingContext,
NonPresentingContext,
Pause,
Resume
};
SynchronousRunnable(const Type aType, void* aContext)
: mType(aType)
, mContext(aContext)
, mUpdateMonitor(new Monitor("SynchronousRunnable_for_Android"))
, mUpdated(false)
{}
NS_DECL_THREADSAFE_ISUPPORTS
nsresult Run() override
{
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
MonitorAutoLock lock(*mUpdateMonitor);
if (mType == Type::PresentingContext) {
SetGVRPresentingContext(mContext);
} else if (mType == Type::NonPresentingContext) {
CleanupGVRNonPresentingContext();
} else if (mType == Type::Pause) {
SetGVRPaused(true);
} else if (mType == Type::Resume) {
SetGVRPaused(false);
} else {
GVR_LOG("UNKNOWN SynchronousRunnable::Type!");
}
mUpdated = true;
lock.NotifyAll();
return NS_OK;
}
void Wait()
{
MonitorAutoLock lock(*mUpdateMonitor);
while(!mUpdated) {
lock.Wait();
}
}
static bool Dispatch(const Type aType, void* aContext)
{
if (!CompositorThreadHolder::IsInCompositorThread()) {
RefPtr<SynchronousRunnable> runnable = new SynchronousRunnable(aType, aContext);
CompositorThreadHolder::Loop()->PostTask(do_AddRef(runnable));
runnable->Wait();
return true;
}
return false;
}
protected:
virtual ~SynchronousRunnable()
{
delete mUpdateMonitor;
}
Type mType;
void* mContext;
Monitor* mUpdateMonitor;
bool mUpdated;
};
}
NS_IMPL_ISUPPORTS(SynchronousRunnable, nsIRunnable)
void
mozilla::gfx::SetGVRPresentingContext(void* aGVRPresentingContext)
{
if (SynchronousRunnable::Dispatch(SynchronousRunnable::Type::PresentingContext, aGVRPresentingContext)) {
GVR_LOG("Done waiting for compositor thread to set presenting context.");
return;
}
MOZ_ASSERT(sContextObserver);
if (!sGLContextEGL && aGVRPresentingContext) {
CreateContextFlags flags = CreateContextFlags::NONE;
SurfaceCaps caps = SurfaceCaps::ForRGBA();
nsCString str;
sGLContextEGL = GLContextEGL::CreateEGLPBufferOffscreenContext(flags, IntSize(4, 4), caps, &str);
if (!sGLContextEGL->MakeCurrent()) {
GVR_LOG("Failed to make GL context current");
}
}
sContextObserver->SetPresentingContext(aGVRPresentingContext);
}
void
mozilla::gfx::CleanupGVRNonPresentingContext()
{
if (SynchronousRunnable::Dispatch(SynchronousRunnable::Type::NonPresentingContext, nullptr)) {
GVR_LOG("Done waiting for compositor thread to set non presenting context.");
return;
}
if (sNonPresentingContext) {
sNonPresentingContext = nullptr;
GeckoVRManager::DestroyGVRNonPresentingContext();
}
}
void
mozilla::gfx::SetGVRPaused(const bool aPaused)
{
if (SynchronousRunnable::Dispatch((aPaused ? SynchronousRunnable::Type::Pause : SynchronousRunnable::Type::Resume), nullptr)) {
GVR_LOG("Done waiting for GVR in compositor to: %s",(aPaused ? "Pause" : "Resume"));
return;
}
MOZ_ASSERT(sContextObserver);
sContextObserver->SetPaused(aPaused);
}
VRDisplayGVR::VRDisplayGVR()
: VRDisplayHost(VRDeviceType::GVR)
, mIsPresenting(false)
, mControllerAdded(false)
, mPresentingContext(nullptr)
, mControllerContext(nullptr)
, mControllerState(nullptr)
, mViewportList(nullptr)
, mLeftViewport(nullptr)
, mRightViewport(nullptr)
, mSwapChain(nullptr)
, mFrameBufferSize{0, 0}
{
MOZ_COUNT_CTOR_INHERITED(VRDisplayGVR, VRDisplayHost);
MOZ_ASSERT(GetNonPresentingContext());
MOZ_ASSERT(!sContextObserver); // There can be only one GVR display at a time.
sContextObserver = this;
strncpy(mDisplayInfo.mDisplayName, "GVR HMD", kVRDisplayNameMaxLen);
mDisplayInfo.mIsConnected = true;
mDisplayInfo.mIsMounted = true;
mDisplayInfo.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None |
VRDisplayCapabilityFlags::Cap_Orientation |
VRDisplayCapabilityFlags::Cap_Position | // Not yet...
VRDisplayCapabilityFlags::Cap_Present;
GVR_CHECK(gvr_refresh_viewer_profile(GetNonPresentingContext()));
mViewportList = GVR_CHECK(gvr_buffer_viewport_list_create(GetNonPresentingContext()));
mLeftViewport = GVR_CHECK(gvr_buffer_viewport_create(GetNonPresentingContext()));
mRightViewport = GVR_CHECK(gvr_buffer_viewport_create(GetNonPresentingContext()));
UpdateViewport();
dom::GamepadHand hand = dom::GamepadHand::Right;
const gvr_user_prefs* prefs = GVR_CHECK(gvr_get_user_prefs(GetNonPresentingContext()));
if (prefs) {
hand = ((gvr_user_prefs_get_controller_handedness(prefs) == GVR_CONTROLLER_RIGHT_HANDED) ?
dom::GamepadHand::Right : dom::GamepadHand::Left);
}
mController = new VRControllerGVR(hand, mDisplayInfo.mDisplayID);
}
VRDisplayGVR::~VRDisplayGVR()
{
MOZ_COUNT_DTOR_INHERITED(VRDisplayGVR, VRDisplayHost);
}
void
VRDisplayGVR::ZeroSensor()
{
}
void
VRDisplayGVR::StartPresentation()
{
if (mIsPresenting) {
return;
}
mIsPresenting = true;
GeckoVRManager::EnableVRMode();
}
void
VRDisplayGVR::StopPresentation()
{
if (!mIsPresenting) {
return;
}
mIsPresenting = false;
GeckoVRManager::DisableVRMode();
}
bool
VRDisplayGVR::SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor,
const gfx::Rect& aLeftEyeRect,
const gfx::Rect& aRightEyeRect)
{
if (!mPresentingContext) {
GVR_LOG("Unable to submit frame. No presenting context")
return false;
}
if (!sGLContextEGL) {
GVR_LOG("Unable to submit frame. No GL Context");
return false;
}
if (!sGLContextEGL->MakeCurrent()) {
GVR_LOG("Failed to make GL context current");
return false;
}
EGLImage image = (EGLImage)aDescriptor->image();
EGLSync sync = (EGLSync)aDescriptor->fence();
gfx::IntSize size = aDescriptor->size();
MOZ_ASSERT(mSwapChain);
GVR_CHECK(gvr_get_recommended_buffer_viewports(mPresentingContext, mViewportList));
if ((size.width != mFrameBufferSize.width) || (size.height != mFrameBufferSize.height)) {
mFrameBufferSize.width = size.width;
mFrameBufferSize.height = size.height;
GVR_CHECK(gvr_swap_chain_resize_buffer(mSwapChain, 0, mFrameBufferSize));
GVR_LOG("Resize Swap Chain %d,%d", mFrameBufferSize.width, mFrameBufferSize.height);
}
gvr_frame* frame = GVR_CHECK(gvr_swap_chain_acquire_frame(mSwapChain));
if (!frame) {
// Sometimes the swap chain seems to not initialized correctly so that
// frames can not be acquired. Recreating the swap chain seems to fix the
// issue.
GVR_LOG("Unable to acquire GVR frame. Recreating swap chain.");
RecreateSwapChain();
return false;
}
GVR_CHECK(gvr_frame_bind_buffer(frame, 0));
EGLint status = LOCAL_EGL_CONDITION_SATISFIED;
if (sync) {
MOZ_ASSERT(sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync));
status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), sync, 0, LOCAL_EGL_FOREVER);
}
if (status != LOCAL_EGL_CONDITION_SATISFIED) {
MOZ_ASSERT(status != 0,
"ClientWaitSync generated an error. Has sync already been destroyed?");
return false;
}
if (image) {
GLuint tex = 0;
sGLContextEGL->fGenTextures(1, &tex);
const ScopedSaveMultiTex saveTex(sGLContextEGL, 1, LOCAL_GL_TEXTURE_2D);
sGLContextEGL->fBindTexture(LOCAL_GL_TEXTURE_2D, tex);
sGLContextEGL->TexParams_SetClampNoMips();
sGLContextEGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, image);
sGLContextEGL->BlitHelper()->DrawBlitTextureToFramebuffer(tex, gfx::IntSize(size.width, size.height), gfx::IntSize(mFrameBufferSize.width, mFrameBufferSize.height));
sGLContextEGL->fDeleteTextures(1, &tex);
} else {
GVR_LOG("Unable to submit frame. Unable to extract EGLImage");
return false;
}
GVR_CHECK(gvr_frame_unbind(frame));
GVR_CHECK(gvr_frame_submit(&frame, mViewportList, mHeadMatrix));
return true;
}
static void
FillMatrix(gfx::Matrix4x4 &target, const gvr_mat4f& source)
{
target._11 = source.m[0][0];
target._12 = source.m[0][1];
target._13 = source.m[0][2];
target._14 = source.m[0][3];
target._21 = source.m[1][0];
target._22 = source.m[1][1];
target._23 = source.m[1][2];
target._24 = source.m[1][3];
target._31 = source.m[2][0];
target._32 = source.m[2][1];
target._33 = source.m[2][2];
target._34 = source.m[2][3];
target._41 = source.m[3][0];
target._42 = source.m[3][1];
target._43 = source.m[3][2];
target._44 = source.m[3][3];
}
VRHMDSensorState
VRDisplayGVR::GetSensorState()
{
VRHMDSensorState result{};
gvr_context* context = (mPresentingContext ? mPresentingContext : GetNonPresentingContext());
if (!context) {
GVR_LOG("Unable to get sensor state. Context is null");
return result;
}
gvr_clock_time_point when = GVR_CHECK(gvr_get_time_point_now());
if (mIsPresenting) {
// 50ms into the future is what GVR docs recommends using for head rotation
// prediction.
when.monotonic_system_time_nanos += 50000000;
}
mHeadMatrix = GVR_CHECK(gvr_get_head_space_from_start_space_rotation(context, when));
gvr_mat4f neck = GVR_CHECK(gvr_apply_neck_model(context, mHeadMatrix, 1.0));;
gfx::Matrix4x4 m;
FillMatrix(m, neck);
m.Invert();
gfx::Quaternion rot;
rot.SetFromRotationMatrix(m);
result.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
result.orientation[0] = rot.x;
result.orientation[1] = rot.y;
result.orientation[2] = rot.z;
result.orientation[3] = rot.w;
result.angularVelocity[0] = 0.0f;
result.angularVelocity[1] = 0.0f;
result.angularVelocity[2] = 0.0f;
result.flags |= VRDisplayCapabilityFlags::Cap_Position;
result.position[0] = m._14;
result.position[1] = m._24;
result.position[2] = m._34;
result.linearVelocity[0] = 0.0f;
result.linearVelocity[1] = 0.0f;
result.linearVelocity[2] = 0.0f;
UpdateHeadToEye(context);
CalcViewMatrices(&result, mHeadToEyes);
return result;
}
void
VRDisplayGVR::SetPaused(const bool aPaused)
{
if (aPaused) {
if (mPresentingContext) {
GVR_CHECK(gvr_pause_tracking(mPresentingContext));
} else if (sNonPresentingContext) {
GVR_CHECK(gvr_pause_tracking(sNonPresentingContext));
}
if (mControllerContext) {
GVR_CHECK(gvr_controller_pause(mControllerContext));
}
} else {
if (mPresentingContext) {
GVR_CHECK(gvr_refresh_viewer_profile(mPresentingContext));
GVR_CHECK(gvr_resume_tracking(mPresentingContext));
} else if (sNonPresentingContext) {
GVR_CHECK(gvr_resume_tracking(sNonPresentingContext));
}
if (mControllerContext) {
GVR_CHECK(gvr_controller_resume(mControllerContext));
}
}
}
void
VRDisplayGVR::SetPresentingContext(void* aGVRPresentingContext)
{
MOZ_ASSERT(sGLContextEGL);
sGLContextEGL->MakeCurrent();
mPresentingContext = (gvr_context*)aGVRPresentingContext;
if (mPresentingContext) {
GVR_CHECK(gvr_initialize_gl(mPresentingContext));
RecreateSwapChain();
} else {
if (mSwapChain) {
// gvr_swap_chain_destroy will set the pointer to null
GVR_CHECK(gvr_swap_chain_destroy(&mSwapChain));
MOZ_ASSERT(!mSwapChain);
}
// The presentation context has been destroy, probably by the user so increment the presenting
// generation if we are presenting so that the DOM knows to end the current presentation.
if (mIsPresenting) {
mDisplayInfo.mPresentingGeneration++;
}
}
}
void
VRDisplayGVR::UpdateHeadToEye(gvr_context* aContext)
{
if (!aContext) {
return;
}
for (uint32_t eyeIndex = 0; eyeIndex < 2; eyeIndex++) {
gvr_mat4f eye = GVR_CHECK(gvr_get_eye_from_head_matrix(aContext, eyeIndex));
mDisplayInfo.mEyeTranslation[eyeIndex].x = -eye.m[0][3];
mDisplayInfo.mEyeTranslation[eyeIndex].y = -eye.m[1][3];
mDisplayInfo.mEyeTranslation[eyeIndex].z = -eye.m[2][3];
mHeadToEyes[eyeIndex] = gfx::Matrix4x4();
mHeadToEyes[eyeIndex].PreTranslate(eye.m[0][3], eye.m[1][3], eye.m[2][3]);
}
}
void
VRDisplayGVR::UpdateViewport()
{
gvr_context* context = (mPresentingContext ? mPresentingContext : GetNonPresentingContext());
if (!context) {
return;
}
GVR_CHECK(gvr_get_recommended_buffer_viewports(context, mViewportList));
GVR_CHECK(gvr_buffer_viewport_list_get_item(mViewportList, 0, mLeftViewport));
GVR_CHECK(gvr_buffer_viewport_list_get_item(mViewportList, 1, mRightViewport));
gvr_rectf fov = GVR_CHECK(gvr_buffer_viewport_get_source_fov(mLeftViewport));
mDisplayInfo.mEyeFOV[VRDisplayInfo::Eye_Left] = VRFieldOfView(fov.top, fov.right, fov.bottom, fov.left);
GVR_LOG("FOV:L top:%f right:%f bottom:%f left:%f",(float)fov.top, (float)fov.left, (float)fov.bottom, (float)fov.right);
fov = GVR_CHECK(gvr_buffer_viewport_get_source_fov(mRightViewport));
mDisplayInfo.mEyeFOV[VRDisplayInfo::Eye_Right] = VRFieldOfView(fov.top, fov.right, fov.bottom, fov.left);
GVR_LOG("FOV:R top:%f right:%f bottom:%f left:%f",(float)fov.top, (float)fov.left, (float)fov.bottom, (float)fov.right);
gvr_sizei size = GVR_CHECK(gvr_get_maximum_effective_render_target_size(context));
mDisplayInfo.mEyeResolution = IntSize(size.width / 2, size.height);
GVR_LOG("Eye Resolution: %dx%d",mDisplayInfo.mEyeResolution.width,mDisplayInfo.mEyeResolution.height);
UpdateHeadToEye(context);
}
void
VRDisplayGVR::RecreateSwapChain()
{
MOZ_ASSERT(sGLContextEGL);
sGLContextEGL->MakeCurrent();
if (mSwapChain) {
// gvr_swap_chain_destroy will set the pointer to null
GVR_CHECK(gvr_swap_chain_destroy(&mSwapChain));
MOZ_ASSERT(!mSwapChain);
}
gvr_buffer_spec* spec = GVR_CHECK(gvr_buffer_spec_create(mPresentingContext));
mFrameBufferSize = GVR_CHECK(gvr_get_maximum_effective_render_target_size(mPresentingContext));
GVR_CHECK(gvr_buffer_spec_set_size(spec, mFrameBufferSize));
GVR_CHECK(gvr_buffer_spec_set_samples(spec, 0));
GVR_CHECK(gvr_buffer_spec_set_color_format(spec, GVR_COLOR_FORMAT_RGBA_8888));
GVR_CHECK(gvr_buffer_spec_set_depth_stencil_format(spec, GVR_DEPTH_STENCIL_FORMAT_NONE));
mSwapChain = GVR_CHECK(gvr_swap_chain_create(mPresentingContext, (const gvr_buffer_spec**)&spec, 1));
GVR_CHECK(gvr_buffer_spec_destroy(&spec));
}
void
VRDisplayGVR::EnableControllers(const bool aEnable, VRSystemManager* aManager)
{
if (aEnable && !mControllerAdded) {
// Sometimes the gamepad doesn't get removed cleanly so just try to remove it before adding it.
aManager->RemoveGamepad(mController->GetControllerInfo().mControllerID);
aManager->AddGamepad(mController->GetControllerInfo());
mControllerAdded = true;
} else if (!aEnable && mControllerAdded) {
mControllerAdded = false;
aManager->RemoveGamepad(mController->GetControllerInfo().mControllerID);
}
gvr_context* context = mPresentingContext;
if (!context) {
if (mControllerContext) {
GVR_CHECK(gvr_controller_destroy(&mControllerContext));
}
return;
}
if ((aEnable && mControllerContext) || (!aEnable && !mControllerContext)) {
return;
}
if (aEnable) {
if (!mControllerContext) {
int32_t options = GVR_CHECK(gvr_controller_get_default_options());
options |= GVR_CONTROLLER_ENABLE_GYRO | GVR_CONTROLLER_ENABLE_ACCEL | GVR_CONTROLLER_ENABLE_ARM_MODEL;
mControllerContext = GVR_CHECK(gvr_controller_create_and_init(options, context));
GVR_CHECK(gvr_controller_resume(mControllerContext));
}
if (!mControllerState) {
mControllerState = GVR_CHECK(gvr_controller_state_create());
}
} else {
GVR_CHECK(gvr_controller_pause(mControllerContext));
GVR_CHECK(gvr_controller_destroy(&mControllerContext));
}
}
void
VRDisplayGVR::UpdateControllers(VRSystemManager* aManager)
{
if (!mControllerContext) {
return;
}
GVR_CHECK(gvr_controller_apply_arm_model(mControllerContext, 0, mController->GetHand() == dom::GamepadHand::Right ? GVR_CONTROLLER_RIGHT_HANDED : GVR_CONTROLLER_LEFT_HANDED, GVR_ARM_MODEL_FOLLOW_GAZE, mHeadMatrix));
GVR_CHECK(gvr_controller_state_update(mControllerContext, 0, mControllerState));
mController->Update(mControllerState, aManager);
}
void
VRDisplayGVR::GetControllers(nsTArray<RefPtr<VRControllerHost> >& aControllerResult)
{
aControllerResult.AppendElement(mController.get());
}
VRControllerGVR::VRControllerGVR(dom::GamepadHand aHand, uint32_t aDisplayID)
: VRControllerHost(VRDeviceType::GVR, aHand, aDisplayID)
{
MOZ_COUNT_CTOR_INHERITED(VRControllerGVR, VRControllerHost);
VRControlerState& state = mControllerInfo.mControllerState;
strncpy(state.mControllerName, "Daydream Controller", kVRControllerNameMaxLen);
// The gvr_controller_button enum starts with GVR_CONTROLLER_BUTTON_NONE at index zero
// so the GVR controller has one less button than GVR_CONTROLLER_BUTTON_COUNT specifies.
state.mNumButtons = GVR_CONTROLLER_BUTTON_COUNT - 1; // Skip dummy none button
state.mNumAxes = 2;
state.mNumHaptics = 0;
}
VRControllerGVR::~VRControllerGVR()
{
MOZ_COUNT_DTOR_INHERITED(VRControllerGVR, VRControllerHost);
}
void
VRControllerGVR::Update(gvr_controller_state* aState, VRSystemManager* aManager)
{
mPose.Clear();
if (gvr_controller_state_get_connection_state(aState) != GVR_CONTROLLER_CONNECTED) {
return;
}
const uint64_t previousPressMask = GetButtonPressed();
const uint64_t previousTouchMask = GetButtonTouched();
uint64_t currentPressMask = 0;
uint64_t currentTouchMask = 0;
// Index 0 is the dummy button so skip it.
for (int ix = 1; ix < GVR_CONTROLLER_BUTTON_COUNT; ix++) {
const uint64_t buttonMask = 0x01 << (ix - 1);
bool pressed = gvr_controller_state_get_button_state(aState, ix);
bool touched = pressed;
if (ix == GVR_CONTROLLER_BUTTON_CLICK) {
touched = gvr_controller_state_is_touching(aState);
double xAxis = 0.0;
double yAxis = 0.0;
if (touched) {
gvr_vec2f axes = gvr_controller_state_get_touch_pos(aState);
xAxis = (axes.x * 2.0) - 1.0;
yAxis = (axes.y * 2.0) - 1.0;
}
aManager->NewAxisMove(0, 0, xAxis);
aManager->NewAxisMove(0, 1, yAxis);
}
if (pressed) {
currentPressMask |= buttonMask;
}
if (touched) {
currentTouchMask |= buttonMask;
}
if (((currentPressMask & buttonMask) ^ (previousPressMask & buttonMask)) ||
((currentTouchMask & buttonMask) ^ (previousTouchMask & buttonMask))) {
aManager->NewButtonEvent(0, ix - 1, pressed, touched, pressed ? 1.0 : 0.0);
}
}
SetButtonPressed(currentPressMask);
SetButtonTouched(currentTouchMask);
mPose.flags = dom::GamepadCapabilityFlags::Cap_Orientation | dom::GamepadCapabilityFlags::Cap_Position | dom::GamepadCapabilityFlags::Cap_LinearAcceleration;
gvr_quatf ori = gvr_controller_state_get_orientation(aState);
mPose.orientation[0] = ori.qx;
mPose.orientation[1] = ori.qy;
mPose.orientation[2] = ori.qz;
mPose.orientation[3] = ori.qw;
mPose.isOrientationValid = true;
gvr_vec3f acc = gvr_controller_state_get_accel(aState);
mPose.linearAcceleration[0] = acc.x;
mPose.linearAcceleration[1] = acc.y;
mPose.linearAcceleration[2] = acc.z;
gvr_vec3f vel = gvr_controller_state_get_gyro(aState);
mPose.angularVelocity[0] = vel.x;
mPose.angularVelocity[1] = vel.y;
mPose.angularVelocity[2] = vel.z;
gvr_vec3f pos = gvr_controller_state_get_position(aState);
mPose.position[0] = pos.x;
mPose.position[1] = pos.y;
mPose.position[2] = pos.z;
aManager->NewPoseState(0, mPose);
}
/*static*/ already_AddRefed<VRSystemManagerGVR>
VRSystemManagerGVR::Create()
{
MOZ_ASSERT(NS_IsMainThread());
if (!gfxPrefs::VREnabled()) {
return nullptr;
}
RefPtr<VRSystemManagerGVR> manager = new VRSystemManagerGVR();
return manager.forget();
}
void
VRSystemManagerGVR::Destroy()
{
}
void
VRSystemManagerGVR::Shutdown()
{
}
void
VRSystemManagerGVR::Enumerate()
{
if (!GeckoVRManager::IsGVRPresent()) {
return;
}
if (!mGVRHMD) {
mGVRHMD = new VRDisplayGVR();
}
}
bool
VRSystemManagerGVR::ShouldInhibitEnumeration()
{
if (VRSystemManager::ShouldInhibitEnumeration()) {
return true;
}
if (mGVRHMD) {
// When we find an a VR device, don't
// allow any further enumeration as it
// may get picked up redundantly by other
// API's.
return true;
}
return false;
}
void
VRSystemManagerGVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
{
if (mGVRHMD) {
aHMDResult.AppendElement(mGVRHMD);
}
}
bool
VRSystemManagerGVR::GetIsPresenting()
{
if (!mGVRHMD) {
return false;
}
VRDisplayInfo displayInfo(mGVRHMD->GetDisplayInfo());
return displayInfo.GetPresentingGroups() != kVRGroupNone;
}
void
VRSystemManagerGVR::HandleInput()
{
if (mGVRHMD) {
mGVRHMD->UpdateControllers(this);
}
}
void
VRSystemManagerGVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
{
if (mGVRHMD) {
mGVRHMD->GetControllers(aControllerResult);
}
}
void
VRSystemManagerGVR::ScanForControllers()
{
if (mGVRHMD) {
mGVRHMD->EnableControllers(true, this);
}
}
void
VRSystemManagerGVR::RemoveControllers()
{
if (mGVRHMD) {
mGVRHMD->EnableControllers(false, this);
}
}
void
VRSystemManagerGVR::VibrateHaptic(uint32_t aControllerIdx,
uint32_t aHapticIndex,
double aIntensity,
double aDuration,
const VRManagerPromise& aPromise)
{
}
void
VRSystemManagerGVR::StopVibrateHaptic(uint32_t aControllerIdx)
{
}
VRSystemManagerGVR::VRSystemManagerGVR()
: mGVRHMD(nullptr)
{
}
VRSystemManagerGVR::~VRSystemManagerGVR()
{
}