--- a/config/system-headers
+++ b/config/system-headers
@@ -1183,16 +1183,20 @@ UTextEdit.h
UTextTraits.h
utime.h
UWindows.h
values.h
varargs.h
vcclr.h
View.h
Volume.h
+#ifdef ANDROID
+vr/gvr/capi/include/gvr.h
+vr/gvr/capi/include/gvr_controller.h
+#endif
wab.h
wait.h
wchar.h
wctype.h
winbase.h
win/compobj.h
windef.h
Window.h
--- a/dom/vr/VRDisplay.cpp
+++ b/dom/vr/VRDisplay.cpp
@@ -653,16 +653,21 @@ VRDisplay::GetLayers(nsTArray<VRLayer>&
}
}
void
VRDisplay::SubmitFrame()
{
AUTO_PROFILER_TRACING("VR", "SubmitFrameAtVRDisplay");
+ if (mClient && !mClient->IsPresentationGenerationCurrent()) {
+ mPresentation = nullptr;
+ mClient->MakePresentationGenerationCurrent();
+ }
+
if (mPresentation) {
mPresentation->SubmitFrame();
}
mFrameInfo.Clear();
}
int32_t
VRDisplay::RequestAnimationFrame(FrameRequestCallback& aCallback,
--- a/gfx/gl/GLBlitHelper.h
+++ b/gfx/gl/GLBlitHelper.h
@@ -31,16 +31,17 @@ class MacIOSurfaceImage;
class SurfaceDescriptorD3D10;
class SurfaceDescriptorDXGIYCbCr;
} // namespace layers
namespace gl {
class BindAnglePlanes;
class GLContext;
+class GLBlitHelper;
bool
GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
gfx::IntSize* const out_divisors);
template<uint8_t N>
struct Mat
{
--- a/gfx/vr/VRDisplayClient.cpp
+++ b/gfx/vr/VRDisplayClient.cpp
@@ -28,16 +28,17 @@ using namespace mozilla;
using namespace mozilla::gfx;
VRDisplayClient::VRDisplayClient(const VRDisplayInfo& aDisplayInfo)
: mDisplayInfo(aDisplayInfo)
, bLastEventWasMounted(false)
, bLastEventWasPresenting(false)
, mPresentationCount(0)
, mLastEventFrameId(0)
+ , mLastPresentingGeneration(0)
{
MOZ_COUNT_CTOR(VRDisplayClient);
}
VRDisplayClient::~VRDisplayClient() {
MOZ_COUNT_DTOR(VRDisplayClient);
}
@@ -72,16 +73,32 @@ VRDisplayClient::ZeroSensor()
void
VRDisplayClient::SetGroupMask(uint32_t aGroupMask)
{
VRManagerChild *vm = VRManagerChild::Get();
vm->SendSetGroupMask(mDisplayInfo.mDisplayID, aGroupMask);
}
+bool
+VRDisplayClient::IsPresentationGenerationCurrent() const
+{
+ if (mLastPresentingGeneration != mDisplayInfo.mPresentingGeneration) {
+ return false;
+ }
+
+ return true;
+}
+
+void
+VRDisplayClient::MakePresentationGenerationCurrent()
+{
+ mLastPresentingGeneration = mDisplayInfo.mPresentingGeneration;
+}
+
void
VRDisplayClient::FireEvents()
{
VRManagerChild *vm = VRManagerChild::Get();
// Only fire these events for non-chrome VR sessions
bool isPresenting = (mDisplayInfo.mPresentingGroups & kVRGroupContent) != 0;
// Check if we need to trigger onVRDisplayPresentChange event
--- a/gfx/vr/VRDisplayClient.h
+++ b/gfx/vr/VRDisplayClient.h
@@ -39,28 +39,32 @@ public:
uint32_t aGroup);
void PresentationDestroyed();
bool GetIsConnected() const;
void NotifyDisconnected();
void SetGroupMask(uint32_t aGroupMask);
+ bool IsPresentationGenerationCurrent() const;
+ void MakePresentationGenerationCurrent();
+
protected:
virtual ~VRDisplayClient();
void FireEvents();
VRDisplayInfo mDisplayInfo;
bool bLastEventWasMounted;
bool bLastEventWasPresenting;
int mPresentationCount;
uint64_t mLastEventFrameId;
+ uint32_t mLastPresentingGeneration;
private:
VRSubmitFrameResultInfo mSubmitFrameResult;
};
} // namespace gfx
} // namespace mozilla
#endif /* GFX_VR_DISPLAY_CLIENT_H */
--- a/gfx/vr/VRDisplayHost.cpp
+++ b/gfx/vr/VRDisplayHost.cpp
@@ -67,16 +67,17 @@ VRDisplayHost::VRDisplayHost(VRDeviceTyp
, mFrameStarted(false)
{
MOZ_COUNT_CTOR(VRDisplayHost);
mDisplayInfo.mType = aType;
mDisplayInfo.mDisplayID = VRSystemManager::AllocateDisplayID();
mDisplayInfo.mPresentingGroups = 0;
mDisplayInfo.mGroupMask = kVRGroupContent;
mDisplayInfo.mFrameId = 0;
+ mDisplayInfo.mPresentingGeneration = 0;
}
VRDisplayHost::~VRDisplayHost()
{
MOZ_COUNT_DTOR(VRDisplayHost);
}
#if defined(XP_WIN)
@@ -328,24 +329,33 @@ VRDisplayHost::SubmitFrame(VRLayerParent
}
IntSize texSize = gfx::IntSize(surf->GetDevicePixelWidth(),
surf->GetDevicePixelHeight());
if (!SubmitFrame(surf, texSize, aLeftEyeRect, aRightEyeRect)) {
return;
}
break;
}
+#elif defined(MOZ_ANDROID_GOOGLE_VR)
+ case SurfaceDescriptor::TEGLImageDescriptor: {
+ const EGLImageDescriptor& desc = aTexture.get_EGLImageDescriptor();
+ if (!SubmitFrame(&desc, aLeftEyeRect, aRightEyeRect)) {
+ return;
+ }
+ break;
+ }
#endif
default: {
NS_WARNING("Unsupported SurfaceDescriptor type for VR layer texture");
return;
}
}
-#if defined(XP_WIN) || defined(XP_MACOSX)
+#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_ANDROID_GOOGLE_VR)
+
/**
* Trigger the next VSync immediately after we are successfully
* submitting frames. As SubmitFrame is responsible for throttling
* the render loop, if we don't successfully call it, we shouldn't trigger
* NotifyVRVsync immediately, as it will run unbounded.
* If NotifyVRVsync is not called here due to SubmitFrame failing, the
* fallback "watchdog" code in VRDisplayHost::NotifyVSync() will cause
* frames to continue at a lower refresh rate until frame submission
--- a/gfx/vr/VRDisplayHost.h
+++ b/gfx/vr/VRDisplayHost.h
@@ -80,16 +80,20 @@ protected:
const IntSize& aSize,
const gfx::Rect& aLeftEyeRect,
const gfx::Rect& aRightEyeRect) = 0;
#elif defined(XP_MACOSX)
virtual bool SubmitFrame(MacIOSurface* aMacIOSurface,
const IntSize& aSize,
const gfx::Rect& aLeftEyeRect,
const gfx::Rect& aRightEyeRect) = 0;
+#elif defined(MOZ_ANDROID_GOOGLE_VR)
+ virtual bool SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor,
+ const gfx::Rect& aLeftEyeRect,
+ const gfx::Rect& aRightEyeRect) = 0;
#endif
VRDisplayInfo mDisplayInfo;
nsTArray<RefPtr<VRLayerParent>> mLayers;
// Weak reference to mLayers entries are cleared in
// VRLayerParent destructor
--- a/gfx/vr/VRManager.cpp
+++ b/gfx/vr/VRManager.cpp
@@ -20,16 +20,20 @@
#include "gfxVR.h"
#if defined(XP_WIN)
#include "gfxVROculus.h"
#endif
#if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
#include "gfxVROpenVR.h"
#include "gfxVROSVR.h"
#endif
+#if defined(MOZ_ANDROID_GOOGLE_VR)
+#include "gfxVRGVR.h"
+#endif // MOZ_ANDROID_GOOGLE_VR
+
#include "gfxVRPuppet.h"
#include "ipc/VRLayerParent.h"
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::layers;
using namespace mozilla::gl;
@@ -88,16 +92,24 @@ VRManager::VRManager()
}
// OSVR is cross platform compatible
mgr = VRSystemManagerOSVR::Create();
if (mgr) {
mManagers.AppendElement(mgr);
}
#endif
+
+#if defined(MOZ_ANDROID_GOOGLE_VR)
+ mgr = VRSystemManagerGVR::Create();
+ if (mgr) {
+ mManagers.AppendElement(mgr);
+ }
+#endif // defined(MOZ_ANDROID_GOOGLE_VR)
+
// Enable gamepad extensions while VR is enabled.
// Preference only can be set at the Parent process.
if (XRE_IsParentProcess() && gfxPrefs::VREnabled()) {
Preferences::SetBool("dom.gamepad.extensions.enabled", true);
}
}
VRManager::~VRManager()
--- a/gfx/vr/gfxVR.h
+++ b/gfx/vr/gfxVR.h
@@ -30,16 +30,17 @@ namespace gfx {
class VRLayerParent;
class VRDisplayHost;
class VRControllerHost;
enum class VRDeviceType : uint16_t {
Oculus,
OpenVR,
OSVR,
+ GVR,
Puppet,
NumVRDeviceTypes
};
enum class VRDisplayCapabilityFlags : uint16_t {
Cap_None = 0,
/**
* Cap_Position is set if the VRDisplay is capable of tracking its position.
@@ -216,16 +217,17 @@ struct VRDisplayInfo
IntSize mEyeResolution;
bool mIsConnected;
bool mIsMounted;
uint32_t mPresentingGroups;
uint32_t mGroupMask;
Size mStageSize;
Matrix4x4 mSittingToStandingTransform;
uint64_t mFrameId;
+ uint32_t mPresentingGeneration;
VRHMDSensorState mLastSensorState[kVRMaxLatencyFrames];
bool operator==(const VRDisplayInfo& other) const {
for (size_t i = 0; i < kVRMaxLatencyFrames; i++) {
if (mLastSensorState[i] != other.mLastSensorState[i]) {
return false;
}
}
@@ -239,17 +241,18 @@ struct VRDisplayInfo
mPresentingGroups == other.mPresentingGroups &&
mGroupMask == other.mGroupMask &&
mEyeFOV[0] == other.mEyeFOV[0] &&
mEyeFOV[1] == other.mEyeFOV[1] &&
mEyeTranslation[0] == other.mEyeTranslation[0] &&
mEyeTranslation[1] == other.mEyeTranslation[1] &&
mStageSize == other.mStageSize &&
mSittingToStandingTransform == other.mSittingToStandingTransform &&
- mFrameId == other.mFrameId;
+ mFrameId == other.mFrameId &&
+ mPresentingGeneration == other.mPresentingGeneration;
}
bool operator!=(const VRDisplayInfo& other) const {
return !(*this == other);
}
const VRHMDSensorState& GetSensorState() const
{
new file mode 100644
--- /dev/null
+++ b/gfx/vr/gfxVRGVR.cpp
@@ -0,0 +1,793 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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;
+
+ mDisplayInfo.mDisplayName.AssignLiteral("GVR HMD");
+ 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;
+}
+
+void
+VRDisplayGVR::NotifyVSync()
+{
+ VRDisplayHost::NotifyVSync();
+}
+
+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);
+ result.CalcViewMatrices(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];
+ FillMatrix(mHeadToEyes[eyeIndex], eye);
+ }
+}
+
+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.right, (float)fov.bottom, (float)fov.left);
+
+ 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.right, (float)fov.bottom, (float)fov.left);
+
+ 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, GVR_CONTROLLER_RIGHT_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);
+ mControllerInfo.mControllerName.AssignLiteral("Daydream Controller");
+ // 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.
+ mControllerInfo.mNumButtons = GVR_CONTROLLER_BUTTON_COUNT - 1; // Skip dummy none button
+ mControllerInfo.mNumAxes = 2;
+ mControllerInfo.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()
+{
+
+}
+
+bool
+VRSystemManagerGVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult)
+{
+ if (!GeckoVRManager::IsGVRPresent()) {
+ return false;
+ }
+
+ if (!mGVRHMD) {
+ mGVRHMD = new VRDisplayGVR();
+ }
+
+ aHMDResult.AppendElement(mGVRHMD);
+ return true;
+}
+
+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,
+ uint32_t aPromiseID)
+{
+
+}
+
+void
+VRSystemManagerGVR::StopVibrateHaptic(uint32_t aControllerIdx)
+{
+
+}
+
+VRSystemManagerGVR::VRSystemManagerGVR()
+ : mGVRHMD(nullptr)
+{
+
+}
+
+VRSystemManagerGVR::~VRSystemManagerGVR()
+{
+
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/gfxVRGVR.h
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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/. */
+
+#ifndef GFX_VR_GVR_H
+#define GFX_VR_GVR_H
+
+#include "gfxVR.h"
+
+#include <memory>
+
+#include "mozilla/EnumeratedArray.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Matrix.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+
+#include "nsTArray.h"
+#include "nsIRunnable.h"
+#include "nsIScreen.h"
+#include "nsCOMPtr.h"
+
+#include "VRDisplayHost.h"
+
+#pragma GCC system_header
+#pragma GCC visibility push(default)
+#include "vr/gvr/capi/include/gvr.h"
+#include "vr/gvr/capi/include/gvr_controller.h"
+#pragma GCC visibility pop
+
+
+namespace mozilla {
+namespace gl {
+class GLContextEGL;
+} // namespace gl
+namespace layers {
+class EGLImageDescriptor;
+} // namespace layers
+namespace gfx {
+namespace impl {
+
+class VRControllerGVR : public VRControllerHost
+{
+public:
+ explicit VRControllerGVR(dom::GamepadHand aHand, uint32_t aDisplayID);
+ virtual ~VRControllerGVR();
+ void Update(gvr_controller_state* aState, VRSystemManager* aManager);
+};
+
+class VRDisplayGVR : public VRDisplayHost
+{
+public:
+ VRDisplayGVR();
+
+ // BEGIN VRDisplayHost interface
+ void ZeroSensor() override;
+ void StartPresentation() override;
+ void StopPresentation() override;
+ bool SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor,
+ const gfx::Rect& aLeftEyeRect,
+ const gfx::Rect& aRightEyeRect) override;
+ void NotifyVSync() override;
+protected:
+ virtual VRHMDSensorState GetSensorState() override;
+ // END VRDisplayHost interface
+
+public:
+ void SetPaused(const bool aPaused);
+ void SetPresentingContext(void* aGVRPresentingContext);
+ void EnableControllers(const bool aEnable, VRSystemManager* aManager);
+ void UpdateControllers(VRSystemManager* aManager);
+ void GetControllers(nsTArray<RefPtr<VRControllerHost> >& aControllerResult);
+
+protected:
+ virtual ~VRDisplayGVR();
+ void UpdateHeadToEye(gvr_context* aContext);
+ void UpdateViewport();
+ void RecreateSwapChain();
+
+ bool mIsPresenting;
+ bool mControllerAdded;
+
+ gfx::Matrix4x4 mHeadToEyes[2];
+ gvr_context* mPresentingContext;
+ gvr_controller_context* mControllerContext;
+ gvr_controller_state* mControllerState;
+ gvr_buffer_viewport_list* mViewportList;
+ gvr_buffer_viewport* mLeftViewport;
+ gvr_buffer_viewport* mRightViewport;
+ gvr_mat4f mHeadMatrix;
+ gvr_swap_chain* mSwapChain;
+ gvr_sizei mFrameBufferSize;
+
+ RefPtr<VRControllerGVR> mController;
+};
+
+
+} // namespace impl
+
+class VRSystemManagerGVR : public VRSystemManager
+{
+public:
+ static already_AddRefed<VRSystemManagerGVR> Create();
+
+ void Destroy() override;
+ void Shutdown() override;
+ bool GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
+ bool GetIsPresenting() override;
+ void HandleInput() override;
+ void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
+ aControllerResult) override;
+ void ScanForControllers() override;
+ void RemoveControllers() override;
+ void VibrateHaptic(uint32_t aControllerIdx,
+ uint32_t aHapticIndex,
+ double aIntensity,
+ double aDuration,
+ uint32_t aPromiseID) override;
+ void StopVibrateHaptic(uint32_t aControllerIdx) override;
+
+protected:
+ VRSystemManagerGVR();
+ virtual ~VRSystemManagerGVR();
+
+private:
+ RefPtr<impl::VRDisplayGVR> mGVRHMD;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+
+#endif /* GFX_VR_GVR_H */
new file mode 100644
--- /dev/null
+++ b/gfx/vr/gfxVRGVRAPI.h
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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/. */
+
+#ifndef GFX_VR_GVR_API_H
+#define GFX_VR_GVR_API_H
+namespace mozilla {
+namespace gfx {
+
+void SetGVRPresentingContext(void* aGVRPresentingContext);
+void CleanupGVRNonPresentingContext();
+void SetGVRPaused(const bool aPaused);
+
+} // namespace gfx
+} // namespace mozilla
+#endif // GFX_VR_GVR_API_H
--- a/gfx/vr/gfxVROSVR.cpp
+++ b/gfx/vr/gfxVROSVR.cpp
@@ -352,16 +352,27 @@ VRDisplayOSVR::SubmitFrame(MacIOSurface*
const IntSize& aSize,
const gfx::Rect& aLeftEyeRect,
const gfx::Rect& aRightEyeRect)
{
// XXX Add code to submit frame
return false;
}
+#elif defined(MOZ_ANDROID_GOOGLE_VR)
+
+bool
+VRDisplayOSVR::SubmitFrame(const mozilla::layers::EGLImageDescriptor*,
+ const gfx::Rect& aLeftEyeRect,
+ const gfx::Rect& aRightEyeRect)
+{
+ // XXX Add code to submit frame
+ return false;
+}
+
#endif
void
VRDisplayOSVR::StartPresentation()
{
// XXX Add code to start VR Presentation
}
--- a/gfx/vr/gfxVROSVR.h
+++ b/gfx/vr/gfxVROSVR.h
@@ -41,16 +41,20 @@ protected:
const IntSize& aSize,
const gfx::Rect& aLeftEyeRect,
const gfx::Rect& aRightEyeRect) override;
#elif defined(XP_MACOSX)
virtual bool SubmitFrame(MacIOSurface* aMacIOSurface,
const IntSize& aSize,
const gfx::Rect& aLeftEyeRect,
const gfx::Rect& aRightEyeRect) override;
+#elif defined(MOZ_ANDROID_GOOGLE_VR)
+ virtual bool SubmitFrame(const mozilla::layers::EGLImageDescriptor*,
+ const gfx::Rect& aLeftEyeRect,
+ const gfx::Rect& aRightEyeRect) override;
#endif
public:
explicit VRDisplayOSVR(OSVR_ClientContext* context,
OSVR_ClientInterface* iface,
OSVR_DisplayConfig* display);
protected:
@@ -119,9 +123,9 @@ private:
void InitializeClientContext();
void InitializeDisplay();
void InitializeInterface();
};
} // namespace gfx
} // namespace mozilla
-#endif /* GFX_VR_OSVR_H */
\ No newline at end of file
+#endif /* GFX_VR_OSVR_H */
--- a/gfx/vr/gfxVRPuppet.cpp
+++ b/gfx/vr/gfxVRPuppet.cpp
@@ -545,16 +545,26 @@ VRDisplayPuppet::SubmitFrame(MacIOSurfac
MOZ_ASSERT(false, "No support for showing VR frames on MacOSX yet.");
break;
}
}
return false;
}
+#elif defined(MOZ_ANDROID_GOOGLE_VR)
+
+bool
+VRDisplayPuppet::SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor,
+ const gfx::Rect& aLeftEyeRect,
+ const gfx::Rect& aRightEyeRect) {
+
+ return false;
+}
+
#endif
void
VRDisplayPuppet::NotifyVSync()
{
// We update mIsConneced once per frame.
mDisplayInfo.mIsConnected = true;
--- a/gfx/vr/gfxVRPuppet.h
+++ b/gfx/vr/gfxVRPuppet.h
@@ -37,16 +37,20 @@ protected:
const IntSize& aSize,
const gfx::Rect& aLeftEyeRect,
const gfx::Rect& aRightEyeRect) override;
#elif defined(XP_MACOSX)
virtual bool SubmitFrame(MacIOSurface* aMacIOSurface,
const IntSize& aSize,
const gfx::Rect& aLeftEyeRect,
const gfx::Rect& aRightEyeRect) override;
+#elif defined(MOZ_ANDROID_GOOGLE_VR)
+ virtual bool SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor,
+ const gfx::Rect& aLeftEyeRect,
+ const gfx::Rect& aRightEyeRect) override;
#endif
public:
explicit VRDisplayPuppet();
protected:
virtual ~VRDisplayPuppet();
void Destroy();
@@ -138,9 +142,9 @@ private:
// there can only be one
RefPtr<impl::VRDisplayPuppet> mPuppetHMD;
nsTArray<RefPtr<impl::VRControllerPuppet>> mPuppetController;
};
} // namespace gfx
} // namespace mozilla
-#endif /* GFX_VR_PUPPET_H*/
\ No newline at end of file
+#endif /* GFX_VR_PUPPET_H*/
--- a/gfx/vr/ipc/VRMessageUtils.h
+++ b/gfx/vr/ipc/VRMessageUtils.h
@@ -40,16 +40,17 @@ struct ParamTraits<mozilla::gfx::VRDispl
WriteParam(aMsg, aParam.mEyeResolution);
WriteParam(aMsg, aParam.mIsConnected);
WriteParam(aMsg, aParam.mIsMounted);
WriteParam(aMsg, aParam.mPresentingGroups);
WriteParam(aMsg, aParam.mGroupMask);
WriteParam(aMsg, aParam.mStageSize);
WriteParam(aMsg, aParam.mSittingToStandingTransform);
WriteParam(aMsg, aParam.mFrameId);
+ WriteParam(aMsg, aParam.mPresentingGeneration);
for (int i = 0; i < mozilla::gfx::VRDisplayInfo::NumEyes; i++) {
WriteParam(aMsg, aParam.mEyeFOV[i]);
WriteParam(aMsg, aParam.mEyeTranslation[i]);
}
for (int i = 0; i < mozilla::gfx::kVRMaxLatencyFrames; i++) {
WriteParam(aMsg, aParam.mLastSensorState[i]);
}
}
@@ -62,17 +63,18 @@ struct ParamTraits<mozilla::gfx::VRDispl
!ReadParam(aMsg, aIter, &(aResult->mCapabilityFlags)) ||
!ReadParam(aMsg, aIter, &(aResult->mEyeResolution)) ||
!ReadParam(aMsg, aIter, &(aResult->mIsConnected)) ||
!ReadParam(aMsg, aIter, &(aResult->mIsMounted)) ||
!ReadParam(aMsg, aIter, &(aResult->mPresentingGroups)) ||
!ReadParam(aMsg, aIter, &(aResult->mGroupMask)) ||
!ReadParam(aMsg, aIter, &(aResult->mStageSize)) ||
!ReadParam(aMsg, aIter, &(aResult->mSittingToStandingTransform)) ||
- !ReadParam(aMsg, aIter, &(aResult->mFrameId))) {
+ !ReadParam(aMsg, aIter, &(aResult->mFrameId)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mPresentingGeneration))) {
return false;
}
for (int i = 0; i < mozilla::gfx::VRDisplayInfo::NumEyes; i++) {
if (!ReadParam(aMsg, aIter, &(aResult->mEyeFOV[i])) ||
!ReadParam(aMsg, aIter, &(aResult->mEyeTranslation[i]))) {
return false;
}
}
new file mode 100644
--- /dev/null
+++ b/gfx/vr/jni/gfxGVRJNI.cpp
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 <jni.h>
+
+extern "C" __attribute__((visibility("default"))) jlong
+Java_com_google_vr_cardboard_DisplaySynchronizer_nativeCreate(
+ JNIEnv* env,
+ jobject jcaller,
+ jclass classLoader,
+ jobject appContext);
+
+// Step 2: method stubs.
+extern "C" __attribute__((visibility("default"))) void
+Java_com_google_vr_cardboard_DisplaySynchronizer_nativeDestroy(
+ JNIEnv* env,
+ jobject jcaller,
+ jlong nativeDisplaySynchronizer);
+
+extern "C" __attribute__((visibility("default"))) void
+Java_com_google_vr_cardboard_DisplaySynchronizer_nativeReset(
+ JNIEnv* env,
+ jobject jcaller,
+ jlong nativeDisplaySynchronizer,
+ jlong expectedInterval,
+ jlong vsyncOffset);
+
+extern "C" __attribute__((visibility("default"))) void
+Java_com_google_vr_cardboard_DisplaySynchronizer_nativeUpdate(
+ JNIEnv* env,
+ jobject jcaller,
+ jlong nativeDisplaySynchronizer,
+ jlong syncTime,
+ jint currentRotation);
+
+namespace {
+
+bool
+check(JNIEnv* env) {
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ return false;
+ }
+ return true;
+}
+
+const char kDisplaySynchronizerClassPath[] = "com/google/vr/cardboard/DisplaySynchronizer";
+
+static const JNINativeMethod kMethodsDisplaySynchronizer[] = {
+ {"nativeCreate",
+ "("
+ "Ljava/lang/ClassLoader;"
+ "Landroid/content/Context;"
+ ")"
+ "J",
+ reinterpret_cast<void*>(
+ Java_com_google_vr_cardboard_DisplaySynchronizer_nativeCreate)},
+ {"nativeDestroy",
+ "("
+ "J"
+ ")"
+ "V",
+ reinterpret_cast<void*>(
+ Java_com_google_vr_cardboard_DisplaySynchronizer_nativeDestroy)},
+ {"nativeReset",
+ "("
+ "J"
+ "J"
+ "J"
+ ")"
+ "V",
+ reinterpret_cast<void*>(
+ Java_com_google_vr_cardboard_DisplaySynchronizer_nativeReset)},
+ {"nativeUpdate",
+ "("
+ "J"
+ "J"
+ "I"
+ ")"
+ "V",
+ reinterpret_cast<void*>(
+ Java_com_google_vr_cardboard_DisplaySynchronizer_nativeUpdate)},
+};
+}
+
+bool
+SetupGVRJNI(JNIEnv* env)
+{
+ jclass displaySynchronizerClazz = env->FindClass(kDisplaySynchronizerClassPath);
+ if (!check(env)) { return false; }
+ if (displaySynchronizerClazz == nullptr) {
+ return false;
+ }
+ env->RegisterNatives(displaySynchronizerClazz, kMethodsDisplaySynchronizer, sizeof(kMethodsDisplaySynchronizer) / sizeof(kMethodsDisplaySynchronizer[0]));
+ if (!check(env)) { return false; }
+ env->DeleteLocalRef(displaySynchronizerClazz);
+ if (!check(env)) { return false; }
+
+ return true;
+}
+
--- a/gfx/vr/moz.build
+++ b/gfx/vr/moz.build
@@ -52,16 +52,24 @@ if CONFIG['OS_TARGET'] in ('WINNT', 'Lin
'gfxVROpenVR.cpp',
]
if CONFIG['OS_TARGET'] == 'WINNT':
SOURCES += [
'gfxVROculus.cpp',
]
+if CONFIG['MOZ_ANDROID_GOOGLE_VR']:
+ SOURCES += [
+ 'gfxVRGVR.cpp',
+ 'jni/gfxGVRJNI.cpp',
+ ]
+ CXXFLAGS += ['-I%s' % CONFIG['MOZ_ANDROID_GOOGLE_VR_INCLUDE']]
+ LOCAL_INCLUDES += ['/widget/android']
+
IPDL_SOURCES = [
'ipc/PVRLayer.ipdl',
'ipc/PVRManager.ipdl',
]
# For building with the real SDK instead of our local hack
#SOURCES += [
# 'OVR_CAPI_Util.cpp',