mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
[error] shader module creation, separate descriptor
This commit is contained in:
parent
e96e5f917c
commit
fccbca28bd
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1121,7 +1121,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/gfx-rs/naga?rev=27ec95a2381ae8e0afd07fa13c83a436a9e0bd41#27ec95a2381ae8e0afd07fa13c83a436a9e0bd41"
|
||||
source = "git+https://github.com/gfx-rs/naga?rev=7c7702c9d8d59325328aa7081347e151a7bb63d7#7c7702c9d8d59325328aa7081347e151a7bb63d7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fxhash",
|
||||
|
@ -208,20 +208,23 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
A::DestroyBindGroup(id) => {
|
||||
self.bind_group_drop::<B>(id);
|
||||
}
|
||||
A::CreateShaderModule { id, data } => {
|
||||
let source = if data.ends_with(".wgsl") {
|
||||
let code = fs::read_to_string(dir.join(data)).unwrap();
|
||||
wgc::pipeline::ShaderModuleSource::Wgsl(Cow::Owned(code))
|
||||
} else {
|
||||
let byte_vec = fs::read(dir.join(data)).unwrap();
|
||||
let spv = byte_vec
|
||||
.chunks(4)
|
||||
.map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
|
||||
.collect::<Vec<_>>();
|
||||
wgc::pipeline::ShaderModuleSource::SpirV(Cow::Owned(spv))
|
||||
A::CreateShaderModule { id, data, label } => {
|
||||
let desc = wgc::pipeline::ShaderModuleDescriptor {
|
||||
source: if data.ends_with(".wgsl") {
|
||||
let code = fs::read_to_string(dir.join(data)).unwrap();
|
||||
wgc::pipeline::ShaderModuleSource::Wgsl(Cow::Owned(code))
|
||||
} else {
|
||||
let byte_vec = fs::read(dir.join(data)).unwrap();
|
||||
let spv = byte_vec
|
||||
.chunks(4)
|
||||
.map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
|
||||
.collect::<Vec<_>>();
|
||||
wgc::pipeline::ShaderModuleSource::SpirV(Cow::Owned(spv))
|
||||
},
|
||||
label,
|
||||
};
|
||||
self.device_create_shader_module::<B>(device, source, id)
|
||||
.unwrap();
|
||||
let (_, error) = self.device_create_shader_module::<B>(device, &desc, id);
|
||||
assert_eq!(error, None);
|
||||
}
|
||||
A::DestroyShaderModule(id) => {
|
||||
self.shader_module_drop::<B>(id);
|
||||
|
@ -9,6 +9,7 @@
|
||||
)),
|
||||
CreateShaderModule(
|
||||
id: Id(0, 1, Empty),
|
||||
label: None,
|
||||
data: "empty.comp.spv",
|
||||
),
|
||||
CreateComputePipeline(Id(0, 1, Empty), (
|
||||
|
@ -40,7 +40,7 @@ gpu-alloc = { git = "https://github.com/zakarumych/gpu-alloc", rev = "7bd745e488
|
||||
[dependencies.naga]
|
||||
version = "0.2"
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "27ec95a2381ae8e0afd07fa13c83a436a9e0bd41"
|
||||
rev = "7c7702c9d8d59325328aa7081347e151a7bb63d7"
|
||||
features = ["spv-in", "spv-out", "wgsl-in"]
|
||||
|
||||
[dependencies.wgt]
|
||||
|
@ -833,6 +833,89 @@ impl<B: GfxBackend> Device<B> {
|
||||
})
|
||||
}
|
||||
|
||||
fn create_shader_module<'a>(
|
||||
&self,
|
||||
self_id: id::DeviceId,
|
||||
desc: &'a pipeline::ShaderModuleDescriptor<'a>,
|
||||
) -> Result<(pipeline::ShaderModule<B>, Cow<'a, [u32]>), pipeline::CreateShaderModuleError>
|
||||
{
|
||||
let spv_flags = if cfg!(debug_assertions) {
|
||||
naga::back::spv::WriterFlags::DEBUG
|
||||
} else {
|
||||
naga::back::spv::WriterFlags::empty()
|
||||
};
|
||||
|
||||
let (spv, naga) = match desc.source {
|
||||
pipeline::ShaderModuleSource::SpirV(ref spv) => {
|
||||
let module = if self.private_features.shader_validation {
|
||||
// Parse the given shader code and store its representation.
|
||||
let spv_iter = spv.iter().cloned();
|
||||
naga::front::spv::Parser::new(spv_iter, &Default::default())
|
||||
.parse()
|
||||
.map_err(|err| {
|
||||
// TODO: eventually, when Naga gets support for all features,
|
||||
// we want to convert these to a hard error,
|
||||
tracing::warn!("Failed to parse shader SPIR-V code: {:?}", err);
|
||||
tracing::warn!("Shader module will not be validated");
|
||||
})
|
||||
.ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
(Cow::Borrowed(&**spv), module)
|
||||
}
|
||||
pipeline::ShaderModuleSource::Wgsl(ref code) => {
|
||||
// TODO: refactor the corresponding Naga error to be owned, and then
|
||||
// display it instead of unwrapping
|
||||
let module = naga::front::wgsl::parse_str(code).unwrap();
|
||||
let spv = naga::back::spv::Writer::new(&module.header, spv_flags).write(&module);
|
||||
(
|
||||
Cow::Owned(spv),
|
||||
if self.private_features.shader_validation {
|
||||
Some(module)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
} /*
|
||||
pipeline::ShaderModuleSource::Naga(module) => {
|
||||
let spv = naga::back::spv::Writer::new(&module.header, spv_flags).write(&module);
|
||||
(
|
||||
Cow::Owned(spv),
|
||||
if device.private_features.shader_validation {
|
||||
Some(module)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
}*/
|
||||
};
|
||||
|
||||
if let Some(ref module) = naga {
|
||||
naga::proc::Validator::new().validate(module)?;
|
||||
}
|
||||
|
||||
let raw = unsafe {
|
||||
self.raw
|
||||
.create_shader_module(&spv)
|
||||
.map_err(|err| match err {
|
||||
hal::device::ShaderError::OutOfMemory(_) => DeviceError::OutOfMemory,
|
||||
_ => panic!("failed to create shader module: {}", err),
|
||||
})?
|
||||
};
|
||||
let shader = pipeline::ShaderModule {
|
||||
raw,
|
||||
device_id: Stored {
|
||||
value: id::Valid(self_id),
|
||||
ref_count: self.life_guard.add_ref(),
|
||||
},
|
||||
module: naga,
|
||||
#[cfg(debug_assertions)]
|
||||
label: desc.label.to_string_or_default(),
|
||||
};
|
||||
Ok((shader, spv))
|
||||
}
|
||||
|
||||
/// Create a compatible render pass with a given key.
|
||||
///
|
||||
/// This functions doesn't consider the following aspects for compatibility:
|
||||
@ -2569,119 +2652,59 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
pub fn device_create_shader_module<B: GfxBackend>(
|
||||
&self,
|
||||
device_id: id::DeviceId,
|
||||
source: pipeline::ShaderModuleSource,
|
||||
desc: &pipeline::ShaderModuleDescriptor,
|
||||
id_in: Input<G, id::ShaderModuleId>,
|
||||
) -> Result<id::ShaderModuleId, pipeline::CreateShaderModuleError> {
|
||||
) -> (
|
||||
id::ShaderModuleId,
|
||||
Option<pipeline::CreateShaderModuleError>,
|
||||
) {
|
||||
span!(_guard, INFO, "Device::create_shader_module");
|
||||
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
|
||||
let (device_guard, mut token) = hub.devices.read(&mut token);
|
||||
let device = device_guard
|
||||
.get(device_id)
|
||||
.map_err(|_| DeviceError::Invalid)?;
|
||||
let spv_flags = if cfg!(debug_assertions) {
|
||||
naga::back::spv::WriterFlags::DEBUG
|
||||
} else {
|
||||
naga::back::spv::WriterFlags::empty()
|
||||
};
|
||||
let error = loop {
|
||||
let device = match device_guard.get(device_id) {
|
||||
Ok(device) => device,
|
||||
Err(_) => break DeviceError::Invalid.into(),
|
||||
};
|
||||
let (shader, spv) = match device.create_shader_module(device_id, desc) {
|
||||
Ok(pair) => pair,
|
||||
Err(e) => break e,
|
||||
};
|
||||
|
||||
let (spv, naga) = match source {
|
||||
pipeline::ShaderModuleSource::SpirV(spv) => {
|
||||
let module = if device.private_features.shader_validation {
|
||||
// Parse the given shader code and store its representation.
|
||||
let spv_iter = spv.into_iter().cloned();
|
||||
naga::front::spv::Parser::new(spv_iter, &Default::default())
|
||||
.parse()
|
||||
.map_err(|err| {
|
||||
// TODO: eventually, when Naga gets support for all features,
|
||||
// we want to convert these to a hard error,
|
||||
tracing::warn!("Failed to parse shader SPIR-V code: {:?}", err);
|
||||
tracing::warn!("Shader module will not be validated");
|
||||
})
|
||||
.ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
(spv, module)
|
||||
}
|
||||
pipeline::ShaderModuleSource::Wgsl(code) => {
|
||||
// TODO: refactor the corresponding Naga error to be owned, and then
|
||||
// display it instead of unwrapping
|
||||
let module = naga::front::wgsl::parse_str(&code).unwrap();
|
||||
let spv = naga::back::spv::Writer::new(&module.header, spv_flags).write(&module);
|
||||
(
|
||||
Cow::Owned(spv),
|
||||
if device.private_features.shader_validation {
|
||||
Some(module)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
}
|
||||
pipeline::ShaderModuleSource::Naga(module) => {
|
||||
let spv = naga::back::spv::Writer::new(&module.header, spv_flags).write(&module);
|
||||
(
|
||||
Cow::Owned(spv),
|
||||
if device.private_features.shader_validation {
|
||||
Some(module)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
let id = hub
|
||||
.shader_modules
|
||||
.register_identity(id_in, shader, &mut token);
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref trace) = device.trace {
|
||||
let mut trace = trace.lock();
|
||||
let data = trace.make_binary("spv", unsafe {
|
||||
std::slice::from_raw_parts(spv.as_ptr() as *const u8, spv.len() * 4)
|
||||
});
|
||||
let label = desc.label.clone();
|
||||
trace.add(trace::Action::CreateShaderModule {
|
||||
id: id.0,
|
||||
data,
|
||||
label,
|
||||
});
|
||||
}
|
||||
|
||||
let _ = spv;
|
||||
return (id.0, None);
|
||||
};
|
||||
|
||||
if let Some(ref module) = naga {
|
||||
naga::proc::Validator::new().validate(module)?;
|
||||
}
|
||||
|
||||
let raw = unsafe {
|
||||
device
|
||||
.raw
|
||||
.create_shader_module(&spv)
|
||||
.map_err(|err| match err {
|
||||
hal::device::ShaderError::OutOfMemory(_) => DeviceError::OutOfMemory,
|
||||
_ => panic!("failed to create shader module: {}", err),
|
||||
})?
|
||||
};
|
||||
let shader = pipeline::ShaderModule {
|
||||
raw,
|
||||
device_id: Stored {
|
||||
value: id::Valid(device_id),
|
||||
ref_count: device.life_guard.add_ref(),
|
||||
},
|
||||
module: naga,
|
||||
};
|
||||
|
||||
let id = hub
|
||||
.shader_modules
|
||||
.register_identity(id_in, shader, &mut token);
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref trace) = device.trace {
|
||||
let mut trace = trace.lock();
|
||||
let data = trace.make_binary("spv", unsafe {
|
||||
std::slice::from_raw_parts(spv.as_ptr() as *const u8, spv.len() * 4)
|
||||
});
|
||||
trace.add(trace::Action::CreateShaderModule { id: id.0, data });
|
||||
}
|
||||
Ok(id.0)
|
||||
let id =
|
||||
hub.shader_modules
|
||||
.register_error(id_in, desc.label.borrow_or_default(), &mut token);
|
||||
(id, Some(error))
|
||||
}
|
||||
|
||||
pub fn shader_module_label<B: GfxBackend>(&self, id: id::ShaderModuleId) -> String {
|
||||
B::hub(self).shader_modules.label_for_resource(id)
|
||||
}
|
||||
|
||||
pub fn shader_module_error<B: GfxBackend>(
|
||||
&self,
|
||||
id_in: Input<G, id::ShaderModuleId>,
|
||||
) -> id::ShaderModuleId {
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
let (_, mut token) = hub.devices.read(&mut token);
|
||||
hub.shader_modules.register_error(id_in, "", &mut token)
|
||||
}
|
||||
|
||||
pub fn shader_module_drop<B: GfxBackend>(&self, shader_module_id: id::ShaderModuleId) {
|
||||
span!(_guard, INFO, "ShaderModule::drop");
|
||||
|
||||
|
@ -71,6 +71,7 @@ pub enum Action<'a> {
|
||||
DestroyBindGroup(id::BindGroupId),
|
||||
CreateShaderModule {
|
||||
id: id::ShaderModuleId,
|
||||
label: crate::Label<'a>,
|
||||
data: FileName,
|
||||
},
|
||||
DestroyShaderModule(id::ShaderModuleId),
|
||||
|
@ -14,13 +14,23 @@ use std::borrow::Cow;
|
||||
use thiserror::Error;
|
||||
use wgt::{BufferAddress, IndexFormat, InputStepMode};
|
||||
|
||||
// Unable to serialize with `naga::Module` in here:
|
||||
// requires naga serialization feature.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
pub enum ShaderModuleSource<'a> {
|
||||
SpirV(Cow<'a, [u32]>),
|
||||
Wgsl(Cow<'a, str>),
|
||||
Naga(naga::Module),
|
||||
// Unable to serialize with `naga::Module` in here:
|
||||
// requires naga serialization feature.
|
||||
//Naga(naga::Module),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
pub struct ShaderModuleDescriptor<'a> {
|
||||
pub label: Label<'a>,
|
||||
pub source: ShaderModuleSource<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -28,6 +38,8 @@ pub struct ShaderModule<B: hal::Backend> {
|
||||
pub(crate) raw: B::ShaderModule,
|
||||
pub(crate) device_id: Stored<DeviceId>,
|
||||
pub(crate) module: Option<naga::Module>,
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) label: String,
|
||||
}
|
||||
|
||||
impl<B: hal::Backend> Resource for ShaderModule<B> {
|
||||
@ -38,11 +50,14 @@ impl<B: hal::Backend> Resource for ShaderModule<B> {
|
||||
}
|
||||
|
||||
fn label(&self) -> &str {
|
||||
"<ShaderModule>"
|
||||
#[cfg(debug_assertions)]
|
||||
return &self.label;
|
||||
#[cfg(not(debug_assertions))]
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
pub enum CreateShaderModuleError {
|
||||
#[error(transparent)]
|
||||
Device(#[from] DeviceError),
|
||||
|
Loading…
Reference in New Issue
Block a user