Bug 1299937 - Part 3: Implement haptic pulse for OpenVR controller; r=kip,qdot

MozReview-Commit-ID: TUIbJpyng4

--HG--
extra : rebase_source : e449c85d0e8f9a64a63929d1211dbca3fed8a4b6
This commit is contained in:
Daosheng Mu 2017-02-02 14:57:58 +08:00
parent 49b8854fd8
commit 3905da3aea
17 changed files with 250 additions and 3 deletions

View File

@ -146,6 +146,7 @@ VRDisplayHost::CheckClearDisplayInfoDirty()
}
VRControllerHost::VRControllerHost(VRDeviceType aType)
: mVibrateIndex(0)
{
MOZ_COUNT_CTOR(VRControllerHost);
mControllerInfo.mType = aType;
@ -193,3 +194,14 @@ VRControllerHost::GetHand()
return mControllerInfo.mHand;
}
void
VRControllerHost::SetVibrateIndex(uint64_t aIndex)
{
mVibrateIndex = aIndex;
}
uint64_t
VRControllerHost::GetVibrateIndex()
{
return mVibrateIndex;
}

View File

@ -93,6 +93,8 @@ public:
void SetPose(const dom::GamepadPoseState& aPose);
const dom::GamepadPoseState& GetPose();
dom::GamepadHand GetHand();
void SetVibrateIndex(uint64_t aIndex);
uint64_t GetVibrateIndex();
protected:
explicit VRControllerHost(VRDeviceType aType);
@ -101,6 +103,7 @@ protected:
VRControllerInfo mControllerInfo;
// The current button pressed bit of button mask.
uint64_t mButtonPressed;
uint64_t mVibrateIndex;
dom::GamepadPoseState mPose;
};

View File

@ -423,5 +423,15 @@ VRManager::NotifyGamepadChange(const T& aInfo)
}
}
void
VRManager::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
double aIntensity, double aDuration)
{
for (uint32_t i = 0; i < mManagers.Length(); ++i) {
mManagers[i]->VibrateHaptic(aControllerIdx, aHapticIndex,
aIntensity, aDuration);
}
}
} // namespace gfx
} // namespace mozilla

View File

@ -49,6 +49,8 @@ public:
RefPtr<gfx::VRControllerHost> GetController(const uint32_t& aControllerID);
void GetVRControllerInfo(nsTArray<VRControllerInfo>& aControllerInfo);
void CreateVRTestSystem();
void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
double aIntensity, double aDuration);
protected:
VRManager();

View File

@ -67,7 +67,8 @@ VRSystemManager::AddGamepad(const VRControllerInfo& controllerInfo)
controllerInfo.GetHand(),
dom::GamepadServiceType::VR,
controllerInfo.GetNumButtons(),
controllerInfo.GetNumAxes());
controllerInfo.GetNumAxes(),
controllerInfo.GetNumHaptics());
VRManager* vm = VRManager::Get();
MOZ_ASSERT(vm);

View File

@ -214,6 +214,7 @@ struct VRControllerInfo
dom::GamepadHand GetHand() const { return mHand; }
uint32_t GetNumButtons() const { return mNumButtons; }
uint32_t GetNumAxes() const { return mNumAxes; }
uint32_t GetNumHaptics() const { return mNumHaptics; }
uint32_t mControllerID;
VRDeviceType mType;
@ -222,6 +223,7 @@ struct VRControllerInfo
dom::GamepadHand mHand;
uint32_t mNumButtons;
uint32_t mNumAxes;
uint32_t mNumHaptics;
bool operator==(const VRControllerInfo& other) const {
return mType == other.mType &&
@ -230,7 +232,8 @@ struct VRControllerInfo
mMappingType == other.mMappingType &&
mHand == other.mHand &&
mNumButtons == other.mNumButtons &&
mNumAxes == other.mNumAxes;
mNumAxes == other.mNumAxes &&
mNumHaptics == other.mNumHaptics;
}
bool operator!=(const VRControllerInfo& other) const {
@ -256,6 +259,9 @@ public:
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult) = 0;
virtual void ScanForControllers() = 0;
virtual void RemoveControllers() = 0;
virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
double aIntensity, double aDuration, uint32_t aPromiseID) = 0;
virtual void StopVibrateHaptic(uint32_t aControllerIdx) = 0;
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed, double aValue);
void NewAxisMove(uint32_t aIndex, uint32_t aAxis, double aValue);
void NewPoseState(uint32_t aIndex, const dom::GamepadPoseState& aPose);

View File

