- Revision
- 291313
- Author
- [email protected]
- Date
- 2022-03-15 14:22:35 -0700 (Tue, 15 Mar 2022)
Log Message
[WebGPU] Allow for scheduling asynchronous work
https://bugs.webkit.org/show_bug.cgi?id=237755
Reviewed by Kimmo Kinnunen.
Source/WebCore/PAL:
WebGPU doesn't know how to schedule asynchronous work, so that will have to be handled
by dependency injection from the caller. The way it works is Instance creation takes
a block, which is retained. Whenever asynchronous work needs to be scheduled on the
relevant thread, this block is called, and is passed another block for the work to be
performed.
The API contract is: callers of WebGPU must call its functions in a non-racey way. The
schedule function will execute on a background thread, and it must schedule the block
it's passed to be run in a non-racey way with regards to all the other WebGPU calls.
The schedule function can be NULL, in which case the asynchronous tasks will just be
internally queued up inside WebGPU, and then users will have to call
wgpuInstanceProcessEvents() periodically to synchronously call the queued callbacks.
* pal/graphics/WebGPU/Impl/WebGPUImpl.cpp:
(PAL::WebGPU::GPUImpl::create):
* pal/graphics/WebGPU/Impl/WebGPUImpl.h:
Source/WebGPU:
* WebGPU/Instance.h:
(WebGPU::Instance::runLoop const): Deleted.
* WebGPU/Instance.mm:
(WebGPU::Instance::create):
(WebGPU::Instance::Instance):
(WebGPU::Instance::scheduleWork):
(WebGPU::Instance::defaultScheduleWork):
(WebGPU::Instance::processEvents):
* WebGPU/WebGPUExt.h:
Source/WebKit:
* GPUProcess/graphics/WebGPU/RemoteGPU.cpp:
(WebKit::RemoteGPU::workQueueInitialize):
(WebKit::RemoteGPU::workQueueUninitialize):
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::createGPUForWebGPU const):
Source/WebKitLegacy/mac:
* WebCoreSupport/WebChromeClient.mm:
(WebChromeClient::createGPUForWebGPU const):
Modified Paths
Diff
Modified: trunk/Source/WebCore/PAL/ChangeLog (291312 => 291313)
--- trunk/Source/WebCore/PAL/ChangeLog 2022-03-15 21:17:33 UTC (rev 291312)
+++ trunk/Source/WebCore/PAL/ChangeLog 2022-03-15 21:22:35 UTC (rev 291313)
@@ -1,3 +1,27 @@
+2022-03-15 Myles C. Maxfield <[email protected]>
+
+ [WebGPU] Allow for scheduling asynchronous work
+ https://bugs.webkit.org/show_bug.cgi?id=237755
+
+ Reviewed by Kimmo Kinnunen.
+
+ WebGPU doesn't know how to schedule asynchronous work, so that will have to be handled
+ by dependency injection from the caller. The way it works is Instance creation takes
+ a block, which is retained. Whenever asynchronous work needs to be scheduled on the
+ relevant thread, this block is called, and is passed another block for the work to be
+ performed.
+
+ The API contract is: callers of WebGPU must call its functions in a non-racey way. The
+ schedule function will execute on a background thread, and it must schedule the block
+ it's passed to be run in a non-racey way with regards to all the other WebGPU calls.
+ The schedule function can be NULL, in which case the asynchronous tasks will just be
+ internally queued up inside WebGPU, and then users will have to call
+ wgpuInstanceProcessEvents() periodically to synchronously call the queued callbacks.
+
+ * pal/graphics/WebGPU/Impl/WebGPUImpl.cpp:
+ (PAL::WebGPU::GPUImpl::create):
+ * pal/graphics/WebGPU/Impl/WebGPUImpl.h:
+
2022-03-15 Jer Noble <[email protected]>
[Cocoa] Adopt AVAssetPrefersSandboxedParsingOptionKey
Modified: trunk/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.cpp (291312 => 291313)
--- trunk/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.cpp 2022-03-15 21:17:33 UTC (rev 291312)
+++ trunk/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.cpp 2022-03-15 21:22:35 UTC (rev 291313)
@@ -31,6 +31,7 @@
#include "WebGPUAdapterImpl.h"
#include "WebGPUDowncastConvertToBackingContext.h"
#include <WebGPU/WebGPUExt.h>
+#include <wtf/BlockPtr.h>
#if PLATFORM(COCOA)
#include <wtf/darwin/WeakLinking.h>
@@ -40,9 +41,21 @@
namespace PAL::WebGPU {
-RefPtr<GPUImpl> GPUImpl::create()
+RefPtr<GPUImpl> GPUImpl::create(ScheduleWorkFunction&& scheduleWorkFunction)
{
- WGPUInstanceDescriptor descriptor = { nullptr };
+ auto scheduleWorkBlock = makeBlockPtr([scheduleWorkFunction = WTFMove(scheduleWorkFunction)](WGPUWorkItem workItem)
+ {
+ scheduleWorkFunction(makeBlockPtr(WTFMove(workItem)));
+ });
+ WGPUInstanceCocoaDescriptor cocoaDescriptor {
+ {
+ nullptr,
+ static_cast<WGPUSType>(WGPUSTypeExtended_InstanceCocoaDescriptor),
+ },
+ scheduleWorkBlock.get(),
+ };
+ WGPUInstanceDescriptor descriptor = { &cocoaDescriptor.chain };
+
if (!&wgpuCreateInstance)
return nullptr;
auto instance = wgpuCreateInstance(&descriptor);
Modified: trunk/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.h (291312 => 291313)
--- trunk/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.h 2022-03-15 21:17:33 UTC (rev 291312)
+++ trunk/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.h 2022-03-15 21:22:35 UTC (rev 291313)
@@ -29,7 +29,9 @@
#include "WebGPU.h"
#include <WebGPU/WebGPU.h>
+#include <functional>
#include <wtf/Deque.h>
+#include <wtf/Function.h>
namespace PAL::WebGPU {
@@ -38,7 +40,9 @@
class GPUImpl final : public GPU {
WTF_MAKE_FAST_ALLOCATED;
public:
- PAL_EXPORT static RefPtr<GPUImpl> create();
+ using WorkItem = Function<void(void)>;
+ using ScheduleWorkFunction = Function<void(WorkItem&&)>;
+ PAL_EXPORT static RefPtr<GPUImpl> create(ScheduleWorkFunction&&);
static Ref<GPUImpl> create(WGPUInstance instance, ConvertToBackingContext& convertToBackingContext)
{
Modified: trunk/Source/WebGPU/ChangeLog (291312 => 291313)
--- trunk/Source/WebGPU/ChangeLog 2022-03-15 21:17:33 UTC (rev 291312)
+++ trunk/Source/WebGPU/ChangeLog 2022-03-15 21:22:35 UTC (rev 291313)
@@ -1,3 +1,20 @@
+2022-03-15 Myles C. Maxfield <[email protected]>
+
+ [WebGPU] Allow for scheduling asynchronous work
+ https://bugs.webkit.org/show_bug.cgi?id=237755
+
+ Reviewed by Kimmo Kinnunen.
+
+ * WebGPU/Instance.h:
+ (WebGPU::Instance::runLoop const): Deleted.
+ * WebGPU/Instance.mm:
+ (WebGPU::Instance::create):
+ (WebGPU::Instance::Instance):
+ (WebGPU::Instance::scheduleWork):
+ (WebGPU::Instance::defaultScheduleWork):
+ (WebGPU::Instance::processEvents):
+ * WebGPU/WebGPUExt.h:
+
2022-03-12 Tim Horton <[email protected]>
Adopt FALLBACK_PLATFORM_NAME in place of FALLBACK_PLATFORM
Modified: trunk/Source/WebGPU/WebGPU/Instance.h (291312 => 291313)
--- trunk/Source/WebGPU/WebGPU/Instance.h 2022-03-15 21:17:33 UTC (rev 291312)
+++ trunk/Source/WebGPU/WebGPU/Instance.h 2022-03-15 21:22:35 UTC (rev 291313)
@@ -25,12 +25,13 @@
#pragma once
-#import <Foundation/Foundation.h>
+#import <wtf/Deque.h>
#import <wtf/FastMalloc.h>
#import <wtf/Function.h>
+#import <wtf/Lock.h>
#import <wtf/Ref.h>
-#import <wtf/RefCounted.h>
#import <wtf/RefPtr.h>
+#import <wtf/ThreadSafeRefCounted.h>
namespace WebGPU {
@@ -37,7 +38,7 @@
class Adapter;
class Surface;
-class Instance : public RefCounted<Instance> {
+class Instance : public ThreadSafeRefCounted<Instance> {
WTF_MAKE_FAST_ALLOCATED;
public:
static RefPtr<Instance> create(const WGPUInstanceDescriptor&);
@@ -48,12 +49,20 @@
void processEvents();
void requestAdapter(const WGPURequestAdapterOptions&, WTF::Function<void(WGPURequestAdapterStatus, RefPtr<Adapter>&&, const char*)>&& callback);
- NSRunLoop *runLoop() const { return m_runLoop; }
+ // This can be called on a background thread.
+ using WorkItem = Function<void(void)>;
+ void scheduleWork(WorkItem&&);
private:
- Instance(NSRunLoop *);
+ Instance(WGPUScheduleWorkBlock);
- NSRunLoop *m_runLoop;
+ // This can be called on a background thread.
+ void defaultScheduleWork(WGPUWorkItem&&);
+
+ // This can be used on a background thread.
+ Deque<WGPUWorkItem> m_pendingWork WTF_GUARDED_BY_LOCK(m_lock);
+ WGPUScheduleWorkBlock m_scheduleWorkBlock;
+ Lock m_lock;
};
} // namespace WebGPU
Modified: trunk/Source/WebGPU/WebGPU/Instance.mm (291312 => 291313)
--- trunk/Source/WebGPU/WebGPU/Instance.mm 2022-03-15 21:17:33 UTC (rev 291312)
+++ trunk/Source/WebGPU/WebGPU/Instance.mm 2022-03-15 21:22:35 UTC (rev 291313)
@@ -29,26 +29,29 @@
#import "Adapter.h"
#import "Surface.h"
#import <cstring>
+#import <wtf/BlockPtr.h>
#import <wtf/StdLibExtras.h>
namespace WebGPU {
-static constexpr NSString *runLoopMode = @"kCFRunLoopWebGPUMode";
-
RefPtr<Instance> Instance::create(const WGPUInstanceDescriptor& descriptor)
{
- if (descriptor.nextInChain)
+ if (!descriptor.nextInChain)
+ return adoptRef(*new Instance(nullptr));
+
+ if (descriptor.nextInChain->sType != static_cast<WGPUSType>(WGPUSTypeExtended_InstanceCocoaDescriptor))
return nullptr;
- NSRunLoop *runLoop = NSRunLoop.currentRunLoop;
- if (!runLoop)
+ const WGPUInstanceCocoaDescriptor& cocoaDescriptor = reinterpret_cast<const WGPUInstanceCocoaDescriptor&>(*descriptor.nextInChain);
+
+ if (cocoaDescriptor.chain.next)
return nullptr;
- return adoptRef(*new Instance(runLoop));
+ return adoptRef(*new Instance(cocoaDescriptor.scheduleWorkBlock));
}
-Instance::Instance(NSRunLoop *runLoop)
- : m_runLoop(runLoop)
+Instance::Instance(WGPUScheduleWorkBlock scheduleWorkBlock)
+ : m_scheduleWorkBlock(scheduleWorkBlock ? WTFMove(scheduleWorkBlock) : ^(WGPUWorkItem workItem) { defaultScheduleWork(WTFMove(workItem)); })
{
}
@@ -61,17 +64,30 @@
return Surface::create();
}
+void Instance::scheduleWork(WorkItem&& workItem)
+{
+ m_scheduleWorkBlock(makeBlockPtr(WTFMove(workItem)).get());
+}
+
+void Instance::defaultScheduleWork(WGPUWorkItem&& workItem)
+{
+ LockHolder lockHolder(m_lock);
+ m_pendingWork.append(WTFMove(workItem));
+}
+
void Instance::processEvents()
{
- // NSRunLoops are not thread-safe, but then again neither is WebGPU.
- // If the caller does all the necessary synchronization themselves, this will be safe.
- // In that situation, we have to make sure we're using the run loop we were created on,
- // so tasks that were queued up on one thread actually get executed here, even if
- // this is executing on a different thread.
- BOOL result;
- do {
- result = [m_runLoop runMode:runLoopMode beforeDate:[NSDate date]];
- } while (result);
+ while (true) {
+ Deque<WGPUWorkItem> localWork;
+ {
+ LockHolder lockHolder(m_lock);
+ std::swap(m_pendingWork, localWork);
+ }
+ if (localWork.isEmpty())
+ return;
+ for (auto& workItem : localWork)
+ workItem();
+ }
}
static NSArray<id<MTLDevice>> *sortedDevices(NSArray<id<MTLDevice>> *devices, WGPUPowerPreference powerPreference)
Modified: trunk/Source/WebGPU/WebGPU/WebGPUExt.h (291312 => 291313)
--- trunk/Source/WebGPU/WebGPU/WebGPUExt.h 2022-03-15 21:17:33 UTC (rev 291312)
+++ trunk/Source/WebGPU/WebGPU/WebGPUExt.h 2022-03-15 21:22:35 UTC (rev 291313)
@@ -39,13 +39,26 @@
typedef void (^WGPUQueueWorkDoneBlockCallback)(WGPUQueueWorkDoneStatus status);
typedef void (^WGPURequestAdapterBlockCallback)(WGPURequestAdapterStatus status, WGPUAdapter adapter, char const * message);
typedef void (^WGPURequestDeviceBlockCallback)(WGPURequestDeviceStatus status, WGPUDevice device, char const * message);
+typedef void (^WGPUWorkItem)(void);
+typedef void (^WGPUScheduleWorkBlock)(WGPUWorkItem workItem);
typedef enum WGPUSTypeExtended {
WGPUSTypeExtended_ShaderModuleDescriptorHints = 0x348970F3, // Random
WGPUSTypeExtended_TextureDescriptorViewFormats = 0x1D5BC57, // Random
+ WGPUSTypeExtended_InstanceCocoaDescriptor = 0x151BBC00, // Random
WGPUSTypeExtended_Force32 = 0x7FFFFFFF
} WGPUSTypeExtended;
+typedef struct WGPUInstanceCocoaDescriptor {
+ WGPUChainedStruct chain;
+ // The API contract is: callers must call WebGPU's functions in a non-racey way with respect
+ // to each other. This scheduleWorkBlock will execute on a background thread, and it must
+ // schedule the block it's passed to be run in a non-racey way with regards to all the other
+ // WebGPU calls. It's fine to pass NULL here, but if you do, you must periodically call
+ // wgpuInstanceProcessEvents() to synchronously run the queued callbacks.
+ WGPUScheduleWorkBlock scheduleWorkBlock;
+} WGPUInstanceCocoaDescriptor;
+
typedef struct WGPUShaderModuleCompilationHint {
WGPUPipelineLayout layout;
} WGPUShaderModuleCompilationHint;
Modified: trunk/Source/WebKit/ChangeLog (291312 => 291313)
--- trunk/Source/WebKit/ChangeLog 2022-03-15 21:17:33 UTC (rev 291312)
+++ trunk/Source/WebKit/ChangeLog 2022-03-15 21:22:35 UTC (rev 291313)
@@ -1,3 +1,16 @@
+2022-03-15 Myles C. Maxfield <[email protected]>
+
+ [WebGPU] Allow for scheduling asynchronous work
+ https://bugs.webkit.org/show_bug.cgi?id=237755
+
+ Reviewed by Kimmo Kinnunen.
+
+ * GPUProcess/graphics/WebGPU/RemoteGPU.cpp:
+ (WebKit::RemoteGPU::workQueueInitialize):
+ (WebKit::RemoteGPU::workQueueUninitialize):
+ * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+ (WebKit::WebChromeClient::createGPUForWebGPU const):
+
2022-03-15 Chris Dumez <[email protected]>
Fix logging in GPUProcessProxy::didCreateContextForVisibilityPropagation()
Modified: trunk/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteGPU.cpp (291312 => 291313)
--- trunk/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteGPU.cpp 2022-03-15 21:17:33 UTC (rev 291312)
+++ trunk/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteGPU.cpp 2022-03-15 21:22:35 UTC (rev 291313)
@@ -79,7 +79,14 @@
{
assertIsCurrent(workQueue());
#if HAVE(WEBGPU_IMPLEMENTATION)
- auto backing = PAL::WebGPU::GPUImpl::create();
+ // BEWARE: This is a retain cycle.
+ // this owns m_backing, but m_backing contains a callback which has a stong reference to this.
+ // The retain cycle is required because callbacks need to execute even if this is disowned
+ // (because the callbacks handle resource cleanup, etc.).
+ // The retain cycle is broken in workQueueUninitialize().
+ auto backing = PAL::WebGPU::GPUImpl::create([protectedThis = Ref { *this }](PAL::WebGPU::GPUImpl::WorkItem&& workItem) {
+ protectedThis->workQueue().dispatch(WTFMove(workItem));
+ });
#else
RefPtr<PAL::WebGPU::GPU> backing;
#endif
@@ -95,6 +102,7 @@
assertIsCurrent(workQueue());
m_streamConnection = nullptr;
m_objectHeap->clear();
+ m_backing = nullptr;
}
void RemoteGPU::requestAdapter(const WebGPU::RequestAdapterOptions& options, WebGPUIdentifier identifier, WTF::CompletionHandler<void(std::optional<RequestAdapterResponse>&&)>&& callback)
Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp (291312 => 291313)
--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp 2022-03-15 21:17:33 UTC (rev 291312)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp 2022-03-15 21:22:35 UTC (rev 291313)
@@ -957,7 +957,9 @@
#if ENABLE(GPU_PROCESS)
return RemoteGPUProxy::create(WebProcess::singleton().ensureGPUProcessConnection(), WebGPU::DowncastConvertToBackingContext::create(), WebGPUIdentifier::generate(), m_page.ensureRemoteRenderingBackendProxy().ensureBackendCreated());
#else
- return PAL::WebGPU::GPUImpl::create();
+ return PAL::WebGPU::GPUImpl::create([](PAL::WebGPU::GPUImpl::WorkItem&& workItem) {
+ callOnMainRunLoop(WTFMove(workItem));
+ });
#endif
#else
return nullptr;
Modified: trunk/Source/WebKitLegacy/mac/ChangeLog (291312 => 291313)
--- trunk/Source/WebKitLegacy/mac/ChangeLog 2022-03-15 21:17:33 UTC (rev 291312)
+++ trunk/Source/WebKitLegacy/mac/ChangeLog 2022-03-15 21:22:35 UTC (rev 291313)
@@ -1,3 +1,13 @@
+2022-03-15 Myles C. Maxfield <[email protected]>
+
+ [WebGPU] Allow for scheduling asynchronous work
+ https://bugs.webkit.org/show_bug.cgi?id=237755
+
+ Reviewed by Kimmo Kinnunen.
+
+ * WebCoreSupport/WebChromeClient.mm:
+ (WebChromeClient::createGPUForWebGPU const):
+
2022-03-15 Wenson Hsieh <[email protected]>
[macOS] Tooltip no longer disappears after leaving hovered element
Modified: trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm (291312 => 291313)
--- trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm 2022-03-15 21:17:33 UTC (rev 291312)
+++ trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm 2022-03-15 21:22:35 UTC (rev 291313)
@@ -1163,7 +1163,9 @@
RefPtr<PAL::WebGPU::GPU> WebChromeClient::createGPUForWebGPU() const
{
#if HAVE(WEBGPU_IMPLEMENTATION)
- return PAL::WebGPU::GPUImpl::create();
+ return PAL::WebGPU::GPUImpl::create([](PAL::WebGPU::GPUImpl::WorkItem&& workItem) {
+ callOnMainRunLoop(WTFMove(workItem));
+ });
#else
return nullptr;
#endif