Bug 1581374 - Implement WebGLContext.makeXRCompatible (WIP) r=jgilbert,daoshengmu,bzbarsky
authorKearwood "Kip" Gilbert <kgilbert@mozilla.com>
Fri, 15 Nov 2019 21:32:15 +0000
changeset 502305 10d924f0c08118b3241a0fe60e3ee7af59ad68ef
parent 502304 c5c17edb79f55f30fb8243e36b14688513c103c9
child 502306 c078f40b72b1c246d0475e443bfa70fb7e74db2e
push id100739
push userkgilbert@mozilla.com
push dateFri, 15 Nov 2019 22:15:42 +0000
treeherderautoland@10d924f0c081 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert, daoshengmu, bzbarsky
bugs1581374
milestone72.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1581374 - Implement WebGLContext.makeXRCompatible (WIP) r=jgilbert,daoshengmu,bzbarsky Differential Revision: https://phabricator.services.mozilla.com/D45952
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/webidl/WebGLRenderingContext.webidl
modules/libpref/init/StaticPrefList.yaml
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -107,16 +107,17 @@ bool WebGLContextOptions::operator==(con
   bool eq = true;
   eq &= (alpha == r.alpha);
   eq &= (depth == r.depth);
   eq &= (stencil == r.stencil);
   eq &= (premultipliedAlpha == r.premultipliedAlpha);
   eq &= (antialias == r.antialias);
   eq &= (preserveDrawingBuffer == r.preserveDrawingBuffer);
   eq &= (failIfMajorPerformanceCaveat == r.failIfMajorPerformanceCaveat);
+  eq &= (xrCompatible == r.xrCompatible);
   eq &= (powerPreference == r.powerPreference);
   return eq;
 }
 
 WebGLContext::WebGLContext()
     : gl(mGL_OnlyClearInDestroyResourcesAndContext)  // const reference
       ,
       mMaxPerfWarnings(StaticPrefs::webgl_perf_max_warnings()),
@@ -136,16 +137,17 @@ WebGLContext::WebGLContext()
   mCapturedFrameInvalidated = false;
   mShouldPresent = true;
   mResetLayer = true;
   mOptionsFrozen = false;
   mDisableExtensions = false;
   mIsMesa = false;
   mWebGLError = 0;
   mVRReady = false;
+  mXRCompatible = false;
 
   mViewportX = 0;
   mViewportY = 0;
   mViewportWidth = 0;
   mViewportHeight = 0;
 
   mDitherEnabled = 1;
   mRasterizerDiscardEnabled = 0;  // OpenGL ES 3.0 spec p244
