wgpu/api/
shader_module.rs

1use std::{borrow::Cow, future::Future, marker::PhantomData, sync::Arc, thread};
2
3use crate::*;
4
5/// Handle to a compiled shader module.
6///
7/// A `ShaderModule` represents a compiled shader module on the GPU. It can be created by passing
8/// source code to [`Device::create_shader_module`] or valid SPIR-V binary to
9/// [`Device::create_shader_module_spirv`]. Shader modules are used to define programmable stages
10/// of a pipeline.
11///
12/// Corresponds to [WebGPU `GPUShaderModule`](https://gpuweb.github.io/gpuweb/#shader-module).
13#[derive(Debug)]
14pub struct ShaderModule {
15    pub(crate) context: Arc<C>,
16    pub(crate) data: Box<Data>,
17}
18#[cfg(send_sync)]
19static_assertions::assert_impl_all!(ShaderModule: Send, Sync);
20
21super::impl_partialeq_eq_hash!(ShaderModule);
22
23impl Drop for ShaderModule {
24    fn drop(&mut self) {
25        if !thread::panicking() {
26            self.context.shader_module_drop(self.data.as_ref());
27        }
28    }
29}
30
31impl ShaderModule {
32    /// Get the compilation info for the shader module.
33    pub fn get_compilation_info(&self) -> impl Future<Output = CompilationInfo> + WasmNotSend {
34        self.context.shader_get_compilation_info(self.data.as_ref())
35    }
36}
37
38/// Compilation information for a shader module.
39///
40/// Corresponds to [WebGPU `GPUCompilationInfo`](https://gpuweb.github.io/gpuweb/#gpucompilationinfo).
41/// The source locations use bytes, and index a UTF-8 encoded string.
42#[derive(Debug, Clone)]
43pub struct CompilationInfo {
44    /// The messages from the shader compilation process.
45    pub messages: Vec<CompilationMessage>,
46}
47
48/// A single message from the shader compilation process.
49///
50/// Roughly corresponds to [`GPUCompilationMessage`](https://www.w3.org/TR/webgpu/#gpucompilationmessage),
51/// except that the location uses UTF-8 for all positions.
52#[derive(Debug, Clone)]
53pub struct CompilationMessage {
54    /// The text of the message.
55    pub message: String,
56    /// The type of the message.
57    pub message_type: CompilationMessageType,
58    /// Where in the source code the message points at.
59    pub location: Option<SourceLocation>,
60}
61
62/// The type of a compilation message.
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub enum CompilationMessageType {
65    /// An error message.
66    Error,
67    /// A warning message.
68    Warning,
69    /// An informational message.
70    Info,
71}
72
73/// A human-readable representation for a span, tailored for text source.
74///
75/// Roughly corresponds to the positional members of [`GPUCompilationMessage`][gcm] from
76/// the WebGPU specification, except
77/// - `offset` and `length` are in bytes (UTF-8 code units), instead of UTF-16 code units.
78/// - `line_position` is in bytes (UTF-8 code units), and is usually not directly intended for humans.
79///
80/// [gcm]: https://www.w3.org/TR/webgpu/#gpucompilationmessage
81#[derive(Copy, Clone, Debug, PartialEq, Eq)]
82pub struct SourceLocation {
83    /// 1-based line number.
84    pub line_number: u32,
85    /// 1-based column in code units (in bytes) of the start of the span.
86    /// Remember to convert accordingly when displaying to the user.
87    pub line_position: u32,
88    /// 0-based Offset in code units (in bytes) of the start of the span.
89    pub offset: u32,
90    /// Length in code units (in bytes) of the span.
91    pub length: u32,
92}
93
94#[cfg(all(feature = "wgsl", wgpu_core))]
95impl From<crate::naga::error::ShaderError<crate::naga::front::wgsl::ParseError>>
96    for CompilationInfo
97{
98    fn from(value: crate::naga::error::ShaderError<crate::naga::front::wgsl::ParseError>) -> Self {
99        CompilationInfo {
100            messages: vec![CompilationMessage {
101                message: value.to_string(),
102                message_type: CompilationMessageType::Error,
103                location: value.inner.location(&value.source).map(Into::into),
104            }],
105        }
106    }
107}
108#[cfg(feature = "glsl")]
109impl From<naga::error::ShaderError<naga::front::glsl::ParseErrors>> for CompilationInfo {
110    fn from(value: naga::error::ShaderError<naga::front::glsl::ParseErrors>) -> Self {
111        let messages = value
112            .inner
113            .errors
114            .into_iter()
115            .map(|err| CompilationMessage {
116                message: err.to_string(),
117                message_type: CompilationMessageType::Error,
118                location: err.location(&value.source).map(Into::into),
119            })
120            .collect();
121        CompilationInfo { messages }
122    }
123}
124
125#[cfg(feature = "spirv")]
126impl From<naga::error::ShaderError<naga::front::spv::Error>> for CompilationInfo {
127    fn from(value: naga::error::ShaderError<naga::front::spv::Error>) -> Self {
128        CompilationInfo {
129            messages: vec![CompilationMessage {
130                message: value.to_string(),
131                message_type: CompilationMessageType::Error,
132                location: None,
133            }],
134        }
135    }
136}
137
138#[cfg(any(wgpu_core, naga))]
139impl
140    From<
141        crate::naga::error::ShaderError<crate::naga::WithSpan<crate::naga::valid::ValidationError>>,
142    > for CompilationInfo
143{
144    fn from(
145        value: crate::naga::error::ShaderError<
146            crate::naga::WithSpan<crate::naga::valid::ValidationError>,
147        >,
148    ) -> Self {
149        CompilationInfo {
150            messages: vec![CompilationMessage {
151                message: value.to_string(),
152                message_type: CompilationMessageType::Error,
153                location: value.inner.location(&value.source).map(Into::into),
154            }],
155        }
156    }
157}
158
159#[cfg(any(wgpu_core, naga))]
160impl From<crate::naga::SourceLocation> for SourceLocation {
161    fn from(value: crate::naga::SourceLocation) -> Self {
162        SourceLocation {
163            length: value.length,
164            offset: value.offset,
165            line_number: value.line_number,
166            line_position: value.line_position,
167        }
168    }
169}
170
171/// Source of a shader module.
172///
173/// The source will be parsed and validated.
174///
175/// Any necessary shader translation (e.g. from WGSL to SPIR-V or vice versa)
176/// will be done internally by wgpu.
177///
178/// This type is unique to the Rust API of `wgpu`. In the WebGPU specification,
179/// only WGSL source code strings are accepted.
180#[cfg_attr(feature = "naga-ir", allow(clippy::large_enum_variant))]
181#[derive(Clone, Debug)]
182#[non_exhaustive]
183pub enum ShaderSource<'a> {
184    /// SPIR-V module represented as a slice of words.
185    ///
186    /// See also: [`util::make_spirv`], [`include_spirv`]
187    #[cfg(feature = "spirv")]
188    SpirV(Cow<'a, [u32]>),
189    /// GLSL module as a string slice.
190    ///
191    /// Note: GLSL is not yet fully supported and must be a specific ShaderStage.
192    #[cfg(feature = "glsl")]
193    Glsl {
194        /// The source code of the shader.
195        shader: Cow<'a, str>,
196        /// The shader stage that the shader targets. For example, `naga::ShaderStage::Vertex`
197        stage: naga::ShaderStage,
198        /// Defines to unlock configured shader features.
199        defines: naga::FastHashMap<String, String>,
200    },
201    /// WGSL module as a string slice.
202    #[cfg(feature = "wgsl")]
203    Wgsl(Cow<'a, str>),
204    /// Naga module.
205    #[cfg(feature = "naga-ir")]
206    Naga(Cow<'static, naga::Module>),
207    /// Dummy variant because `Naga` doesn't have a lifetime and without enough active features it
208    /// could be the last one active.
209    #[doc(hidden)]
210    Dummy(PhantomData<&'a ()>),
211}
212static_assertions::assert_impl_all!(ShaderSource<'_>: Send, Sync);
213
214/// Descriptor for use with [`Device::create_shader_module`].
215///
216/// Corresponds to [WebGPU `GPUShaderModuleDescriptor`](
217/// https://gpuweb.github.io/gpuweb/#dictdef-gpushadermoduledescriptor).
218#[derive(Clone, Debug)]
219pub struct ShaderModuleDescriptor<'a> {
220    /// Debug label of the shader module. This will show up in graphics debuggers for easy identification.
221    pub label: Label<'a>,
222    /// Source code for the shader.
223    pub source: ShaderSource<'a>,
224}
225static_assertions::assert_impl_all!(ShaderModuleDescriptor<'_>: Send, Sync);
226
227/// Descriptor for a shader module given by SPIR-V binary, for use with
228/// [`Device::create_shader_module_spirv`].
229///
230/// This type is unique to the Rust API of `wgpu`. In the WebGPU specification,
231/// only WGSL source code strings are accepted.
232#[derive(Debug)]
233pub struct ShaderModuleDescriptorSpirV<'a> {
234    /// Debug label of the shader module. This will show up in graphics debuggers for easy identification.
235    pub label: Label<'a>,
236    /// Binary SPIR-V data, in 4-byte words.
237    pub source: Cow<'a, [u32]>,
238}
239static_assertions::assert_impl_all!(ShaderModuleDescriptorSpirV<'_>: Send, Sync);