Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add better async support for wgpu-native #609

Merged
merged 5 commits into from
Oct 2, 2024
Merged

Add better async support for wgpu-native #609

merged 5 commits into from
Oct 2, 2024

Conversation

almarklein
Copy link
Member

@almarklein almarklein commented Oct 1, 2024

Relates to #391

This PR adds support for true async behavior for wgpu-native, to the extend that this is implemented in wgpu-native.

What this does

  • Implements WgpuWaitable as a basic component to use for async methods.
  • Apply it to the async methods where possible.

Notes

  • The request_adapter() and request_device() are not really async in native (only in wasm/remote implementations?)
  • The wgpuDeviceCreateRenderPipelineAsync is not yet implemented 🤷
  • Amongst the stuff that we have not yet implemented are also a few async ones.
  • So the only real async version is buffer.map_async().
  • The API for async methods in webgpu.h is in the process of being changed, so we will have to modify the code later, but it will likely be good that we have our basics in place. See below.

The new upcoming wgpu-native API

(Also added this info to #391)

In the new API, wgpu-native methods that are async will return a "GPUFuture". This future can be polled (similar to what we do now), and there will be a call to wait for the future: wgpuInstanceWaitAny(). The latter, however, won't help make it async in Python. There is an idea for an API to expose OS-level constructs so proper integration with an event loop is possible.

@almarklein
Copy link
Member Author

Is there no way to register a callback on is_done? That way you could get rid of the busy loop.

I'm answering this in the mean comments, since I want to be able to read back what I write later 😄

Good question. The short answer is no. Such an API would require wgpu-native to run a separate thread or something, which will introduce other complications, which is why they did not go this route.

The longer answer: in (probably) the next release of wgpu-native, we can use wgpuInstanceProcessEvents() which will fire the callbacks when they're done. So as long as we make sure that method is called periodically, we can kindof have that. For example by using the trick that asyncio.sleep uses (https://github.com/python/cpython/blob/9ce90206b7a4649600218cf0bd4826db79c9a312/Lib/asyncio/tasks.py#L688-L705):

  • We create and return an asyncio.Future
  • In the callbacks, we can do loop.call_soon(set_that_features_result)

One problem with the above: it'd bind us to asyncio. We can investigate whether a framework agnostic method is possible.

But in the end, the current solution works pretty well. Yes, it turns your CPU to 100%, but the wait time for these functions is typically very short, and other async tasks can run while this happens.

BTW: I also added a section in the top comment on the upcoming API, with links to docs that explain it.

@almarklein almarklein mentioned this pull request Oct 2, 2024
10 tasks
@almarklein almarklein marked this pull request as ready for review October 2, 2024 08:52
@almarklein
Copy link
Member Author

I am updating the examples so cube.py can touch buffer.map_async(), but it needs some refactoring so I'll post that in a separate PR.

@almarklein almarklein marked this pull request as draft October 2, 2024 08:53
@almarklein
Copy link
Member Author

Oh, I have a codegen issue to fix before this can be merged.

@Korijn
Copy link
Collaborator

Korijn commented Oct 2, 2024

Well, good to hear some improvement is coming later on. Futures are designed to solve this problem specifically. All we need is a callback to resolve the future. :)

@almarklein almarklein marked this pull request as ready for review October 2, 2024 11:08
@almarklein almarklein merged commit 95d01d9 into main Oct 2, 2024
20 checks passed
@almarklein almarklein deleted the async-native branch October 2, 2024 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants