Bug 1310663 - WIP Linux Support for OpenVR draft
authorKearwood Gilbert <kgilbert@mozilla.com>
Tue, 05 Dec 2017 16:06:37 -0800
changeset 724467 5477e0fff8c5fe6909308c1e0a03e21c8a522c97
parent 724404 32b850fa28ae1c29039cb7ddcdfd71b324762c05
child 747156 c23d561cf53c7c80bb73f2ad3c3fd9651e98eea8
push id96752
push userbmo:kgilbert@mozilla.com
push dateThu, 25 Jan 2018 00:44:53 +0000
bugs1310663
milestone60.0a1
Bug 1310663 - WIP Linux Support for OpenVR MozReview-Commit-ID: 4zJ6JkAywx8
dom/vr/test/reftest/reftest.list
gfx/thebes/gfxPrefs.h
gfx/vr/VRDisplayHost.cpp
gfx/vr/VRDisplayHost.h
gfx/vr/gfxVROSVR.cpp
gfx/vr/gfxVROSVR.h
gfx/vr/gfxVROpenVR.cpp
gfx/vr/gfxVROpenVR.h
gfx/vr/gfxVRPuppet.cpp
gfx/vr/gfxVRPuppet.h
--- a/dom/vr/test/reftest/reftest.list
+++ b/dom/vr/test/reftest/reftest.list
@@ -1,10 +1,10 @@
 # WebVR Reftests
 # Please confirm there is no other VR display connected. Otherwise, VRPuppetDisplay can't be attached.
 default-preferences pref(dom.vr.puppet.enabled,true) pref(dom.vr.test.enabled,true) pref(dom.vr.require-gesture,false) pref(dom.vr.puppet.submitframe,1) pref(dom.vr.display.rafMaxDuration,200) pref(dom.vr.display.enumerate.interval,0) pref(dom.vr.controller.enumerate.interval,0)
 
 # VR SubmitFrame is only implemented for D3D11.1 and MacOSX now.
 # Our Windows 7 test machines don't support D3D11.1, so we run these tests on Windows 8+ only.
-skip-if((!winWidget&&release_or_beta)||Android||gtkWidget||!layersGPUAccelerated||/^Windows\x20NT\x206\.1/.test(http.oscpu)) == draw_rect.html wrapper.html?draw_rect.png
+skip-if((!winWidget&&release_or_beta)||Android||/^Windows\x20NT\x206\.1/.test(http.oscpu)) == draw_rect.html wrapper.html?draw_rect.png
 # On MacOSX platform, getting different color interpolation result.
 # For lower resolution Mac hardware, we need to adjust it to fuzzy-if(cocoaWidget,1,1200).
 fuzzy-if(cocoaWidget,1,600) skip-if((!winWidget&&release_or_beta)||Android||gtkWidget||!layersGPUAccelerated||/^Windows\x20NT\x206\.1/.test(http.oscpu)) == change_size.html wrapper.html?change_size.png
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -491,17 +491,17 @@ private:
   DECL_GFX_PREF(Live, "gfx.perf-warnings.enabled",             PerfWarnings, bool, false);
   DECL_GFX_PREF(Live, "gfx.testing.device-reset",              DeviceResetForTesting, int32_t, 0);
   DECL_GFX_PREF(Live, "gfx.testing.device-fail",               DeviceFailForTesting, bool, false);
   DECL_GFX_PREF(Once, "gfx.text.disable-aa",                   DisableAllTextAA, bool, false);
   DECL_GFX_PREF(Live, "gfx.ycbcr.accurate-conversion",         YCbCrAccurateConversion, bool, false);
 
   // Disable surface sharing due to issues with compatible FBConfigs on
   // NVIDIA drivers as described in bug 1193015.
-  DECL_GFX_PREF(Live, "gfx.use-glx-texture-from-pixmap",       UseGLXTextureFromPixmap, bool, false);
+  DECL_GFX_PREF(Live, "gfx.use-glx-texture-from-pixmap",       UseGLXTextureFromPixmap, bool, true); // FINDME!!! KIP!! HACK!!
   DECL_GFX_PREF(Once, "gfx.use-iosurface-textures",            UseIOSurfaceTextures, bool, false);
   DECL_GFX_PREF(Once, "gfx.use-mutex-on-present",              UseMutexOnPresent, bool, false);
   DECL_GFX_PREF(Once, "gfx.use-surfacetexture-textures",       UseSurfaceTextureTextures, bool, false);
 
   DECL_GFX_PREF(Live, "gfx.vsync.collect-scroll-transforms",   CollectScrollTransforms, bool, false);
   DECL_GFX_PREF(Once, "gfx.vsync.compositor.unobserve-count",  CompositorUnobserveCount, int32_t, 10);
 
   DECL_GFX_PREF(Once, "gfx.webrender.all",                     WebRenderAll, bool, false);
