Changeset 269032 in webkit


Ignore:
Timestamp:
Oct 27, 2020 5:30:53 AM (3 years ago)
Author:
svillar@igalia.com
Message:

[WebXR] Move OpenXR calls off the main thread
https://bugs.webkit.org/show_bug.cgi?id=217752

Reviewed by Youenn Fablet.

The OpenXR API is synchronous. Many of the calls involve dealing with external hardware devices
meaning that they have to potential to block the main thread. They should be moved to a different
thread in order to avoid that.

The PlatformXR::Instance creates a WorkQueue which is going to be used by the OpenXR devices to
issue OpenXR calls and also serialize them to ensure that they are executed sequentially. The
OpenXRDevice's are created in the main thread anyway because we need to get weak pointers from
them in the main thread.

  • Modules/webxr/WebXRSystem.cpp:

(WebCore::WebXRSystem::ensureImmersiveXRDeviceIsSelected): Use a scoped exit to call callback. Also
the Vector of immersive devices is now a pointer which might be null, meaning no available devices.

  • platform/xr/PlatformXR.h: Added a "using" for the Vector of devices.
  • platform/xr/openxr/PlatformXROpenXR.cpp:

(PlatformXR::Instance::Impl::queue const): New getter returning the WorkQueue.
(PlatformXR::Instance::Impl::enumerateApiLayerProperties const): Added an ASSERT.
(PlatformXR::Instance::Impl::checkInstanceExtensionProperties const): Ditto.
(PlatformXR::Instance::Impl::Impl): Create the OpenXR WorkQueue and dispatch a task to perform the
OpenXR system initialization in the queue.
(PlatformXR::Instance::Impl::~Impl): Delete the instance in the WorkQueue
(PlatformXR::Instance::enumerateImmersiveXRDevices): Moved the code to a task in the WorkQueue.
(PlatformXR::OpenXRDevice::OpenXRDevice): Ditto. Also added a completion handler to notify the caller
about the end of the device initialization process.
(PlatformXR::OpenXRDevice::collectSupportedSessionModes): Added an ASSERT.
(PlatformXR::OpenXRDevice::collectConfigurationViews): Ditto.

  • platform/xr/openxr/PlatformXROpenXR.h: Added WorkQueue attribute and parameter to device constructor.