@ -542,6 +542,20 @@ VRSystemManagerOSVR::HandleInput()
{
}
void
VRSystemManagerOSVR::VibrateHaptic(uint32_t aControllerIdx,
uint32_t aHapticIndex,
double aIntensity,
double aDuration,
uint32_t aPromiseID)
{
}
void
VRSystemManagerOSVR::StopVibrateHaptic(uint32_t aControllerIdx)
{
}
void
VRSystemManagerOSVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
{

View File

@ -73,6 +73,9 @@ public:
aControllerResult) override;
virtual void ScanForControllers() override;
virtual void RemoveControllers() override;
virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
double aIntensity, double aDuration, uint32_t aPromiseID) override;
virtual void StopVibrateHaptic(uint32_t aControllerIdx) override;
protected:
VRSystemManagerOSVR()

View File

@ -912,7 +912,8 @@ VRControllerOculus::VRControllerOculus(dom::GamepadHand aHand)
mControllerInfo.mNumButtons = kNumOculusButton;
mControllerInfo.mNumAxes = static_cast<uint32_t>(
OculusControllerAxisType::NumVRControllerAxisType);;
OculusControllerAxisType::NumVRControllerAxisType);
mControllerInfo.mNumHaptics = kNumOculusHaptcs;
}
float
@ -1254,6 +1255,21 @@ VRSystemManagerOculus::HandlePoseTracking(uint32_t aControllerIdx,
}
}
void
VRSystemManagerOculus::VibrateHaptic(uint32_t aControllerIdx,
uint32_t aHapticIndex,
double aIntensity,
double aDuration,
uint32_t aPromiseID)
{
// TODO: Bug 1305892
}
void
VRSystemManagerOculus::StopVibrateHaptic(uint32_t aControllerIdx)
{
}
void
VRSystemManagerOculus::GetControllers(nsTArray<RefPtr<VRControllerHost>>&
aControllerResult)

View File

@ -129,6 +129,9 @@ public:
aControllerResult) override;
virtual void ScanForControllers() override;
virtual void RemoveControllers() override;
virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
double aIntensity, double aDuration, uint32_t aPromiseID) override;
virtual void StopVibrateHaptic(uint32_t aControllerIdx) override;
protected:
VRSystemManagerOculus()

View File

