Skip to content

Adding missing enums to FeatureName and CanvasAlphaMode. #719

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

anadodik
Copy link

@anadodik anadodik commented Jun 1, 2025

Hi friends,

Please let me know if I am missing something in this PR! I tried going through the how-to-contribute docs but it's highly likely I missed something.

I ran into an issue where unpremultiplied was the only canvas alpha mode available on my Mac, but the check on line 350 of _classes.py inside of GPUCanvasConfigure would fail. Adding this to the enum fixes it and I am able to use alpha blending.

I also had to use texture-adapter-specific-format-features to enable multisampling on f32 textures. Using the string works, but I figured I'd add it too since I am changing things.

Looking forward to feedback!

Best,
Ana

@anadodik anadodik requested a review from Korijn as a code owner June 1, 2025 23:25
@Vipitis
Copy link
Contributor

Vipitis commented Jun 2, 2025

hey,

I had a look and I believe the issue might actually be related to this line

c_alpha_mode = getattr(lib, f"WGPUCompositeAlphaMode_{alpha_mode.capitalize()}")
perhaps we shouldn't just check against the CanvasAlphaModes in _classes.

Can you check what capabilities your canvas/adapter return?

import wgpu
from wgpu.gui.auto import WgpuCanvas

canvas = WgpuCanvas()
adapter = wgpu.gpu.request_adapter_sync()
context = canvas.get_context("wgpu")
capabilities = context._get_capabilities(adapter)

print(capabilities)

as for the changes. .idl is an external file - so it can't be edited. Differences are marked in ._classes.py with @apidiff

texture-adapter-specific-format-features is a native only feature, so it will not be part of the .idl and instead is from the external file wgpu.h. It does exist in _mappings.py under "NativeFeature" so should be requestable from there.

@almarklein
Copy link
Member

ran into an issue where unpremultiplied was the only canvas alpha mode available on my Mac

That's odd 🤔

So it looks like "unpremultiplied" is referenced in webgpu.h, but not in the webgpu spec. I'm not sure if this is a deliberate difference, or that the spec simply has not caught up yet.

I don't think there's a super-elegant way to fix this, but we should make sure that things can work on machine such as yours. I think @Vipitis's idea makes sense. In _classes.py:

-        if alpha_mode not in enums.CanvasAlphaMode:
+        if not (alpha_mode in enums.CanvasAlphaMode or alpha_mode in ["unpremultiplied"]}:


I'm thinking that if "opaque" is used, but it's not in `capabilities["alpha_modes"]`, maybe we should fallback to an alpha mode that is supported, and print a warning. What do you think @Vipitis ?

@Vipitis
Copy link
Contributor

Vipitis commented Jun 2, 2025

I am more wondering how you get a difference between CompositeAlphaMode and CanvasAlphaMode in the first place, I suspect it is a screen vs off screen thing. Maybe there is some discussion upstream that gives insight. Or it could be specifically related to the native feature needing it.

Alpha blending is one of these cases where you get undefined behavior by some GPU vendors and even spec violations. So being a little more lenient might be the way to go.

@anadodik
Copy link
Author

anadodik commented Jun 2, 2025

Thanks for such a quick reply!

Can you check what capabilities your canvas/adapter return?

Yes, this is the query that made me think there is a missing field in CanvasAlphaModes, here is the output:

{'usages': 17, 'formats': ['bgra8unorm-srgb', 'bgra8unorm', 'rgba16float', 'rgb10a2unorm'], 'alpha_modes': ['opaque', 'unpremultiplied'], 'present_modes': ['fifo', 'immediate'], 'view_formats': ['bgra8unorm-srgb', 'bgra8unorm', 'rgba16float', 'rgb10a2unorm']}

For the record, I'm on a 2022 M2 Mac Air running Ventura 13.4.

texture-adapter-specific-format-features is a native only feature, so it will not be part of the .idl and instead is from the external file wgpu.h. It does exist in _mappings.py under "NativeFeature" so should be requestable from there.

Oh, thanks! I wasn't able to run into this casually digging through the code, do you think there is some way to make it more discoverable?

I think @Vipitis's idea makes sense. In _classes.py:

This works on my machine too---happy to change the diff to this if y'all say it's the way to go.

@Vipitis
Copy link
Contributor

Vipitis commented Jun 2, 2025

Oh, thanks! I wasn't able to run into this casually digging through the code, do you think there is some way to make it more discoverable?

I think a good explanation is given in the codegen readme: https://github.com/pygfx/wgpu-py/blob/main/codegen/README.md

After spending maybe 100 hours in this codebase doing the updates I feel like I understand most of it by now. It helps to see the separation between the webgpu front such as _classes.py and enums.py and the actual implementation/backend with wgpu-native in the files _api.py and _mappings.py. There is a ton of code generation going on for writing some files completely, adding header comments and making sure structs are filled. You will usually end up in _classes.py if you follower your editors "jump to definition" which can be confusing since that's not really where the interesting stuff happens. I am no LSP expert but we might be able to improve these links, as we added type hints just a little ago.
The webgpu enums are defined in the .idl but the actual values are in the webgpu.h headerfile. So the codegen will write to multiple files for each enum (and flag). However additional enums/flags for native only features (meaning the wgpu implementation/backend specific) are just defined in wgpu.h and not all of them will be made into enums and none of them will be made flags. Here is where we manually add some enums to be included:

# Write a few native-only mappings: key => int

I ran into this myself the other day, perhaps we can find a way to include all native only flags and enums without needing to manually whitelist them there. But some of the names are nearly the same and could be confusing.

I hope this helps a little, maybe if you can share which direction your code digging went - maybe that can help to improve the documentation.

@almarklein
Copy link
Member

[...] 'alpha_modes': ['opaque', 'unpremultiplied'],

Oh, glad to see 'opqaue' is in there 😅 I initially misread that you meant 'unpremultiplied' was the only one.

To provide some context on API 'discoverability'; the idea is that we stick to the WebGPU spec for the main API, and users can include native-specific features from wgpu.backends.wgpu_native. But this case is a little different, because (apparently) the windowing layer may not always support the alpa modes that WebGPU specified (opaque and premultiplied).

perhaps we can find a way to include all native only flags and enums without needing to manually whitelist them there. But some of the names are nearly the same and could be confusing.

Yeah, also these cases are rare, and tend to be edge-cases that are each special in their own way, so I guess just local whitelisting is the easiest way 🤷

This works on my machine too---happy to change the diff to this if y'all say it's the way to go.

Thanks for testing. That would be great!

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.

3 participants