Skip to content

Commit

Permalink
allow handling errors for spirv and glsl shader (#313)
Browse files Browse the repository at this point in the history
  • Loading branch information
rajveermalviya authored Nov 3, 2023
1 parent 262436a commit d5a0084
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 26 deletions.
29 changes: 22 additions & 7 deletions src/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,18 +566,28 @@ pub fn map_required_limits(
wgt_limits
}

#[derive(Debug, thiserror::Error)]
pub enum ShaderParseError {
#[error(transparent)]
Spirv(#[from] naga::front::spv::Error),
#[error("GLSL Parse Error: {0:?}")]
Glsl(Vec<naga::front::glsl::Error>),
}

#[inline]
pub fn map_shader_module<'a>(
_: &native::WGPUShaderModuleDescriptor,
spirv: Option<&native::WGPUShaderModuleSPIRVDescriptor>,
wgsl: Option<&native::WGPUShaderModuleWGSLDescriptor>,
glsl: Option<&native::WGPUShaderModuleGLSLDescriptor>,
) -> wgc::pipeline::ShaderModuleSource<'a> {
) -> Result<wgc::pipeline::ShaderModuleSource<'a>, ShaderParseError> {
#[cfg(feature = "wgsl")]
if let Some(wgsl) = wgsl {
let c_str: &CStr = unsafe { CStr::from_ptr(wgsl.code) };
let str_slice: &str = c_str.to_str().expect("not a valid utf-8 string");
return wgc::pipeline::ShaderModuleSource::Wgsl(Cow::Borrowed(str_slice));
return Ok(wgc::pipeline::ShaderModuleSource::Wgsl(Cow::Borrowed(
str_slice,
)));
}

#[cfg(feature = "spirv")]
Expand All @@ -590,16 +600,19 @@ pub fn map_shader_module<'a>(
block_ctx_dump_prefix: None,
};
let frontend = naga::front::spv::Frontend::new(slice.iter().cloned(), &options);
let module = frontend.parse().unwrap();
return wgc::pipeline::ShaderModuleSource::Naga(Cow::Owned(module));
match frontend.parse() {
Ok(module) => return Ok(wgc::pipeline::ShaderModuleSource::Naga(Cow::Owned(module))),
Err(cause) => return Err(ShaderParseError::Spirv(cause)),
};
}

#[cfg(feature = "glsl")]
if let Some(glsl) = glsl {
let c_str: &CStr = unsafe { CStr::from_ptr(glsl.code) };
let str_slice: &str = c_str.to_str().expect("not a valid utf-8 string");
let mut options = naga::front::glsl::Options::from(
map_shader_stage(glsl.stage).expect("Unknown shader stage"),
map_shader_stage(glsl.stage)
.expect("invalid shader stage for shader module glsl descriptor"),
);

let raw_defines = make_slice(glsl.defines, glsl.defineCount as usize);
Expand All @@ -616,8 +629,10 @@ pub fn map_shader_module<'a>(
}

let mut frontend = naga::front::glsl::Frontend::default();
let module = frontend.parse(&options, str_slice).unwrap();
return wgc::pipeline::ShaderModuleSource::Naga(Cow::Owned(module));
match frontend.parse(&options, str_slice) {
Ok(module) => return Ok(wgc::pipeline::ShaderModuleSource::Naga(Cow::Owned(module))),
Err(causes) => return Err(ShaderParseError::Glsl(causes)),
};
}