@ -59,6 +59,8 @@ static pfn_VR_GetGenericInterface vr_GetGenericInterface = nullptr;
#define BTN_MASK_FROM_ID(_id) \
vr::ButtonMaskFromId(vr::EVRButtonId::_id)
static const uint32_t kNumOpenVRHaptcs = 1;
bool
LoadOpenVRRuntime()
@ -392,6 +394,8 @@ VRControllerOpenVR::VRControllerOpenVR(dom::GamepadHand aHand, uint32_t aNumButt
uint32_t aNumAxes)
: VRControllerHost(VRDeviceType::OpenVR)
, mTrigger(0)
, mVibrateThread(nullptr)
, mIsVibrating(false)
{
MOZ_COUNT_CTOR_INHERITED(VRControllerOpenVR, VRControllerHost);
mControllerInfo.mControllerName.AssignLiteral("OpenVR Gamepad");
@ -399,10 +403,16 @@ VRControllerOpenVR::VRControllerOpenVR(dom::GamepadHand aHand, uint32_t aNumButt
mControllerInfo.mHand = aHand;
mControllerInfo.mNumButtons = aNumButtons;
mControllerInfo.mNumAxes = aNumAxes;
mControllerInfo.mNumHaptics = kNumOpenVRHaptcs;
}
VRControllerOpenVR::~VRControllerOpenVR()
{
if (mVibrateThread) {
mVibrateThread->Shutdown();
mVibrateThread = nullptr;
}
MOZ_COUNT_DTOR_INHERITED(VRControllerOpenVR, VRControllerHost);
}
@ -430,6 +440,75 @@ VRControllerOpenVR::GetTrigger()
return mTrigger;
}
void
VRControllerOpenVR::UpdateVibrateHaptic(vr::IVRSystem* aVRSystem,
uint32_t aHapticIndex,
double aIntensity,
double aDuration,
uint64_t aVibrateIndex,
uint32_t aPromiseID)
{
// UpdateVibrateHaptic() only can be called by mVibrateThread
MOZ_ASSERT(mVibrateThread == NS_GetCurrentThread());
// Avoid the previous vibrate event to override the new one.
if (mVibrateIndex != aVibrateIndex) {
return;
}
double duration = (aIntensity == 0) ? 0 : aDuration;
// We expect OpenVR to vibrate for 5 ms, but we found it only response the
// commend ~ 3.9 ms. For duration time longer than 3.9 ms, we separate them
// to a loop of 3.9 ms for make users feel that is a continuous events.
uint32_t microSec = (duration < 3.9 ? duration : 3.9) * 1000 * aIntensity;
aVRSystem->TriggerHapticPulse(GetTrackedIndex(),
aHapticIndex, microSec);
// In OpenVR spec, it mentions TriggerHapticPulse() may not trigger another haptic pulse
// on this controller and axis combination for 5ms.
const double kVibrateRate = 5.0;
if (duration >= kVibrateRate) {
MOZ_ASSERT(mVibrateThread);
RefPtr<Runnable> runnable =
NewRunnableMethod<vr::IVRSystem*, uint32_t, double, double, uint64_t, uint32_t>
(this, &VRControllerOpenVR::UpdateVibrateHaptic, aVRSystem,
aHapticIndex, aIntensity, duration - kVibrateRate, aVibrateIndex, aPromiseID);
NS_DelayedDispatchToCurrentThread(runnable.forget(), kVibrateRate);
}
}
void
VRControllerOpenVR::VibrateHaptic(vr::IVRSystem* aVRSystem,
uint32_t aHapticIndex,
double aIntensity,
double aDuration,
uint32_t aPromiseID)
{
// Spinning up the haptics thread at the first haptics call.
if (!mVibrateThread) {
nsresult rv = NS_NewThread(getter_AddRefs(mVibrateThread));
MOZ_ASSERT(mVibrateThread);
if (NS_FAILED(rv)) {
MOZ_ASSERT(false, "Failed to create async thread.");
}
}
++mVibrateIndex;
mIsVibrating = true;
RefPtr<Runnable> runnable =
NewRunnableMethod<vr::IVRSystem*, uint32_t, double, double, uint64_t, uint32_t>
(this, &VRControllerOpenVR::UpdateVibrateHaptic, aVRSystem,
aHapticIndex, aIntensity, aDuration, mVibrateIndex, aPromiseID);
mVibrateThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
}
void
VRControllerOpenVR::StopVibrateHaptic()
{
mIsVibrating = false;
}
VRSystemManagerOpenVR::VRSystemManagerOpenVR()
: mVRSystem(nullptr)
, mOpenVRInstalled(false)
@ -744,12 +823,47 @@ VRSystemManagerOpenVR::HandlePoseTracking(uint32_t aControllerIdx,
const GamepadPoseState& aPose,
VRControllerHost* aController)
{
MOZ_ASSERT(aController);
if (aPose != aController->GetPose()) {
aController->SetPose(aPose);
NewPoseState(aControllerIdx, aPose);
}
}
void
VRSystemManagerOpenVR::VibrateHaptic(uint32_t aControllerIdx,
uint32_t aHapticIndex,
double aIntensity,
double aDuration,
uint32_t aPromiseID)
{
// mVRSystem is available after VRDisplay is created
// at GetHMDs().
if (!mVRSystem) {
return;
}
RefPtr<impl::VRControllerOpenVR> controller = mOpenVRController[aControllerIdx];
MOZ_ASSERT(controller);
controller->VibrateHaptic(mVRSystem, aHapticIndex, aIntensity, aDuration, aPromiseID);
}
void
VRSystemManagerOpenVR::StopVibrateHaptic(uint32_t aControllerIdx)
{
// mVRSystem is available after VRDisplay is created
// at GetHMDs().
if (!mVRSystem) {
return;
}
RefPtr<impl::VRControllerOpenVR> controller = mOpenVRController[aControllerIdx];
MOZ_ASSERT(controller);
controller->StopVibrateHaptic();
}
void
VRSystemManagerOpenVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
{
@ -888,3 +1002,4 @@ VRSystemManagerOpenVR::RemoveControllers()
mOpenVRController.Clear();
mControllerCount = 0;
}

View File

@ -77,14 +77,29 @@ public:
uint32_t GetTrackedIndex();
void SetTrigger(float aValue);
float GetTrigger();
void VibrateHaptic(vr::IVRSystem* aVRSystem,
uint32_t aHapticIndex,
double aIntensity,
double aDuration,
uint32_t aPromiseID);
void StopVibrateHaptic();
protected:
virtual ~VRControllerOpenVR();
private:
void UpdateVibrateHaptic(vr::IVRSystem* aVRSystem,
uint32_t aHapticIndex,
double aIntensity,
double aDuration,
uint64_t aVibrateIndex,
uint32_t aPromiseID);
// The index of tracked devices from vr::IVRSystem.
uint32_t mTrackedIndex;
float mTrigger;
nsCOMPtr<nsIThread> mVibrateThread;
bool mIsVibrating;
};
} // namespace impl
@ -103,6 +118,12 @@ public:
aControllerResult) override;
virtual void ScanForControllers() override;
virtual void RemoveControllers() override;
virtual void VibrateHaptic(uint32_t aControllerIdx,
uint32_t aHapticIndex,
double aIntensity,
double aDuration,
uint32_t aPromiseID) override;
virtual void StopVibrateHaptic(uint32_t aControllerIdx) override;
protected:
VRSystemManagerOpenVR();

