Bug 1306415 - Part 1: Implement VRFrameData and VRDisplay.getFrameData,r=smaug,r=dmu

MozReview-Commit-ID: HlZUtZ7iZb5

--HG--
extra : rebase_source : 2d5de1522c0b06aa49d5a0ad3fe2170fff78ec37
This commit is contained in:
Kearwood (Kip) Gilbert 2016-09-30 16:43:33 -07:00
parent 43c76f1bba
commit 423a243482
5 changed files with 275 additions and 2 deletions

View File

@ -303,6 +303,20 @@ VRPose::VRPose(nsISupports* aParent, const gfx::VRHMDSensorState& aState)
mozilla::HoldJSObjects(this);
}
VRPose::VRPose(nsISupports* aParent)
: mParent(aParent)
, mPosition(nullptr)
, mLinearVelocity(nullptr)
, mLinearAcceleration(nullptr)
, mOrientation(nullptr)
, mAngularVelocity(nullptr)
, mAngularAcceleration(nullptr)
{
mFrameId = 0;
mVRState.Clear();
mozilla::HoldJSObjects(this);
}
VRPose::~VRPose()
{
mozilla::DropJSObjects(this);
@ -490,6 +504,15 @@ VRDisplay::GetStageParameters()
return mStageParameters;
}
bool
VRDisplay::GetFrameData(VRFrameData& aFrameData)
{
gfx::VRHMDSensorState state = mClient->GetSensorState();
const gfx::VRDisplayInfo& info = mClient->GetDisplayInfo();
aFrameData.Update(info, state, mDepthNear, mDepthFar);
return true;
}
already_AddRefed<VRPose>
VRDisplay::GetPose()
{
@ -658,5 +681,174 @@ NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, DOMEventTargetHelper)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_CLASS(VRFrameData)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(VRFrameData)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent, mPose)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
tmp->mLeftProjectionMatrix = nullptr;
tmp->mLeftViewMatrix = nullptr;
tmp->mRightProjectionMatrix = nullptr;
tmp->mRightViewMatrix = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(VRFrameData)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent, mPose)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(VRFrameData)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLeftProjectionMatrix)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLeftViewMatrix)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRightProjectionMatrix)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRightViewMatrix)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRFrameData, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRFrameData, Release)
VRFrameData::VRFrameData(nsISupports* aParent)
: mParent(aParent)
, mLeftProjectionMatrix(nullptr)
, mLeftViewMatrix(nullptr)
, mRightProjectionMatrix(nullptr)
, mRightViewMatrix(nullptr)
{
mPose = new VRPose(aParent);
}
VRFrameData::~VRFrameData()
{
mozilla::DropJSObjects(this);
}
/* static */ already_AddRefed<VRFrameData>
VRFrameData::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{
RefPtr<VRFrameData> obj = new VRFrameData(aGlobal.GetAsSupports());
return obj.forget();
}
JSObject*
VRFrameData::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto)
{
return VRFrameDataBinding::Wrap(aCx, this, aGivenProto);
}
VRPose*
VRFrameData::Pose()
{
return mPose;
}
void
VRFrameData::LazyCreateMatrix(JS::Heap<JSObject*>& aArray, gfx::Matrix4x4& aMat, JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv)
{
if (!aArray) {
// Lazily create the Float32Array
aArray = dom::Float32Array::Create(aCx, this, 16, aMat.components);
if (!aArray) {
aRv.NoteJSContextException(aCx);
return;
}
}
if (aArray) {
JS::ExposeObjectToActiveJS(aArray);
}
aRetval.set(aArray);
}
double
VRFrameData::Timestamp() const
{
return mVRState.timestamp * 1000.0f; // Converting from seconds to milliseconds
}
void
VRFrameData::GetLeftProjectionMatrix(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv)
{
LazyCreateMatrix(mLeftProjectionMatrix, mLeftProjection, aCx, aRetval, aRv);
}
void
VRFrameData::GetLeftViewMatrix(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv)
{
LazyCreateMatrix(mLeftViewMatrix, mLeftView, aCx, aRetval, aRv);
}
void
VRFrameData::GetRightProjectionMatrix(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv)
{
LazyCreateMatrix(mRightProjectionMatrix, mRightProjection, aCx, aRetval, aRv);
}
void
VRFrameData::GetRightViewMatrix(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv)
{
LazyCreateMatrix(mRightViewMatrix, mRightView, aCx, aRetval, aRv);
}
void
VRFrameData::Update(const gfx::VRDisplayInfo& aInfo,
const gfx::VRHMDSensorState& aState,
float aDepthNear,
float aDepthFar)
{
mVRState = aState;
mLeftProjectionMatrix = nullptr;
mLeftViewMatrix = nullptr;
mRightProjectionMatrix = nullptr;
mRightViewMatrix = nullptr;
mPose = new VRPose(GetParentObject(), aState);
gfx::Quaternion qt;
if (mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation) {
qt.x = mVRState.orientation[0];
qt.y = mVRState.orientation[1];
qt.z = mVRState.orientation[2];
qt.w = mVRState.orientation[3];
}
gfx::Point3D pos;
if (mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position) {
pos.x = -mVRState.position[0];
pos.y = -mVRState.position[1];
pos.z = -mVRState.position[2];
}
gfx::Matrix4x4 matHead;
matHead.SetRotationFromQuaternion(qt);
matHead.PreTranslate(pos);
mLeftView = matHead;
mLeftView.PostTranslate(-aInfo.mEyeTranslation[gfx::VRDisplayInfo::Eye_Left]);
mRightView = matHead;
mRightView.PostTranslate(-aInfo.mEyeTranslation[gfx::VRDisplayInfo::Eye_Right]);
// Avoid division by zero within ConstructProjectionMatrix
const float kEpsilon = 0.00001f;
if (fabs(aDepthFar - aDepthNear) < kEpsilon) {
aDepthFar = aDepthNear + kEpsilon;
}
const gfx::VRFieldOfView leftFOV = aInfo.mEyeFOV[gfx::VRDisplayInfo::Eye_Left];
mLeftProjection = leftFOV.ConstructProjectionMatrix(aDepthNear, aDepthFar, true);
const gfx::VRFieldOfView rightFOV = aInfo.mEyeFOV[gfx::VRDisplayInfo::Eye_Right];
mRightProjection = rightFOV.ConstructProjectionMatrix(aDepthNear, aDepthFar, true);
}
} // namespace dom
} // namespace mozilla

