Changeset 272734 in webkit
- Timestamp:
- Feb 11, 2021 9:26:14 AM (3 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r272726 r272734 1 2021-02-11 Sergio Villar Senin <svillar@igalia.com> and Imanol Fernandez <ifernandez@igalia.com> 2 3 Complete XRSession::requestAnimationFrame implementation 4 https://bugs.webkit.org/show_bug.cgi?id=220979 5 6 Reviewed by Youenn Fablet. 7 8 * platform/wpe/TestExpectations: 9 1 10 2021-02-11 Manuel Rego Casasnovas <rego@igalia.com> 2 11 -
trunk/LayoutTests/imported/w3c/ChangeLog
r272726 r272734 1 2021-02-11 Sergio Villar Senin <svillar@igalia.com> and Imanol Fernandez <ifernandez@igalia.com> 2 3 Complete XRSession::requestAnimationFrame implementation 4 https://bugs.webkit.org/show_bug.cgi?id=220979 5 6 Reviewed by Youenn Fablet. 7 8 Enable XRSession RAF tests. 9 10 * web-platform-tests/webxr/xrSession_requestAnimationFrame_timestamp.https-expected.txt: Added. 11 1 12 2021-02-11 Manuel Rego Casasnovas <rego@igalia.com> 2 13 -
trunk/LayoutTests/platform/wpe/TestExpectations
r272492 r272734 641 641 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrSession_features_deviceSupport.https.html [ Pass ] 642 642 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrSession_requestAnimationFrame_callback_calls.https.html [ Pass ] 643 imported/w3c/web-platform-tests/webxr/xrSession_requestAnimationFrame_timestamp.https.html [ Pass ] 643 644 webkit.org/b/209859 imported/w3c/web-platform-tests/webxr/xrSession_requestReferenceSpace.https.html [ Pass ] 644 645 imported/w3c/web-platform-tests/webxr/xrSession_viewer_availability.https.html [ Pass ] -
trunk/Source/WebCore/ChangeLog
r272731 r272734 1 2021-02-11 Sergio Villar Senin <svillar@igalia.com> and Imanol Fernandez <ifernandez@igalia.com> 2 3 Complete XRSession::requestAnimationFrame implementation 4 https://bugs.webkit.org/show_bug.cgi?id=220979 5 6 Reviewed by Youenn Fablet. 7 8 - Implement the render loop for immersive and inline XR sessions. 9 - Implement WebXR render state updates. 10 - Create the FrameData struct used to query frame specific data from XR devices. 11 - Use window RAF for inline XR sessions. 12 - Implement WebFakeXRDevice testing rendering loop using a timer. 13 - Implement OpenXR session states and session tracking. 14 - Improve OpenXR event handling. 15 16 Tested by the WebXR platform tests. 17 18 * Modules/webxr/WebXRFrame.cpp: Add m_active, m_time and m_session members 19 (WebCore::WebXRFrame::create): 20 (WebCore::WebXRFrame::WebXRFrame): 21 * Modules/webxr/WebXRFrame.h: 22 (WebCore::WebXRFrame::setTime): 23 (WebCore::WebXRFrame::setActive): 24 (WebCore::WebXRFrame::isActive const): 25 26 * Modules/webxr/WebXRRenderState.h: Add m_compositionDisabled member and output canvas setter 27 (WebCore::WebXRRenderState::setOutputCanvas): 28 (WebCore::WebXRRenderState::compositionDisabled const): 29 (WebCore::WebXRRenderState::setCompositionDisabled): 30 31 * Modules/webxr/WebXRSession.cpp: 32 (WebCore::WebXRSession::create): 33 (WebCore::WebXRSession::WebXRSession): 34 (WebCore::WebXRSession::initialize): required to creat the XRFrame with makeRef(this) 35 (WebCore::WebXRSession::requestReferenceSpace): implement reference space creation 36 (WebCore::WebXRSession::requestAnimationFrame): implement render loop for immersive and inline sessions 37 (WebCore::WebXRSession::applyPendingRenderState): implement WebXR render state updates 38 (WebCore::WebXRSession::frameShouldBeRendered const): add check based on the spec 39 (WebCore::WebXRSession::requestFrame): implement helper function to dispatch a frame request to XR devices 40 (WebCore::WebXRSession::onFrame): process the XR frame and call the RAF callbacks 41 * Modules/webxr/WebXRSession.h: 42 43 * Modules/webxr/WebXRSystem.cpp: Implement render loop using window raf loop. 44 (WebCore::WebXRSystem::WebXRSystem): 45 (WebCore::WebXRSystem::DummyInlineDevice::DummyInlineDevice): Add ScriptExecutionContext 46 (WebCore::WebXRSystem::DummyInlineDevice::requestFrame): Adapt to the new interface 47 48 * Modules/webxr/WebXRSystem.h: 49 * Modules/webxr/WebXRWebGLLayer.cpp: 50 (WebCore::WebXRWebGLLayer::canvas const): Implement canvas getter 51 * Modules/webxr/WebXRWebGLLayer.h: 52 (WebCore::WebXRWebGLLayer::compositionDisabled const): add 53 (WebCore::WebXRWebGLLayer::setCompositionDisabled): add 54 55 * platform/xr/PlatformXR.h: Add FrameData struct 56 57 * platform/xr/openxr/PlatformXROpenXR.cpp: Implement render loop using OpenXR API 58 (PlatformXR::OpenXRDevice::resetSession): 59 (PlatformXR::OpenXRDevice::shutDownTrackingAndRendering): 60 (PlatformXR::OpenXRDevice::pollEvents): Implement event loop to query m_sessionState 61 (PlatformXR::sessionIsActive): add 62 (PlatformXR::sessionIsRunning): add 63 (PlatformXR::OpenXRDevice::beginSession): 64 (PlatformXR::xrViewToViewData): helper function to convert data from OpenXR 65 (PlatformXR::OpenXRDevice::requestFrame): start OpenXR frame, query pose and view data 66 (PlatformXR::OpenXRDevice::waitUntilStopping): properly wait for OpenXR event before ending the session. 67 * platform/xr/openxr/PlatformXROpenXR.h: 68 69 70 * testing/WebFakeXRDevice.cpp: Implement render loop using a timer 71 (WebCore::SimulatedXRDevice::SimulatedXRDevice): 72 (WebCore::SimulatedXRDevice::~SimulatedXRDevice): 73 (WebCore::SimulatedXRDevice::shutDownTrackingAndRendering): 74 (WebCore::SimulatedXRDevice::stopTimer): 75 (WebCore::SimulatedXRDevice::frameTimerFired): 76 (WebCore::SimulatedXRDevice::requestFrame): 77 * testing/WebFakeXRDevice.h: 78 1 79 2021-02-11 Sam Weinig <weinig@apple.com> 2 80 -
trunk/Source/WebCore/Modules/webxr/WebXRFrame.cpp
r258498 r272734 49 49 WebXRFrame::~WebXRFrame() = default; 50 50 51 const WebXRSession& WebXRFrame::session() const52 {53 return m_session;54 }55 51 56 52 RefPtr<WebXRViewerPose> WebXRFrame::getViewerPose(const WebXRReferenceSpace&) -
trunk/Source/WebCore/Modules/webxr/WebXRFrame.h
r258498 r272734 28 28 #if ENABLE(WEBXR) 29 29 30 #include "DOMHighResTimeStamp.h" 30 31 #include <wtf/IsoMalloc.h> 31 32 #include <wtf/Ref.h> … … 47 48 ~WebXRFrame(); 48 49 49 const WebXRSession& session() const ;50 const WebXRSession& session() const { return m_session.get(); } 50 51 51 52 RefPtr<WebXRViewerPose> getViewerPose(const WebXRReferenceSpace&); 52 53 RefPtr<WebXRPose> getPose(const WebXRSpace&, const WebXRSpace&); 53 54 55 void setTime(DOMHighResTimeStamp time) { m_time = time; } 56 void setActive(bool active) { m_active = active; } 57 bool isActive() const { return m_active; } 58 54 59 private: 55 WebXRFrame(Ref<WebXRSession>&&);60 explicit WebXRFrame(Ref<WebXRSession>&&); 56 61 62 bool m_active { false }; 63 DOMHighResTimeStamp m_time; 57 64 Ref<WebXRSession> m_session; 58 65 }; -
trunk/Source/WebCore/Modules/webxr/WebXRRenderState.h
r265665 r272734 57 57 58 58 HTMLCanvasElement* outputCanvas() const { return m_outputCanvas.get(); } 59 void setOutputCanvas(HTMLCanvasElement* canvas) { m_outputCanvas = makeWeakPtr(canvas); } 60 61 bool isCompositionEnabled() const { return m_compositionEnabled; } 62 void setCompositionEnabled(bool compositionEnabled) { m_compositionEnabled = compositionEnabled; } 59 63 60 64 private: … … 70 74 RefPtr<WebXRWebGLLayer> m_baseLayer; 71 75 WeakPtr<HTMLCanvasElement> m_outputCanvas; 76 bool m_compositionEnabled { true }; 72 77 }; 73 78 -
trunk/Source/WebCore/Modules/webxr/WebXRSession.cpp
r272014 r272734 56 56 , m_device(makeWeakPtr(device)) 57 57 , m_activeRenderState(WebXRRenderState::create(mode)) 58 , m_ animationTimer(*this, &WebXRSession::animationTimerFired)58 , m_timeOrigin(MonotonicTime::now()) 59 59 { 60 60 m_device->initializeTrackingAndRendering(mode); 61 61 m_device->setTrackingAndRenderingClient(makeWeakPtr(*this)); 62 63 // https://immersive-web.github.io/webxr/#ref-for-dom-xrreferencespacetype-viewer%E2%91%A2 64 // Every session MUST support viewer XRReferenceSpaces. 65 m_device->initializeReferenceSpace(XRReferenceSpaceType::Viewer); 62 66 63 67 suspendIfNeeded(); … … 199 203 return; 200 204 } 205 201 206 // 1. Let promise be a new Promise. 202 207 // 2. Run the following steps in parallel: 203 scriptExecutionContext()->postTask([this, promise = WTFMove(promise), type] (auto& context) mutable { 204 // 2.1. Create a reference space, referenceSpace, with the XRReferenceSpaceType type. 205 // 2.2. If referenceSpace is null, reject promise with a NotSupportedError and abort these steps. 208 scriptExecutionContext()->postTask([this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise), type](auto&) mutable { 209 if (!weakThis) 210 return; 211 // 2.1. If the result of running reference space is supported for type and session is false, queue a task to reject promise 212 // with a NotSupportedError and abort these steps. 206 213 if (!referenceSpaceIsSupported(type)) { 207 promise.reject(Exception { NotSupportedError }); 214 queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [promise = WTFMove(promise)]() mutable { 215 promise.reject(Exception { NotSupportedError }); 216 }); 208 217 return; 209 218 } 210 211 // https://immersive-web.github.io/webxr/#create-a-reference-space 212 RefPtr<WebXRReferenceSpace> referenceSpace; 213 if (type == XRReferenceSpaceType::BoundedFloor) 214 referenceSpace = WebXRBoundedReferenceSpace::create(downcast<Document>(context), makeRef(*this), type); 215 else 216 referenceSpace = WebXRReferenceSpace::create(downcast<Document>(context), makeRef(*this), type); 217 218 // 2.3. Resolve promise with referenceSpace. 219 // 3. Return promise. 220 promise.resolve(referenceSpace.releaseNonNull()); 219 // 2.2. Set up any platform resources required to track reference spaces of type type. 220 m_device->initializeReferenceSpace(type); 221 222 // 2.3. Queue a task to run the following steps: 223 queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [this, type, promise = WTFMove(promise)]() mutable { 224 if (!scriptExecutionContext()) { 225 promise.reject(Exception { InvalidStateError }); 226 return; 227 } 228 auto& document = downcast<Document>(*scriptExecutionContext()); 229 // 2.4. Create a reference space, referenceSpace, with type and session. 230 // https://immersive-web.github.io/webxr/#create-a-reference-space 231 RefPtr<WebXRReferenceSpace> referenceSpace; 232 if (type == XRReferenceSpaceType::BoundedFloor) 233 referenceSpace = WebXRBoundedReferenceSpace::create(document, makeRef(*this), type); 234 else 235 referenceSpace = WebXRReferenceSpace::create(document, makeRef(*this), type); 236 237 // 2.5. Resolve promise with referenceSpace. 238 promise.resolve(referenceSpace.releaseNonNull()); 239 }); 221 240 }); 222 }223 224 void WebXRSession::animationTimerFired()225 {226 m_lastAnimationFrameTimestamp = MonotonicTime::now();227 228 if (m_callbacks.isEmpty())229 return;230 231 // TODO: retrieve frame from platform.232 auto frame = WebXRFrame::create(*this);233 234 m_runningCallbacks.swap(m_callbacks);235 for (auto& callback : m_runningCallbacks) {236 if (callback->isCancelled())237 continue;238 callback->handleEvent(m_lastAnimationFrameTimestamp.secondsSinceEpoch().milliseconds(), frame.get());239 }240 241 m_runningCallbacks.clear();242 }243 244 void WebXRSession::scheduleAnimation()245 {246 if (m_animationTimer.isActive())247 return;248 249 if (m_ended)250 return;251 252 // TODO: use device's refresh rate. Let's start with 60fps.253 Seconds animationInterval = 15_ms;254 Seconds scheduleDelay = std::max(animationInterval - (MonotonicTime::now() - m_lastAnimationFrameTimestamp), 0_s);255 m_animationTimer.startOneShot(scheduleDelay);256 241 } 257 242 … … 259 244 unsigned WebXRSession::requestAnimationFrame(Ref<XRFrameRequestCallback>&& callback) 260 245 { 246 // Ignore any new frame requests once the session is ended. 247 if (m_ended) 248 return 0; 249 261 250 // 1. Let session be the target XRSession object. 262 251 // 2. Increment session's animation frame callback identifier by one. … … 268 257 m_callbacks.append(WTFMove(callback)); 269 258 270 scheduleAnimation(); 259 // Script can add multiple requestAnimationFrame callbacks but we should only request a device frame once. 260 // When requestAnimationFrame is called during processing RAF callbacks the next requestFrame is scheduled 261 // at the end of WebXRSession::onFrame() to prevent requesting a new frame before the current one has ended. 262 if (m_callbacks.size() == 1) 263 requestFrame(); 271 264 272 265 // 4. Return session's animation frame callback identifier's current value. … … 287 280 288 281 if (position != notFound) { 289 m_callbacks[position]->cancel(); 290 m_callbacks.remove(position); 282 m_callbacks[position]->setFiredOrCancelled(); 291 283 return; 292 284 } 293 294 position = m_runningCallbacks.findMatching([callbackId] (auto& item) {295 return item->callbackId() == callbackId;296 });297 298 if (position != notFound)299 m_runningCallbacks[position]->cancel();300 285 } 301 286 … … 421 406 } 422 407 408 void WebXRSession::applyPendingRenderState() 409 { 410 // https: //immersive-web.github.io/webxr/#apply-the-pending-render-state 411 // 1. Let activeState be session’s active render state. 412 // 2. Let newState be session’s pending render state. 413 // 3. Set session’s pending render state to null. 414 auto newState = m_pendingRenderState; 415 ASSERT(newState); 416 417 // 4. Let oldBaseLayer be activeState’s baseLayer. 418 // 5. Let oldLayers be activeState’s layers. 419 // FIXME: those are only needed for step 6.2. 420 421 // 6.1 Set activeState to newState. 422 m_activeRenderState = newState; 423 424 // 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. 425 // FIXME: implement this. 426 427 // 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. 428 if (m_activeRenderState->inlineVerticalFieldOfView() < m_minimumInlineFOV) 429 m_activeRenderState->setInlineVerticalFieldOfView(m_minimumInlineFOV); 430 431 // 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. 432 if (m_activeRenderState->inlineVerticalFieldOfView() > m_maximumInlineFOV) 433 m_activeRenderState->setInlineVerticalFieldOfView(m_maximumInlineFOV); 434 435 // 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. 436 if (m_activeRenderState->depthNear() < m_minimumNearClipPlane) 437 m_activeRenderState->setDepthNear(m_minimumNearClipPlane); 438 439 // 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. 440 if (m_activeRenderState->depthFar() > m_maximumFarClipPlane) 441 m_activeRenderState->setDepthFar(m_maximumFarClipPlane); 442 443 // 6.7 Let baseLayer be activeState’s baseLayer. 444 auto baseLayer = m_activeRenderState->baseLayer(); 445 446 // 6.8 Set activeState’s composition enabled and output canvas as follows: 447 if (m_mode == XRSessionMode::Inline && is<WebXRWebGLLayer>(baseLayer) && !baseLayer->isCompositionEnabled()) { 448 m_activeRenderState->setCompositionEnabled(false); 449 m_activeRenderState->setOutputCanvas(baseLayer->canvas()); 450 } else { 451 m_activeRenderState->setCompositionEnabled(true); 452 m_activeRenderState->setOutputCanvas(nullptr); 453 } 454 } 455 456 // https://immersive-web.github.io/webxr/#should-be-rendered 457 bool WebXRSession::frameShouldBeRendered() const 458 { 459 if (!m_activeRenderState->baseLayer()) 460 return false; 461 if (m_mode == XRSessionMode::Inline && !m_activeRenderState->outputCanvas()) 462 return false; 463 return true; 464 } 465 466 void WebXRSession::requestFrame() 467 { 468 m_device->requestFrame([this, protectedThis = makeRef(*this)](auto&& frameData) { 469 onFrame(WTFMove(frameData)); 470 }); 471 } 472 473 void WebXRSession::onFrame(PlatformXR::Device::FrameData&& frameData) 474 { 475 ASSERT(isMainThread()); 476 477 if (m_ended) 478 return; 479 480 // Queue a task to perform the following steps. 481 queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [this, frameData = WTFMove(frameData)]() { 482 if (m_ended) 483 return; 484 // 1.Let now be the current high resolution time. 485 auto now = (MonotonicTime::now() - m_timeOrigin).milliseconds(); 486 487 auto frame = WebXRFrame::create(makeRef(*this)); 488 // 2.Let frame be session’s animation frame. 489 // 3.Set frame’s time to frameTime. 490 frame->setTime(static_cast<DOMHighResTimeStamp>(frameData.predictedDisplayTime)); 491 492 // 4. For each view in list of views, set view’s viewport modifiable flag to true. 493 // 5. If the active flag of any view in the list of views has changed since the last XR animation frame, update the viewports. 494 // FIXME: implement. 495 496 // FIXME: I moved step 7 before 6 because of https://github.com/immersive-web/webxr/issues/1164 497 // 7.If session’s pending render state is not null, apply the pending render state. 498 if (m_pendingRenderState) 499 applyPendingRenderState(); 500 501 // 6. If the frame should be rendered for session: 502 if (frameShouldBeRendered()) { 503 // 6.1.Set session’s list of currently running animation frame callbacks to be session’s list of animation frame callbacks. 504 // 6.2.Set session’s list of animation frame callbacks to the empty list. 505 auto callbacks = m_callbacks; 506 507 // 6.3.Set frame’s active boolean to true. 508 frame->setActive(true); 509 510 // 6.4.Apply frame updates for frame. 511 // FIXME: implement. 512 513 // 6.5.For each entry in session’s list of currently running animation frame callbacks, in order: 514 for (auto& callback : callbacks) { 515 // 6.6.If the entry’s cancelled boolean is true, continue to the next entry. 516 if (callback->isFiredOrCancelled()) 517 continue; 518 callback->setFiredOrCancelled(); 519 // 6.7.Invoke the Web IDL callback function for entry, passing now and frame as the arguments 520 callback->handleEvent(now, frame.get()); 521 522 // 6.8.If an exception is thrown, report the exception. 523 } 524 // 6.9.Set session’s list of currently running animation frame callbacks to the empty list. 525 m_callbacks.removeAllMatching([](auto& callback) { 526 return callback->isFiredOrCancelled(); 527 }); 528 529 // 6.10.Set frame’s active boolean to false. 530 // If the session is ended, m_animationFrame->setActive false is set in shutdown(). 531 frame->setActive(false); 532 533 if (!m_callbacks.isEmpty()) 534 requestFrame(); 535 } 536 537 }); 538 } 539 423 540 } // namespace WebCore 424 541 -
trunk/Source/WebCore/Modules/webxr/WebXRSession.h
r271988 r272734 31 31 #include "EventTarget.h" 32 32 #include "JSDOMPromiseDeferred.h" 33 #include " Timer.h"33 #include "WebXRFrame.h" 34 34 #include "WebXRInputSourceArray.h" 35 35 #include "WebXRRenderState.h" … … 110 110 void didCompleteShutdown(); 111 111 112 void animationTimerFired(); 113 void scheduleAnimation(); 112 bool referenceSpaceIsSupported(XRReferenceSpaceType) const; 114 113 115 bool referenceSpaceIsSupported(XRReferenceSpaceType) const; 114 bool frameShouldBeRendered() const; 115 void requestFrame(); 116 void onFrame(PlatformXR::Device::FrameData&&); 117 void applyPendingRenderState(); 116 118 117 119 XREnvironmentBlendMode m_environmentBlendMode; … … 127 129 RefPtr<WebXRRenderState> m_activeRenderState; 128 130 RefPtr<WebXRRenderState> m_pendingRenderState; 131 MonotonicTime m_timeOrigin; 129 132 130 133 unsigned m_nextCallbackId { 1 }; 131 134 Vector<Ref<XRFrameRequestCallback>> m_callbacks; 132 Vector<Ref<XRFrameRequestCallback>> m_runningCallbacks;133 135 134 Timer m_animationTimer; 135 MonotonicTime m_lastAnimationFrameTimestamp; 136 double m_minimumInlineFOV { 0.0 }; 137 double m_maximumInlineFOV { piFloat }; 138 139 // In meters. 140 double m_minimumNearClipPlane { 0.1 }; 141 double m_maximumFarClipPlane { 1000.0 }; 136 142 }; 137 143 -
trunk/Source/WebCore/Modules/webxr/WebXRSystem.cpp
r272492 r272734 36 36 #include "JSXRReferenceSpaceType.h" 37 37 #include "PlatformXR.h" 38 #include "RequestAnimationFrameCallback.h" 38 39 #include "RuntimeEnabledFeatures.h" 39 40 #include "SecurityOrigin.h" … … 50 51 WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRSystem); 51 52 52 WebXRSystem::DummyInlineDevice::DummyInlineDevice()53 {54 setEnabledFeatures(XRSessionMode::Inline, { XRReferenceSpaceType::Viewer });55 }56 57 53 Ref<WebXRSystem> WebXRSystem::create(ScriptExecutionContext& scriptExecutionContext) 58 54 { … … 62 58 WebXRSystem::WebXRSystem(ScriptExecutionContext& scriptExecutionContext) 63 59 : ActiveDOMObject(&scriptExecutionContext) 60 , m_defaultInlineDevice(scriptExecutionContext) 64 61 { 65 62 m_inlineXRDevice = makeWeakPtr(m_defaultInlineDevice); … … 487 484 } 488 485 486 class InlineRequestAnimationFrameCallback final: public RequestAnimationFrameCallback { 487 public: 488 static Ref<InlineRequestAnimationFrameCallback> create(ScriptExecutionContext& scriptExecutionContext, Function<void()>&& callback) 489 { 490 return adoptRef(*new InlineRequestAnimationFrameCallback(scriptExecutionContext, WTFMove(callback))); 491 } 492 private: 493 InlineRequestAnimationFrameCallback(ScriptExecutionContext& scriptExecutionContext, Function<void()>&& callback) 494 : RequestAnimationFrameCallback(&scriptExecutionContext), m_callback(WTFMove(callback)) 495 { 496 } 497 498 CallbackResult<void> handleEvent(double) final 499 { 500 m_callback(); 501 return { }; 502 } 503 504 Function<void()> m_callback; 505 }; 506 507 508 WebXRSystem::DummyInlineDevice::DummyInlineDevice(ScriptExecutionContext& scriptExecutionContext) 509 : ContextDestructionObserver(&scriptExecutionContext) 510 { 511 setEnabledFeatures(XRSessionMode::Inline, { XRReferenceSpaceType::Viewer }); 512 } 513 514 void WebXRSystem::DummyInlineDevice::requestFrame(PlatformXR::Device::RequestFrameCallback&& callback) 515 { 516 if (!scriptExecutionContext()) 517 return; 518 // Inline XR sessions rely on document.requestAnimationFrame to perform the render loop. 519 auto document = downcast<Document>(scriptExecutionContext()); 520 if (!document) 521 return; 522 523 auto raf = InlineRequestAnimationFrameCallback::create(*m_scriptExecutionContext, [callback = WTFMove(callback)]() mutable { 524 callback({ }); 525 }); 526 527 document->requestAnimationFrame(raf); 528 } 529 530 489 531 } // namespace WebCore 490 532 -
trunk/Source/WebCore/Modules/webxr/WebXRSystem.h
r271806 r272734 105 105 106 106 // https://immersive-web.github.io/webxr/#default-inline-xr-device 107 class DummyInlineDevice final : public PlatformXR::Device {107 class DummyInlineDevice final : public PlatformXR::Device, private ContextDestructionObserver { 108 108 public: 109 DummyInlineDevice();109 explicit DummyInlineDevice(ScriptExecutionContext&); 110 110 111 111 private: 112 112 void initializeTrackingAndRendering(PlatformXR::SessionMode) final { } 113 113 void shutDownTrackingAndRendering() final { } 114 void initializeReferenceSpace(PlatformXR::ReferenceSpaceType) final { }; 115 116 void requestFrame(PlatformXR::Device::RequestFrameCallback&&) final; 114 117 }; 115 118 DummyInlineDevice m_defaultInlineDevice; -
trunk/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp
r272571 r272734 29 29 #if ENABLE(WEBXR) 30 30 31 #include "HTMLCanvasElement.h" 31 32 #include "IntSize.h" 33 #include "OffscreenCanvas.h" 32 34 #include "WebGLFramebuffer.h" 33 35 #include "WebGLRenderingContext.h" … … 199 201 } 200 202 203 HTMLCanvasElement* WebXRWebGLLayer::canvas() const 204 { 205 return WTF::switchOn(m_context, [](const RefPtr<WebGLRenderingContextBase>& baseContext) { 206 auto canvas = baseContext->canvas(); 207 return WTF::switchOn(canvas, [](const RefPtr<HTMLCanvasElement>& canvas) { 208 return canvas.get(); 209 }, [](const RefPtr<OffscreenCanvas>) { 210 ASSERT_NOT_REACHED("baseLayer of a WebXRWebGLLayer must be an HTMLCanvasElement"); 211 return nullptr; 212 }); 213 }); 214 } 215 201 216 } // namespace WebCore 202 217 -
trunk/Source/WebCore/Modules/webxr/WebXRWebGLLayer.h
r272571 r272734 37 37 namespace WebCore { 38 38 39 class HTMLCanvasElement; 39 40 class IntSize; 40 41 class WebGLFramebuffer; … … 75 76 const WebXRSession& session() { return m_session; } 76 77 78 bool isCompositionEnabled() const { return m_isCompositionEnabled; } 79 80 HTMLCanvasElement* canvas() const; 81 77 82 private: 78 83 WebXRWebGLLayer(Ref<WebXRSession>&&, WebXRRenderingContext&&, const XRWebGLLayerInit&); -
trunk/Source/WebCore/Modules/webxr/XRFrameRequestCallback.h
r263256 r272734 44 44 unsigned callbackId() { ASSERT(m_id); return m_id; } 45 45 void setCallbackId(unsigned id) { ASSERT(!m_id); m_id = id; } 46 void cancel() { m_cancelled = true; }47 bool is Cancelled() const { return m_cancelled; }46 void setFiredOrCancelled() { m_firedOrCancelled = true; } 47 bool isFiredOrCancelled() const { return m_firedOrCancelled; } 48 48 49 49 private: 50 50 unsigned m_id { 0 }; 51 bool m_ cancelled { false };51 bool m_firedOrCancelled { false }; 52 52 }; 53 53 -
trunk/Source/WebCore/platform/xr/PlatformXR.h
r271988 r272734 19 19 #pragma once 20 20 21 #include "FloatPoint3D.h" 21 22 #include "IntSize.h" 22 23 #include <memory> … … 76 77 // when the platform has completed all steps to shut down the XR session. 77 78 virtual bool supportsSessionShutdownNotification() const { return false; } 79 virtual void initializeReferenceSpace(ReferenceSpaceType) = 0; 80 81 struct FrameData { 82 long predictedDisplayTime; 83 struct ViewData { 84 struct { 85 WebCore::FloatPoint3D position; 86 struct { 87 float x; 88 float y; 89 float z; 90 float w; 91 } orientation; 92 } pose; 93 struct { 94 float rUp; 95 float rDown; 96 float rLeft; 97 float rRight; 98 } fov; 99 }; 100 Vector<ViewData> viewPoses; 101 }; 102 using RequestFrameCallback = Function<void(FrameData&&)>; 103 virtual void requestFrame(RequestFrameCallback&&) = 0; 78 104 79 105 protected: -
trunk/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp
r271288 r272734 261 261 } 262 262 263 OpenXRDevice::~OpenXRDevice()264 {265 shutDownTrackingAndRendering();266 }267 268 263 Device::ListOfEnabledFeatures OpenXRDevice::enumerateReferenceSpaces(XrSession& session) const 269 264 { … … 396 391 } 397 392 393 static bool isSessionActive(XrSessionState state) 394 { 395 return state == XR_SESSION_STATE_VISIBLE || state == XR_SESSION_STATE_FOCUSED; 396 } 397 398 static bool isSessionReady(XrSessionState state) 399 { 400 return state >= XR_SESSION_STATE_READY && state < XR_SESSION_STATE_STOPPING; 401 } 402 398 403 void OpenXRDevice::initializeTrackingAndRendering(SessionMode mode) 399 404 { … … 415 420 void OpenXRDevice::resetSession() 416 421 { 422 ASSERT(&RunLoop::current() == &m_queue.runLoop()); 423 if (m_session != XR_NULL_HANDLE) { 424 xrDestroySession(m_session); 425 m_session = XR_NULL_HANDLE; 426 } 427 m_sessionState = XR_SESSION_STATE_UNKNOWN; 428 } 429 430 void OpenXRDevice::handleSessionStateChange() 431 { 432 ASSERT(&RunLoop::current() == &m_queue.runLoop()); 433 if (m_sessionState == XR_SESSION_STATE_STOPPING) { 434 // The application should exit the render loop and call xrEndSession 435 endSession(); 436 } else if (m_sessionState == XR_SESSION_STATE_READY) { 437 // The application is ready to call xrBeginSession. 438 beginSession(); 439 } 440 } 441 442 void OpenXRDevice::shutDownTrackingAndRendering() 443 { 417 444 m_queue.dispatch([this]() { 418 445 if (m_session == XR_NULL_HANDLE) 419 446 return; 420 xrDestroySession(m_session); 421 m_session = XR_NULL_HANDLE; 422 }); 423 } 424 425 void OpenXRDevice::shutDownTrackingAndRendering() 426 { 447 448 // xrRequestExitSession() will transition the session to STOPPED state. 449 // If the session was not running we have to reset the session ourselves. 450 if (XR_FAILED(xrRequestExitSession(m_session))) { 451 resetSession(); 452 return; 453 } 454 455 // OpenXR needs to wait for the XR_SESSION_STATE_STOPPING state to properly end the session. 456 waitUntilStopping(); 457 }); 458 } 459 460 void OpenXRDevice::waitUntilStopping() 461 { 462 ASSERT(&RunLoop::current() == &m_queue.runLoop()); 463 pollEvents(); 464 if (m_sessionState >= XR_SESSION_STATE_STOPPING) 465 return; 466 m_queue.dispatch([this]() { 467 waitUntilStopping(); 468 }); 469 } 470 471 void OpenXRDevice::pollEvents() 472 { 473 ASSERT(!isMainThread()); 474 auto runtimeEvent = createStructure<XrEventDataBuffer, XR_TYPE_EVENT_DATA_BUFFER>(); 475 while (xrPollEvent(m_instance, &runtimeEvent) == XR_SUCCESS) { 476 switch (runtimeEvent.type) { 477 case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: { 478 auto* event = (XrEventDataSessionStateChanged*)&runtimeEvent; 479 m_sessionState = event->state; 480 handleSessionStateChange(); 481 break; 482 } 483 case XR_TYPE_EVENT_DATA_EVENTS_LOST: 484 case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: 485 case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING: 486 case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED: 487 case XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX: 488 case XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR: 489 case XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT: 490 break; 491 default: 492 ASSERT_NOT_REACHED("Unhandled event type %d\n", runtimeEvent.type); 493 } 494 } 495 } 496 497 XrResult OpenXRDevice::beginSession() 498 { 499 ASSERT(!isMainThread()); 500 ASSERT(m_sessionState == XR_SESSION_STATE_READY); 501 502 auto sessionBeginInfo = createStructure<XrSessionBeginInfo, XR_TYPE_SESSION_BEGIN_INFO>(); 503 sessionBeginInfo.primaryViewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; 504 auto result = xrBeginSession(m_session, &sessionBeginInfo); 505 #if !LOG_DISABLED 506 if (XR_FAILED(result)) 507 LOG(XR, "%s %s: %s\n", __func__, "xrBeginSession", resultToString(result, m_instance).utf8().data()); 508 #endif 509 return result; 510 } 511 512 void OpenXRDevice::endSession() 513 { 514 ASSERT(m_session != XR_NULL_HANDLE); 515 xrEndSession(m_session); 427 516 resetSession(); 517 if (!m_trackingAndRenderingClient) 518 return; 519 520 // Notify did end event 521 callOnMainThread([this, weakThis = makeWeakPtr(*this)]() { 522 if (!weakThis) 523 return; 524 if (m_trackingAndRenderingClient) 525 m_trackingAndRenderingClient->sessionDidEnd(); 526 }); 527 } 528 529 530 Device::FrameData::ViewData xrViewToViewData(XrView view) 531 { 532 Device::FrameData::ViewData data; 533 data.fov = { view.fov.angleUp, view.fov.angleDown, view.fov.angleLeft, view.fov.angleRight }; 534 data.pose.orientation = { view.pose.orientation.x, view.pose.orientation.y, view.pose.orientation.z, view.pose.orientation.w }; 535 data.pose.position = { view.pose.position.x, view.pose.position.y, view.pose.position.z }; 536 return data; 537 } 538 539 void OpenXRDevice::requestFrame(RequestFrameCallback&& callback) 540 { 541 m_queue.dispatch([this, callback = WTFMove(callback)]() mutable { 542 pollEvents(); 543 if (!isSessionReady(m_sessionState)) { 544 callOnMainThread([callback = WTFMove(callback)]() mutable { 545 // Device not ready or stopping. Report frameData with invalid tracking. 546 callback({ }); 547 }); 548 return; 549 } 550 551 auto frameState = createStructure<XrFrameState, XR_TYPE_FRAME_STATE>(); 552 auto frameWaitInfo = createStructure<XrFrameWaitInfo, XR_TYPE_FRAME_WAIT_INFO>(); 553 auto result = xrWaitFrame(m_session, &frameWaitInfo, &frameState); 554 RETURN_IF_FAILED(result, "xrWaitFrame", m_instance); 555 XrTime predictedTime = frameState.predictedDisplayTime; 556 557 auto frameBeginInfo = createStructure<XrFrameBeginInfo, XR_TYPE_FRAME_BEGIN_INFO>(); 558 result = xrBeginFrame(m_session, &frameBeginInfo); 559 RETURN_IF_FAILED(result, "xrBeginFrame", m_instance); 560 561 Device::FrameData frameData; 562 frameData.predictedDisplayTime = frameState.predictedDisplayTime; 563 564 if (isSessionActive(m_sessionState)) { 565 ASSERT(m_configurationViews.contains(m_currentViewConfigurationType)); 566 const auto& configurationView = m_configurationViews.get(m_currentViewConfigurationType); 567 568 auto viewLocateInfo = createStructure<XrViewLocateInfo, XR_TYPE_VIEW_LOCATE_INFO>(); 569 viewLocateInfo.displayTime = predictedTime; 570 // FIXME: use the current reference space. 571 // viewLocateInfo.space = m_localSpace; 572 573 uint32_t viewCount = configurationView.size(); 574 Vector<XrView> views(viewCount, [] { 575 XrView object; 576 std::memset(&object, 0, sizeof(XrView)); 577 object.type = XR_TYPE_VIEW; 578 return object; 579 }()); 580 581 auto viewState = createStructure<XrViewState, XR_TYPE_VIEW_STATE>(); 582 uint32_t viewCountOutput; 583 result = xrLocateViews(m_session, &viewLocateInfo, &viewState, viewCount, &viewCountOutput, views.data()); 584 if (!XR_FAILED(result)) { 585 for (auto& view : views) 586 frameData.viewPoses.append(xrViewToViewData(view)); 587 } 588 } 589 590 callOnMainThread([frameData = WTFMove(frameData), callback = WTFMove(callback)]() mutable { 591 callback(WTFMove(frameData)); 592 }); 593 594 auto frameEndInfo = createStructure<XrFrameEndInfo, XR_TYPE_FRAME_END_INFO>(); 595 frameEndInfo.displayTime = predictedTime; 596 frameEndInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; 597 frameEndInfo.layerCount = 0; 598 result = xrEndFrame(m_session, &frameEndInfo); 599 RETURN_IF_FAILED(result, "xrEndFrame", m_instance); 600 }); 428 601 } 429 602 -
trunk/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h
r271288 r272734 45 45 public: 46 46 OpenXRDevice(XrSystemId, XrInstance, WorkQueue&, CompletionHandler<void()>&&); 47 ~OpenXRDevice();48 47 XrSystemId xrSystemId() const { return m_systemId; } 49 48 … … 53 52 54 53 ListOfEnabledFeatures enumerateReferenceSpaces(XrSession&) const; 54 void initializeReferenceSpace(ReferenceSpaceType) final { }; 55 55 56 56 WebCore::IntSize recommendedResolution(SessionMode) final; … … 58 58 void initializeTrackingAndRendering(SessionMode) final; 59 59 void shutDownTrackingAndRendering() final; 60 bool supportsSessionShutdownNotification() const final { return true; } 61 void waitUntilStopping(); 60 62 63 void pollEvents(); 64 XrResult beginSession(); 65 void endSession(); 61 66 void resetSession(); 67 void handleSessionStateChange(); 68 69 void requestFrame(RequestFrameCallback&&) final; 62 70 63 71 using ViewConfigurationPropertiesMap = HashMap<XrViewConfigurationType, XrViewConfigurationProperties, IntHash<XrViewConfigurationType>, WTF::StrongEnumHashTraits<XrViewConfigurationType>>; … … 69 77 XrInstance m_instance; 70 78 XrSession m_session { XR_NULL_HANDLE }; 79 XrSessionState m_sessionState { XR_SESSION_STATE_UNKNOWN }; 71 80 72 81 WorkQueue& m_queue; -
trunk/Source/WebCore/testing/WebFakeXRDevice.cpp
r271988 r272734 32 32 #include "JSDOMPromiseDeferred.h" 33 33 #include "WebFakeXRInputController.h" 34 #include <wtf/CompletionHandler.h> 34 35 35 36 namespace WebCore { 36 37 38 static constexpr Seconds FakeXRFrameTime = 15_ms; 39 37 40 void FakeXRView::setFieldOfView(FakeXRViewInit::FieldOfViewInit fov) 38 41 { 39 42 m_fov = fov; 43 } 44 45 SimulatedXRDevice::SimulatedXRDevice() 46 : m_frameTimer(*this, &SimulatedXRDevice::frameTimerFired) 47 { 48 m_supportsOrientationTracking = true; 49 } 50 51 SimulatedXRDevice::~SimulatedXRDevice() 52 { 53 stopTimer(); 40 54 } 41 55 … … 50 64 if (m_supportsShutdownNotification) 51 65 simulateShutdownCompleted(); 66 stopTimer(); 67 } 68 69 void SimulatedXRDevice::stopTimer() 70 { 71 if (m_frameTimer.isActive()) 72 m_frameTimer.stop(); 73 } 74 75 void SimulatedXRDevice::frameTimerFired() 76 { 77 auto callbacks = WTFMove(m_callbacks); 78 for (auto& callback : callbacks) 79 callback({ }); 80 } 81 82 void SimulatedXRDevice::requestFrame(RequestFrameCallback&& callback) 83 { 84 m_callbacks.append(WTFMove(callback)); 85 if (!m_frameTimer.isActive()) 86 m_frameTimer.startOneShot(FakeXRFrameTime); 52 87 } 53 88 -
trunk/Source/WebCore/testing/WebFakeXRDevice.h
r271988 r272734 64 64 WTF_MAKE_FAST_ALLOCATED; 65 65 public: 66 SimulatedXRDevice() { m_supportsOrientationTracking = true; } 66 SimulatedXRDevice(); 67 ~SimulatedXRDevice(); 67 68 void setNativeBoundsGeometry(Vector<FakeXRBoundsPoint> geometry) { m_nativeBoundsGeometry = geometry; } 68 69 void setViewerOrigin(RefPtr<WebXRRigidTransform>&& origin) { m_viewerOrigin = WTFMove(origin); } … … 76 77 void shutDownTrackingAndRendering() final; 77 78 bool supportsSessionShutdownNotification() const final { return m_supportsShutdownNotification; } 79 void initializeReferenceSpace(PlatformXR::ReferenceSpaceType) final { } 80 void requestFrame(RequestFrameCallback&&) final; 81 82 void stopTimer(); 83 void frameTimerFired(); 84 78 85 Optional<Vector<FakeXRBoundsPoint>> m_nativeBoundsGeometry; 79 86 RefPtr<WebXRRigidTransform> m_viewerOrigin; … … 82 89 Vector<Ref<FakeXRView>> m_views; 83 90 bool m_supportsShutdownNotification { false }; 91 Timer m_frameTimer; 92 Vector<RequestFrameCallback> m_callbacks; 84 93 }; 85 94
Note: See TracChangeset
for help on using the changeset viewer.