-
-
Notifications
You must be signed in to change notification settings - Fork 50
[WIP] js_webgpu backend prototype #753
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
base: main
Are you sure you want to change the base?
Conversation
|
there are were many headaches around the type conversion which aren't well documented... but I got to the cube in the end. self._internal.getMappedRange(offset=js_offset, size=data.nbytes)vs self._internal.getMappedRange(0, size)And the error you get is about browser_cube.mp4I will hopefully find some more time this coming week to continue and maybe get some more interesting examples to run (pygfx?/fastplotlib?). |
|
super exciting to get imgui working with a few tweaks imgui_example.mp4cc @pthom thanks a lot for your article I read a few weeks ago, that motivated me to give it a try here! |
|
@Vipitis : many thanks for the info, that looks very promising. Please keep me in the loop! |
|
I was expecting codegen to come a long way here. The codegen knows when the arguments of a function were actually wrapped in a dict in IDL, so we can generate the code to reconstruct the dict before passing it to the JS WebGPU API call. |
|
I also think that codegen can do a lot, I just need to give it a try. The def some_function(self, *args, **kwargs):
js_args = to_js(args, eager_converter=js_acccessor)
js_kwrags = to_js(kwargs, eager_converter=js_accessor, dict_converter=Object.from_entries)
self._internal.someFunction(*js_args, js_kwargs) |
|
Whatever way this goes, what I care most about, is that when the IDL changes for a certain method, it will place some FIXME comment in the code for the JS backend, so that we won't forget to update that method there. |
|
I feel like I have finally moved passt all the headaches and found a "general" approach to most functions. I switched to the pyodide dev branch as the upcoming 0.29 release makes changes to how dictionaries are converted... which has been a ton of pain and the upcoming version seems to work much better. I couldn't find any release timeline so it might still be month until there is a release... Also got started with a codegen prototype and I am feeling confident this is largely going to work, depends on how much time I find in the coming week. There was also some weirdness with css scaled canvas for click events and resizing with the imgui example - so the rendercanvas PR likely needs some more fixes, I will see if I can find time for that too. |
|
|
||
| # basically three cases for methods (from idl+apidiff): | ||
| # 1. alreayd exists in _classes.py and can be used as is (generate nothing) | ||
| # 2. custom implementation in _implementations.py (copy string over) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
two way too long evenings but I reached a codegen approach that works... but it feels really awkward and I am not happy with it. Still needs more patcher integration etc; but this finally allows autogeneration as well as custom implementations to be imported correctly.
(newest commit should be running the examples again)
|
apart from the imgui_backend example this works again with all the changes of todays rendercanvas and wgpu releases. Still needs the physical size most likely. I will only find time on Friday the earliest to look into the timestamp query problem and writing a proper patcher. I will try to add the remaining todos at the top when I find time tomorrow. |
| class GPUCanvasContext(classes.GPUCanvasContext, ): | ||
|
|
||
| # Custom implementation for configure from _implementation.py: | ||
| def configure(self, **kwargs): | ||
| descriptor = structs.CanvasConfiguration(**kwargs) | ||
| js_descriptor = to_js(descriptor, eager_converter=simple_js_accessor) | ||
|
|
||
| self._internal.configure(js_descriptor) | ||
| self._config = { | ||
| "device": kwargs.get("device"), | ||
| "format": kwargs.get("format"), | ||
| "usage": kwargs.get("usage", 0x10), | ||
| "view_formats": kwargs.get("view_formats", ()), | ||
| "color_space": kwargs.get("color_space", "srgb"), | ||
| "tone_mapping": kwargs.get("tone_mapping", None), | ||
| "alpha_mode": kwargs.get("alpha_mode", "opaque"), | ||
| } | ||
|
|
||
| def unconfigure(self) -> None: | ||
| self._internal.unconfigure() | ||
|
|
||
| # TODO: implement codegen for getConfiguration with args [] or return type GPUCanvasConfiguration? | ||
| # Custom implementation for getCurrentTexture from _implementation.py: | ||
| def get_current_texture(self) -> GPUTexture: | ||
| js_texture = self._internal.getCurrentTexture() | ||
|
|
||
| label = "" # always empty? | ||
| return GPUTexture(label, js_texture, self._config["device"]) | ||
|
|
||
| # Additional custom methods from _implementation.py: | ||
| def __init__(self, present_info: dict): | ||
| super().__init__(present_info) | ||
| canvas_element = present_info["window"] | ||
| self._internal = canvas_element.getContext("webgpu") | ||
|
|
||
| def get_preferred_format(self, adapter: GPUAdapter | None) -> enums.TextureFormat: | ||
| return gpu._internal.getPreferredCanvasFormat() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
|
again, @almarklein feel free to take over the branch if you have the capacity. I hope the current state isn't too messy 😬 |
Thanks! For the time being I have other priorities. But this is nevertheless super-interesting so I definitely want to get this in at some point! |
Remaining todos:
jswriter.pyas aPatcherand add the comment injectornew weekend, new project...
I think there is two options to get wgpu-py into the browser: compile wgpu-native for wasm and package that, or call the js backend directly. I run into compilation errors with the rust code, so gave up there... but:
basically autocompleted my way through errors to see what kind of patterns are needed... everything around moving data requires more effort. While pyodide provides some functions, they feel buggy and unpredictable.
It is likely possible to codegen the vast majority of this and then fix up all the api diff - might get to that over the next few days.
structs have potential to make this easier.
I changed some of the examples to auto layout since I couldn't get
.create_bindgroup_layout()to work - and you don't need it with auto layout.works with pygfx/rendercanvas#115

couldn't get the cube example to work just yet, but triangle does - so the potential is there
more to come