Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
44 changes: 35 additions & 9 deletions wgpu-core/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,25 @@ impl ShaderModule {
})
}

/// Select an entry point name, given an optional name and a shader stage.
///
/// This function takes care of turning the `Option<&str>`
/// [`ProgrammableStageDescriptor::entry_point`][ep] into a specific name.
///
/// For non-passthrough shaders, if `entry_point` is `Some`, then return it
/// as a `String`. Otherwise, return the name of the unique entry point in
/// `self`'s module for `stage`; if there is not exactly one such entry
/// point, return an error.
///
/// The non-passthrough case counts on `Interface::check_stage` to verify
/// that an entry point with the given name actually exists.
///
/// For passthrough shaders, if `entry_point` is `Some`, verify that an
/// entry point by that name exists (returning an error if not), and return
/// it as a `String`. Otherwise, if `entry_point` is `None`, then check that
/// this module has exactly one entry point, and return its name.
///
/// [ep]: crate::pipeline::ProgrammableStageDescriptor::entry_point
pub(crate) fn finalize_entry_point_name(
&self,
stage: naga::ShaderStage,
Expand Down Expand Up @@ -223,25 +242,32 @@ impl WebGpuError for CreateShaderModuleError {
pub struct ProgrammableStageDescriptor<'a, SM = ShaderModuleId> {
/// The compiled shader module for this stage.
pub module: SM,
/// The name of the entry point in the compiled shader. The name is selected using the
/// following logic:

/// The name of the entry point in `module` that this stage should use.
///
/// - If this is `Some(name)`, `module` must contain an entry point with the
/// given name.
///
/// * If `Some(name)` is specified, there must be a function with this name in the shader.
/// * If a single entry point associated with this stage must be in the shader, then proceed as
/// if `Some(…)` was specified with that entry point's name.
/// - If this is `None`, `module` must have only one entry point for this
/// stage; we use that one.
pub entry_point: Option<Cow<'a, str>>,
/// Specifies the values of pipeline-overridable constants in the shader module.

/// Values for pipeline-overridable constants in `module` that this stage
/// should use.
///
/// If an `@id` attribute was specified on the declaration,
/// the key must be the pipeline constant ID as a decimal ASCII number; if not,
/// the key must be the constant's identifier name.
///
/// The value may represent any of WGSL's concrete scalar types.
pub constants: naga::back::PipelineConstants,
/// Whether workgroup scoped memory will be initialized with zero values for this stage.

/// Whether variables in the workgroup address space will be initialized
/// with zero values for this stage.
///
/// This is required by the WebGPU spec, but may have overhead which can be avoided
/// for cross-platform applications
/// The WebGPU spec requires variables in the workgroup address space to be
/// zeroed. However, initialization does impose some overhead, and
/// non-browser applications may not need it.
pub zero_initialize_workgroup_memory: bool,
}

Expand Down
120 changes: 118 additions & 2 deletions wgpu-core/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,16 +292,65 @@ struct EntryPointMeshInfo {
primitive_topology: wgt::PrimitiveTopology,
}

/// The [shader interface][si] of an entry point in a [`naga::Module`].
///
/// [si]: https://www.w3.org/TR/WGSL/#shader-interface
#[derive(Debug, Default)]
struct EntryPoint {
/// The builtin and user-defined values passed to the entry point.
///
/// In WGSL, these can be either passed directly as arguments or
/// gathered up in structs that are passed; here, they are all
/// flattened out.
inputs: Vec<Varying>,

/// The builtin and user-defined values returned by the entry point.
///
/// In WGSL, a function either returns a single varying directly,
/// or returns a struct of varyings; here, they are all flattened
/// out.
///
/// For mesh shaders, this also includes the vertex and primitive outputs.
outputs: Vec<Varying>,

/// This entry point's [resource interface][ri].
///
/// This lists all the bound resources (that is, global variables with
/// `@group` and `@binding` attributes) that this entry point statically
/// uses.
///
/// Handles here refer to elements of [`Interface::resources`].
///
/// [ri]: https://www.w3.org/TR/WGSL/#resource-interface
resources: Vec<naga::Handle<Resource>>,

/// Pairs of (texture, sampler) handles that this entry point uses
/// together.
///
/// This is the same information that Naga provides in
/// [`naga::valid::FunctionInfo::sampling_set`] (used for generating GLSL),
/// but adjusted to use handles referring to [`Interface::resources`].
sampling_pairs: FastHashSet<(naga::Handle<Resource>, naga::Handle<Resource>)>,

/// This entry point's workgroup size, if it is a [compute-like] shader
/// (`compute`, `task`, or `mesh`).
///
/// For non-compute-like entry points, this is `[0, 0, 0]`.
///
/// [compute-like]: naga::ShaderStage::compute_like
workgroup_size: [u32; 3],

/// Indicates that the entry point uses dual source blending.
dual_source_blending: bool,

/// For task shaders and mesh shaders, the size of the task payload global
/// they use to communicate.
task_payload_size: Option<u32>,

/// Additional information for mesh shader entry points.
mesh_info: Option<EntryPointMeshInfo>,

/// Size of the immediate data, and which slots this entry point uses.
immediate_usage: naga::valid::ImmediateUsage,
}

Expand All @@ -317,10 +366,35 @@ impl hashbrown::Equivalent<EntryPointKey> for EntryPointKeyRef<'_> {
}
}

