RESOLVED FIXED 237755
[WebGPU] Allow for scheduling asynchronous work
https://bugs.webkit.org/show_bug.cgi?id=237755
Summary [WebGPU] Allow for scheduling asynchronous work
Myles C. Maxfield
Reported 2022-03-10 21:36:42 PST
[WebGPU] Allow for scheduling asynchronous work
Attachments
Patch (14.01 KB, patch)
2022-03-10 21:52 PST, Myles C. Maxfield
no flags
Patch (16.21 KB, patch)
2022-03-14 00:59 PDT, Myles C. Maxfield
no flags
Patch (15.81 KB, patch)
2022-03-14 14:57 PDT, Myles C. Maxfield
kkinnunen: review+
Myles C. Maxfield
Comment 1 2022-03-10 21:52:27 PST
Myles C. Maxfield
Comment 2 2022-03-13 22:54:25 PDT
Comment on attachment 454444 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=454444&action=review > Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.cpp:52 > + scheduleWorkFunction(WTFMove(workItem)); This is a UAF. scheduleWorkFunction refers to the reference, not the function itself.
Myles C. Maxfield
Comment 3 2022-03-14 00:59:44 PDT
Kimmo Kinnunen
Comment 4 2022-03-14 06:44:09 PDT
Comment on attachment 454566 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=454566&action=review Sorry for not understanding the system.. Initially I don't understand the distinction: WGPUWorkItem -- I see this as a task coming from wgpu and webkit executing it. WorkItem -- I see this as a task coming from WebKit going to wgpu, which initially doesn't make sense. Why would we ask wgpu to invoke this item, why wouldn't we just invoke it? Is it then coming back as WGPUWorkItem for ordering reasons? > Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.cpp:50 > + ScheduleWorkFunction localScheduleWorkFunction = WTFMove(scheduleWorkFunction); scheduleWorkFunction is a block-equivalent.. > Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.cpp:57 > + ^(WGPUWorkItem workItem) this is a block.. > Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.cpp:59 > + localScheduleWorkFunction(makeBlockPtr(workItem)); makeBlockPtr makes a block.. workItem is a block.. Maybe there's now some nested blocks that don't need to be blocks? > Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.h:45 > + // and anything captured by a block needs to be copyable. I think this is now somehow mixed, or I'm not undertstanding everything. We capture WTF::Functions as blocks via makeBlockPtr in WorkQueueCocoa.mm. > Source/WebGPU/WebGPU/Instance.h:53 > + using WorkItem = std::function<void(void)>; This appears to be somehow redundant? If the work is sent by WGPU as WGPUWorkItem, then WebKit should just be able to apply it via WGPUWorkItem and no need to wrap it redundantly in std::function?
Myles C. Maxfield
Comment 5 2022-03-14 10:48:51 PDT
Comment on attachment 454566 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=454566&action=review >> Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.cpp:59 >> + localScheduleWorkFunction(makeBlockPtr(workItem)); > > makeBlockPtr makes a block.. > > workItem is a block.. > > Maybe there's now some nested blocks that don't need to be blocks? Yeah, let me see if I can get rid of some. >> Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.h:45 >> + // and anything captured by a block needs to be copyable. > > I think this is now somehow mixed, or I'm not undertstanding everything. > We capture WTF::Functions as blocks via makeBlockPtr in WorkQueueCocoa.mm. Good point! Let me investigate more. >> Source/WebGPU/WebGPU/Instance.h:53 >> + using WorkItem = std::function<void(void)>; > > This appears to be somehow redundant? > > If the work is sent by WGPU as WGPUWorkItem, then WebKit should just be able to apply it via WGPUWorkItem and no need to wrap it redundantly in std::function? These exists for layering. The WGPU types shouldn't exist outside WebCore/PAL/pal/graphics/WebGPU/Impl.
Myles C. Maxfield
Comment 6 2022-03-14 14:57:37 PDT
Myles C. Maxfield
Comment 7 2022-03-14 15:01:21 PDT
Comment on attachment 454566 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=454566&action=review >>> Source/WebGPU/WebGPU/Instance.h:53 >>> + using WorkItem = std::function<void(void)>; >> >> This appears to be somehow redundant? >> >> If the work is sent by WGPU as WGPUWorkItem, then WebKit should just be able to apply it via WGPUWorkItem and no need to wrap it redundantly in std::function? > > These exists for layering. The WGPU types shouldn't exist outside WebCore/PAL/pal/graphics/WebGPU/Impl. Oh, whoops, I was confused when I made this comment ☝️. The reason is because I prefer using C++ lambdas wherever possible because they are more expressive than C blocks (e.g. lambdas can be moved from, etc.). So, internally to the framework, I'm using lambdas, and they get converted to block pointers at framework boundaries.
Kimmo Kinnunen
Comment 8 2022-03-15 02:32:58 PDT
Comment on attachment 454624 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=454624&action=review > Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.cpp:48 > + scheduleWorkFunction(makeBlockPtr(workItem)); WGPUWorkItem is a block, so it shouldn't need to be wrapped in a block? Also, the call could move the `workItem`.. > Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.h:44 > + using ScheduleWorkFunction = Function<void(WorkItem&&)>; > The reason is because I prefer using C++ lambdas wherever possible because they are more expressive than C blocks (e.g. lambdas can be moved from, etc.). So, internally to the framework, I'm using lambdas, and they get converted to block pointers at framework boundaries. The ScheduleWorkFunction will not move anything from WorkItem (which wrapsWGPUWorkItem) . It won't move anything out of WGPUWorkItem either, as that is just a block pointer (opaque function with context.) WorkItem cannot be used in any other way than called. So you are redundantly wrapping the WGPUWorkItem call inside a redundant call. I think it's ok if your requirements are: 1) Not expose that blocks exist in this layer of the SW stack (sw layer == WebKit WebGPU client) 2) Not expose WGPU* types in this layer of the SW stack However, since both of these are given forever in WebKit, having the extra indirection forever sounds silly. I'd imagine WGPU* types are like uint32_t types: they're the fundamental types this particular implementation is being built on.
Kimmo Kinnunen
Comment 9 2022-03-15 05:56:29 PDT
Comment on attachment 454624 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=454624&action=review > Source/WebGPU/WebGPU/Instance.h:54 > + void scheduleWork(WorkItem&&); In fact, if you keep this as a wrapped thingy, then your "WorkItem" could be a CompletionHandler. E.g. Function == "I give this to you and you may call this once or more times" CompletionHandler = "I give this to you and you may call this once" This will come up in later patches, where you hold list of items. > Source/WebGPU/WebGPU/Instance.mm:89 > + workItem(); Example iteration related to the CompletionHandler if you have 700 items in the list, it may be desired for the very nit-picker client that the closures held by each of the functions are discarded as soon as they're not needed, e.g. immediately after called. CompletionHandler expresses this.
Myles C. Maxfield
Comment 10 2022-03-15 13:31:53 PDT
Comment on attachment 454624 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=454624&action=review >> Source/WebGPU/WebGPU/Instance.h:54 >> + void scheduleWork(WorkItem&&); > > In fact, if you keep this as a wrapped thingy, then your "WorkItem" could be a CompletionHandler. > E.g. > Function == "I give this to you and you may call this once or more times" > CompletionHandler = "I give this to you and you may call this once" > > This will come up in later patches, where you hold list of items. Yes, CompletionHandler is a great idea. Asynchronous functions will take a CompletionHandler, whereas functions like Device::setUncapturedErrorCallback() will take a Function.
Myles C. Maxfield
Comment 11 2022-03-15 13:34:47 PDT
Comment on attachment 454624 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=454624&action=review >>> Source/WebGPU/WebGPU/Instance.h:54 >>> + void scheduleWork(WorkItem&&); >> >> In fact, if you keep this as a wrapped thingy, then your "WorkItem" could be a CompletionHandler. >> E.g. >> Function == "I give this to you and you may call this once or more times" >> CompletionHandler = "I give this to you and you may call this once" >> >> This will come up in later patches, where you hold list of items. > > Yes, CompletionHandler is a great idea. Asynchronous functions will take a CompletionHandler, whereas functions like Device::setUncapturedErrorCallback() will take a Function. I started migrating to CompletionHandler, but it's ending up being bigger than the original patch, so I'll separate this migration to a follow-up patch.
Myles C. Maxfield
Comment 12 2022-03-15 13:38:20 PDT
(In reply to Kimmo Kinnunen from comment #8) > The ScheduleWorkFunction will not move anything from WorkItem (which > wrapsWGPUWorkItem) . It won't move anything out of WGPUWorkItem either, as > that is just a block pointer (opaque function with context.) WorkItem cannot > be used in any other way than called. > > So you are redundantly wrapping the WGPUWorkItem call inside a redundant > call. > > I think it's ok if your requirements are: > 1) Not expose that blocks exist in this layer of the SW stack (sw layer == > WebKit WebGPU client) > 2) Not expose WGPU* types in this layer of the SW stack > > However, since both of these are given forever in WebKit, having the extra > indirection forever sounds silly. > I'd imagine WGPU* types are like uint32_t types: they're the fundamental > types this particular implementation is being built on. Yeah, I think this is kind of important for layering - I think both your 1) and 2) are true. I think I disagree about the comparison with uint32_t - that is clearly shared among many libraries and layers, whereas WGPU is just an implementation detail. And, since the source comes from a WTF::BlockPtr, copying to a second WTF::BlockPtr is free - it doesn't copy the context.
Myles C. Maxfield
Comment 13 2022-03-15 13:39:16 PDT
Comment on attachment 454624 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=454624&action=review >> Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUImpl.cpp:48 >> + scheduleWorkFunction(makeBlockPtr(workItem)); > > WGPUWorkItem is a block, so it shouldn't need to be wrapped in a block? > Also, the call could move the `workItem`.. Can you describe what you mean by "it shouldn't need to be wrapped in a block?"
Myles C. Maxfield
Comment 14 2022-03-15 13:40:28 PDT
I'm going to land this making the adjustments that I can, make a follow-up patch about CompletionHandler, and then make another follow-up patch according to Kimmo's yet-to-be-made comments when he makes them.
Myles C. Maxfield
Comment 15 2022-03-15 14:22:59 PDT
Radar WebKit Bug Importer
Comment 16 2022-03-15 14:23:24 PDT
Myles C. Maxfield
Comment 17 2022-03-15 14:24:02 PDT
Leaving bug open because there's more discussion to be had.
Myles C. Maxfield
Comment 18 2022-03-15 15:35:40 PDT
Comment on attachment 454624 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=454624&action=review >>>> Source/WebGPU/WebGPU/Instance.h:54 >>>> + void scheduleWork(WorkItem&&); >>> >>> In fact, if you keep this as a wrapped thingy, then your "WorkItem" could be a CompletionHandler. >>> E.g. >>> Function == "I give this to you and you may call this once or more times" >>> CompletionHandler = "I give this to you and you may call this once" >>> >>> This will come up in later patches, where you hold list of items. >> >> Yes, CompletionHandler is a great idea. Asynchronous functions will take a CompletionHandler, whereas functions like Device::setUncapturedErrorCallback() will take a Function. > > I started migrating to CompletionHandler, but it's ending up being bigger than the original patch, so I'll separate this migration to a follow-up patch. https://bugs.webkit.org/show_bug.cgi?id=237925 [WebGPU] Migrate from WTF::Function to WTF::CompletionHandler
Kimmo Kinnunen
Comment 19 2022-03-16 05:40:44 PDT
workItem needs makeBlockPtr
Note You need to log in before you can comment on or make changes to this bug.