View File

@ -39,6 +39,8 @@ static const uint32_t kPuppetAxes[] = {
static const uint32_t kNumPuppetAxis = sizeof(kPuppetAxes) /
sizeof(uint32_t);
static const uint32_t kNumPuppetHaptcs = 1;
VRDisplayPuppet::VRDisplayPuppet()
: VRDisplayHost(VRDeviceType::Puppet)
, mIsPresenting(false)
@ -236,6 +238,7 @@ VRControllerPuppet::VRControllerPuppet(dom::GamepadHand aHand)
mControllerInfo.mHand = aHand;
mControllerInfo.mNumButtons = kNumPuppetButtonMask;
mControllerInfo.mNumAxes = kNumPuppetAxis;
mControllerInfo.mNumHaptics = kNumPuppetHaptcs;
}
VRControllerPuppet::~VRControllerPuppet()
@ -418,6 +421,20 @@ VRSystemManagerPuppet::HandlePoseTracking(uint32_t aControllerIdx,
}
}
void
VRSystemManagerPuppet::VibrateHaptic(uint32_t aControllerIdx,
uint32_t aHapticIndex,
double aIntensity,
double aDuration,
uint32_t aPromiseID)
{
}
void
VRSystemManagerPuppet::StopVibrateHaptic(uint32_t aControllerIdx)
{
}
void
VRSystemManagerPuppet::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
{

View File

@ -95,6 +95,12 @@ public:
aControllerResult) override;
virtual void ScanForControllers() override;
virtual void RemoveControllers() override;
virtual void VibrateHaptic(uint32_t aControllerIdx,
uint32_t aHapticIndex,
double aIntensity,
double aDuration,
uint32_t aPromiseID) override;
virtual void StopVibrateHaptic(uint32_t aControllerIdx) override;
protected:
VRSystemManagerPuppet();

View File

@ -54,11 +54,15 @@ parent:
async ControllerListenerAdded();
async ControllerListenerRemoved();
async VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
double aIntensity, double aDuration);
async CreateVRTestSystem();
async CreateVRServiceTestDisplay(nsCString aID, uint32_t aPromiseID);
async CreateVRServiceTestController(nsCString aID, uint32_t aPromiseID);
async SetDisplayInfoToMockDisplay(uint32_t aDeviceID, VRDisplayInfo aDisplayInfo);
async SetSensorStateToMockDisplay(uint32_t aDeviceID, VRHMDSensorState aSensorState);
async NewButtonEventToMockController(uint32_t aDeviceID, long aButton,
bool aPressed);
async NewAxisMoveEventToMockController(uint32_t aDeviceID, long aAxis,

View File

@ -438,6 +438,18 @@ VRManagerParent::RecvNewPoseMoveToMockController(const uint32_t& aDeviceID,
return IPC_OK();
}
mozilla::ipc::IPCResult
VRManagerParent::RecvVibrateHaptic(const uint32_t& aControllerIdx,
const uint32_t& aHapticIndex,
const double& aIntensity,
const double& aDuration)
{
VRManager* vm = VRManager::Get();
vm->VibrateHaptic(aControllerIdx, aHapticIndex, aIntensity,
aDuration);
return IPC_OK();
}
bool
VRManagerParent::SendGamepadUpdate(const GamepadChangeEvent& aGamepadEvent)
{

View File

@ -91,6 +91,8 @@ protected:
virtual mozilla::ipc::IPCResult RecvSetHaveEventListener(const bool& aHaveEventListener) override;
virtual mozilla::ipc::IPCResult RecvControllerListenerAdded() override;
virtual mozilla::ipc::IPCResult RecvControllerListenerRemoved() override;
virtual mozilla::ipc::IPCResult RecvVibrateHaptic(const uint32_t& aControllerIdx, const uint32_t& aHapticIndex,
const double& aIntensity, const double& aDuration) override;
virtual mozilla::ipc::IPCResult RecvCreateVRTestSystem() override;
virtual mozilla::ipc::IPCResult RecvCreateVRServiceTestDisplay(const nsCString& aID, const uint32_t& aPromiseID) override;
virtual mozilla::ipc::IPCResult RecvCreateVRServiceTestController(const nsCString& aID, const uint32_t& aPromiseID) override;