View File

@ -100,6 +100,7 @@ class VRPose final : public nsWrapperCache
public:
VRPose(nsISupports* aParent, const gfx::VRHMDSensorState& aState);
explicit VRPose(nsISupports* aParent);
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VRPose)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRPose)
@ -144,6 +145,63 @@ protected:
};
class VRFrameData final : public nsWrapperCache
{
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VRFrameData)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRFrameData)
explicit VRFrameData(nsISupports* aParent);
static already_AddRefed<VRFrameData> Constructor(const GlobalObject& aGlobal,
ErrorResult& aRv);
void Update(const gfx::VRDisplayInfo& aInfo,
const gfx::VRHMDSensorState& aState,
float aDepthNear,
float aDepthFar);
// WebIDL Members
double Timestamp() const;
void GetLeftProjectionMatrix(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv);
void GetLeftViewMatrix(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv);
void GetRightProjectionMatrix(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv);
void GetRightViewMatrix(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv);
VRPose* Pose();
// WebIDL Boilerplate
nsISupports* GetParentObject() const { return mParent; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
protected:
~VRFrameData();
nsCOMPtr<nsISupports> mParent;
gfx::VRHMDSensorState mVRState;
RefPtr<VRPose> mPose;
JS::Heap<JSObject*> mLeftProjectionMatrix;
JS::Heap<JSObject*> mLeftViewMatrix;
JS::Heap<JSObject*> mRightProjectionMatrix;
JS::Heap<JSObject*> mRightViewMatrix;
gfx::Matrix4x4 mLeftProjection;
gfx::Matrix4x4 mLeftView;
gfx::Matrix4x4 mRightProjection;
gfx::Matrix4x4 mRightView;
void LazyCreateMatrix(JS::Heap<JSObject*>& aArray, gfx::Matrix4x4& aMat,
JSContext* aCx, JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv);
};
class VRStageParameters final : public nsWrapperCache
{
public:
@ -235,6 +293,7 @@ public:
virtual already_AddRefed<VREyeParameters> GetEyeParameters(VREye aEye);
bool GetFrameData(VRFrameData& aFrameData);
already_AddRefed<VRPose> GetPose();
already_AddRefed<VRPose> GetImmediatePose();
void ResetPose();

View File

@ -133,6 +133,21 @@ interface VRPose {
[Constant, Throws] readonly attribute Float32Array? angularAcceleration;
};
[Constructor,
Pref="dom.vr.enabled",
HeaderFile="mozilla/dom/VRDisplay.h"]
interface VRFrameData {
readonly attribute DOMHighResTimeStamp timestamp;
[Throws, Pure] readonly attribute Float32Array leftProjectionMatrix;
[Throws, Pure] readonly attribute Float32Array leftViewMatrix;
[Throws, Pure] readonly attribute Float32Array rightProjectionMatrix;
[Throws, Pure] readonly attribute Float32Array rightViewMatrix;
[Pure] readonly attribute VRPose pose;
};
[Pref="dom.vr.enabled",
HeaderFile="mozilla/dom/VRDisplay.h"]
interface VREyeParameters {
@ -187,6 +202,12 @@ interface VRDisplay : EventTarget {
*/
[Constant] readonly attribute DOMString displayName;
/**
* Populates the passed VRFrameData with the information required to render
* the current frame.
*/
boolean getFrameData(VRFrameData frameData);
/**
* Return a VRPose containing the future predicted pose of the VRDisplay
* when the current frame will be presented. Subsequent calls to getPose()

View File

@ -23,7 +23,8 @@ VRDisplayManager::AllocateDisplayID()
}
Matrix4x4
VRFieldOfView::ConstructProjectionMatrix(float zNear, float zFar, bool rightHanded)
VRFieldOfView::ConstructProjectionMatrix(float zNear, float zFar,
bool rightHanded) const
{
float upTan = tan(upDegrees * M_PI / 180.0);
float downTan = tan(downDegrees * M_PI / 180.0);

View File

@ -112,7 +112,7 @@ struct VRFieldOfView {
leftDegrees == 0.0;
}
Matrix4x4 ConstructProjectionMatrix(float zNear, float zFar, bool rightHanded);
Matrix4x4 ConstructProjectionMatrix(float zNear, float zFar, bool rightHanded) const;
double upDegrees;
double rightDegrees;