898: Update naga with improved SPIR-V parsing and reflection r=cwfitzgerald a=kvark

**Connections**
Fixes #892
Fixes #899
Includes https://github.com/gfx-rs/naga/pull/153 and the awesome https://github.com/gfx-rs/naga/pull/122
Also includes https://github.com/gfx-rs/naga/pull/157 now.

**Description**
This PR updates naga and our validation code.
~~We can successfully validate only `hello-triangle` and `cube` examples, still.~~
We mostly pass the validation of the examples now!
Meta-issue filed in https://github.com/gfx-rs/naga/issues/155 to unlock the rest.

**Testing**
Tested on examples in https://github.com/gfx-rs/wgpu-rs/pull/537

Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
bors[bot] 2020-08-27 21:06:27 +00:00 committed by GitHub
commit 4de1d24bc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 217 additions and 132 deletions

39
Cargo.lock generated
View File

@ -338,6 +338,12 @@ dependencies = [
"termcolor",
]
[[package]]
name = "fixedbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
name = "float-cmp"
version = "0.7.0"
@ -542,6 +548,15 @@ dependencies = [
"slab",
]
[[package]]
name = "hashbrown"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25"
dependencies = [
"autocfg",
]
[[package]]
name = "hermit-abi"
version = "0.1.13"
@ -569,6 +584,16 @@ dependencies = [
"quick-error",
]
[[package]]
name = "indexmap"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "inplace_it"
version = "0.3.2"
@ -805,13 +830,13 @@ dependencies = [
[[package]]
name = "naga"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0873deb76cf44b7454fba7b2ba6a89d3de70c08aceffd2c489379b3d9d08e661"
source = "git+https://github.com/gfx-rs/naga?rev=bd9efe5915e548b9a2ec1f3d3e9296c90b31e69a#bd9efe5915e548b9a2ec1f3d3e9296c90b31e69a"
dependencies = [
"bitflags",
"fxhash",
"log",
"num-traits",
"petgraph",
"spirv_headers",
"thiserror",
]
@ -1002,6 +1027,16 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "petgraph"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "pkg-config"
version = "0.3.17"

View File

@ -39,9 +39,9 @@ gfx-memory = "0.2"
[dependencies.naga]
version = "0.2"
#git = "https://github.com/gfx-rs/naga"
#rev = "1eb637038dd15fc1dad770eca8e6943424dbc122"
features = ["spirv"]
git = "https://github.com/gfx-rs/naga"
rev = "bd9efe5915e548b9a2ec1f3d3e9296c90b31e69a"
features = ["spirv-in", "spirv-out"]
[dependencies.wgt]
path = "../wgpu-types"

View File

@ -65,16 +65,22 @@ pub enum BindingError {
dim: naga::ImageDimension,
is_array: bool,
},
#[error("component type {0:?} of a sampled texture doesn't match the shader")]
WrongTextureComponentType(Option<naga::ScalarKind>),
#[error("texture sampling capability doesn't match the shader")]
WrongTextureSampled,
#[error("multisampled flag doesn't match the shader")]
WrongTextureMultisampled,
#[error("component type {binding:?} of a sampled texture doesn't match the shader {shader:?}")]
WrongTextureComponentType {
binding: naga::ScalarKind,
shader: naga::ScalarKind,
},
#[error("texture class {binding:?} doesn't match the shader {shader:?}")]
WrongTextureClass {
binding: naga::ImageClass,
shader: naga::ImageClass,
},
#[error("comparison flag doesn't match the shader")]
WrongSamplerComparison,
#[error("derived bind group layout type is not consistent between stages")]
InconsistentlyDerivedType,
#[error("texture format {0:?} isn't recognized")]
UnknownStorageFormat(wgt::TextureFormat),
}
#[derive(Clone, Debug, Error)]
@ -151,6 +157,7 @@ fn get_aligned_type_size(
},
Ti::Struct { ref members } => members.last().map_or(0, |member| {
let offset = match member.origin {
naga::MemberOrigin::Empty => 0,
naga::MemberOrigin::BuiltIn(_) => {
tracing::error!("Missing offset on a struct member");
0 // TODO: make it a proper error
@ -204,22 +211,19 @@ fn check_binding_use(
naga::TypeInner::Sampler { comparison } => match entry.ty {
BindingType::Sampler { comparison: cmp } => {
if cmp == comparison {
Ok(naga::GlobalUse::empty())
Ok(naga::GlobalUse::LOAD)
} else {
Err(BindingError::WrongSamplerComparison)
}
}
_ => Err(BindingError::WrongType),
},
naga::TypeInner::Image { base, dim, flags } => {
if flags.contains(naga::ImageFlags::MULTISAMPLED) {
match entry.ty {
BindingType::SampledTexture {
multisampled: true, ..
} => {}
_ => return Err(BindingError::WrongTextureMultisampled),
}
}
naga::TypeInner::Image {
kind,
dim,
arrayed,
class,
} => {
let view_dimension = match entry.ty {
BindingType::SampledTexture { dimension, .. }
| BindingType::StorageTexture { dimension, .. } => dimension,
@ -230,7 +234,7 @@ fn check_binding_use(
})
}
};
if flags.contains(naga::ImageFlags::ARRAYED) {
if arrayed {
match (dim, view_dimension) {
(naga::ImageDimension::D2, wgt::TextureViewDimension::D2Array) => (),
(naga::ImageDimension::Cube, wgt::TextureViewDimension::CubeArray) => (),
@ -255,39 +259,66 @@ fn check_binding_use(
}
}
}
let (allowed_usage, is_sampled) = match entry.ty {
BindingType::SampledTexture { component_type, .. } => {
let expected_scalar_kind = match component_type {
wgt::TextureComponentType::Float => naga::ScalarKind::Float,
wgt::TextureComponentType::Sint => naga::ScalarKind::Sint,
wgt::TextureComponentType::Uint => naga::ScalarKind::Uint,
};
match module.types[base].inner {
naga::TypeInner::Scalar { kind, .. }
| naga::TypeInner::Vector { kind, .. }
if kind == expected_scalar_kind => {}
naga::TypeInner::Scalar { kind, .. }
| naga::TypeInner::Vector { kind, .. } => {
return Err(BindingError::WrongTextureComponentType(Some(kind)))
let expected_class = match entry.ty {
BindingType::SampledTexture {
dimension: _,
component_type,
multisampled,
} => {
let (expected_scalar_kind, comparison) = match component_type {
wgt::TextureComponentType::Float => (naga::ScalarKind::Float, false),
wgt::TextureComponentType::Sint => (naga::ScalarKind::Sint, false),
wgt::TextureComponentType::Uint => (naga::ScalarKind::Uint, false),
wgt::TextureComponentType::DepthComparison => {
(naga::ScalarKind::Float, true)
}
_ => return Err(BindingError::WrongTextureComponentType(None)),
};
(naga::GlobalUse::LOAD, true)
}
BindingType::StorageTexture { readonly, .. } => {
if readonly {
//TODO: check entry.storage_texture_format
(naga::GlobalUse::LOAD, false)
} else {
(naga::GlobalUse::STORE, false)
if kind != expected_scalar_kind {
return Err(BindingError::WrongTextureComponentType {
binding: expected_scalar_kind,
shader: kind,
});
}
if multisampled {
naga::ImageClass::Multisampled
} else if comparison {
naga::ImageClass::Depth
} else {
naga::ImageClass::Sampled
}
}
BindingType::StorageTexture {
readonly,
format,
dimension: _,
} => {
let naga_format = match format {
wgt::TextureFormat::Rgba32Float => naga::StorageFormat::Rgba32f,
_ => return Err(BindingError::UnknownStorageFormat(format)),
};
let access = if readonly {
naga::StorageAccess::LOAD
} else {
naga::StorageAccess::STORE
};
naga::ImageClass::Storage(naga_format, access)
}
_ => return Err(BindingError::WrongType),
};
if is_sampled != flags.contains(naga::ImageFlags::SAMPLED) {
return Err(BindingError::WrongTextureSampled);
if class != expected_class {
return Err(BindingError::WrongTextureClass {
binding: expected_class,
shader: class,
});
}
Ok(allowed_usage)
Ok(match class {
naga::ImageClass::Storage(_, access)
if access.contains(naga::StorageAccess::STORE) =>
{
naga::GlobalUse::STORE
}
_ => naga::GlobalUse::LOAD,
})
}
_ => Err(BindingError::WrongType),
}
@ -367,133 +398,137 @@ impl<'a, T> std::ops::Deref for MaybeOwned<'a, T> {
pub fn map_vertex_format(format: wgt::VertexFormat) -> naga::TypeInner {
use naga::TypeInner as Ti;
use wgt::VertexFormat as Vf;
//Note: Shader always sees data as int, uint, or float.
// It doesn't know if the original is normalized in a tighter form.
let width = 4;
match format {
Vf::Uchar2 => Ti::Vector {
size: naga::VectorSize::Bi,
kind: naga::ScalarKind::Uint,
width: 1,
width,
},
Vf::Uchar4 => Ti::Vector {
size: naga::VectorSize::Quad,
kind: naga::ScalarKind::Uint,
width: 1,
width,
},
Vf::Char2 => Ti::Vector {
size: naga::VectorSize::Bi,
kind: naga::ScalarKind::Sint,
width: 1,
width,
},
Vf::Char4 => Ti::Vector {
size: naga::VectorSize::Quad,
kind: naga::ScalarKind::Sint,
width: 1,
width,
},
Vf::Uchar2Norm => Ti::Vector {
size: naga::VectorSize::Bi,
kind: naga::ScalarKind::Float,
width: 1,
width,
},
Vf::Uchar4Norm => Ti::Vector {
size: naga::VectorSize::Quad,
kind: naga::ScalarKind::Float,
width: 1,
width,
},
Vf::Char2Norm => Ti::Vector {
size: naga::VectorSize::Bi,
kind: naga::ScalarKind::Float,
width: 1,
width,
},
Vf::Char4Norm => Ti::Vector {
size: naga::VectorSize::Quad,
kind: naga::ScalarKind::Float,
width: 1,
width,
},
Vf::Ushort2 => Ti::Vector {
size: naga::VectorSize::Bi,
kind: naga::ScalarKind::Uint,
width: 2,
width,
},
Vf::Ushort4 => Ti::Vector {
size: naga::VectorSize::Quad,
kind: naga::ScalarKind::Uint,
width: 2,
width,
},
Vf::Short2 => Ti::Vector {
size: naga::VectorSize::Bi,
kind: naga::ScalarKind::Sint,
width: 2,
width,
},
Vf::Short4 => Ti::Vector {
size: naga::VectorSize::Quad,
kind: naga::ScalarKind::Sint,
width: 2,
width,
},
Vf::Ushort2Norm | Vf::Short2Norm | Vf::Half2 => Ti::Vector {
size: naga::VectorSize::Bi,
kind: naga::ScalarKind::Float,
width: 2,
width,
},
Vf::Ushort4Norm | Vf::Short4Norm | Vf::Half4 => Ti::Vector {
size: naga::VectorSize::Quad,
kind: naga::ScalarKind::Float,
width: 2,
width,
},
Vf::Float => Ti::Scalar {
kind: naga::ScalarKind::Float,
width: 4,
width,
},
Vf::Float2 => Ti::Vector {
size: naga::VectorSize::Bi,
kind: naga::ScalarKind::Float,
width: 4,
width,
},
Vf::Float3 => Ti::Vector {
size: naga::VectorSize::Tri,
kind: naga::ScalarKind::Float,
width: 4,
width,
},
Vf::Float4 => Ti::Vector {
size: naga::VectorSize::Quad,
kind: naga::ScalarKind::Float,
width: 4,
width,
},
Vf::Uint => Ti::Scalar {
kind: naga::ScalarKind::Uint,
width: 4,
width,
},
Vf::Uint2 => Ti::Vector {
size: naga::VectorSize::Bi,
kind: naga::ScalarKind::Uint,
width: 4,
width,
},
Vf::Uint3 => Ti::Vector {
size: naga::VectorSize::Tri,
kind: naga::ScalarKind::Uint,
width: 4,
width,
},
Vf::Uint4 => Ti::Vector {
size: naga::VectorSize::Quad,
kind: naga::ScalarKind::Uint,
width: 4,
width,
},
Vf::Int => Ti::Scalar {
kind: naga::ScalarKind::Sint,
width: 4,
width,
},
Vf::Int2 => Ti::Vector {
size: naga::VectorSize::Bi,
kind: naga::ScalarKind::Sint,
width: 4,
width,
},
Vf::Int3 => Ti::Vector {
size: naga::VectorSize::Tri,
kind: naga::ScalarKind::Sint,
width: 4,
width,
},
Vf::Int4 => Ti::Vector {
size: naga::VectorSize::Quad,
kind: naga::ScalarKind::Sint,
width: 4,
width,
},
}
}
@ -502,72 +537,75 @@ fn map_texture_format(format: wgt::TextureFormat) -> naga::TypeInner {
use naga::{ScalarKind as Sk, TypeInner as Ti, VectorSize as Vs};
use wgt::TextureFormat as Tf;
//Note: Shader always sees data as int, uint, or float.
// It doesn't know if the original is normalized in a tighter form.
let width = 4;
match format {
Tf::R8Unorm | Tf::R8Snorm => Ti::Scalar {
kind: Sk::Float,
width: 1,
width,
},
Tf::R8Uint => Ti::Scalar {
kind: Sk::Uint,
width: 1,
width,
},
Tf::R8Sint => Ti::Scalar {
kind: Sk::Sint,
width: 1,
width,
},
Tf::R16Uint => Ti::Scalar {
kind: Sk::Uint,
width: 2,
width,
},
Tf::R16Sint => Ti::Scalar {
kind: Sk::Sint,
width: 2,
width,
},
Tf::R16Float => Ti::Scalar {
kind: Sk::Float,
width: 2,
width,
},
Tf::Rg8Unorm | Tf::Rg8Snorm => Ti::Vector {
size: Vs::Bi,
kind: Sk::Float,
width: 1,
width,
},
Tf::Rg8Uint => Ti::Vector {
size: Vs::Bi,
kind: Sk::Uint,
width: 1,
width,
},
Tf::Rg8Sint => Ti::Vector {
size: Vs::Bi,
kind: Sk::Sint,
width: 1,
width,
},
Tf::R32Uint => Ti::Scalar {
kind: Sk::Uint,
width: 4,
width,
},
Tf::R32Sint => Ti::Scalar {
kind: Sk::Sint,
width: 4,
width,
},
Tf::R32Float => Ti::Scalar {
kind: Sk::Float,
width: 4,
width,
},
Tf::Rg16Uint => Ti::Vector {
size: Vs::Bi,
kind: Sk::Uint,
width: 2,
width,
},
Tf::Rg16Sint => Ti::Vector {
size: Vs::Bi,
kind: Sk::Sint,
width: 2,
width,
},
Tf::Rg16Float => Ti::Vector {
size: Vs::Bi,
kind: Sk::Float,
width: 2,
width,
},
Tf::Rgba8Unorm
| Tf::Rgba8UnormSrgb
@ -576,72 +614,72 @@ fn map_texture_format(format: wgt::TextureFormat) -> naga::TypeInner {
| Tf::Bgra8UnormSrgb => Ti::Vector {
size: Vs::Quad,
kind: Sk::Float,
width: 1,
width,
},
Tf::Rgba8Uint => Ti::Vector {
size: Vs::Quad,
kind: Sk::Uint,
width: 1,
width,
},
Tf::Rgba8Sint => Ti::Vector {
size: Vs::Quad,
kind: Sk::Sint,
width: 1,
width,
},
Tf::Rgb10a2Unorm => Ti::Vector {
size: Vs::Quad,
kind: Sk::Float,
width: 1,
width,
},
Tf::Rg11b10Float => Ti::Vector {
size: Vs::Tri,
kind: Sk::Float,
width: 1,
width,
},
Tf::Rg32Uint => Ti::Vector {
size: Vs::Bi,
kind: Sk::Uint,
width: 4,
width,
},
Tf::Rg32Sint => Ti::Vector {
size: Vs::Bi,
kind: Sk::Sint,
width: 4,
width,
},
Tf::Rg32Float => Ti::Vector {
size: Vs::Bi,
kind: Sk::Float,
width: 4,
width,
},
Tf::Rgba16Uint => Ti::Vector {
size: Vs::Quad,
kind: Sk::Uint,
width: 2,
width,
},
Tf::Rgba16Sint => Ti::Vector {
size: Vs::Quad,
kind: Sk::Sint,
width: 2,
width,
},
Tf::Rgba16Float => Ti::Vector {
size: Vs::Quad,
kind: Sk::Float,
width: 2,
width,
},
Tf::Rgba32Uint => Ti::Vector {
size: Vs::Quad,
kind: Sk::Uint,
width: 4,
width,
},
Tf::Rgba32Sint => Ti::Vector {
size: Vs::Quad,
kind: Sk::Sint,
width: 4,
width,
},
Tf::Rgba32Float => Ti::Vector {
size: Vs::Quad,
kind: Sk::Float,
width: 4,
width,
},
Tf::Depth32Float | Tf::Depth24Plus | Tf::Depth24PlusStencil8 => {
panic!("Unexpected depth format")
@ -656,21 +694,21 @@ fn map_texture_format(format: wgt::TextureFormat) -> naga::TypeInner {
| Tf::Bc7RgbaUnormSrgb => Ti::Vector {
size: Vs::Quad,
kind: Sk::Float,
width: 1,
width,
},
Tf::Bc4RUnorm | Tf::Bc4RSnorm => Ti::Scalar {
kind: Sk::Float,
width: 1,
width,
},
Tf::Bc5RgUnorm | Tf::Bc5RgSnorm => Ti::Vector {
size: Vs::Bi,
kind: Sk::Float,
width: 1,
width,
},
Tf::Bc6hRgbUfloat | Tf::Bc6hRgbSfloat => Ti::Vector {
size: Vs::Tri,
kind: Sk::Float,
width: 1,
width,
},
}
}
@ -715,39 +753,49 @@ fn derive_binding_type(
}
}
naga::TypeInner::Sampler { comparison } => BindingType::Sampler { comparison },
naga::TypeInner::Image { base, dim, flags } => {
let array = flags.contains(naga::ImageFlags::ARRAYED);
naga::TypeInner::Image {
kind,
dim,
arrayed,
class,
} => {
let dimension = match dim {
naga::ImageDimension::D1 => wgt::TextureViewDimension::D1,
naga::ImageDimension::D2 if array => wgt::TextureViewDimension::D2Array,
naga::ImageDimension::D2 if arrayed => wgt::TextureViewDimension::D2Array,
naga::ImageDimension::D2 => wgt::TextureViewDimension::D2,
naga::ImageDimension::D3 => wgt::TextureViewDimension::D3,
naga::ImageDimension::Cube if array => wgt::TextureViewDimension::CubeArray,
naga::ImageDimension::Cube if arrayed => wgt::TextureViewDimension::CubeArray,
naga::ImageDimension::Cube => wgt::TextureViewDimension::Cube,
};
if flags.contains(naga::ImageFlags::SAMPLED) {
BindingType::SampledTexture {
let component_type = match kind {
naga::ScalarKind::Float => wgt::TextureComponentType::Float,
naga::ScalarKind::Sint => wgt::TextureComponentType::Sint,
naga::ScalarKind::Uint => wgt::TextureComponentType::Uint,
naga::ScalarKind::Bool => unreachable!(),
};
match class {
naga::ImageClass::Sampled => BindingType::SampledTexture {
dimension,
component_type: match module.types[base].inner {
naga::TypeInner::Scalar { kind, .. }
| naga::TypeInner::Vector { kind, .. } => match kind {
naga::ScalarKind::Float => wgt::TextureComponentType::Float,
naga::ScalarKind::Sint => wgt::TextureComponentType::Sint,
naga::ScalarKind::Uint => wgt::TextureComponentType::Uint,
other => {
return Err(BindingError::WrongTextureComponentType(Some(other)))
}
},
_ => return Err(BindingError::WrongTextureComponentType(None)),
component_type,
multisampled: false,
},
naga::ImageClass::Multisampled => BindingType::SampledTexture {
dimension,
component_type,
multisampled: true,
},
naga::ImageClass::Depth => BindingType::SampledTexture {
dimension,
component_type: wgt::TextureComponentType::DepthComparison,
multisampled: false,
},
naga::ImageClass::Storage(format, access) => BindingType::StorageTexture {
dimension,
format: match format {
naga::StorageFormat::Rgba32f => wgt::TextureFormat::Rgba32Float,
},
multisampled: flags.contains(naga::ImageFlags::MULTISAMPLED),
}
} else {
BindingType::StorageTexture {
dimension,
format: wgt::TextureFormat::Rgba8Unorm, //TODO
readonly: !flags.contains(naga::ImageFlags::CAN_STORE),
}
readonly: !access.contains(naga::StorageAccess::STORE),
},
}
}
_ => return Err(BindingError::WrongType),

View File

@ -1591,6 +1591,8 @@ pub enum TextureComponentType {
Sint,
/// They see it as a unsigned integer `utexture1D`, `utexture2D` etc
Uint,
/// They see it as a floating point 0-1 result of comparison, i.e. `shadowTexture2D`
DepthComparison,
}
impl From<TextureFormat> for TextureComponentType {