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