Skip to content

wgpu-core implementation for external textures #7823

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 5 commits into
base: trunk
Choose a base branch
from

Conversation

jamienicol
Copy link
Contributor

Connections
Depends on #7822
Part of #4386

Description
Add wgpu and wgpu-core implementation for external texture. wgpu-hal and naga implementations to follow, so for now this isn't particularly useful. But it does work with the noop backend, as can be seen in the added validation tests

Testing
Noop backend validation tests. Local testing. CTS testing can follow when more pieces are in place.

Squash or Rebase?

Rebase. If there are fixup! commits after review then squash them into the appropriate commit first

Checklist

  • Run cargo fmt.
  • Run taplo format.
  • Run cargo clippy --tests. If applicable, add:
    • --target wasm32-unknown-unknown
  • Run cargo xtask test to run tests.
  • If this contains user-facing changes, add a CHANGELOG.md entry.

Don't think this is changelog worthy yet

Make wgsl-in correctly parse `texture_external` texture declarations,
and allow such textures to be used in `textureDimensions()`,
`textureSampleBaseClampToEdge()`, and `textureLoad()` function
calls. In IR these are represented by the `ImageClass::External` image
class, which is a 2D, non-multisampled, non-mipmapped, float-sampled
image.

Adds a new Capability `TEXTURE_EXTERNAL` and ensure validation rejects
shaders containing external textures if this capability flag is not
set. This capability is enabled for validation by wgpu devices which
support the `TEXTURE_EXTERNAL` feature (currently only when using the
noop backend), and by the Naga CLI when validating-only or when
outputting WGSL.

The WGSL backend can of course emit `ImageClass::External` images
directly as `texture_external` textures. Other backends are, for now,
unimplemented.

Lastly, we add a snapshot test covering all the valid uses of a
texture_external texture. These are:
  - As a global variable declaration
  - As an argument to the built-in functions `textureDimensions()`,
    `textureSampleBaseClampToEdge()`, and `textureLoad()`
  - As an argument to user-defined function declarations and calls.

We keep these in their own test so that we can control which targets
to run them against (currently WGSL and IR). When external textures
are supported by all Naga backends we can, if so inclined, integrate
these with existing texture tests.
@jamienicol jamienicol requested a review from a team as a code owner June 18, 2025 16:05
@jamienicol jamienicol changed the title Wgpu core texture external wgpu-core implementation for external textures Jun 18, 2025
@jamienicol jamienicol force-pushed the wgpu-core-texture-external branch 2 times, most recently from 1f52857 to 53866d8 Compare June 18, 2025 18:18
`ExternalTexture` will form the basis of wgpu's implementation of
WebGPU's `GPUExternalTexture`. [1]

The application will be responsible for creating `Texture`(s) and
`TextureView`(s) from the external texture source and managing their
lifecycle. It may have a single RGBA texture, or it may have multiple
textures for separate Y and Cb/Cr planes. It can then create an external
texture by calling `create_external_texture()`, providing the texture
views and a descriptor. The descriptor provides the following required
information:

  * Whether the texture data is RGBA, or multiplanar or interleaved
    YCbCr.
  * The purpoted size of the external texture, which may not match the
    actual size of the underlying textures.
  * A matrix for converting from YCbCr to RGBA, if required.
  * A transform to apply to texture sample coordinates, allowing for
    rotation and crop rects.

The external texture stores a reference to the provided texture views,
and additionally owns a `Buffer`. This buffer holds data of the type
`ExternalTextureParams`, and will be provided as a uniform buffer to
shaders containing external textures. This contains information that
will be required by the shaders to handle external textures correctly.

Note that attempting to create an external texture will fail unless the
`Feature::EXTERNAL_TEXTURE` feature is enabled, which as of yet is not
supported by any HAL backends.

Additionally add the relevant API to wgpu, implemented for the
wgpu-core backend. The web and custom backends are unimplemented.

[1] https://www.w3.org/TR/webgpu/#gpuexternaltexture
In upcoming patches, wgpu will allowing the creation of bind groups
with either `TextureView`s or `ExternalTexture`s bound to a
`BindingType::ExternalTexture` bind group layout entry.

Wgpu-hal and the Naga-generated shaders must be able to handle both of
these cases. For external textures they will be provided a uniform
buffer containing the external texture's `ExternalTextureParams`. For
the texture view case, we must therefore provide the same.

To do this, we create a single buffer per device which can be shared
between all texture views. We initialize it with the required values
in Device::late_init_resources_with_queue(). We know that texture
views must have a single RGBA plane, with no rotation or
crop-rect. The only thing that can vary between them is their size. We
will therefore use the value of [0, 0] in the params buffer to
indicate to the shader that it should query the actual texture's size
rather than using the value provided in the buffer.
Adds a `BindingResource` variant for external textures. In core's
create_bind_group() implementation, allow binding either external
textures or texture views to `BindingType::ExternalTexture` layout
entries.

In either case, provide HAL with a `hal::ExternalTextureBinding`,
consisting of 3 `hal::TextureBinding`s and a `hal::BufferBinding`. In
the texture view case we use the device's default params buffer for
the buffer. When there are fewer than 3 planes we can simply repeat an
existing plane multiple times - the contents of the params buffer will
ensure the shader only accesses the correct number of planes anyway.

Track the view or external texture in `BindGroupStates` to ensure they
remain alive whilst required.

And finally, add the corresponding API to wgpu, with an implementation
for the wgpu-core backend.
Adds validation tests using the noop backend covering creation of
external textures, and creation of bind groups containing external
textures.
@jamienicol jamienicol force-pushed the wgpu-core-texture-external branch from 53866d8 to ec8b51a Compare June 19, 2025 12:31
@teoxoy teoxoy self-assigned this Jun 20, 2025
Copy link
Member

@teoxoy teoxoy left a comment

Choose a reason for hiding this comment

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

Looks good overall!

/// Uniform buffer containing [`ExternalTextureParams`] with values such
/// that a [`TextureView`] bound to a [`wgt::BindingType::ExternalTexture`]
/// binding point will be rendered correctly.
pub(crate) default_external_texture_params_buffer: std::sync::OnceLock<Arc<Buffer>>,
Copy link
Member

Choose a reason for hiding this comment

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

Unfortunately the device can't hold wgpu-core buffers since buffers hold a strong ref to devices. This should be a hal buffer, you can use zero_buffer as inspiration.

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