panic!("Shader not provided.");
Expand Down
61 changes: 42 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,13 +265,15 @@ impl Drop for WGPUSamplerImpl {

pub struct WGPUShaderModuleImpl {
context: Arc<Context>,
id: id::ShaderModuleId,
id: Option<id::ShaderModuleId>,
}
impl Drop for WGPUShaderModuleImpl {
fn drop(&mut self) {
if !thread::panicking() {
let context = &self.context;
gfx_select!(self.id => context.shader_module_drop(self.id));
if let Some(id) = self.id {
if !thread::panicking() {
let context = &self.context;
gfx_select!(id => context.shader_module_drop(id));
}
}
}
}
Expand Down Expand Up @@ -367,7 +369,7 @@ unsafe extern "C" fn default_uncaptured_error_handler(
_userdata: *mut ::std::os::raw::c_void,
) {
let message = unsafe { CStr::from_ptr(message) }.to_str().unwrap();
log::error!("Handling wgpu uncaptured errors as fatal by default");
log::warn!("Handling wgpu uncaptured errors as fatal by default");
panic!("wgpu uncaptured error:\n{message}\n");
}
const DEFAULT_UNCAPTURED_ERROR_HANDLER: UncapturedErrorCallback = UncapturedErrorCallback {
Expand All @@ -381,7 +383,7 @@ unsafe extern "C" fn default_device_lost_handler(
_userdata: *mut ::std::os::raw::c_void,
) {
let message = unsafe { CStr::from_ptr(message) }.to_str().unwrap();
log::error!("Handling wgpu device lost errors as fatal by default");
log::warn!("Handling wgpu device lost errors as fatal by default");
panic!("wgpu device lost error:\n{message}\n");
}
const DEFAULT_DEVICE_LOST_HANDLER: DeviceLostCallback = DeviceLostCallback {
Expand Down Expand Up @@ -1890,7 +1892,8 @@ pub unsafe extern "C" fn wgpuDeviceCreateComputePipeline(
.module
.as_ref()
.expect("invalid shader module for compute pipeline descriptor")
.id,
.id
.expect("invalid shader module for compute pipeline descriptor"),
entry_point: ptr_into_label(descriptor.compute.entryPoint)
.expect("invalid entry point for compute pipeline descriptor"),
};
Expand Down Expand Up @@ -1921,7 +1924,7 @@ pub unsafe extern "C" fn wgpuDeviceCreateComputePipeline(
wgt::ShaderStages::COMPUTE,
error
);
log::warn!("Please report it to https://github.com/gfx-rs/naga");
log::warn!("Please report it to https://github.com/gfx-rs/wgpu");
}
handle_error(
context,
Expand Down Expand Up @@ -2070,7 +2073,8 @@ pub unsafe extern "C" fn wgpuDeviceCreateRenderPipeline(
.module
.as_ref()
.expect("invalid vertex shader module for vertex state")
.id,
.id
.expect("invalid vertex shader module for vertex state"),
entry_point: ptr_into_label(descriptor.vertex.entryPoint)
.expect("invalid entry point for vertex state"),
},
Expand Down Expand Up @@ -2157,7 +2161,8 @@ pub unsafe extern "C" fn wgpuDeviceCreateRenderPipeline(
.module
.as_ref()
.expect("invalid fragment shader module for render pipeline descriptor")
.id,
.id
.expect("invalid fragment shader module for render pipeline descriptor"),
entry_point: ptr_into_label(fragment.entryPoint)
.expect("invalid entry point for fragment state"),
},
Expand Down Expand Up @@ -2197,7 +2202,7 @@ pub unsafe extern "C" fn wgpuDeviceCreateRenderPipeline(
if let Some(cause) = error {
if let wgc::pipeline::CreateRenderPipelineError::Internal { stage, ref error } = cause {
log::error!("Shader translation error for stage {:?}: {}", stage, error);
log::error!("Please report it to https://github.com/gfx-rs/naga");
log::error!("Please report it to https://github.com/gfx-rs/wgpu");
}
handle_error(
context,
Expand Down Expand Up @@ -2293,17 +2298,35 @@ pub unsafe extern "C" fn wgpuDeviceCreateShaderModule(
};
let descriptor = descriptor.expect("invalid descriptor");

let source = follow_chain!(
let desc = wgc::pipeline::ShaderModuleDescriptor {
label: ptr_into_label(descriptor.label),
shader_bound_checks: wgt::ShaderBoundChecks::default(),
};

let source = match follow_chain!(
map_shader_module((descriptor),
WGPUSType_ShaderModuleSPIRVDescriptor => native::WGPUShaderModuleSPIRVDescriptor,
WGPUSType_ShaderModuleWGSLDescriptor => native::WGPUShaderModuleWGSLDescriptor,
WGPUSType_ShaderModuleGLSLDescriptor => native::WGPUShaderModuleGLSLDescriptor)
);
) {
Ok(source) => source,
Err(cause) => {
handle_error(
context,
error_sink,
cause,
LABEL,
desc.label,
"wgpuDeviceCreateShaderModule",
);

let desc = wgc::pipeline::ShaderModuleDescriptor {
label: ptr_into_label(descriptor.label),
shader_bound_checks: wgt::ShaderBoundChecks::default(),
return Arc::into_raw(Arc::new(WGPUShaderModuleImpl {
context: context.clone(),
id: None,
}));
}
};

let (shader_module_id, error) =
gfx_select!(device_id => context.device_create_shader_module(device_id, &desc, source, ()));
if let Some(cause) = error {
Expand All @@ -2319,7 +2342,7 @@ pub unsafe extern "C" fn wgpuDeviceCreateShaderModule(

Arc::into_raw(Arc::new(WGPUShaderModuleImpl {
context: context.clone(),
id: shader_module_id,
id: Some(shader_module_id),
}))
}

Expand Down Expand Up @@ -2384,7 +2407,7 @@ pub unsafe extern "C" fn wgpuDeviceCreateTexture(

#[no_mangle]
pub extern "C" fn wgpuDeviceDestroy(_device: native::WGPUDevice) {
//TODO: empty implementation, wait till wgpu-core implements a way.
//TODO: needs to be implemented in wgpu-core
}

#[no_mangle]
Expand Down Expand Up @@ -2727,7 +2750,7 @@ pub unsafe extern "C" fn wgpuPipelineLayoutRelease(pipeline_layout: native::WGPU

#[no_mangle]
pub unsafe extern "C" fn wgpuQuerySetDestroy(_query_set: native::WGPUQuerySet) {
//TODO: empty implementation, wait till wgpu-core implements a way.
//TODO: needs to be implemented in wgpu-core
}

#[no_mangle]
Expand Down

0 comments on commit d5a0084

Please sign in to comment.