/// A summary of the [shader interfaces][si] of the entry points in a [`naga::Module`].
///
/// [si]: https://www.w3.org/TR/WGSL/#shader-interface
#[derive(Debug)]
pub struct Interface {
/// A clone of the limits of the [`Device`] this module was created from.
///
/// [`Interface::check_stage`] consults this for workgroup size checks.
///
/// [`Device`]: crate::device::Device
limits: wgt::Limits,

/// All the resources the module cites as global variables.
///
/// This lists all the module's bound resources: global variables with
/// `@group` and `@binding` attributes.
///
/// Fields of [`EntryPoint`] like [`resources`] and [`sampling_pairs`] refer to
/// elements in this arena by [`naga::Handle`].
///
/// [`resources`]: EntryPoint::resources
/// [`sampling_pairs`]: EntryPoint::sampling_pairs
resources: naga::Arena<Resource>,

/// The shader interface of each [`naga::EntryPoint`] in the module.
///
/// This table is keyed by (stage, name) pairs: [`naga::Module`]s are
/// allowed to contain multiple entry points with the same name, as long as
/// they are for different shader stages.
entry_points: FastHashMap<EntryPointKey, EntryPoint>,
}

Expand Down Expand Up @@ -1115,6 +1189,19 @@ pub struct StageIo {
}

impl Interface {
/// Build some entry point's list of inputs or outputs.
///
/// Given `ty` and `binding` that describe an entry point's argument or
/// return value, figure out which builtins or locations are involved and
/// add them to `list`, which is either [`EntryPoint::inputs`] or
/// [`EntryPoint::outputs`].
///
/// - If `ty` is a struct type, visit its members to find
/// individual bindings, and add them to `list`.
///
/// - Otherwise, `binding` must be `Some(b)` where `b` describes a
/// binding's builtin or location, and `ty` gives its type. Add
/// this binding to `list`.
fn populate(
list: &mut Vec<Varying>,
binding: Option<&naga::Binding>,
Expand Down Expand Up @@ -1252,6 +1339,11 @@ impl Interface {
list.push(varying);
}

/// Construct an [`Interface`] value describing `module`.
///
/// The `info` argument must be the results from validating `module`, and
/// `limits` must be the limits for the device that we will use to create
/// this shader module.
pub fn new(module: &naga::Module, info: &naga::valid::ModuleInfo, limits: wgt::Limits) -> Self {
let mut resources = naga::Arena::new();
let mut resource_mapping = FastHashMap::default();
Expand Down Expand Up @@ -1404,6 +1496,11 @@ impl Interface {
.unwrap_or_default()
}

/// Select an entry point name, given an optional name and a shader stage.
///
/// See [`ShaderModule::finalize_entry_point_name`] for details.
///
/// [`ShaderModule::finalize_entry_point_name`]: crate::pipeline::ShaderModule::finalize_entry_point_name
pub fn finalize_entry_point_name(
&self,
stage: naga::ShaderStage,
Expand All @@ -1427,8 +1524,27 @@ impl Interface {
})
}

/// Among other things, this implements some validation logic defined by the WebGPU spec. at
/// <https://www.w3.org/TR/webgpu/#abstract-opdef-validating-inter-stage-interfaces>.
/// Analyze and validate an entry point for use as a given shader stage.
///
/// Validate the entry point named `entry_point_name` for use in
/// `shader_stage`:
///
/// - Apply the WebGPU specification's [validating inter-stage interfaces]
/// algorithm.
///
/// - Enforce workgroup size limits.
///
/// - Check bind group layouts, and fill in derived bind group layouts.
///
/// - Compute the minimum binding sizes, given the shader's resource
/// interface.
///
/// - Check the compatibility between textures and samplers.
///
/// Given `inputs`, describing this stage's inputs, return a [`StageIo`]
/// describing its outputs.
///
/// [validating inter-stage interfaces]: https://www.w3.org/TR/webgpu/#abstract-opdef-validating-inter-stage-interfaces
pub fn check_stage(
&self,
layouts: &mut BindingLayoutSource,
Expand Down
3 changes: 1 addition & 2 deletions wgpu-types/src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
//! The `wgpu` Rust API always uses the `Features` bit flag type to represent a
//! set of features. However, the WebGPU-defined JavaScript API uses
//! `kebab-case` feature name strings, so some utilities are provided for
//! working with those names. See [`Features::as_str`] and [`<Features as
//! FromStr>::from_str`].
//! working with those names. See [`Features::as_str`] and [`Features::from_str`].
//!
//! The [`bitflags`] crate names flags by stringifying the
//! `SCREAMING_SNAKE_CASE` identifier. These names are returned by
Expand Down