Location:
trunk/Source/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r269031 r269032  
     12020-10-15  Sergio Villar Senin  <svillar@igalia.com>
     2
     3        [WebXR] Move OpenXR calls off the main thread
     4        https://bugs.webkit.org/show_bug.cgi?id=217752
     5
     6        Reviewed by Youenn Fablet.
     7
     8        The OpenXR API is synchronous. Many of the calls involve dealing with external hardware devices
     9        meaning that they have to potential to block the main thread. They should be moved to a different
     10        thread in order to avoid that.
     11
     12        The PlatformXR::Instance creates a WorkQueue which is going to be used by the OpenXR devices to
     13        issue OpenXR calls and also serialize them to ensure that they are executed sequentially. The
     14        OpenXRDevice's are created in the main thread anyway because we need to get weak pointers from
     15        them in the main thread.
     16
     17        * Modules/webxr/WebXRSystem.cpp:
     18        (WebCore::WebXRSystem::ensureImmersiveXRDeviceIsSelected): Use a scoped exit to call callback. Also
     19        the Vector of immersive devices is now a pointer which might be null, meaning no available devices.
     20        * platform/xr/PlatformXR.h: Added a "using" for the Vector of devices.
     21        * platform/xr/openxr/PlatformXROpenXR.cpp:
     22        (PlatformXR::Instance::Impl::queue const): New getter returning the WorkQueue.
     23        (PlatformXR::Instance::Impl::enumerateApiLayerProperties const): Added an ASSERT.
     24        (PlatformXR::Instance::Impl::checkInstanceExtensionProperties const): Ditto.
     25        (PlatformXR::Instance::Impl::Impl): Create the OpenXR WorkQueue and dispatch a task to perform the
     26        OpenXR system initialization in the queue.
     27        (PlatformXR::Instance::Impl::~Impl): Delete the instance in the WorkQueue
     28        (PlatformXR::Instance::enumerateImmersiveXRDevices): Moved the code to a task in the WorkQueue.
     29        (PlatformXR::OpenXRDevice::OpenXRDevice): Ditto. Also added a completion handler to notify the caller
     30        about the end of the device initialization process.
     31        (PlatformXR::OpenXRDevice::collectSupportedSessionModes): Added an ASSERT.
     32        (PlatformXR::OpenXRDevice::collectConfigurationViews): Ditto.
     33        * platform/xr/openxr/PlatformXROpenXR.h: Added WorkQueue attribute and parameter to device constructor.
     34
    1352020-10-27  Xabier Rodriguez Calvar  <calvaris@igalia.com>
    236
  • trunk/Source/WebCore/Modules/webxr/WebXRSystem.cpp

    r268700 r269032  
    8989        m_immersiveXRDevicesHaveBeenEnumerated = true;
    9090
     91        auto callbackOnExit = makeScopeExit([&]() {
     92            callOnMainThread(WTFMove(callback));
     93        });
     94
    9195        // https://immersive-web.github.io/webxr/#select-an-immersive-xr-device
    9296        auto* oldDevice = m_activeImmersiveDevice.get();
    9397        if (immersiveXRDevices.isEmpty()) {
    9498            m_activeImmersiveDevice = nullptr;
    95             callback();
    9699            return;
    97100        }
    98101        if (immersiveXRDevices.size() == 1) {
    99102            m_activeImmersiveDevice = makeWeakPtr(immersiveXRDevices.first().get());
    100             callback();
    101             return;
    102         }
    103 
    104         if (m_activeImmersiveSession && oldDevice && immersiveXRDevices.findMatching([&](auto& entry) { return entry.get() == oldDevice; }) != notFound)
     103            return;
     104        }
     105
     106        if (m_activeImmersiveSession && oldDevice && immersiveXRDevices.findMatching([&](auto& entry) { return &entry == oldDevice; }) != notFound)
    105107            ASSERT(m_activeImmersiveDevice.get() == oldDevice);
    106108        else {
     
    110112
    111113        if (isFirstXRDevicesEnumeration || m_activeImmersiveDevice.get() == oldDevice) {
    112             callback();
    113114            return;
    114115        }
     
    117118        // FIXME: 8. Set the XR compatible boolean of all WebGLRenderingContextBase instances to false.
    118119        // FIXME: 9. Queue a task to fire an event named devicechange on the context object.
    119 
    120         callback();
    121120    });
    122121}
  • trunk/Source/WebCore/platform/xr/PlatformXR.h

    r268255 r269032  
    7676    static Instance& singleton();
    7777
    78     void enumerateImmersiveXRDevices(CompletionHandler<void(const Vector<std::unique_ptr<Device>>&)>&&);
     78    using DeviceList = Vector<UniqueRef<Device>>;
     79    void enumerateImmersiveXRDevices(CompletionHandler<void(const DeviceList&)>&&);
    7980
    8081private:
     
    8687    UniqueRef<Impl> m_impl;
    8788
    88     Vector<std::unique_ptr<Device>> m_immersiveXRDevices;
     89    DeviceList m_immersiveXRDevices;
    8990};
    9091
  • trunk/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp

    r268255 r269032  
    7474#if USE_OPENXR
    7575    XrInstance xrInstance() const { return m_instance; }
     76    WorkQueue& queue() const { return m_workQueue; }
    7677#endif
    7778
     
    8283
    8384    XrInstance m_instance { XR_NULL_HANDLE };
     85    Ref<WorkQueue> m_workQueue;
    8486#endif // USE_OPENXR
    8587};
     
    8890void Instance::Impl::enumerateApiLayerProperties() const
    8991{
     92    ASSERT(&RunLoop::current() == &m_workQueue->runLoop());
    9093    uint32_t propertyCountOutput { 0 };
    9194    XrResult result = xrEnumerateApiLayerProperties(0, &propertyCountOutput, nullptr);
     
    120123bool Instance::Impl::checkInstanceExtensionProperties() const
    121124{
     125    ASSERT(&RunLoop::current() == &m_workQueue->runLoop());
    122126    uint32_t propertyCountOutput { 0 };
    123127    XrResult result = xrEnumerateInstanceExtensionProperties(nullptr, 0, &propertyCountOutput, nullptr);
     
    155159
    156160Instance::Impl::Impl()
    157 {
    158 #if USE_OPENXR
    159     LOG(XR, "OpenXR: initializing\n");
    160 
    161     enumerateApiLayerProperties();
    162 
    163     if (!checkInstanceExtensionProperties())
    164         return;
    165 
    166     static const char* s_applicationName = "WebXR (WebKit)";
    167     static const uint32_t s_applicationVersion = 1;
    168 
    169     const char* const enabledExtensions[] = {
    170         XR_MND_HEADLESS_EXTENSION_NAME,
    171     };
    172 
    173     auto createInfo = createStructure<XrInstanceCreateInfo, XR_TYPE_INSTANCE_CREATE_INFO>();
    174     createInfo.createFlags = 0;
    175     std::memcpy(createInfo.applicationInfo.applicationName, s_applicationName, XR_MAX_APPLICATION_NAME_SIZE);
    176     createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
    177     createInfo.applicationInfo.applicationVersion = s_applicationVersion;
    178     createInfo.enabledApiLayerCount = 0;
    179     createInfo.enabledExtensionCount = WTF_ARRAY_LENGTH(enabledExtensions);
    180     createInfo.enabledExtensionNames = enabledExtensions;
    181 
    182     XrInstance instance;
    183     XrResult result = xrCreateInstance(&createInfo, &instance);
    184     RETURN_IF_FAILED(result, "xrCreateInstance()", m_instance);
    185     m_instance = instance;
    186     LOG(XR, "xrCreateInstance(): using instance %p\n", m_instance);
     161#if USE_OPENXR
     162    : m_workQueue(WorkQueue::create("OpenXR queue"))
     163#endif
     164{
     165#if USE_OPENXR
     166    m_workQueue->dispatch([this]() {
     167        LOG(XR, "OpenXR: initializing\n");
     168
     169        enumerateApiLayerProperties();
     170
     171        if (!checkInstanceExtensionProperties())
     172            return;
     173
     174        static const char* s_applicationName = "WebXR (WebKit)";
     175        static const uint32_t s_applicationVersion = 1;
     176
     177        const char* const enabledExtensions[] = {
     178            XR_MND_HEADLESS_EXTENSION_NAME,
     179        };
     180
     181        auto createInfo = createStructure<XrInstanceCreateInfo, XR_TYPE_INSTANCE_CREATE_INFO>();
     182        createInfo.createFlags = 0;
     183        std::memcpy(createInfo.applicationInfo.applicationName, s_applicationName, XR_MAX_APPLICATION_NAME_SIZE);
     184        createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
     185        createInfo.applicationInfo.applicationVersion = s_applicationVersion;
     186        createInfo.enabledApiLayerCount = 0;
     187        createInfo.enabledExtensionCount = WTF_ARRAY_LENGTH(enabledExtensions);
     188        createInfo.enabledExtensionNames = enabledExtensions;
     189
     190        XrInstance instance;
     191        XrResult result = xrCreateInstance(&createInfo, &instance);
     192        RETURN_IF_FAILED(result, "xrCreateInstance()", m_instance);
     193        m_instance = instance;
     194        LOG(XR, "xrCreateInstance(): using instance %p\n", m_instance);
     195    });
    187196#endif // USE_OPENXR
    188197}
     
    191200{
    192201#if USE_OPENXR
    193     if (m_instance != XR_NULL_HANDLE)
    194         xrDestroyInstance(m_instance);
     202    m_workQueue->dispatch([this] {
     203        if (m_instance != XR_NULL_HANDLE)
     204            xrDestroyInstance(m_instance);
     205    });
    195206#endif
    196207}
     
    212223}
    213224
    214 void Instance::enumerateImmersiveXRDevices(CompletionHandler<void(const Vector<std::unique_ptr<Device>>& devices)>&& callback)
    215 {
    216 #if USE_OPENXR
    217     auto callbackOnExit = makeScopeExit([&]() {
    218         callback({ });
     225void Instance::enumerateImmersiveXRDevices(CompletionHandler<void(const DeviceList& devices)>&& callback)
     226{
     227#if USE_OPENXR
     228    m_impl->queue().dispatch([this, callback = WTFMove(callback)]() mutable {
     229        auto callbackOnExit = makeScopeExit([&]() {
     230            callOnMainThread([callback = WTFMove(callback)]() mutable {
     231                callback({ });
     232            });
     233        });
     234
     235        if (m_impl->xrInstance() == XR_NULL_HANDLE) {
     236            LOG(XR, "%s Unable to enumerate XR devices. No XrInstance present\n", __FUNCTION__);
     237            return;
     238        }
     239
     240        auto systemGetInfo = createStructure<XrSystemGetInfo, XR_TYPE_SYSTEM_GET_INFO>();
     241        systemGetInfo.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
     242
     243        XrSystemId systemId;
     244        XrResult result = xrGetSystem(m_impl->xrInstance(), &systemGetInfo, &systemId);
     245        RETURN_IF_FAILED(result, "xrGetSystem", m_impl->xrInstance());
     246
     247        callbackOnExit.release();
     248
     249        callOnMainThread([this, callback = WTFMove(callback), systemId]() mutable {
     250            m_immersiveXRDevices = DeviceList::from(makeUniqueRef<OpenXRDevice>(systemId, m_impl->xrInstance(), m_impl->queue(), [this, callback = WTFMove(callback)]() mutable {
     251                ASSERT(isMainThread());
     252                callback(m_immersiveXRDevices);
     253            }));
     254        });
    219255    });
    220     if (m_impl->xrInstance() == XR_NULL_HANDLE) {
    221         LOG(XR, "%s Unable to enumerate XR devices. No XrInstance present\n", __FUNCTION__);
    222         return;
    223     }
    224 
    225     auto systemGetInfo = createStructure<XrSystemGetInfo, XR_TYPE_SYSTEM_GET_INFO>();
    226     systemGetInfo.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
    227 
    228     XrSystemId systemId;
    229     XrResult result = xrGetSystem(m_impl->xrInstance(), &systemGetInfo, &systemId);
    230     RETURN_IF_FAILED(result, "xrGetSystem", m_impl->xrInstance());
    231 
     256
     257#endif // USE_OPENXR
     258}
     259
     260#if USE_OPENXR
     261OpenXRDevice::OpenXRDevice(XrSystemId id, XrInstance instance, WorkQueue& queue, CompletionHandler<void()>&& callback)
     262    : m_systemId(id)
     263    , m_instance(instance)
     264    , m_queue(queue)
     265{
     266    ASSERT(isMainThread());
     267    m_queue.dispatch([this, callback = WTFMove(callback)]() mutable {
     268        auto systemProperties = createStructure<XrSystemProperties, XR_TYPE_SYSTEM_PROPERTIES>();
     269        auto result = xrGetSystemProperties(m_instance, m_systemId, &systemProperties);
     270        if (XR_SUCCEEDED(result))
     271            m_supportsOrientationTracking = systemProperties.trackingProperties.orientationTracking == XR_TRUE;
    232272#if !LOG_DISABLED
    233     auto systemProperties = createStructure<XrSystemProperties, XR_TYPE_SYSTEM_PROPERTIES>();
    234     result = xrGetSystemProperties(m_impl->xrInstance(), systemId, &systemProperties);
    235     if (result == XR_SUCCESS)
     273        else
     274            LOG(XR, "xrGetSystemProperties(): error %s\n", resultToString(result, m_instance).utf8().data());
    236275        LOG(XR, "Found XRSystem %lu: \"%s\", vendor ID %d\n", systemProperties.systemId, systemProperties.systemName, systemProperties.vendorId);
    237276#endif
    238277
    239     m_immersiveXRDevices.append(makeUnique<OpenXRDevice>(systemId, m_impl->xrInstance()));
    240     callback(m_immersiveXRDevices);
    241     callbackOnExit.release();
    242 #endif // USE_OPENXR
    243 }
    244 
    245 #if USE_OPENXR
    246 OpenXRDevice::OpenXRDevice(XrSystemId id, XrInstance instance)
    247     : m_systemId(id)
    248     , m_instance(instance)
    249 {
    250     auto systemProperties = createStructure<XrSystemProperties, XR_TYPE_SYSTEM_PROPERTIES>();
    251     XrResult result = xrGetSystemProperties(instance, m_systemId, &systemProperties);
    252     if (result == XR_SUCCESS)
    253         m_supportsOrientationTracking = systemProperties.trackingProperties.orientationTracking == XR_TRUE;
    254     else
    255         LOG(XR, "xrGetSystemProperties(): error %s\n", resultToString(result, m_instance).utf8().data());
    256 
    257     collectSupportedSessionModes();
    258     collectConfigurationViews();
     278        collectSupportedSessionModes();
     279        collectConfigurationViews();
     280
     281        callOnMainThread(WTFMove(callback));
     282    });
    259283}
    260284
     
    300324void OpenXRDevice::collectSupportedSessionModes()
    301325{
     326    ASSERT(&RunLoop::current() == &m_queue.runLoop());
    302327    uint32_t viewConfigurationCount;
    303328    auto result = xrEnumerateViewConfigurations(m_instance, m_systemId, 0, &viewConfigurationCount, nullptr);
     
    342367void OpenXRDevice::collectConfigurationViews()
    343368{
     369    ASSERT(&RunLoop::current() == &m_queue.runLoop());
    344370    for (auto& config : m_viewConfigurationProperties.values()) {
    345371        uint32_t viewCount;
  • trunk/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h

    r265137 r269032  
    2727#if USE_OPENXR
    2828#include <openxr/openxr.h>
     29#include <wtf/WorkQueue.h>
    2930
    3031namespace PlatformXR {
     
    4445class OpenXRDevice final : public Device {
    4546public:
    46     OpenXRDevice(XrSystemId, XrInstance);
     47    OpenXRDevice(XrSystemId, XrInstance, WorkQueue&, CompletionHandler<void()>&&);
    4748    XrSystemId xrSystemId() const { return m_systemId; }
     49
    4850private:
    4951    void collectSupportedSessionModes();
     
    6264    XrInstance m_instance;
    6365    XrSession m_session;
     66
     67    WorkQueue& m_queue;
    6468};
    6569
Note: See TracChangeset for help on using the changeset viewer.