[WebXR] Implement WebGLRenderingContextBase::makeXRCompatible()
authorsvillar@igalia.com <svillar@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 May 2020 07:45:17 +0000 (07:45 +0000)
committersvillar@igalia.com <svillar@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 May 2020 07:45:17 +0000 (07:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=211506

Reviewed by Youenn Fablet.

The WebXR spec defines a way to mark a WebGLRenderingContext as
compatible with WebXR. This can be made at creation time (by setting the
xrCompatible) attribute or by calling makeXRCompatible().

There are several web-platform-tests testing/using this feature, however we
cannot enable them right now as we need some other features to be implemented
first.

* Modules/webxr/NavigatorWebXR.cpp:
(WebCore::NavigatorWebXR::xr): Do not pass ScriptExecutionContext and use
the Navigator's instead.
* Modules/webxr/NavigatorWebXR.h: Ditto.
* Modules/webxr/NavigatorWebXR.idl: Ditto.
* Modules/webxr/WebXRSystem.h: expose ensureImmersiveXRDeviceIsSelected() and
hasActiveImmersiveXRDevice() to be used from canvas and the rendering context.
* html/HTMLCanvasElement.cpp:
(WebCore::HTMLCanvasElement::createContextWebGL): call
ensureImmersiveXRDeviceIsSelected() if xrCompatible is set.
* html/canvas/WebGLContextAttributes.idl: Added xrCompatible.
* html/canvas/WebGLRenderingContextBase.cpp:
(WebCore::WebGLRenderingContextBase::WebGLRenderingContextBase):
Initialize m_isXRCompatible.
(WebCore::WebGLRenderingContextBase::makeXRCompatible): Implemented.
* html/canvas/WebGLRenderingContextBase.h: Defined makeXRCompatible().
* html/canvas/WebGLRenderingContextBase.idl: Added makeXRCompatible().
* platform/graphics/GraphicsContextGLAttributes.h: Added xrCompatible.
* testing/Internals.cpp:
(WebCore::Internals::xrTest): Simplified the usage of NavigatorWebXR.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261679 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Modules/webxr/NavigatorWebXR.cpp
Source/WebCore/Modules/webxr/NavigatorWebXR.h
Source/WebCore/Modules/webxr/NavigatorWebXR.idl
Source/WebCore/Modules/webxr/WebXRSystem.h
Source/WebCore/html/HTMLCanvasElement.cpp
Source/WebCore/html/canvas/WebGLContextAttributes.idl
Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp
Source/WebCore/html/canvas/WebGLRenderingContextBase.h
Source/WebCore/html/canvas/WebGLRenderingContextBase.idl
Source/WebCore/platform/graphics/GraphicsContextGLAttributes.h
Source/WebCore/testing/Internals.cpp

index 0d4eccd..b446627 100644 (file)
@@ -1,3 +1,39 @@
+2020-05-06  Sergio Villar Senin  <svillar@igalia.com>
+
+        [WebXR] Implement WebGLRenderingContextBase::makeXRCompatible()
+        https://bugs.webkit.org/show_bug.cgi?id=211506
+
+        Reviewed by Youenn Fablet.
+
+        The WebXR spec defines a way to mark a WebGLRenderingContext as
+        compatible with WebXR. This can be made at creation time (by setting the
+        xrCompatible) attribute or by calling makeXRCompatible().
+
+        There are several web-platform-tests testing/using this feature, however we
+        cannot enable them right now as we need some other features to be implemented
+        first.
+
+        * Modules/webxr/NavigatorWebXR.cpp:
+        (WebCore::NavigatorWebXR::xr): Do not pass ScriptExecutionContext and use
+        the Navigator's instead.
+        * Modules/webxr/NavigatorWebXR.h: Ditto.
+        * Modules/webxr/NavigatorWebXR.idl: Ditto.
+        * Modules/webxr/WebXRSystem.h: expose ensureImmersiveXRDeviceIsSelected() and
+        hasActiveImmersiveXRDevice() to be used from canvas and the rendering context.
+        * html/HTMLCanvasElement.cpp:
+        (WebCore::HTMLCanvasElement::createContextWebGL): call
+        ensureImmersiveXRDeviceIsSelected() if xrCompatible is set.
+        * html/canvas/WebGLContextAttributes.idl: Added xrCompatible.
+        * html/canvas/WebGLRenderingContextBase.cpp:
+        (WebCore::WebGLRenderingContextBase::WebGLRenderingContextBase):
+        Initialize m_isXRCompatible.
+        (WebCore::WebGLRenderingContextBase::makeXRCompatible): Implemented.
+        * html/canvas/WebGLRenderingContextBase.h: Defined makeXRCompatible().
+        * html/canvas/WebGLRenderingContextBase.idl: Added makeXRCompatible().
+        * platform/graphics/GraphicsContextGLAttributes.h: Added xrCompatible.
+        * testing/Internals.cpp:
+        (WebCore::Internals::xrTest): Simplified the usage of NavigatorWebXR.
+
 2020-05-13  Zalan Bujtas  <zalan@apple.com>
 
         [LFC][TFC] Add support for cases when the balancing is not based on the initial width
index 06a4c5d..cce3032 100644 (file)
 
 namespace WebCore {
 
-WebXRSystem& NavigatorWebXR::xr(ScriptExecutionContext& scriptExecutionContext, Navigator& navigatorObject)
+WebXRSystem& NavigatorWebXR::xr(Navigator& navigatorObject)
 {
     auto& navigator = NavigatorWebXR::from(navigatorObject);
     if (!navigator.m_xr)
-        navigator.m_xr = WebXRSystem::create(scriptExecutionContext);
+        navigator.m_xr = WebXRSystem::create(*navigatorObject.scriptExecutionContext());
     return *navigator.m_xr;
 }
 
index 23c60c5..a66bb77 100644 (file)
@@ -39,7 +39,7 @@ class WebXRSystem;
 class NavigatorWebXR final : public Supplement<Navigator> {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    WEBCORE_EXPORT static WebXRSystem& xr(ScriptExecutionContext&, Navigator&);
+    WEBCORE_EXPORT static WebXRSystem& xr(Navigator&);
 
     WEBCORE_EXPORT static NavigatorWebXR& from(Navigator&);
 
index d9bbf5d..4ce9049 100644 (file)
@@ -27,5 +27,5 @@
     EnabledAtRuntime=WebXR,
     Conditional=WEBXR
 ] partial interface Navigator {
-    [SecureContext, SameObject, CallWith=ScriptExecutionContext] readonly attribute WebXRSystem xr;
+    [SecureContext, SameObject] readonly attribute WebXRSystem xr;
 };
index d8247e7..2e9ce84 100644 (file)
 
 #include "ActiveDOMObject.h"
 #include "EventTarget.h"
+#include "HTMLCanvasElement.h"
 #include "JSDOMPromiseDeferred.h"
+#include "WebGLContextAttributes.h"
+#include "WebGLRenderingContextBase.h"
 #include "XRSessionMode.h"
 #include <wtf/IsoMalloc.h>
 #include <wtf/RefCounted.h>
@@ -56,6 +59,10 @@ public:
     void isSessionSupported(XRSessionMode, IsSessionSupportedPromise&&);
     void requestSession(XRSessionMode, const XRSessionInit&, RequestSessionPromise&&);
 
+    // This is also needed by WebGLRenderingContextBase::makeXRCompatible() and HTMLCanvasElement::createContextWebGL().
+    void ensureImmersiveXRDeviceIsSelected();
+    bool hasActiveImmersiveXRDevice() { return !!m_activeImmersiveDevice; }
+
     // For testing purpouses only.
     void registerSimulatedXRDeviceForTesting(const PlatformXR::Device&);
     void unregisterSimulatedXRDeviceForTesting(PlatformXR::Device*);
@@ -74,8 +81,6 @@ protected:
 private:
     WebXRSystem(ScriptExecutionContext&);
 
-    void ensureImmersiveXRDeviceIsSelected();
-
     // https://immersive-web.github.io/webxr/#default-inline-xr-device
     class DummyInlineDevice final : public PlatformXR::Device {
     public:
index 0db5268..da179db 100644 (file)
 #include "GPUCanvasContext.h"
 #endif
 
+#if ENABLE(WEBXR)
+#include "DOMWindow.h"
+#include "Navigator.h"
+#include "NavigatorWebXR.h"
+#include "WebXRSystem.h"
+#endif
+
 #if PLATFORM(COCOA)
 #include "MediaSampleAVFObjC.h"
 #include <pal/cf/CoreMediaSoftLink.h>
@@ -416,10 +423,23 @@ WebGLRenderingContextBase* HTMLCanvasElement::createContextWebGL(const String& t
     if (!shouldEnableWebGL(document().settings()))
         return nullptr;
 
+#if ENABLE(WEBXR)
+    // https://immersive-web.github.io/webxr/#xr-compatible
+    if (attrs.xrCompatible) {
+        if (auto* window = document().domWindow())
+            NavigatorWebXR::xr(window->navigator()).ensureImmersiveXRDeviceIsSelected();
+    }
+#endif
+
+    // TODO(WEBXR): ensure the context is created in a compatible graphics
+    // adapter when there is an active immersive device.
     m_context = WebGLRenderingContextBase::create(*this, attrs, type);
     if (m_context) {
         // Need to make sure a RenderLayer and compositing layer get created for the Canvas.
         invalidateStyleAndLayerComposition();
+#if ENABLE(WEBXR)
+        ASSERT(!attrs.xrCompatible || m_context.isXRCompatible());
+#endif
     }
 
     return downcast<WebGLRenderingContextBase>(m_context.get());
index 3be5ac5..3902bae 100644 (file)
@@ -45,4 +45,5 @@ enum WebGLPowerPreference {
     GLboolean preserveDrawingBuffer = false;
     WebGLPowerPreference powerPreference = "default";
     GLboolean failIfMajorPerformanceCaveat = false;
+    [Conditional=WEBXR] boolean xrCompatible = false;
 };
index 153bc98..e4a1d36 100644 (file)
@@ -57,6 +57,7 @@
 #include "IntSize.h"
 #include "JSExecState.h"
 #include "Logging.h"
+#include "NavigatorWebXR.h"
 #include "NotImplemented.h"
 #include "OESElementIndexUint.h"
 #include "OESStandardDerivatives.h"
@@ -95,6 +96,7 @@
 #include "WebGLShaderPrecisionFormat.h"
 #include "WebGLTexture.h"
 #include "WebGLUniformLocation.h"
+#include "WebXRSystem.h"
 #include <JavaScriptCore/ConsoleMessage.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/ScriptCallStack.h>
 #include <wtf/HexNumber.h>
 #include <wtf/IsoMallocInlines.h>
 #include <wtf/Lock.h>
+#include <wtf/Scope.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/UniqueArray.h>
 #include <wtf/text/CString.h>
@@ -737,6 +740,9 @@ WebGLRenderingContextBase::WebGLRenderingContextBase(CanvasBase& canvas, WebGLCo
     , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
     , m_isPendingPolicyResolution(true)
     , m_checkForContextLossHandlingTimer(*this, &WebGLRenderingContextBase::checkForContextLossHandling)
+#if ENABLE(WEBXR)
+    , m_isXRCompatible(attributes.xrCompatible)
+#endif
 {
     m_restoreTimer.suspendIfNeeded();
 
@@ -752,6 +758,9 @@ WebGLRenderingContextBase::WebGLRenderingContextBase(CanvasBase& canvas, Ref<Gra
     , m_attributes(attributes)
     , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
     , m_checkForContextLossHandlingTimer(*this, &WebGLRenderingContextBase::checkForContextLossHandling)
+#if ENABLE(WEBXR)
+    , m_isXRCompatible(attributes.xrCompatible)
+#endif
 {
     m_restoreTimer.suspendIfNeeded();
 
@@ -3706,6 +3715,52 @@ bool WebGLRenderingContextBase::linkProgramWithoutInvalidatingAttribLocations(We
     return true;
 }
 
+#if ENABLE(WEBXR)
+// https://immersive-web.github.io/webxr/#dom-webglrenderingcontextbase-makexrcompatible
+void WebGLRenderingContextBase::makeXRCompatible(MakeXRCompatiblePromise&& promise)
+{
+    auto rejectPromiseWithInvalidStateError = makeScopeExit([&] () {
+        m_isXRCompatible = false;
+        promise.reject(Exception { InvalidStateError });
+    });
+
+    // Returning an exception in these two checks is not part of the spec.
+    auto canvas = htmlCanvas();
+    if (!canvas)
+        return;
+
+    auto* window = canvas->document().domWindow();
+    if (!window)
+        return;
+
+    // 1. Let promise be a new Promise.
+    // 2. Let context be the target WebGLRenderingContextBase object.
+    // 3. Ensure an immersive XR device is selected.
+    auto& xrSystem = NavigatorWebXR::xr(window->navigator());
+    xrSystem.ensureImmersiveXRDeviceIsSelected();
+
+    // 4. Set context’s XR compatible boolean as follows:
+    //    If context’s WebGL context lost flag is set
+    //      Set context’s XR compatible boolean to false and reject promise with an InvalidStateError.
+    if (isContextLostOrPending())
+        return;
+
+    // If the immersive XR device is null
+    //    Set context’s XR compatible boolean to false and reject promise with an InvalidStateError.
+    if (!xrSystem.hasActiveImmersiveXRDevice())
+        return;
+
+    // If context’s XR compatible boolean is true. Resolve promise.
+    // If context was created on a compatible graphics adapter for the immersive XR device
+    //  Set context’s XR compatible boolean to true and resolve promise.
+    // Otherwise: Queue a task on the WebGL task source to perform the following steps:
+    // TODO: add a way to verify that we're using a compatible graphics adapter.
+    m_isXRCompatible = true;
+    promise.resolve();
+    rejectPromiseWithInvalidStateError.release();
+}
+#endif
+
 void WebGLRenderingContextBase::pixelStorei(GCGLenum pname, GCGLint param)
 {
     if (isContextLostOrPending())
index 84e38d9..91cf0b9 100644 (file)
 #include "WebGLVertexArrayObject.h"
 #endif
 
+#if ENABLE(WEBXR)
+#include "JSDOMPromiseDeferred.h"
+#endif
+
 namespace WebCore {
 
 class ANGLEInstancedArrays;
@@ -230,6 +234,11 @@ public:
     void linkProgram(WebGLProgram*);
     bool linkProgramWithoutInvalidatingAttribLocations(WebGLProgram*);
     virtual void pixelStorei(GCGLenum pname, GCGLint param);
+#if ENABLE(WEBXR)
+    using MakeXRCompatiblePromise = DOMPromiseDeferred<void>;
+    void makeXRCompatible(MakeXRCompatiblePromise&&);
+    bool isXRCompatible() const { return m_isXRCompatible; }
+#endif
     void polygonOffset(GCGLfloat factor, GCGLfloat units);
     void readPixels(GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height, GCGLenum format, GCGLenum type, ArrayBufferView& pixels);
     void releaseShaderCompiler();
@@ -1034,6 +1043,10 @@ private:
     WebGLStateTracker::Token m_trackerToken;
     Timer m_checkForContextLossHandlingTimer;
     bool m_isSuspended { false };
+
+#if ENABLE(WEBXR)
+    bool m_isXRCompatible { false };
+#endif
 };
 
 template <typename T>
index 45a7b38..662b330 100644 (file)
@@ -602,6 +602,9 @@ typedef (HTMLCanvasElement) WebGLCanvas;
     GLboolean isTexture(WebGLTexture? texture);
     void lineWidth(GLfloat width);
     void linkProgram(WebGLProgram? program);
+
+    [NewObject, Conditional=WEBXR] Promise<void> makeXRCompatible();
+
     void pixelStorei(GLenum pname, GLint param);
     void polygonOffset(GLfloat factor, GLfloat units);
 
index 8841a45..5cca1da 100644 (file)
@@ -53,6 +53,9 @@ struct GraphicsContextGLAttributes {
     bool noExtensions { false };
     float devicePixelRatio { 1 };
     PowerPreference initialPowerPreference { PowerPreference::Default };
+#if ENABLE(WEBXR)
+    bool xrCompatible { false };
+#endif
 };
 
 }
index aa56383..b2a0013 100644 (file)
@@ -5750,10 +5750,7 @@ ExceptionOr<RefPtr<WebXRTest>> Internals::xrTest()
         if (!navigator)
             return Exception { InvalidAccessError };
 
-        auto& navigatorXR = NavigatorWebXR::from(*navigator);
-        auto& xrSystem = navigatorXR.xr(*scriptExecutionContext(), *navigator);
-
-        m_xrTest = WebXRTest::create(makeWeakPtr(&xrSystem));
+        m_xrTest = WebXRTest::create(makeWeakPtr(&NavigatorWebXR::xr(*navigator)));
     }
     return m_xrTest.get();
 }