WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-220979-20210208154927.patch (text/plain), 47.00 KB, created by
Imanol Fernandez
on 2021-02-08 06:49:28 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Imanol Fernandez
Created:
2021-02-08 06:49:28 PST
Size:
47.00 KB
patch
obsolete
>Subversion Revision: 272489 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index a2a07f7a25c924aac3de4b0c27369bc030ced5e8..5a97cd8a5715b96d7a4f81c786728263265fcdfa 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,81 @@ >+2021-02-03 Sergio Villar Senin <svillar@igalia.com> and Imanol Fernandez <ifernandez@igalia.com> >+ >+ Complete XRSession::requestAnimationFrame implementation >+ https://bugs.webkit.org/show_bug.cgi?id=220979 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ - Implement the render loop for immersive and inline XR sessions. >+ - Implement WebXR render state updates. >+ - Create the FrameData struct used to query frame specific data from XR devices. >+ - Use window RAF for inline XR sessions. >+ - Implement WebFakeXRDevice testing rendering loop using a timer. >+ - Implement OpenXR session states and session tracking. >+ - Improve OpenXR event handling. >+ >+ Tested by the WebXR platform tests. >+ >+ * Modules/webxr/WebXRFrame.cpp: Add m_active, m_time and m_session members >+ (WebCore::WebXRFrame::create): >+ (WebCore::WebXRFrame::WebXRFrame): >+ * Modules/webxr/WebXRFrame.h: >+ (WebCore::WebXRFrame::setTime): >+ (WebCore::WebXRFrame::setActive): >+ (WebCore::WebXRFrame::isActive const): >+ >+ * Modules/webxr/WebXRRenderState.h: Add m_compositionDisabled member and output canvas setter >+ (WebCore::WebXRRenderState::setOutputCanvas): >+ (WebCore::WebXRRenderState::compositionDisabled const): >+ (WebCore::WebXRRenderState::setCompositionDisabled): >+ >+ * Modules/webxr/WebXRSession.cpp: >+ (WebCore::WebXRSession::create): >+ (WebCore::WebXRSession::WebXRSession): >+ (WebCore::WebXRSession::initialize): required to creat the XRFrame with makeRef(this) >+ (WebCore::WebXRSession::requestReferenceSpace): implement reference space creation >+ (WebCore::WebXRSession::requestAnimationFrame): implement render loop for immersive and inline sessions >+ (WebCore::WebXRSession::applyPendingRenderState): implement WebXR render state updates >+ (WebCore::WebXRSession::frameShouldBeRendered const): add check based on the spec >+ (WebCore::WebXRSession::requestFrame): implement helper function to dispatch a frame request to XR devices >+ (WebCore::WebXRSession::onFrame): process the XR frame and call the RAF callbacks >+ * Modules/webxr/WebXRSession.h: >+ >+ * Modules/webxr/WebXRSystem.cpp: Implement render loop using window raf loop. >+ (WebCore::WebXRSystem::WebXRSystem): >+ (WebCore::WebXRSystem::DummyInlineDevice::DummyInlineDevice): Add ScriptExecutionContext >+ (WebCore::WebXRSystem::DummyInlineDevice::requestFrame): Adapt to the new interface >+ >+ * Modules/webxr/WebXRSystem.h: >+ * Modules/webxr/WebXRWebGLLayer.cpp: >+ (WebCore::WebXRWebGLLayer::canvas const): Implement canvas getter >+ * Modules/webxr/WebXRWebGLLayer.h: >+ (WebCore::WebXRWebGLLayer::compositionDisabled const): add >+ (WebCore::WebXRWebGLLayer::setCompositionDisabled): add >+ >+ * platform/xr/PlatformXR.h: Add FrameData struct >+ >+ * platform/xr/openxr/PlatformXROpenXR.cpp: Implement render loop using OpenXR API >+ (PlatformXR::OpenXRDevice::resetSession): >+ (PlatformXR::OpenXRDevice::shutDownTrackingAndRendering): >+ (PlatformXR::OpenXRDevice::pollEvents): Implement event loop to query m_sessionState >+ (PlatformXR::sessionIsActive): add >+ (PlatformXR::sessionIsRunning): add >+ (PlatformXR::OpenXRDevice::beginSession): >+ (PlatformXR::xrViewToViewData): helper function to convert data from OpenXR >+ (PlatformXR::OpenXRDevice::requestFrame): start OpenXR frame, query pose and view data >+ (PlatformXR::OpenXRDevice::waitUntilStopping): properly wait for OpenXR event before ending the session. >+ * platform/xr/openxr/PlatformXROpenXR.h: >+ >+ >+ * testing/WebFakeXRDevice.cpp: Implement render loop using a timer >+ (WebCore::SimulatedXRDevice::SimulatedXRDevice): >+ (WebCore::SimulatedXRDevice::~SimulatedXRDevice): >+ (WebCore::SimulatedXRDevice::shutDownTrackingAndRendering): >+ (WebCore::SimulatedXRDevice::stopTimer): >+ (WebCore::SimulatedXRDevice::frameTimerFired): >+ (WebCore::SimulatedXRDevice::requestFrame): >+ * testing/WebFakeXRDevice.h: >+ > 2021-02-08 Frédéric Wang <fwang@igalia.com> > > Perform layout before running Editor::findString >diff --git a/Source/WebCore/Modules/webxr/WebXRFrame.cpp b/Source/WebCore/Modules/webxr/WebXRFrame.cpp >index 935dc127c9d07a7c8d2384154587d5135887ae1a..f278761b0a7b7d29d179422350a2aa198a23bdec 100644 >--- a/Source/WebCore/Modules/webxr/WebXRFrame.cpp >+++ b/Source/WebCore/Modules/webxr/WebXRFrame.cpp >@@ -48,10 +48,6 @@ WebXRFrame::WebXRFrame(Ref<WebXRSession>&& session) > > WebXRFrame::~WebXRFrame() = default; > >-const WebXRSession& WebXRFrame::session() const >-{ >- return m_session; >-} > > RefPtr<WebXRViewerPose> WebXRFrame::getViewerPose(const WebXRReferenceSpace&) > { >diff --git a/Source/WebCore/Modules/webxr/WebXRFrame.h b/Source/WebCore/Modules/webxr/WebXRFrame.h >index 808a6764f0d2c5ae61e4d658c28250579fe5b627..2a26ad86a2c30da8c23dfb6c7bbb90382d12e05d 100644 >--- a/Source/WebCore/Modules/webxr/WebXRFrame.h >+++ b/Source/WebCore/Modules/webxr/WebXRFrame.h >@@ -27,6 +27,7 @@ > > #if ENABLE(WEBXR) > >+#include "DOMHighResTimeStamp.h" > #include <wtf/IsoMalloc.h> > #include <wtf/Ref.h> > #include <wtf/RefCounted.h> >@@ -46,14 +47,20 @@ public: > static Ref<WebXRFrame> create(Ref<WebXRSession>&&); > ~WebXRFrame(); > >- const WebXRSession& session() const; >+ const WebXRSession& session() const { return m_session.get(); } > > RefPtr<WebXRViewerPose> getViewerPose(const WebXRReferenceSpace&); > RefPtr<WebXRPose> getPose(const WebXRSpace&, const WebXRSpace&); > >+ void setTime(DOMHighResTimeStamp time) { m_time = time; } >+ void setActive(bool active) { m_active = active; } >+ bool isActive() const { return m_active; } >+ > private: >- WebXRFrame(Ref<WebXRSession>&&); >+ explicit WebXRFrame(Ref<WebXRSession>&&); > >+ bool m_active { false }; >+ DOMHighResTimeStamp m_time; > Ref<WebXRSession> m_session; > }; > >diff --git a/Source/WebCore/Modules/webxr/WebXRRenderState.h b/Source/WebCore/Modules/webxr/WebXRRenderState.h >index 1e4363f1f19431e4a1ec958f1bfa2b47074577a2..e6d43c04689598b53da6d4bbb73f2dc1a413a2c2 100644 >--- a/Source/WebCore/Modules/webxr/WebXRRenderState.h >+++ b/Source/WebCore/Modules/webxr/WebXRRenderState.h >@@ -56,6 +56,10 @@ public: > void setBaseLayer(WebXRWebGLLayer* baseLayer) { m_baseLayer = baseLayer; } > > HTMLCanvasElement* outputCanvas() const { return m_outputCanvas.get(); } >+ void setOutputCanvas(HTMLCanvasElement* canvas) { m_outputCanvas = makeWeakPtr(canvas); } >+ >+ bool compositionDisabled() const { return m_compositionDisabled; } >+ void setCompositionDisabled(bool compositionDisabled) { m_compositionDisabled = compositionDisabled; } > > private: > explicit WebXRRenderState(Optional<double> fieldOfView); >@@ -69,6 +73,7 @@ private: > Optional<double> m_inlineVerticalFieldOfView; // in radians > RefPtr<WebXRWebGLLayer> m_baseLayer; > WeakPtr<HTMLCanvasElement> m_outputCanvas; >+ bool m_compositionDisabled { false }; > }; > > } // namespace WebCore >diff --git a/Source/WebCore/Modules/webxr/WebXRSession.cpp b/Source/WebCore/Modules/webxr/WebXRSession.cpp >index d8e2f811c245b0ceb0acefea3dfeda54e528b005..c52da4f978362b040ae861b9f77fc8ad87342159 100644 >--- a/Source/WebCore/Modules/webxr/WebXRSession.cpp >+++ b/Source/WebCore/Modules/webxr/WebXRSession.cpp >@@ -45,7 +45,9 @@ WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRSession); > > Ref<WebXRSession> WebXRSession::create(Document& document, WebXRSystem& system, XRSessionMode mode, PlatformXR::Device& device) > { >- return adoptRef(*new WebXRSession(document, system, mode, device)); >+ auto session = adoptRef(*new WebXRSession(document, system, mode, device)); >+ session->initialize(); >+ return session; > } > > WebXRSession::WebXRSession(Document& document, WebXRSystem& system, XRSessionMode mode, PlatformXR::Device& device) >@@ -55,11 +57,15 @@ WebXRSession::WebXRSession(Document& document, WebXRSystem& system, XRSessionMod > , m_mode(mode) > , m_device(makeWeakPtr(device)) > , m_activeRenderState(WebXRRenderState::create(mode)) >- , m_animationTimer(*this, &WebXRSession::animationTimerFired) >+ , m_timeOrigin(MonotonicTime::now()) > { > m_device->initializeTrackingAndRendering(mode); > m_device->setTrackingAndRenderingClient(makeWeakPtr(*this)); > >+ // https://immersive-web.github.io/webxr/#ref-for-dom-xrreferencespacetype-viewer%E2%91%A2 >+ // Every session MUST support viewer XRReferenceSpaces. >+ m_device->initializeReferenceSpace(XRReferenceSpaceType::Viewer); >+ > suspendIfNeeded(); > } > >@@ -69,6 +75,11 @@ WebXRSession::~WebXRSession() > m_device->shutDownTrackingAndRendering(); > } > >+void WebXRSession::initialize() >+{ >+ m_animationFrame = WebXRFrame::create(makeRef(*this)); >+} >+ > XREnvironmentBlendMode WebXRSession::environmentBlendMode() const > { > return m_environmentBlendMode; >@@ -198,66 +209,47 @@ void WebXRSession::requestReferenceSpace(XRReferenceSpaceType type, RequestRefer > promise.reject(Exception { InvalidStateError }); > return; > } >+ > // 1. Let promise be a new Promise. > // 2. Run the following steps in parallel: >- scriptExecutionContext()->postTask([this, promise = WTFMove(promise), type] (auto& context) mutable { >- // 2.1. Create a reference space, referenceSpace, with the XRReferenceSpaceType type. >- // 2.2. If referenceSpace is null, reject promise with a NotSupportedError and abort these steps. >+ scriptExecutionContext()->postTask([this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise), type](auto&) mutable { >+ if (!weakThis) >+ return; >+ // 2.1. If the result of running reference space is supported for type and session is false, queue a task to reject promise >+ // with a NotSupportedError and abort these steps. > if (!referenceSpaceIsSupported(type)) { >- promise.reject(Exception { NotSupportedError }); >+ queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [promise = WTFMove(promise)]() mutable { >+ promise.reject(Exception { NotSupportedError }); >+ }); > return; > } >- >- // https://immersive-web.github.io/webxr/#create-a-reference-space >- RefPtr<WebXRReferenceSpace> referenceSpace; >- if (type == XRReferenceSpaceType::BoundedFloor) >- referenceSpace = WebXRBoundedReferenceSpace::create(downcast<Document>(context), makeRef(*this), type); >- else >- referenceSpace = WebXRReferenceSpace::create(downcast<Document>(context), makeRef(*this), type); >- >- // 2.3. Resolve promise with referenceSpace. >- // 3. Return promise. >- promise.resolve(referenceSpace.releaseNonNull()); >+ // 2.2. Set up any platform resources required to track reference spaces of type type. >+ m_device->initializeReferenceSpace(type); >+ >+ // 2.3. Queue a task to run the following steps: >+ queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [this, type, promise = WTFMove(promise)]() mutable { >+ auto document = makeRef(downcast<Document>(*scriptExecutionContext())); >+ // 2.4. Create a reference space, referenceSpace, with type and session. >+ // https://immersive-web.github.io/webxr/#create-a-reference-space >+ RefPtr<WebXRReferenceSpace> referenceSpace; >+ if (type == XRReferenceSpaceType::BoundedFloor) >+ referenceSpace = WebXRBoundedReferenceSpace::create(document, makeRef(*this), type); >+ else >+ referenceSpace = WebXRReferenceSpace::create(document, makeRef(*this), type); >+ >+ // 2.5. Resolve promise with referenceSpace. >+ promise.resolve(referenceSpace.releaseNonNull()); >+ }); > }); > } > >-void WebXRSession::animationTimerFired() >-{ >- m_lastAnimationFrameTimestamp = MonotonicTime::now(); >- >- if (m_callbacks.isEmpty()) >- return; >- >- // TODO: retrieve frame from platform. >- auto frame = WebXRFrame::create(*this); >- >- m_runningCallbacks.swap(m_callbacks); >- for (auto& callback : m_runningCallbacks) { >- if (callback->isCancelled()) >- continue; >- callback->handleEvent(m_lastAnimationFrameTimestamp.secondsSinceEpoch().milliseconds(), frame.get()); >- } >- >- m_runningCallbacks.clear(); >-} >- >-void WebXRSession::scheduleAnimation() >-{ >- if (m_animationTimer.isActive()) >- return; >- >- if (m_ended) >- return; >- >- // TODO: use device's refresh rate. Let's start with 60fps. >- Seconds animationInterval = 15_ms; >- Seconds scheduleDelay = std::max(animationInterval - (MonotonicTime::now() - m_lastAnimationFrameTimestamp), 0_s); >- m_animationTimer.startOneShot(scheduleDelay); >-} >- > // https://immersive-web.github.io/webxr/#dom-xrsession-requestanimationframe > unsigned WebXRSession::requestAnimationFrame(Ref<XRFrameRequestCallback>&& callback) > { >+ // Ignore any new frame requests once the session is ended. >+ if (m_ended) >+ return 0; >+ > // 1. Let session be the target XRSession object. > // 2. Increment session's animation frame callback identifier by one. > unsigned newId = m_nextCallbackId++; >@@ -267,7 +259,12 @@ unsigned WebXRSession::requestAnimationFrame(Ref<XRFrameRequestCallback>&& callb > callback->setCallbackId(newId); > m_callbacks.append(WTFMove(callback)); > >- scheduleAnimation(); >+ ASSERT(m_animationFrame); >+ // Script can add multiple requestAnimationFrame callbacks but we should only request a device frame once. >+ // When m_animationFrame is active, the next requestFrame is scheduled at the end of WebXRSession::onFrame() to prevent >+ // requesting a new frame before the current one has ended. >+ if (m_callbacks.size() == 1 && !m_animationFrame->isActive()) >+ requestFrame(); > > // 4. Return session's animation frame callback identifier's current value. > return newId; >@@ -336,6 +333,10 @@ void WebXRSession::shutdown(InitiatedBySystem initiatedBySystem) > // 2. Set session's ended value to true. > m_ended = true; > >+ // Release animationFrame, which contains a Ref to this session. >+ m_animationFrame->setActive(false); >+ m_animationFrame = nullptr; >+ > // 3. If the active immersive session is equal to session, set the active immersive session to null. > // 4. Remove session from the list of inline sessions. > m_xrSystem.sessionEnded(*this); >@@ -420,6 +421,137 @@ void WebXRSession::sessionDidEnd() > shutdown(InitiatedBySystem::Yes); > } > >+void WebXRSession::applyPendingRenderState() >+{ >+ // https: //immersive-web.github.io/webxr/#apply-the-pending-render-state >+ // 1. Let activeState be sessionâs active render state. >+ // 2. Let newState be sessionâs pending render state. >+ // 3. Set sessionâs pending render state to null. >+ auto newState = m_pendingRenderState; >+ ASSERT(newState); >+ >+ // 4. Let oldBaseLayer be activeStateâs baseLayer. >+ // 5. Let oldLayers be activeStateâs layers. >+ // FIXME: those are only needed for step 6.2. >+ >+ // 6.1 Set activeState to newState. >+ m_activeRenderState = newState; >+ >+ // 6.2 If oldBaseLayer is not equal to activeStateâs baseLayer, oldLayers is not equal to activeStateâs layers, or the dimensions of any of the layers have changed, update the viewports for session. >+ // FIXME: implement this. >+ >+ // 6.3 If activeStateâs inlineVerticalFieldOfView is less than sessionâs minimum inline field of view set activeStateâs inlineVerticalFieldOfView to sessionâs minimum inline field of view. >+ if (m_activeRenderState->inlineVerticalFieldOfView() < m_minimumInlineFOV) >+ m_activeRenderState->setInlineVerticalFieldOfView(m_minimumInlineFOV); >+ >+ // 6.4 If activeStateâs inlineVerticalFieldOfView is greater than sessionâs maximum inline field of view set activeStateâs inlineVerticalFieldOfView to sessionâs maximum inline field of view. >+ if (m_activeRenderState->inlineVerticalFieldOfView() > m_maximumInlineFOV) >+ m_activeRenderState->setInlineVerticalFieldOfView(m_maximumInlineFOV); >+ >+ // 6.5 If activeStateâs depthNear is less than sessionâs minimum near clip plane set activeStateâs depthNear to sessionâs minimum near clip plane. >+ if (m_activeRenderState->depthNear() < m_minimumNearClipPlane) >+ m_activeRenderState->setDepthNear(m_minimumNearClipPlane); >+ >+ // 6.6 If activeStateâs depthFar is greater than sessionâs maximum far clip plane set activeStateâs depthFar to sessionâs maximum far clip plane. >+ if (m_activeRenderState->depthFar() > m_maximumFarClipPlane) >+ m_activeRenderState->setDepthFar(m_maximumFarClipPlane); >+ >+ // 6.7 Let baseLayer be activeStateâs baseLayer. >+ auto baseLayer = m_activeRenderState->baseLayer(); >+ >+ // 6.8 Set activeStateâs composition disabled and output canvas as follows: >+ m_activeRenderState->setCompositionDisabled(true); >+ if (m_mode == XRSessionMode::Inline && is<WebXRWebGLLayer>(baseLayer) && baseLayer->compositionDisabled()) { >+ m_activeRenderState->setCompositionDisabled(true); >+ m_activeRenderState->setOutputCanvas(baseLayer->canvas()); >+ } else { >+ m_activeRenderState->setCompositionDisabled(false); >+ m_activeRenderState->setOutputCanvas(nullptr); >+ } >+} >+ >+// https://immersive-web.github.io/webxr/#should-be-rendered >+bool WebXRSession::frameShouldBeRendered() const >+{ >+ if (!m_activeRenderState->baseLayer()) >+ return false; >+ if (m_mode == XRSessionMode::Inline && !m_activeRenderState->outputCanvas()) >+ return false; >+ return true; >+} >+ >+void WebXRSession::requestFrame() >+{ >+ m_device->requestFrame([this, protectedThis = makeRef(*this)](auto&& frameData) { >+ onFrame(WTFMove(frameData)); >+ }); >+} >+ >+void WebXRSession::onFrame(PlatformXR::Device::FrameData&& frameData) >+{ >+ ASSERT(isMainThread()); >+ >+ if (m_ended) >+ return; >+ >+ // Queue a task to perform the following steps. >+ queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [this, frameData = WTFMove(frameData)]() { >+ if (m_ended) >+ return; >+ // 1.Let now be the current high resolution time. >+ auto now = (MonotonicTime::now() - m_timeOrigin).milliseconds(); >+ >+ ASSERT(m_animationFrame); >+ // 2.Let frame be sessionâs animation frame. >+ // 3.Set frameâs time to frameTime. >+ m_animationFrame->setTime(static_cast<DOMHighResTimeStamp>(frameData.predictedDisplayTime)); >+ >+ // 4. For each view in list of views, set viewâs viewport modifiable flag to true. >+ // 5. If the active flag of any view in the list of views has changed since the last XR animation frame, update the viewports. >+ // FIXME: implement. >+ >+ // FIXME: I moved step 7 before 6 because of https://github.com/immersive-web/webxr/issues/1164 >+ // 7.If sessionâs pending render state is not null, apply the pending render state. >+ if (m_pendingRenderState) >+ applyPendingRenderState(); >+ >+ // 6. If the frame should be rendered for session: >+ if (frameShouldBeRendered()) { >+ // 6.1.Set sessionâs list of currently running animation frame callbacks to be sessionâs list of animation frame callbacks. >+ // 6.2.Set sessionâs list of animation frame callbacks to the empty list. >+ m_runningCallbacks.swap(m_callbacks); >+ >+ // 6.3.Set frameâs active boolean to true. >+ m_animationFrame->setActive(true); >+ >+ // 6.4.Apply frame updates for frame. >+ // FIXME: implement. >+ >+ // 6.5.For each entry in sessionâs list of currently running animation frame callbacks, in order: >+ for (auto& callback : m_runningCallbacks) { >+ // 6.6.If the entryâs cancelled boolean is true, continue to the next entry. >+ if (callback->isCancelled()) >+ continue; >+ // 6.7.Invoke the Web IDL callback function for entry, passing now and frame as the arguments >+ callback->handleEvent(now, *m_animationFrame); >+ >+ // 6.8.If an exception is thrown, report the exception. >+ } >+ // 6.9.Set sessionâs list of currently running animation frame callbacks to the empty list. >+ m_runningCallbacks.clear(); >+ >+ // 6.10.Set frameâs active boolean to false. >+ // If the session is ended, m_animationFrame->setActive false is set in shutdown(). >+ if (m_animationFrame) >+ m_animationFrame->setActive(false); >+ >+ if (!m_callbacks.isEmpty()) >+ requestFrame(); >+ } >+ >+ }); >+} >+ > } // namespace WebCore > > #endif // ENABLE(WEBXR) >diff --git a/Source/WebCore/Modules/webxr/WebXRSession.h b/Source/WebCore/Modules/webxr/WebXRSession.h >index 555430c8c3f731231aaf4f0c3ffb5829d6929b36..42be88c637db2510fd7b1e3b513d01e607d90fa2 100644 >--- a/Source/WebCore/Modules/webxr/WebXRSession.h >+++ b/Source/WebCore/Modules/webxr/WebXRSession.h >@@ -30,7 +30,7 @@ > #include "ActiveDOMObject.h" > #include "EventTarget.h" > #include "JSDOMPromiseDeferred.h" >-#include "Timer.h" >+#include "WebXRFrame.h" > #include "WebXRInputSourceArray.h" > #include "WebXRRenderState.h" > #include "WebXRSpace.h" >@@ -91,7 +91,8 @@ public: > XRSessionMode mode() const { return m_mode; } > > private: >- WebXRSession(Document&, WebXRSystem&, XRSessionMode, PlatformXR::Device&); >+ explicit WebXRSession(Document&, WebXRSystem&, XRSessionMode, PlatformXR::Device&); >+ void initialize(); > > // EventTarget > EventTargetInterface eventTargetInterface() const override { return WebXRSessionEventTargetInterfaceType; } >@@ -109,11 +110,13 @@ private: > void shutdown(InitiatedBySystem); > void didCompleteShutdown(); > >- void animationTimerFired(); >- void scheduleAnimation(); >- > bool referenceSpaceIsSupported(XRReferenceSpaceType) const; > >+ bool frameShouldBeRendered() const; >+ void requestFrame(); >+ void onFrame(PlatformXR::Device::FrameData&&); >+ void applyPendingRenderState(); >+ > XREnvironmentBlendMode m_environmentBlendMode; > XRInteractionMode m_interactionMode; > XRVisibilityState m_visibilityState; >@@ -126,13 +129,20 @@ private: > WeakPtr<PlatformXR::Device> m_device; > RefPtr<WebXRRenderState> m_activeRenderState; > RefPtr<WebXRRenderState> m_pendingRenderState; >+ MonotonicTime m_timeOrigin; > > unsigned m_nextCallbackId { 1 }; > Vector<Ref<XRFrameRequestCallback>> m_callbacks; > Vector<Ref<XRFrameRequestCallback>> m_runningCallbacks; > >- Timer m_animationTimer; >- MonotonicTime m_lastAnimationFrameTimestamp; >+ RefPtr<WebXRFrame> m_animationFrame; >+ >+ double m_minimumInlineFOV { 0.0 }; >+ double m_maximumInlineFOV { piFloat }; >+ >+ // In meters. >+ double m_minimumNearClipPlane { 0.1 }; >+ double m_maximumFarClipPlane { 1000.0 }; > }; > > } // namespace WebCore >diff --git a/Source/WebCore/Modules/webxr/WebXRSystem.cpp b/Source/WebCore/Modules/webxr/WebXRSystem.cpp >index 12a9f21e724a12ddc15da9a84c1b82eb4d17d4d8..288c6f0d5b2b00293e71b8635ced772fbf222e5d 100644 >--- a/Source/WebCore/Modules/webxr/WebXRSystem.cpp >+++ b/Source/WebCore/Modules/webxr/WebXRSystem.cpp >@@ -35,6 +35,7 @@ > #include "JSWebXRSession.h" > #include "JSXRReferenceSpaceType.h" > #include "PlatformXR.h" >+#include "RequestAnimationFrameCallback.h" > #include "RuntimeEnabledFeatures.h" > #include "SecurityOrigin.h" > #include "UserGestureIndicator.h" >@@ -49,11 +50,6 @@ namespace WebCore { > > WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRSystem); > >-WebXRSystem::DummyInlineDevice::DummyInlineDevice() >-{ >- setEnabledFeatures(XRSessionMode::Inline, { XRReferenceSpaceType::Viewer }); >-} >- > Ref<WebXRSystem> WebXRSystem::create(ScriptExecutionContext& scriptExecutionContext) > { > return adoptRef(*new WebXRSystem(scriptExecutionContext)); >@@ -61,6 +57,7 @@ Ref<WebXRSystem> WebXRSystem::create(ScriptExecutionContext& scriptExecutionCont > > WebXRSystem::WebXRSystem(ScriptExecutionContext& scriptExecutionContext) > : ActiveDOMObject(&scriptExecutionContext) >+ , m_defaultInlineDevice(scriptExecutionContext) > { > m_inlineXRDevice = makeWeakPtr(m_defaultInlineDevice); > suspendIfNeeded(); >@@ -475,6 +472,49 @@ void WebXRSystem::sessionEnded(WebXRSession& session) > m_inlineSessions.remove(session); > } > >+class InlineRequestAnimationFrameCallback final: public RequestAnimationFrameCallback { >+public: >+ static Ref<InlineRequestAnimationFrameCallback> create(ScriptExecutionContext& scriptExecutionContext, Function<void()>&& callback) >+ { >+ return adoptRef(*new InlineRequestAnimationFrameCallback(scriptExecutionContext, WTFMove(callback))); >+ } >+private: >+ InlineRequestAnimationFrameCallback(ScriptExecutionContext& scriptExecutionContext, Function<void()>&& callback) >+ : RequestAnimationFrameCallback(&scriptExecutionContext), m_callback(WTFMove(callback)) >+ { >+ } >+ >+ CallbackResult<void> handleEvent(double) final >+ { >+ m_callback(); >+ return { }; >+ } >+ >+ Function<void()> m_callback; >+}; >+ >+ >+WebXRSystem::DummyInlineDevice::DummyInlineDevice(ScriptExecutionContext& scriptExecutionContext) >+ : m_scriptExecutionContext(&scriptExecutionContext) >+{ >+ setEnabledFeatures(XRSessionMode::Inline, { XRReferenceSpaceType::Viewer }); >+} >+ >+void WebXRSystem::DummyInlineDevice::requestFrame(PlatformXR::Device::RequestFrameCallback&& callback) >+{ >+ // Inline XR sessions rely on document.requestAnimationFrame to perform the render loop. >+ auto document = downcast<Document>(m_scriptExecutionContext); >+ if (!document) >+ return; >+ >+ auto raf = InlineRequestAnimationFrameCallback::create(*m_scriptExecutionContext, [callback = WTFMove(callback)]() mutable { >+ callback({ }); >+ }); >+ >+ document->requestAnimationFrame(raf); >+} >+ >+ > } // namespace WebCore > > #endif // ENABLE(WEBXR) >diff --git a/Source/WebCore/Modules/webxr/WebXRSystem.h b/Source/WebCore/Modules/webxr/WebXRSystem.h >index c762d46ac0e904a3983d397f686561d4c165b355..c33cf73b8124e6503821509a382094b930efb568 100644 >--- a/Source/WebCore/Modules/webxr/WebXRSystem.h >+++ b/Source/WebCore/Modules/webxr/WebXRSystem.h >@@ -106,11 +106,16 @@ private: > // https://immersive-web.github.io/webxr/#default-inline-xr-device > class DummyInlineDevice final : public PlatformXR::Device { > public: >- DummyInlineDevice(); >+ DummyInlineDevice(ScriptExecutionContext&); > > private: > void initializeTrackingAndRendering(PlatformXR::SessionMode) final { } > void shutDownTrackingAndRendering() final { } >+ void initializeReferenceSpace(PlatformXR::ReferenceSpaceType) final { }; >+ >+ void requestFrame(PlatformXR::Device::RequestFrameCallback&&) final; >+ >+ ScriptExecutionContext* m_scriptExecutionContext; > }; > DummyInlineDevice m_defaultInlineDevice; > >diff --git a/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp b/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp >index 86dd11b00143bf80ea81ae2add8de84dc02d033f..ca5878861d24c7ef5d2fceb52a77dfab7e608d1b 100644 >--- a/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp >+++ b/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp >@@ -28,7 +28,9 @@ > > #if ENABLE(WEBXR) > >+#include "HTMLCanvasElement.h" > #include "IntSize.h" >+#include "OffscreenCanvas.h" > #include "WebGLFramebuffer.h" > #include "WebGLRenderingContext.h" > #if ENABLE(WEBGL2) >@@ -198,6 +200,20 @@ double WebXRWebGLLayer::getNativeFramebufferScaleFactor(const WebXRSession& sess > return (nativeSize / recommendedSize).width(); > } > >+HTMLCanvasElement* WebXRWebGLLayer::canvas() const >+{ >+ HTMLCanvasElement* c = WTF::switchOn(m_context, [](const RefPtr<WebGLRenderingContextBase>& baseContext) { >+ auto canvas = baseContext->canvas(); >+ return WTF::switchOn(canvas, [](const RefPtr<HTMLCanvasElement>& canvas) { >+ return canvas.get(); >+ }, [](const RefPtr<OffscreenCanvas>) { >+ ASSERT_NOT_REACHED("baseLayer of a WebXRWebGLLayer must be an HTMLCanvasElement"); >+ return nullptr; >+ }); >+ }); >+ return c; >+} >+ > } // namespace WebCore > > #endif // ENABLE(WEBXR) >diff --git a/Source/WebCore/Modules/webxr/WebXRWebGLLayer.h b/Source/WebCore/Modules/webxr/WebXRWebGLLayer.h >index 31755d8496a6a702e23329cfbf329b9cc4b8a9df..3f7587de89da6e231c943c4f905fc1cf18059295 100644 >--- a/Source/WebCore/Modules/webxr/WebXRWebGLLayer.h >+++ b/Source/WebCore/Modules/webxr/WebXRWebGLLayer.h >@@ -36,6 +36,7 @@ > > namespace WebCore { > >+class HTMLCanvasElement; > class IntSize; > class WebGLFramebuffer; > class WebGLRenderingContext; >@@ -74,6 +75,11 @@ public: > > const WebXRSession& session() { return m_session; } > >+ bool compositionDisabled() const { return m_isCompositionDisabled; } >+ void setCompositionDisabled(bool compositionDisabled) { m_isCompositionDisabled = compositionDisabled; } >+ >+ HTMLCanvasElement* canvas() const; >+ > private: > WebXRWebGLLayer(Ref<WebXRSession>&&, WebXRRenderingContext&&, const XRWebGLLayerInit&); > >diff --git a/Source/WebCore/platform/xr/PlatformXR.h b/Source/WebCore/platform/xr/PlatformXR.h >index b9ef45c0c69714ae83c704454d954bd51ea4766b..4325f3375cf3028a47dffcc6df59bb74383500d5 100644 >--- a/Source/WebCore/platform/xr/PlatformXR.h >+++ b/Source/WebCore/platform/xr/PlatformXR.h >@@ -18,6 +18,7 @@ > */ > #pragma once > >+#include "FloatPoint3D.h" > #include "IntSize.h" > #include <memory> > #include <wtf/CompletionHandler.h> >@@ -75,6 +76,31 @@ public: > // If this method returns true, that means the device will notify TrackingAndRenderingClient > // when the platform has completed all steps to shut down the XR session. > virtual bool supportsSessionShutdownNotification() const { return false; } >+ virtual void initializeReferenceSpace(ReferenceSpaceType) = 0; >+ >+ struct FrameData { >+ long predictedDisplayTime; >+ struct ViewData { >+ struct { >+ WebCore::FloatPoint3D position; >+ struct { >+ float x; >+ float y; >+ float z; >+ float w; >+ } orientation; >+ } pose; >+ struct { >+ float rUp; >+ float rDown; >+ float rLeft; >+ float rRight; >+ } fov; >+ }; >+ Vector<ViewData> viewPoses; >+ }; >+ using RequestFrameCallback = Function<void(FrameData&&)>; >+ virtual void requestFrame(RequestFrameCallback&&) = 0; > > protected: > Device() = default; >diff --git a/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp b/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp >index fe865e671d70686de791f1400e6cf3e2c869ec22..cc4d72153c6eeafdf2162e9882a9e07758b21df7 100644 >--- a/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp >+++ b/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp >@@ -260,11 +260,6 @@ OpenXRDevice::OpenXRDevice(XrSystemId id, XrInstance instance, WorkQueue& queue, > }); > } > >-OpenXRDevice::~OpenXRDevice() >-{ >- shutDownTrackingAndRendering(); >-} >- > Device::ListOfEnabledFeatures OpenXRDevice::enumerateReferenceSpaces(XrSession& session) const > { > uint32_t referenceSpacesCount; >@@ -395,6 +390,16 @@ XrViewConfigurationType toXrViewConfigurationType(SessionMode mode) > return XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO; > } > >+static bool isSessionActive(XrSessionState state) >+{ >+ return state == XR_SESSION_STATE_VISIBLE || state == XR_SESSION_STATE_FOCUSED; >+} >+ >+static bool isSessionReady(XrSessionState state) >+{ >+ return state >= XR_SESSION_STATE_READY && state < XR_SESSION_STATE_STOPPING; >+} >+ > void OpenXRDevice::initializeTrackingAndRendering(SessionMode mode) > { > m_queue.dispatch([this, mode]() { >@@ -413,18 +418,186 @@ void OpenXRDevice::initializeTrackingAndRendering(SessionMode mode) > } > > void OpenXRDevice::resetSession() >+{ >+ ASSERT(&RunLoop::current() == &m_queue.runLoop()); >+ if (m_session != XR_NULL_HANDLE) { >+ xrDestroySession(m_session); >+ m_session = XR_NULL_HANDLE; >+ } >+ m_sessionState = XR_SESSION_STATE_UNKNOWN; >+} >+ >+void OpenXRDevice::handleSessionStateChange() >+{ >+ ASSERT(&RunLoop::current() == &m_queue.runLoop()); >+ if (m_sessionState == XR_SESSION_STATE_STOPPING) { >+ // The application should exit the render loop and call xrEndSession >+ endSession(); >+ } else if (m_sessionState == XR_SESSION_STATE_READY) { >+ // The application is ready to call xrBeginSession. >+ beginSession(); >+ } >+} >+ >+void OpenXRDevice::shutDownTrackingAndRendering() > { > m_queue.dispatch([this]() { > if (m_session == XR_NULL_HANDLE) > return; >- xrDestroySession(m_session); >- m_session = XR_NULL_HANDLE; >+ >+ // xrRequestExitSession() will transition the session to STOPPED state. >+ // If the session was not running we have to reset the session ourselves. >+ if (XR_FAILED(xrRequestExitSession(m_session))) { >+ resetSession(); >+ return; >+ } >+ >+ // OpenXR needs to wait for the XR_SESSION_STATE_STOPPING state to properly end the session. >+ waitUntilStopping(); > }); > } > >-void OpenXRDevice::shutDownTrackingAndRendering() >+void OpenXRDevice::waitUntilStopping() > { >+ ASSERT(&RunLoop::current() == &m_queue.runLoop()); >+ pollEvents(); >+ if (m_sessionState >= XR_SESSION_STATE_STOPPING) >+ return; >+ m_queue.dispatch([this]() { >+ waitUntilStopping(); >+ }); >+} >+ >+void OpenXRDevice::pollEvents() >+{ >+ ASSERT(!isMainThread()); >+ auto runtimeEvent = createStructure<XrEventDataBuffer, XR_TYPE_EVENT_DATA_BUFFER>(); >+ while (xrPollEvent(m_instance, &runtimeEvent) == XR_SUCCESS) { >+ switch (runtimeEvent.type) { >+ case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: { >+ auto* event = (XrEventDataSessionStateChanged*)&runtimeEvent; >+ m_sessionState = event->state; >+ handleSessionStateChange(); >+ break; >+ } >+ case XR_TYPE_EVENT_DATA_EVENTS_LOST: >+ case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: >+ case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING: >+ case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED: >+ case XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX: >+ case XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR: >+ case XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT: >+ break; >+ default: >+ ASSERT_NOT_REACHED("Unhandled event type %d\n", runtimeEvent.type); >+ } >+ } >+} >+ >+XrResult OpenXRDevice::beginSession() >+{ >+ ASSERT(!isMainThread()); >+ ASSERT(m_sessionState == XR_SESSION_STATE_READY); >+ >+ auto sessionBeginInfo = createStructure<XrSessionBeginInfo, XR_TYPE_SESSION_BEGIN_INFO>(); >+ sessionBeginInfo.primaryViewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; >+ auto result = xrBeginSession(m_session, &sessionBeginInfo); >+#if !LOG_DISABLED >+ if (XR_FAILED(result)) >+ LOG(XR, "%s %s: %s\n", __func__, "xrBeginSession", resultToString(result, m_instance).utf8().data()); >+#endif >+ return result; >+} >+ >+void OpenXRDevice::endSession() >+{ >+ ASSERT(m_session != XR_NULL_HANDLE); >+ xrEndSession(m_session); > resetSession(); >+ if (!m_trackingAndRenderingClient) >+ return; >+ >+ // Notify did end event >+ callOnMainThread([this, weakThis = makeWeakPtr(*this)]() { >+ if (!weakThis) >+ return; >+ if (m_trackingAndRenderingClient) >+ m_trackingAndRenderingClient->sessionDidEnd(); >+ }); >+} >+ >+ >+Device::FrameData::ViewData xrViewToViewData(XrView view) >+{ >+ Device::FrameData::ViewData data; >+ data.fov = { view.fov.angleUp, view.fov.angleDown, view.fov.angleLeft, view.fov.angleRight }; >+ data.pose.orientation = { view.pose.orientation.x, view.pose.orientation.y, view.pose.orientation.z, view.pose.orientation.w }; >+ data.pose.position = { view.pose.position.x, view.pose.position.y, view.pose.position.z }; >+ return data; >+} >+ >+void OpenXRDevice::requestFrame(RequestFrameCallback&& callback) >+{ >+ m_queue.dispatch([this, callback = WTFMove(callback)]() mutable { >+ pollEvents(); >+ if (!isSessionReady(m_sessionState)) { >+ callOnMainThread([callback = WTFMove(callback)]() mutable { >+ // Device not ready or stopping. Report frameData with invalid tracking. >+ callback({ }); >+ }); >+ return; >+ } >+ >+ auto frameState = createStructure<XrFrameState, XR_TYPE_FRAME_STATE>(); >+ auto frameWaitInfo = createStructure<XrFrameWaitInfo, XR_TYPE_FRAME_WAIT_INFO>(); >+ auto result = xrWaitFrame(m_session, &frameWaitInfo, &frameState); >+ RETURN_IF_FAILED(result, "xrWaitFrame", m_instance); >+ XrTime predictedTime = frameState.predictedDisplayTime; >+ >+ auto frameBeginInfo = createStructure<XrFrameBeginInfo, XR_TYPE_FRAME_BEGIN_INFO>(); >+ result = xrBeginFrame(m_session, &frameBeginInfo); >+ RETURN_IF_FAILED(result, "xrBeginFrame", m_instance); >+ >+ Device::FrameData frameData; >+ frameData.predictedDisplayTime = frameState.predictedDisplayTime; >+ >+ if (isSessionActive(m_sessionState)) { >+ ASSERT(m_configurationViews.contains(m_currentViewConfigurationType)); >+ const auto& configurationView = m_configurationViews.get(m_currentViewConfigurationType); >+ >+ auto viewLocateInfo = createStructure<XrViewLocateInfo, XR_TYPE_VIEW_LOCATE_INFO>(); >+ viewLocateInfo.displayTime = predictedTime; >+ // FIXME: use the current reference space. >+ // viewLocateInfo.space = m_localSpace; >+ >+ uint32_t viewCount = configurationView.size(); >+ Vector<XrView> views(viewCount, [] { >+ XrView object; >+ std::memset(&object, 0, sizeof(XrView)); >+ object.type = XR_TYPE_VIEW; >+ return object; >+ }()); >+ >+ auto viewState = createStructure<XrViewState, XR_TYPE_VIEW_STATE>(); >+ uint32_t viewCountOutput; >+ result = xrLocateViews(m_session, &viewLocateInfo, &viewState, viewCount, &viewCountOutput, views.data()); >+ if (!XR_FAILED(result)) { >+ for (auto& view : views) >+ frameData.viewPoses.append(xrViewToViewData(view)); >+ } >+ } >+ >+ callOnMainThread([frameData = WTFMove(frameData), callback = WTFMove(callback)]() mutable { >+ callback(WTFMove(frameData)); >+ }); >+ >+ auto frameEndInfo = createStructure<XrFrameEndInfo, XR_TYPE_FRAME_END_INFO>(); >+ frameEndInfo.displayTime = predictedTime; >+ frameEndInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; >+ frameEndInfo.layerCount = 0; >+ result = xrEndFrame(m_session, &frameEndInfo); >+ RETURN_IF_FAILED(result, "xrEndFrame", m_instance); >+ }); > } > > } // namespace PlatformXR >diff --git a/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h b/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h >index aa2f780ef9129620f4412db49a0e8a042d58b529..5bebe69669327db2c815b556aedd1ca99b46e176 100644 >--- a/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h >+++ b/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h >@@ -44,7 +44,6 @@ namespace PlatformXR { > class OpenXRDevice final : public Device { > public: > OpenXRDevice(XrSystemId, XrInstance, WorkQueue&, CompletionHandler<void()>&&); >- ~OpenXRDevice(); > XrSystemId xrSystemId() const { return m_systemId; } > > private: >@@ -52,13 +51,22 @@ private: > void collectConfigurationViews(); > > ListOfEnabledFeatures enumerateReferenceSpaces(XrSession&) const; >+ void initializeReferenceSpace(ReferenceSpaceType) final { }; > > WebCore::IntSize recommendedResolution(SessionMode) final; > > void initializeTrackingAndRendering(SessionMode) final; > void shutDownTrackingAndRendering() final; >+ bool supportsSessionShutdownNotification() const final { return true; } >+ void waitUntilStopping(); > >+ void pollEvents(); >+ XrResult beginSession(); >+ void endSession(); > void resetSession(); >+ void handleSessionStateChange(); >+ >+ void requestFrame(RequestFrameCallback&&) final; > > using ViewConfigurationPropertiesMap = HashMap<XrViewConfigurationType, XrViewConfigurationProperties, IntHash<XrViewConfigurationType>, WTF::StrongEnumHashTraits<XrViewConfigurationType>>; > ViewConfigurationPropertiesMap m_viewConfigurationProperties; >@@ -68,6 +76,7 @@ private: > XrSystemId m_systemId; > XrInstance m_instance; > XrSession m_session { XR_NULL_HANDLE }; >+ XrSessionState m_sessionState { XR_SESSION_STATE_UNKNOWN }; > > WorkQueue& m_queue; > >diff --git a/Source/WebCore/testing/WebFakeXRDevice.cpp b/Source/WebCore/testing/WebFakeXRDevice.cpp >index a47c1eca7dedceda5050ad97bc47d8565ba590ef..54018da7ebb53dd51942de766149672ff1ac8457 100644 >--- a/Source/WebCore/testing/WebFakeXRDevice.cpp >+++ b/Source/WebCore/testing/WebFakeXRDevice.cpp >@@ -31,14 +31,28 @@ > #include "DOMPointReadOnly.h" > #include "JSDOMPromiseDeferred.h" > #include "WebFakeXRInputController.h" >+#include <wtf/CompletionHandler.h> > > namespace WebCore { > >+static constexpr Seconds FakeXRFrameTime = 15_ms; >+ > void FakeXRView::setFieldOfView(FakeXRViewInit::FieldOfViewInit fov) > { > m_fov = fov; > } > >+SimulatedXRDevice::SimulatedXRDevice() >+ : m_frameTimer(*this, &SimulatedXRDevice::frameTimerFired) >+{ >+ m_supportsOrientationTracking = true; >+} >+ >+SimulatedXRDevice::~SimulatedXRDevice() >+{ >+ stopTimer(); >+} >+ > void SimulatedXRDevice::simulateShutdownCompleted() > { > if (m_trackingAndRenderingClient) >@@ -49,6 +63,27 @@ void SimulatedXRDevice::shutDownTrackingAndRendering() > { > if (m_supportsShutdownNotification) > simulateShutdownCompleted(); >+ stopTimer(); >+} >+ >+void SimulatedXRDevice::stopTimer() >+{ >+ if (m_frameTimer.isActive()) >+ m_frameTimer.stop(); >+} >+ >+void SimulatedXRDevice::frameTimerFired() >+{ >+ auto callbacks = WTFMove(m_callbacks); >+ for (auto& callback : callbacks) >+ callback({ }); >+} >+ >+void SimulatedXRDevice::requestFrame(RequestFrameCallback&& callback) >+{ >+ m_callbacks.append(WTFMove(callback)); >+ if (!m_frameTimer.isActive()) >+ m_frameTimer.startOneShot(FakeXRFrameTime); > } > > WebFakeXRDevice::WebFakeXRDevice() = default; >diff --git a/Source/WebCore/testing/WebFakeXRDevice.h b/Source/WebCore/testing/WebFakeXRDevice.h >index 847bbcb17448448f0ec7e8ceb1b6fd6e9fac9588..391bfc347eef9aaaf17bd2ba8b6ba436f00046d5 100644 >--- a/Source/WebCore/testing/WebFakeXRDevice.h >+++ b/Source/WebCore/testing/WebFakeXRDevice.h >@@ -63,7 +63,8 @@ private: > class SimulatedXRDevice final : public PlatformXR::Device { > WTF_MAKE_FAST_ALLOCATED; > public: >- SimulatedXRDevice() { m_supportsOrientationTracking = true; } >+ SimulatedXRDevice(); >+ ~SimulatedXRDevice(); > void setNativeBoundsGeometry(Vector<FakeXRBoundsPoint> geometry) { m_nativeBoundsGeometry = geometry; } > void setViewerOrigin(RefPtr<WebXRRigidTransform>&& origin) { m_viewerOrigin = WTFMove(origin); } > void setFloorOrigin(RefPtr<WebXRRigidTransform>&& origin) { m_floorOrigin = WTFMove(origin); } >@@ -75,12 +76,20 @@ private: > void initializeTrackingAndRendering(PlatformXR::SessionMode) final { } > void shutDownTrackingAndRendering() final; > bool supportsSessionShutdownNotification() const final { return m_supportsShutdownNotification; } >+ void initializeReferenceSpace(PlatformXR::ReferenceSpaceType) final { } >+ void requestFrame(RequestFrameCallback&&) final; >+ >+ void stopTimer(); >+ void frameTimerFired(); >+ > Optional<Vector<FakeXRBoundsPoint>> m_nativeBoundsGeometry; > RefPtr<WebXRRigidTransform> m_viewerOrigin; > RefPtr<WebXRRigidTransform> m_floorOrigin; > bool m_emulatedPosition { false }; > Vector<Ref<FakeXRView>> m_views; > bool m_supportsShutdownNotification { false }; >+ Timer m_frameTimer; >+ Vector<RequestFrameCallback> m_callbacks; > }; > > class WebFakeXRDevice final : public RefCounted<WebFakeXRDevice> { >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index b8b7a9a4d2d90a05a66346cde2568e180b93f2a5..4f48e0acd871a0b28e99790cd3a168a996e97ec3 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,12 @@ >+2021-02-03 Sergio Villar Senin <svillar@igalia.com> and Imanol Fernandez <ifernandez@igalia.com> >+ >+ Complete XRSession::requestAnimationFrame implementation >+ https://bugs.webkit.org/show_bug.cgi?id=220979 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * platform/wpe/TestExpectations: >+ > 2021-02-08 Manuel Rego Casasnovas <rego@igalia.com> > > [GTK] event.ctrlKey and other are false in keydown event >diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog >index 23de76c2caeccb77230e484f7fae880c6a5674e7..de97e407400375c2c34ed7fa8e92ee1e49995db6 100644 >--- a/LayoutTests/imported/w3c/ChangeLog >+++ b/LayoutTests/imported/w3c/ChangeLog >@@ -1,3 +1,14 @@ >+2021-02-03 Sergio Villar Senin <svillar@igalia.com> and Imanol Fernandez <ifernandez@igalia.com> >+ >+ Complete XRSession::requestAnimationFrame implementation >+ https://bugs.webkit.org/show_bug.cgi?id=220979 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Enable XRSession RAF tests. >+ >+ * web-platform-tests/webxr/xrSession_requestAnimationFrame_timestamp.https-expected.txt: Added. >+ > 2021-02-06 Alex Christensen <achristensen@webkit.org> > > Non-special URLs should have an opaque origin >diff --git a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrSession_requestAnimationFrame_timestamp.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/webxr/xrSession_requestAnimationFrame_timestamp.https-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..f58a423fc6b198112935bff2907278fda94fcc56 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/webxr/xrSession_requestAnimationFrame_timestamp.https-expected.txt >@@ -0,0 +1,4 @@ >+ >+PASS XRFrame getViewerPose updates on the next frame for immersive >+PASS XRFrame getViewerPose updates on the next frame for non-immersive >+ >diff --git a/LayoutTests/platform/wpe/TestExpectations b/LayoutTests/platform/wpe/TestExpectations >index 736b8ad1500487b65df0498f759ed5d3a8202ad8..bc3f945c6f07d0ed9441fe8c9119b1a2ae4ccafd 100644 >--- a/LayoutTests/platform/wpe/TestExpectations >+++ b/LayoutTests/platform/wpe/TestExpectations >@@ -640,6 +640,7 @@ webkit.org/b/209859 webkit.org/b/215637 imported/w3c/web-platform-tests/webxr/xr > webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrSession_cancelAnimationFrame_invalidhandle.https.html [ Pass ] > webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrSession_features_deviceSupport.https.html [ Pass ] > webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrSession_requestAnimationFrame_callback_calls.https.html [ Pass ] >+imported/w3c/web-platform-tests/webxr/xrSession_requestAnimationFrame_timestamp.https.html [ Pass ] > webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrSession_requestReferenceSpace.https.html [ Pass ] > webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/ar-module/idlharness.https.window.html [ Pass ] > webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/ar-module/xrDevice_isSessionSupported_immersive-ar.https.html [ Pass ]
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 220979
:
418419
|
418423
|
418924
|
419157
|
419267
|
419579
|
419584
|
419699
|
419709
|
419713
|
419993