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