@@ -352,16 +354,17 @@ WebGLContext::SetContextOptions(JSContex
 
   newOpts.stencil = attributes.mStencil;
   newOpts.depth = attributes.mDepth;
   newOpts.premultipliedAlpha = attributes.mPremultipliedAlpha;
   newOpts.preserveDrawingBuffer = attributes.mPreserveDrawingBuffer;
   newOpts.failIfMajorPerformanceCaveat =
       attributes.mFailIfMajorPerformanceCaveat;
   newOpts.powerPreference = attributes.mPowerPreference;
+  newOpts.xrCompatible = attributes.mXrCompatible;
 
   if (attributes.mAlpha.WasPassed()) {
     newOpts.alpha = attributes.mAlpha.Value();
   }
   if (attributes.mAntialias.WasPassed()) {
     newOpts.antialias = attributes.mAntialias.Value();
   }
 
@@ -953,16 +956,22 @@ WebGLContext::SetDimensions(int32_t sign
   mNeedsFakeNoStencil_UserFBs = false;
 #ifdef MOZ_WIDGET_COCOA
   if (!nsCocoaFeatures::IsAtLeastVersion(10, 12) &&
       gl->Vendor() == GLVendor::Intel) {
     mNeedsFakeNoStencil_UserFBs = true;
   }
 #endif
 
+  if (mOptions.xrCompatible) {
+    // TODO: Bug 1580258 - WebGLContext.MakeXRCompatible needs to switch to
+    //                     the device connected to the XR hardware
+    mXRCompatible = true;
+  }
+
   mResetLayer = true;
   mOptionsFrozen = true;
 
   //////
   // Initial setup.
 
   gl->mImplicitMakeCurrent = true;
 
@@ -1300,16 +1309,17 @@ void WebGLContext::GetContextAttributes(
   result.mAlpha.Construct(mOptions.alpha);
   result.mDepth = mOptions.depth;
   result.mStencil = mOptions.stencil;
   result.mAntialias.Construct(mOptions.antialias);
   result.mPremultipliedAlpha = mOptions.premultipliedAlpha;
   result.mPreserveDrawingBuffer = mOptions.preserveDrawingBuffer;
   result.mFailIfMajorPerformanceCaveat = mOptions.failIfMajorPerformanceCaveat;
   result.mPowerPreference = mOptions.powerPreference;
+  result.mXrCompatible = mOptions.xrCompatible;
 }
 
 // -
 
 namespace webgl {
 
 ScopedPrepForResourceClear::ScopedPrepForResourceClear(
     const WebGLContext& webgl_)
@@ -2361,16 +2371,52 @@ bool WebGLContext::ValidateDeleteObject(
 
   if (!ValidateObjectAllowDeleted("obj", *object)) return false;
 
   if (object->IsDeleteRequested()) return false;
 
   return true;
 }
 
+already_AddRefed<Promise> WebGLContext::MakeXRCompatible(ErrorResult& aRv) {
+  const FuncScope funcScope(*this, "MakeXRCompatible");
+  nsCOMPtr<nsIGlobalObject> global;
+  // TODO: Bug 1596921
+  // Should use nsICanvasRenderingContextInternal::GetParentObject
+  // once it has been updated to work in the offscreencanvas case
+  if (mCanvasElement) {
+    global = GetOwnerDoc()->GetScopeObject();
+  } else if (mOffscreenCanvas) {
+    global = mOffscreenCanvas->GetOwnerGlobal();
+  }
+  if (!global) {
+    aRv.ThrowDOMException(NS_ERROR_DOM_INVALID_ACCESS_ERR,
+                          "Using a WebGL context that is not attached to "
+                          "either a canvas or an OffscreenCanvas");
+    return nullptr;
+  }
+  RefPtr<Promise> promise = Promise::Create(global, aRv);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
+
+  if (IsContextLost()) {
+    promise->MaybeRejectWithDOMException(
+        NS_ERROR_DOM_INVALID_STATE_ERR,
+        "Can not make context XR compatible when context is already lost.");
+    return promise.forget();
+  }
+
+  // TODO: Bug 1580258 - WebGLContext.MakeXRCompatible needs to switch to
+  //                     the device connected to the XR hardware
+
+  mXRCompatible = true;
+
+  promise->MaybeResolveWithUndefined();
+  return promise.forget();
+}
+
 bool WebGLContext::ShouldResistFingerprinting() const {
   if (NS_IsMainThread()) {
     if (mCanvasElement) {
       // If we're constructed from a canvas element
       return nsContentUtils::ShouldResistFingerprinting(GetOwnerDoc());
     }
     if (mOffscreenCanvas->GetOwnerGlobal()) {
       // If we're constructed from an offscreen canvas
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -123,16 +123,17 @@ void AssertUintParamCorrect(gl::GLContex
 struct WebGLContextOptions {
   bool alpha = true;
   bool depth = true;
   bool stencil = false;
   bool premultipliedAlpha = true;
   bool antialias = true;
   bool preserveDrawingBuffer = false;
   bool failIfMajorPerformanceCaveat = false;
+  bool xrCompatible = false;
   dom::WebGLPowerPreference powerPreference =
       dom::WebGLPowerPreference::Default;
 
   WebGLContextOptions();
   bool operator==(const WebGLContextOptions&) const;
 };
 
 // From WebGLContextUtils
@@ -554,16 +555,18 @@ class WebGLContext : public nsICanvasRen
   gl::GLContext* GL() const { return gl; }
 
   bool IsPremultAlpha() const { return mOptions.premultipliedAlpha; }
 
   bool IsPreservingDrawingBuffer() const {
     return mOptions.preserveDrawingBuffer;
   }
 
+  bool IsXRCompatible() const { return mXRCompatible; }
+
   bool PresentScreenBuffer(gl::GLScreenBuffer* const screen = nullptr);
 
   // Prepare the context for capture before compositing
   void BeginComposition(gl::GLScreenBuffer* const screen = nullptr);
   // Clean up the context after captured for compositing
   void EndComposition();
 
   // a number that increments every time we have an event that causes
@@ -758,16 +761,17 @@ class WebGLContext : public nsICanvasRen
   void LineWidth(GLfloat width);
   void LinkProgram(WebGLProgram& prog);
   void PixelStorei(GLenum pname, GLint param);
   void PolygonOffset(GLfloat factor, GLfloat units);
 
   already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame();
   void ClearVRFrame();
   void EnsureVRReady();
+  already_AddRefed<dom::Promise> MakeXRCompatible(ErrorResult& aRv);
 
   ////
 
   webgl::PackingInfo ValidImplementationColorReadPI(
       const webgl::FormatUsageInfo* usage) const;
 
  protected:
   bool ReadPixels_SharedPrecheck(dom::CallerType aCallerType,
@@ -1590,16 +1594,18 @@ class WebGLContext : public nsICanvasRen
   bool mOptionsFrozen;
   bool mDisableExtensions;
   bool mIsMesa;
   bool mLoseContextOnMemoryPressure;
   bool mCanLoseContextInForeground;
   bool mShouldPresent;
   bool mDisableFragHighP;
   bool mVRReady;
+  // https://immersive-web.github.io/webxr/#xr-compatible
+  bool mXRCompatible;
 
   template <typename WebGLObjectType>
   void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
 
   GLuint mActiveTexture = 0;
   GLenum mDefaultFB_DrawBuffer0 = 0;
   GLenum mDefaultFB_ReadBuffer = 0;
 
--- a/dom/webidl/WebGLRenderingContext.webidl
+++ b/dom/webidl/WebGLRenderingContext.webidl
@@ -1163,8 +1163,20 @@ interface EXT_float_blend {
 interface OES_fbo_render_mipmap {
 };
 
 [NoInterfaceObject,
  Exposed=Window]
 interface WEBGL_explicit_present {
     void present();
 };
+
+// https://immersive-web.github.io/webxr/#dom-webglcontextattributes-xrcompatible
+partial dictionary WebGLContextAttributes {
+    [Pref="dom.vr.webxr.enabled"]
+    boolean xrCompatible = false;
+};
+
+// https://immersive-web.github.io/webxr/#dom-webglrenderingcontextbase-makexrcompatible
+partial interface mixin WebGLRenderingContextBase {
+    [NewObject, Pref="dom.vr.webxr.enabled"]
+    Promise<void> makeXRCompatible();
+};
--- a/modules/libpref/init/StaticPrefList.yaml
+++ b/modules/libpref/init/StaticPrefList.yaml
@@ -2580,16 +2580,22 @@
 # as VRDisplayActivate triggered by the system. dom.vr.require-gesture allows
 # this requirement to be disabled for special cases such as during automated
 # tests or in a headless kiosk system.
 - name: dom.vr.require-gesture
   type: RelaxedAtomicBool
   value: true
   mirror: always
 
+# Is support for WebXR APIs enabled?
+- name: dom.vr.webxr.enabled
+  type: RelaxedAtomicBool
+  value: false
+  mirror: always
+
 # W3C draft pointer events
 - name: dom.w3c_pointer_events.enabled
   type: RelaxedAtomicBool
   value: @IS_NOT_ANDROID@
   mirror: always
 
 #ifdef XP_WIN
   # Control firing WidgetMouseEvent by handling Windows pointer messages or