--- a/gfx/vr/VRDisplayHost.cpp
+++ b/gfx/vr/VRDisplayHost.cpp
@@ -19,25 +19,33 @@
 #include "../layers/d3d11/CompositorD3D11.h"
 #include "mozilla/gfx/DeviceManagerDx.h"
 #include "mozilla/layers/TextureD3D11.h"
 
 #elif defined(XP_MACOSX)
 
 #include "mozilla/gfx/MacIOSurface.h"
 
+#elif defined(XP_LINUX) && !defined(MOZ_ANDROID_GOOGLE_VR)
+
+#include "GLContextProvider.h"          // for GLContextProvider
+#include "GLContext.h"                  // for GLContext
+#include "mozilla/gfx/gfxVars.h"        // for gfxVars
+#include "SurfaceTypes.h"               // for SurfaceCaps
+
 #endif
 
 #if defined(MOZ_ANDROID_GOOGLE_VR)
 #include "mozilla/layers/CompositorThread.h"
 #endif // defined(MOZ_ANDROID_GOOGLE_VR)
 
 
 using namespace mozilla;
 using namespace mozilla::gfx;
+using namespace mozilla::gl;
 using namespace mozilla::layers;
 
 VRDisplayHost::AutoRestoreRenderState::AutoRestoreRenderState(VRDisplayHost* aDisplay)
   : mDisplay(aDisplay)
   , mSuccess(true)
 {
 #if defined(XP_WIN)
   ID3D11DeviceContext1* context = mDisplay->GetD3DDeviceContext();
@@ -146,16 +154,46 @@ VRDisplayHost::GetD3DDeviceContext()
 ID3DDeviceContextState*
 VRDisplayHost::GetD3DDeviceContextState()
 {
   return mDeviceContextState;
 }
 
 #endif // defined(XP_WIN)
 
+#if defined(XP_LINUX) && !defined(MOZ_ANDROID_GOOGLE_VR)
+
+bool
+VRDisplayHost::CreateGLContext()
+{
+  if (!mGLContext) {
+    const gfx::IntSize dummySize(16, 16);
+    SurfaceCaps caps = SurfaceCaps::ForRGB();
+    caps.preserve = false;
+    caps.bpp16 = gfxVars::OffscreenFormat() == SurfaceFormat::R5G6B5_UINT16;
+
+    nsCString discardFailureId;
+    mGLContext = GLContextProvider::CreateOffscreen(dummySize,
+                                                    caps, CreateContextFlags::REQUIRE_COMPAT_PROFILE,
+                                                    &discardFailureId);
+  }
+  if (!mGLContext) {
+    NS_WARNING("Failed to create VRDisplayHost context");
+  }
+  return mGLContext != nullptr;
+}
+
+gl::GLContext*
+VRDisplayHost::GetGLContext()
+{
+  return mGLContext;
+}
+
+#endif // defined(XP_LINUX) && !defined(MOZ_ANDROID_GOOGLE_VR)
+
 void
 VRDisplayHost::SetGroupMask(uint32_t aGroupMask)
 {
   mDisplayInfo.mGroupMask = aGroupMask;
 }
 
 bool
 VRDisplayHost::GetIsConnected()
@@ -339,24 +377,35 @@ VRDisplayHost::SubmitFrameInternal(const
 #elif defined(MOZ_ANDROID_GOOGLE_VR)
     case SurfaceDescriptor::TEGLImageDescriptor: {
       const EGLImageDescriptor& desc = aTexture.get_EGLImageDescriptor();
       if (!SubmitFrame(&desc, aLeftEyeRect, aRightEyeRect)) {
         return;
       }
       break;
     }
+#elif defined(XP_LINUX)
+    case SurfaceDescriptor::TSurfaceDescriptorX11: {
+      if (!CreateGLContext()) {
+        return;
+      }
+      const SurfaceDescriptorX11& desc = aTexture.get_SurfaceDescriptorX11();
+      if (!SubmitFrame(&desc, desc.mSize, aLeftEyeRect, aRightEyeRect)) {
+       return;
+      }
+      break;
+    }
 #endif
     default: {
       NS_WARNING("Unsupported SurfaceDescriptor type for VR layer texture");
       return;
     }
   }
 
-#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_ANDROID_GOOGLE_VR)
+#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_ANDROID_GOOGLE_VR) || defined(XP_LINUX)
 
   /**
    * 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
--- a/gfx/vr/VRDisplayHost.h
+++ b/gfx/vr/VRDisplayHost.h
@@ -21,16 +21,19 @@
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 
 #if defined(XP_WIN)
 #include <d3d11_1.h>
 #elif defined(XP_MACOSX)
 class MacIOSurface;
 #endif
 namespace mozilla {
+namespace gl {
+class GLContext;
+}
 namespace gfx {
 class VRThread;
 class VRLayerParent;
 
 class VRDisplayHost {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRDisplayHost)
 
@@ -85,16 +88,21 @@ protected:
   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;
+#elif defined(XP_LINUX)
+  virtual bool SubmitFrame(const mozilla::layers::SurfaceDescriptorX11* aDescriptor,
+                           const IntSize& aSize,
+                           const gfx::Rect& aLeftEyeRect,
+                           const gfx::Rect& aRightEyeRect) = 0;
 #endif
 
   VRDisplayInfo mDisplayInfo;
 
   nsTArray<VRLayerParent *> mLayers;
   // Weak reference to mLayers entries are cleared in
   // VRLayerParent destructor
 
@@ -118,16 +126,23 @@ protected:
   RefPtr<ID3D11Device1> mDevice;
   RefPtr<ID3D11DeviceContext1> mContext;
   ID3D11Device1* GetD3DDevice();
   ID3D11DeviceContext1* GetD3DDeviceContext();
   ID3DDeviceContextState* GetD3DDeviceContextState();
 
 private:
   RefPtr<ID3DDeviceContextState> mDeviceContextState;
+#elif defined(XP_LINUX) && !defined(MOZ_ANDROID_GOOGLE_VR)
+protected:
+  bool CreateGLContext();
+  gl::GLContext* GetGLContext();
+private:
+  RefPtr<gl::GLContext> mGLContext;
+  
 #endif
 };
 
 class VRControllerHost {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRControllerHost)
 
   const VRControllerInfo& GetControllerInfo() const;
--- a/gfx/vr/gfxVROSVR.cpp
+++ b/gfx/vr/gfxVROSVR.cpp
@@ -365,16 +365,28 @@ VRDisplayOSVR::SubmitFrame(const mozilla
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect)
 {
   // XXX Add code to submit frame
   MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
   return false;
 }
 
+#elif defined(XP_LINUX)
+
+bool
+VRDisplayOSVR::SubmitFrame(const mozilla::layers::SurfaceDescriptorX11* aDescriptor,
+                           const IntSize& aSize,
+                           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
@@ -45,16 +45,21 @@ protected:
   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;
+#elif defined(XP_LINUX)
+  virtual bool SubmitFrame(const mozilla::layers::SurfaceDescriptorX11* aDescriptor,
+                           const IntSize& aSize,
+                           const gfx::Rect& aLeftEyeRect,
+                           const gfx::Rect& aRightEyeRect) override;
 #endif
 
 public:
   explicit VRDisplayOSVR(OSVR_ClientContext* context,
                          OSVR_ClientInterface* iface,
                          OSVR_DisplayConfig* display);
 
 protected:
--- a/gfx/vr/gfxVROpenVR.cpp
+++ b/gfx/vr/gfxVROpenVR.cpp
@@ -13,16 +13,22 @@
 
 #include "mozilla/gfx/Quaternion.h"
 
 #ifdef XP_WIN
 #include "CompositorD3D11.h"
 #include "TextureD3D11.h"
 #elif defined(XP_MACOSX)
 #include "mozilla/gfx/MacIOSurface.h"
+#elif defined(XP_LINUX) && !defined(MOZ_ANDROID_GOOGLE_VR)
+#include "gfxXlibSurface.h"
+#include "GLContext.h"                  // for GLContext
+#include "GLContextProvider.h"
+#include "GLContextGLX.h"
+#include "GLXLibrary.h"
 #endif
 
 #include "gfxVROpenVR.h"
 #include "VRManagerParent.h"
 #include "VRManager.h"
 #include "VRThread.h"
 
 #include "nsServiceManagerUtils.h"
@@ -34,16 +40,17 @@
 
 #ifndef M_PI
 # define M_PI 3.14159265358979323846
 #endif
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::gfx::impl;
+using namespace mozilla::gl;
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 
 #define BTN_MASK_FROM_ID(_id) \
   ::vr::ButtonMaskFromId(vr::EVRButtonId::_id)
 
 static const uint32_t kNumOpenVRHaptcs = 1;
 
@@ -417,16 +424,57 @@ VRDisplayOpenVR::SubmitFrame(MacIOSurfac
   } else {
     result = SubmitFrame((void *)ioSurface,
                          ::vr::ETextureType::TextureType_IOSurface,
                          aSize, aLeftEyeRect, aRightEyeRect);
   }
   return result;
 }
 
+#elif defined(XP_LINUX)
+
+bool
+VRDisplayOpenVR::SubmitFrame(const mozilla::layers::SurfaceDescriptorX11* aDescriptor,
+                             const IntSize& aSize,
+                             const gfx::Rect& aLeftEyeRect,
+                             const gfx::Rect& aRightEyeRect)
+{
+  bool result = false;
+
+  RefPtr<gfxXlibSurface> surface = aDescriptor->OpenForeign();
+  // FINDME!! KIP!! HACK!! IMPLEMENT THIS!
+  // KIP - Maybe follow this pattern:
+  //   mozilla::layers::X11TextureSourceOGL::X11TextureSourceOGL
+  // Also follow mozilla::layers::CompositorOGL::CreateContext()...
+
+  GLContext* context = GetGLContext();
+
+  GLuint tex = 0;
+
+  context->fGenTextures(1, &tex);
+
+  context->fBindTexture(LOCAL_GL_TEXTURE_2D, tex);
+  gl::sGLXLibrary.BindTexImage(surface->XDisplay(), surface->GetGLXPixmap());
+
+  if (tex) {
+
+    result = SubmitFrame((void *)tex,
+                         ::vr::ETextureType::TextureType_OpenGL,
+                         aSize, aLeftEyeRect, aRightEyeRect);
+
+    if (context->MakeCurrent()) {
+      gl::sGLXLibrary.ReleaseTexImage(surface->XDisplay(), surface->GetGLXPixmap());
+      context->fDeleteTextures(1, &tex);
+      tex = 0;
+    }
+  }
+
+  return result;
+}
+
 #endif
 
 VRControllerOpenVR::VRControllerOpenVR(dom::GamepadHand aHand, uint32_t aDisplayID,
                                        uint32_t aNumButtons, uint32_t aNumTriggers,
                                        uint32_t aNumAxes, const nsCString& aId)
   : VRControllerHost(VRDeviceType::OpenVR, aHand, aDisplayID)
   , mTrigger(aNumTriggers)
   , mAxisMove(aNumAxes)
--- a/gfx/vr/gfxVROpenVR.h
+++ b/gfx/vr/gfxVROpenVR.h
@@ -43,16 +43,21 @@ 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(XP_LINUX)
+  virtual bool SubmitFrame(const mozilla::layers::SurfaceDescriptorX11* aDescriptor,
+                           const IntSize& aSize,
+                           const gfx::Rect& aLeftEyeRect,
+                           const gfx::Rect& aRightEyeRect) override;
 #endif
 
 public:
   explicit VRDisplayOpenVR(::vr::IVRSystem *aVRSystem,
                            ::vr::IVRChaperone *aVRChaperone,
                            ::vr::IVRCompositor *aVRCompositor);
   void Refresh();
 protected:
--- a/gfx/vr/gfxVRPuppet.cpp
+++ b/gfx/vr/gfxVRPuppet.cpp
@@ -561,16 +561,26 @@ bool
 VRDisplayPuppet::SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect)
 {
   MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
   return false;
 }
 
+#elif defined(XP_LINUX)
+
+bool
+VRDisplayPuppet::SubmitFrame(const mozilla::layers::SurfaceDescriptorX11* aDescriptor,
+                             const IntSize& aSize,
+                             const gfx::Rect& aLeftEyeRect,
+                             const gfx::Rect& aRightEyeRect) {
+  return false;
+}
+
 #endif
 
 void
 VRDisplayPuppet::Refresh()
 {
   // We update mIsConneced once per refresh.
   mDisplayInfo.mIsConnected = true;
 }
--- a/gfx/vr/gfxVRPuppet.h
+++ b/gfx/vr/gfxVRPuppet.h
@@ -41,16 +41,21 @@ protected:
   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;
+#elif defined(XP_LINUX)
+  virtual bool SubmitFrame(const mozilla::layers::SurfaceDescriptorX11* aDescriptor,
+                           const IntSize& aSize,
+                           const gfx::Rect& aLeftEyeRect,
+                           const gfx::Rect& aRightEyeRect) override;
 #endif
 
 public:
   explicit VRDisplayPuppet();
   void Refresh();
 
 protected:
   virtual ~VRDisplayPuppet();