[Webkit-unassigned] [Bug 220979] Complete XRSession::requestAnimationFrame implementation

bugzilla-daemon at webkit.org bugzilla-daemon at webkit.org
Wed Feb 3 10:57:00 PST 2021


https://bugs.webkit.org/show_bug.cgi?id=220979

--- Comment #13 from Imanol Fernandez <ifernandez at igalia.com> ---
Comment on attachment 418924
  --> https://bugs.webkit.org/attachment.cgi?id=418924
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=418924&action=review

>> Source/WebCore/ChangeLog:9
>> +        - Apply pending render state changes
> 
> It would be nice to have some more info in the ChangeLog. Maybe even per-file notes, for areas where there was a lot of change.

I improved the changelog in the new patch

>>> Source/WebCore/Modules/webxr/WebXRFrame.cpp:46
>>> +    , m_session(session)
>> 
>> WebXRFrame is refcounted so could potentially be kept alive longer than its session.
>> Might be better to keep a ref or use a weakptr.
> 
> Since you can access the session from the XRFrame, I think this need to be a ref. The session itself might get disconnected, but the object still needs to exist.

One of the problems was that session holds a Ref<XRFrame>, and XRFrame another Ref<XRSession> that could cause reference cycles.
The WebXR spec states that session from the XRFrame is always valid so I have added a Ref<XRSession> there, because it needs to keep the session alive. 
In XRSession I have changed Ref<XRFrame> to RefPtr<XRFrame>. This RefPtr is cleaned when the session is ended. I added m_ended bailouts and asserts to make sure that we never access a empty m_animationFrame.

>>> Source/WebCore/Modules/webxr/WebXRFrame.cpp:55
>>> +    return *m_session;
>> 
>> How can we guarantee this?
> 
> +1
> 
> If the session can never be null, then we shouldn't be storing a pointer.

Not needed anymore after switching to Ref<XRSession>

>> Source/WebCore/Modules/webxr/WebXRFrame.h:60
>> +    WebXRFrame(WebXRSession*);
> 
> explicit

done

>> Source/WebCore/Modules/webxr/WebXRFrame.h:62
>> +    bool m_active;
> 
> add { false }

done

>> Source/WebCore/Modules/webxr/WebXRFrame.h:66
>> +    WebXRSession* m_session;
> 
> Why is this now a pointer rather than a Ref? When can a Frame be created without a Session?

Fixes as mentioned in prev comments

>> Source/WebCore/Modules/webxr/WebXRSession.cpp:59
>> +    , m_animationFrame(WebXRFrame::create(this))
> 
> Seems like we could use *this there.

switched to Ref<>

