From cfc6792c82ddd714449632f5f06e14649d041de8 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 3 Jun 2021 10:30:35 -0400 Subject: [PATCH] Validate pipeline state formats --- wgpu-core/src/device/mod.rs | 63 +++++++++++++++++++++++++++++++++++-- wgpu-core/src/pipeline.rs | 18 +++++++++++ 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 8d1db631c..5a0bda3c6 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -2255,11 +2255,68 @@ impl Device { targets: Vec::with_capacity(color_states.len()), }; for (i, cs) in color_states.iter().enumerate() { - let bt = conv::map_color_target_state(cs) - .map_err(|error| pipeline::CreateRenderPipelineError::ColorState(i as u8, error))?; - blender.targets.push(bt); + let error = loop { + let format_desc = cs.format.describe(); + self.require_features(format_desc.required_features)?; + if !format_desc + .guaranteed_format_features + .allowed_usages + .contains(wgt::TextureUsage::RENDER_ATTACHMENT) + { + break Some(pipeline::ColorStateError::FormatNotRenderable(cs.format)); + } + if cs.blend.is_some() && !format_desc.guaranteed_format_features.filterable { + break Some(pipeline::ColorStateError::FormatNotBlendable(cs.format)); + } + let hal_format = conv::map_texture_format(cs.format, self.private_features); + if !hal_format + .surface_desc() + .aspects + .contains(hal::format::Aspects::COLOR) + { + break Some(pipeline::ColorStateError::FormatNotColor(cs.format)); + } + + match conv::map_color_target_state(cs) { + Ok(bt) => blender.targets.push(bt), + Err(e) => break Some(e), + } + break None; + }; + if let Some(e) = error { + return Err(pipeline::CreateRenderPipelineError::ColorState(i as u8, e)); + } } + if let Some(ds) = depth_stencil_state { + let error = loop { + let format_desc = ds.format.describe(); + self.require_features(format_desc.required_features)?; + if !format_desc + .guaranteed_format_features + .allowed_usages + .contains(wgt::TextureUsage::RENDER_ATTACHMENT) + { + break Some(pipeline::DepthStencilStateError::FormatNotRenderable( + ds.format, + )); + } + let hal_format = conv::map_texture_format(ds.format, self.private_features); + let aspects = hal_format.surface_desc().aspects; + if ds.is_depth_enabled() && !aspects.contains(hal::format::Aspects::DEPTH) { + break Some(pipeline::DepthStencilStateError::FormatNotDepth(ds.format)); + } + if ds.stencil.is_enabled() && !aspects.contains(hal::format::Aspects::STENCIL) { + break Some(pipeline::DepthStencilStateError::FormatNotStencil( + ds.format, + )); + } + break None; + }; + if let Some(e) = error { + return Err(pipeline::CreateRenderPipelineError::DepthStencilState(e)); + } + } let depth_stencil = depth_stencil_state .map(conv::map_depth_stencil_state) .unwrap_or_default(); diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index a770ba2e5..05adbcd35 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -202,6 +202,12 @@ pub struct RenderPipelineDescriptor<'a> { pub enum ColorStateError { #[error("output is missing")] Missing, + #[error("format {0:?} is not renderable")] + FormatNotRenderable(wgt::TextureFormat), + #[error("format {0:?} is not blendable")] + FormatNotBlendable(wgt::TextureFormat), + #[error("format {0:?} does not have a color aspect")] + FormatNotColor(wgt::TextureFormat), #[error("output format {pipeline} is incompatible with the shader {shader}")] IncompatibleFormat { pipeline: validation::NumericType, @@ -211,6 +217,16 @@ pub enum ColorStateError { InvalidMinMaxBlendFactors(wgt::BlendComponent), } +#[derive(Clone, Debug, Error)] +pub enum DepthStencilStateError { + #[error("format {0:?} is not renderable")] + FormatNotRenderable(wgt::TextureFormat), + #[error("format {0:?} does not have a depth aspect, but depth test/write is enabled")] + FormatNotDepth(wgt::TextureFormat), + #[error("format {0:?} does not have a stencil aspect, but stencil test/write is enabled")] + FormatNotStencil(wgt::TextureFormat), +} + #[derive(Clone, Debug, Error)] pub enum CreateRenderPipelineError { #[error(transparent)] @@ -221,6 +237,8 @@ pub enum CreateRenderPipelineError { Implicit(#[from] ImplicitLayoutError), #[error("color state [{0}] is invalid")] ColorState(u8, #[source] ColorStateError), + #[error("depth/stencil state is invalid")] + DepthStencilState(#[from] DepthStencilStateError), #[error("invalid sample count {0}")] InvalidSampleCount(u32), #[error("the number of vertex buffers {given} exceeds the limit {limit}")]