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

Docs: Extensions #482

Merged
merged 5 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions doc/articles/Extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Extensions {#Extensions}

`webgpu.h` is designed to be an extensible and forward-compatible API.
The following types of extensions are supported:

```
wgpuPrefixNewFunction

WGPUPrefixNewObject
wgpuPrefixNewObjectNewMethod
wgpuOldObjectPrefixNewMethod

WGPUPrefixNewEnum
WGPUPrefixNewEnum_NewValue
WGPUOldEnum_PrefixNewValue

WGPUPrefixNewStruct

WGPUPrefixNewBitflagType
WGPUPrefixNewBitflagType_NewValue
WGPUOldBitflagType_PrefixNewValue

WGPUPrefixNewCallback

WGPU_PREFIX_NEW_CONSTANT
```

("Prefix" is the name of the implementation that owns the extension, if any; see below.)

When an application is running against an unknown `webgpu.h` implementation, extension support may be detected at runtime as follows:

- New functions/methods may be detected via @ref wgpuGetProcAddress().
kainino0x marked this conversation as resolved.
Show resolved Hide resolved
- New objects may be detected by the presence of the methods that create them.
- New (root) structs and callback types are only relevant if the methods that accept them exist.
- New enums, bit flags, [chained structs](@ref StructChaining) are available iff enabled. Like other features, these must be both detected and enabled:
kainino0x marked this conversation as resolved.
Show resolved Hide resolved
- Device features are detected via @ref wgpuAdapterGetFeatures() and enabled via @ref WGPUDeviceDescriptor::requiredFeatures.
- Instance features are detected via @ref wgpuGetInstanceCapabilities() and enabled via @ref WGPUInstanceDescriptor::capabilities.

The following design principles should be followed to ensure future extensibility:

- Enums always have a `Force32 = 0x7FFFFFFF` value to force them to be 32-bit (and have a stable ABI representation).
- Bitflag types are always 64-bit.
- Structures should be extensible (have a `nextInChain`), or at least be associated with some struct (e.g. child, sibling, or parent) that is extensible.

Note also:

- Whenever necessary a version `2` or implementation-specific version of an existing method or type can be added.

## Registry of prefixes and enum blocks

Implementation extensions **should**, and multi-implementation extensions **must**, use the naming conventions listed above with the prefixes listed here.

Implementation-specific and multi-implementation extensions **must** not use block `0x0000_????` when adding values to existing enums.

| | Prefix | Enum Block | Description
|--------------------|--------------|---------------|------------
| Core | (none) | `0x0000_????` | Extensions that are required to implement (e.g. added after 1.0).
| Multi-Vendor | (none) | `0x0001_????` | Extensions that are optional to implement (e.g. platform-specific extensions). *TBD if enum values in this block may become required, or if they would be aliased into block `0x0000_????` first.*
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a question buried here which I noticed in #417 and then completely forgot about.

Should the new enums really use block 0x0001? Seems like if we ever put this stuff in "core" they could use the same enums, would we then duplicate them into block 0x0000 or just use the block 0x0001 values? Or should we just put them in block 0x0000 to start?

Ugh. Can't keep track of all this minutiae.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cwfitzgerald any thoughts? (no rush, I'm ~out until Jan)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe stupid question... but would it be possible to just renumber an enum if it gets promoted? Would that be a breaking change? (I guess it COULD be if someone is using the actual value of the enum or if we have different header versions in a wire situation?) I'm just wondering how much breakage it could cause and whether we could just promote them and say here that we may do that so don't rely on the actual value of the enums.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could say that the value is not API stable, but for ABI stability, we can't just renumber. We can do it if we reserve and implement both the old and new numbers (even though only one is in any given version of the header) but that's kinda obtuse.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok makes sense! Though honestly, the more than one number thing doesn't sound TOO bad IMO.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the problem here is lack of prefixing. If it were WGPUSType_DawnNewThing = 0x0005_0004 we could easily duplicate it as WGPUSType_NewThing = 0x0000_00A3. But since these are unprefixed we can't duplicate, we can only renumber. But the implementation still needs to handle old numbers that now have no name. We could give them a name with something like:
WGPUSType_NewThing = 0x0001_0004
->
WGPUSType_NewThing = 0x0000_00A3
WGPUSType_OldNameForNewThing = 0x0001_0004

... but I think that's worse than the other two options:

  • Give optional extensions a prefix (like Ext) and remove it when making core (which has a questionable benefit of being able to change the behavior when making it core, though I would avoid doing that)
  • Merge blocks 0 and 1 and just use documentation to indicate which things are required and which are not

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ ... or what would happen by default if we didn't change anything:

  • Keep blocks 0 and 1 but with the possibility that some things in block 1 end up being required. This is honestly fine and I think we can just go with it.

Actually thinking about the scenario in which this actually happens, it would have to be a multi-vendor extension (meaning we standardized it) which we initially thought would be optional but later became required. I think the most likely case of this is something that's multi-vendor, but we're not sure it's going to show up in the JS API, and then it does. (Like, if the JS API got SPIR-V support somehow, or we decided it was critical to polyfill, then WGPUShaderSourceSPIRV could become required.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed #490

| Compatibility Mode | *TBD* | `0x0002_????` | **Special:** implementations that don't support Compatibility Mode must ignore any chained structs with @ref WGPUSType values in this block, instead of erroring. This block must only be used for Compat additions that can be ignored without affecting the semantics of a non-erroring program.
| wgpu-native | `Wgpu` | `0x0003_????` |
| Emscripten | `Emscripten` | `0x0004_????` |
| Dawn | `Dawn` | `0x0005_????` |

## Registry of extension bit flag values

Implementation-specific and multi-implementation extensions **should** (*TBD: **must**?*) register new bit flag values of existing bit flag types here.

Core and Compatibility Mode bits will always be in the least-significant 53 bits, because the JS API can only represent 53 bits.
Therefore, extended bit flag values **should** be in the most-significant 11 bits, overflowing into the most-significant end of the least-significant 53 bits if necessary (or avoiding doing so by adding a new bit flag type entirely).

- (None have been registered yet!)
1 change: 1 addition & 0 deletions doc/articles/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- \subpage Asynchronous-Operations
- \subpage Errors
- \subpage Extensions
- \subpage Ownership
- \subpage Surfaces
- \subpage SentinelValues
Expand Down
Loading