>>> Source/WebCore/Modules/webxr/WebXRSession.cpp:208
>>> +    scriptExecutionContext()->postTask([this, promise = WTFMove(promise), type](auto& context) mutable {
>> 
>> There is no guarantee this will be valid within the callback.
> 
> weakThis = makeWeakPtr(this)
> then check the value in the callback

fixed

>> Source/WebCore/Modules/webxr/WebXRSession.cpp:221
>> +        queueTaskKeepingObjectAlive(*this, TaskSource::WebXR, [this, type, promise = WTFMove(promise), protectedDocument = makeRef(downcast<Document>(context))]() mutable {
> 
> Why keeping a protected document here?
> I guess context is equal to this->scriptExecutionContext().
> Can we just use that?

done

>> Source/WebCore/Modules/webxr/WebXRSession.cpp:248
>> +    if (m_callbacks.size() == 1 && !m_animationFrame->isActive())
> 
> Why does the number of callbacks need to equal 1? Shouldn't this just be a non-zero test?

I added some comments to make it clearer. Script can add many RAFs but whe only need to request/schedule the frame once. As the callback is being added before to the vector the size for the check is 1.

We could move m_callbacks.append() and use isEmpty() test but even if the frame runs on a next tick, it felt a bit weird to request a callback before all the data was ready (just thinking on the risk of a port calling the lambda on a sync way)

>>> Source/WebCore/Modules/webxr/WebXRSession.cpp:463
>>> +    m_device->requestFrame([this, protectedThis = makeRef(*this)](PlatformXR::Device::FrameData frameData)
>> 
>> s/PlatformXR::Device::FrameDat/auto/
> 
> Oh cool. I didn't know you could do that.

That's cool, nice C++14 feature :)

>> Source/WebCore/Modules/webxr/WebXRSession.cpp:464
>> +    {
> 
> Should be at the end of the next line.

fixed

>> Source/WebCore/Modules/webxr/WebXRSession.cpp:479
>> +        DOMHighResTimeStamp now = (MonotonicTime::now() - m_timeOrigin).milliseconds();
> 
> auto?

done

>> Source/WebCore/Modules/webxr/WebXRSession.cpp:483
>> +        m_animationFrame->setTime(static_cast<DOMHighResTimeStamp>(frameData.predictedDisplayTime));
> 
> Is there a way to not have to do the static_cast.

The problem is that most SDKs provide the data using a long timestamp but JS doesn't support 64 bit integers. I think is better to make sure we have the most accurate data in the ports and only potentially lose precision in JS.

>>> Source/WebCore/Modules/webxr/WebXRSession.cpp:512
>>> +                callback->handleEvent(now, m_animationFrame.get());
>> 
>> Is there a chance the event will cancel everything (in which case we should stop everything), or will allow changing m_runningCallbacks synchronously?
> 
> The script here can do anything, but it looks like runningCallbacks is only used here, so it might be safe. But that makes me ask why it is exposed as a member variable rather than just a local variable in this block.

runningCallbacks is also accessed from cancelRequestAnimationFrame in order to cancel ongoing rafs. Only the `cancel` flag is modified so multiple vector item modifications are not possible.

>> Source/WebCore/Modules/webxr/WebXRSystem.cpp:475
>> +class InlineRequestAnimationFrameCallback: public RequestAnimationFrameCallback {
> 
> Should it be final?

done

>> Source/WebCore/Modules/webxr/WebXRSystem.cpp:482
>> +    InlineRequestAnimationFrameCallback(ScriptExecutionContext& scriptExecutionContext, Function<void()>&& callback)
> 
> Please move this to private.
> Otherwise people can create it outside of create.

done

>> Source/WebCore/Modules/webxr/WebXRSystem.cpp:487
>> +    CallbackResult<void> handleEvent(double highResTimeMs) override
> 
> final?
> Remove highResTimeMs

done

>> Source/WebCore/Modules/webxr/WebXRSystem.cpp:507
>> +    auto document = downcast<Document>(m_scriptExecutionContext);
> 
> What is the guarantee m_scriptExecutionContext will be a Document?
> Should constructor take a Document?
> What is the guarantee for m_scriptExecutionContext to be valid here?

It uses the same m_scriptExecutionContext from the WebXRSystem, which holds the DummyInlineDevice. The scriptExecutionContext is already downcasted to document in other places in (e.g. WebXRSystem::isSessionSupported)

I have added a make the access to it safer.

>> Source/WebCore/Modules/webxr/WebXRSystem.h:109
>> +        DummyInlineDevice(ScriptExecutionContext&);
> 
> explicit

done

>> Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp:205
>> +    HTMLCanvasElement* c = WTF::switchOn(m_context, [](const RefPtr<WebGLRenderingContextBase>& baseContext) {
> 
> return WTF::switchOn(m_context, [](const RefPtr<WebGLRenderingContextBase>& baseContext) -> HTMLCanvasElement* {
> maybe?

done

>> Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp:212
>> +            [](RefPtr<OffscreenCanvas>) {
> 
> const RefPtr<OffscreenCanvas>&?

done

>> Source/WebCore/platform/xr/PlatformXR.h:87
>> +                    float x, y, z, w;
> 
> Separate line for each of these.

done

>> Source/WebCore/platform/xr/PlatformXR.h:96
>> +    using RequestFrameCallback = WTF::Function<void(FrameData)>;
> 
> No need for WTF::
> Probably also want to pass a FrameData&&

done

>> Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp:435
>> +    callOnMainThread([this, weakThis = makeWeakPtr(this)]() {
> 
> Why is this necessary? Is this just causing the pending callbacks to be flushed? Wouldn't it be better to delete them directly?

OpenXR needs to wait for the XR_SESSION_STATE_STOPPING state to properly end the session. We were reusing the frame loop which already checked this event.

I agree that is confusing. I have done some refactor to improve the event handling and added a separate function that handle the shutdown process (which also uses the sessionDidEnd() notification now)

>> Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp:438
>> +        requestFrame([](FrameData) { });
> 
> s/FrameData/auto

not needed anymore

>> Source/WebCore/testing/WebFakeXRDevice.cpp:46
>> +    m_supportsOrientationTracking = true;
> 
> Why not:
>     , m_supportsOrientationTracking(true)
> Or even better in the header declaration directly.

in this case is a protected member from base class

>> Source/WebCore/testing/WebFakeXRDevice.cpp:76
>> +    runningCallbacks.swap(m_callbacks);
> 
> Could be written as:
> auto callbacks = WTFMove(m_callbacks)?

done

>> Source/WebCore/testing/WebFakeXRDevice.cpp:85
>> +        m_frameTimer.startOneShot(15_ms);
> 
> Might be good to use a constant

done

-- 
You are receiving this mail because:
You are the assignee for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-unassigned/attachments/20210203/902ecc6c/attachment-0001.htm>


More information about the webkit-unassigned mailing list