mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-25 08:13:27 +00:00
Add pervasive Naga support to shader module loading
The purpose of the PR is to support Naga modules everywhere. As a requirement, it updates the gfx-rs version used. Most of the logic is dedicated towards building a shader interface, where previously we just used naga's IR. Now we have our own mini-IR.
This commit is contained in:
parent
d164b0dbc6
commit
749f737c89
30
Cargo.lock
generated
30
Cargo.lock
generated
@ -441,7 +441,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gfx-auxil"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=1d14789011cb892f4c1a205d3f8a87d479c2e354#1d14789011cb892f4c1a205d3f8a87d479c2e354"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=654ad48ee39ce2a341407ae2857ddf4db639ea54#654ad48ee39ce2a341407ae2857ddf4db639ea54"
|
||||
dependencies = [
|
||||
"fxhash",
|
||||
"gfx-hal",
|
||||
@ -451,7 +451,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gfx-backend-dx11"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=1d14789011cb892f4c1a205d3f8a87d479c2e354#1d14789011cb892f4c1a205d3f8a87d479c2e354"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=654ad48ee39ce2a341407ae2857ddf4db639ea54#654ad48ee39ce2a341407ae2857ddf4db639ea54"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
@ -472,7 +472,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gfx-backend-dx12"
|
||||
version = "0.6.2"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=1d14789011cb892f4c1a205d3f8a87d479c2e354#1d14789011cb892f4c1a205d3f8a87d479c2e354"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=654ad48ee39ce2a341407ae2857ddf4db639ea54#654ad48ee39ce2a341407ae2857ddf4db639ea54"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-set",
|
||||
@ -492,7 +492,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gfx-backend-empty"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=1d14789011cb892f4c1a205d3f8a87d479c2e354#1d14789011cb892f4c1a205d3f8a87d479c2e354"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=654ad48ee39ce2a341407ae2857ddf4db639ea54#654ad48ee39ce2a341407ae2857ddf4db639ea54"
|
||||
dependencies = [
|
||||
"gfx-hal",
|
||||
"log",
|
||||
@ -502,7 +502,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gfx-backend-gl"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=1d14789011cb892f4c1a205d3f8a87d479c2e354#1d14789011cb892f4c1a205d3f8a87d479c2e354"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=654ad48ee39ce2a341407ae2857ddf4db639ea54#654ad48ee39ce2a341407ae2857ddf4db639ea54"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
@ -524,7 +524,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gfx-backend-metal"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=1d14789011cb892f4c1a205d3f8a87d479c2e354#1d14789011cb892f4c1a205d3f8a87d479c2e354"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=654ad48ee39ce2a341407ae2857ddf4db639ea54#654ad48ee39ce2a341407ae2857ddf4db639ea54"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
@ -537,6 +537,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"metal",
|
||||
"naga",
|
||||
"objc",
|
||||
"parking_lot 0.11.0",
|
||||
"range-alloc",
|
||||
@ -548,7 +549,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gfx-backend-vulkan"
|
||||
version = "0.6.5"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=1d14789011cb892f4c1a205d3f8a87d479c2e354#1d14789011cb892f4c1a205d3f8a87d479c2e354"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=654ad48ee39ce2a341407ae2857ddf4db639ea54#654ad48ee39ce2a341407ae2857ddf4db639ea54"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"ash",
|
||||
@ -567,10 +568,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gfx-hal"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=1d14789011cb892f4c1a205d3f8a87d479c2e354#1d14789011cb892f4c1a205d3f8a87d479c2e354"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=654ad48ee39ce2a341407ae2857ddf4db639ea54#654ad48ee39ce2a341407ae2857ddf4db639ea54"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"naga",
|
||||
"raw-window-handle",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -605,7 +608,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gpu-descriptor"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zakarumych/gpu-descriptor?rev=831460c4b5120d9a74744d542f39a95b9816b5ab#831460c4b5120d9a74744d542f39a95b9816b5ab"
|
||||
source = "git+https://github.com/zakarumych/gpu-descriptor?rev=df74fd8c7bea03149058a41aab0e4fe04077b266#df74fd8c7bea03149058a41aab0e4fe04077b266"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"gpu-descriptor-types",
|
||||
@ -615,7 +618,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gpu-descriptor-types"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zakarumych/gpu-descriptor?rev=831460c4b5120d9a74744d542f39a95b9816b5ab#831460c4b5120d9a74744d542f39a95b9816b5ab"
|
||||
source = "git+https://github.com/zakarumych/gpu-descriptor?rev=df74fd8c7bea03149058a41aab0e4fe04077b266#df74fd8c7bea03149058a41aab0e4fe04077b266"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@ -830,7 +833,7 @@ version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||
dependencies = [
|
||||
"libc 0.2.80",
|
||||
"libc 0.1.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -924,13 +927,14 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/gfx-rs/naga?rev=96c80738650822de35f77ab6a589f309460c8f39#96c80738650822de35f77ab6a589f309460c8f39"
|
||||
source = "git+https://github.com/gfx-rs/naga?tag=gfx-2#0d81b1f78c763a2f564194ec108bcb8ead10ea2e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fxhash",
|
||||
"log",
|
||||
"num-traits",
|
||||
"petgraph",
|
||||
"serde",
|
||||
"spirv_headers",
|
||||
"thiserror",
|
||||
]
|
||||
@ -1213,7 +1217,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "range-alloc"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=1d14789011cb892f4c1a205d3f8a87d479c2e354#1d14789011cb892f4c1a205d3f8a87d479c2e354"
|
||||
source = "git+https://github.com/gfx-rs/gfx?rev=654ad48ee39ce2a341407ae2857ddf4db639ea54#654ad48ee39ce2a341407ae2857ddf4db639ea54"
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
|
12
Cargo.toml
12
Cargo.toml
@ -5,3 +5,15 @@ members = [
|
||||
"wgpu-core",
|
||||
"wgpu-types",
|
||||
]
|
||||
|
||||
#[patch."https://github.com/gfx-rs/gfx"]
|
||||
#hal = { package = "gfx-hal", path = "../gfx/src/hal" }
|
||||
#gfx-backend-vulkan = { path = "../gfx/src/backend/vulkan" }
|
||||
#gfx-backend-metal = { path = "../gfx/src/backend/metal", features = ["naga"] }
|
||||
#gfx-backend-gl = { path = "../gfx/src/backend/gl" }
|
||||
#gfx-backend-dx12 = { path = "../gfx/src/backend/dx12" }
|
||||
#gfx-backend-dx11 = { path = "../gfx/src/backend/dx11" }
|
||||
#gfx-backend-empty = { path = "../gfx/src/backend/empty" }
|
||||
|
||||
#[patch."https://github.com/gfx-rs/naga"]
|
||||
#naga = { path = "../naga" }
|
||||
|
@ -209,22 +209,23 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
A::DestroyBindGroup(id) => {
|
||||
self.bind_group_drop::<B>(id);
|
||||
}
|
||||
A::CreateShaderModule { id, data, label } => {
|
||||
A::CreateShaderModule { id, label, data } => {
|
||||
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,
|
||||
experimental_translation: false,
|
||||
};
|
||||
let (_, error) = self.device_create_shader_module::<B>(device, &desc, id);
|
||||
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))
|
||||
};
|
||||
let (_, error) = self.device_create_shader_module::<B>(device, &desc, source, id);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
|
@ -213,5 +213,12 @@ impl Corpus {
|
||||
|
||||
#[test]
|
||||
fn test_api() {
|
||||
wgpu_subscriber::initialize_default_subscriber(
|
||||
std::env::var("WGPU_CHROME_TRACE")
|
||||
.as_ref()
|
||||
.map(Path::new)
|
||||
.ok(),
|
||||
);
|
||||
|
||||
Corpus::run_from(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/data/all.ron"))
|
||||
}
|
||||
|
@ -14,9 +14,9 @@ license = "MPL-2.0"
|
||||
[features]
|
||||
default = []
|
||||
# Enable API tracing
|
||||
trace = ["ron", "serde", "wgt/trace"]
|
||||
trace = ["ron", "serde", "wgt/trace", "naga/serialize"]
|
||||
# Enable API replaying
|
||||
replay = ["serde", "wgt/replay"]
|
||||
replay = ["serde", "wgt/replay", "naga/deserialize"]
|
||||
# Enable serializable compute/render passes, and bundle encoders.
|
||||
serial-pass = ["serde", "wgt/serde", "arrayvec/serde"]
|
||||
|
||||
@ -25,8 +25,6 @@ arrayvec = "0.5"
|
||||
bitflags = "1.0"
|
||||
copyless = "0.1"
|
||||
fxhash = "0.2"
|
||||
hal = { package = "gfx-hal", git = "https://github.com/gfx-rs/gfx", rev = "1d14789011cb892f4c1a205d3f8a87d479c2e354" }
|
||||
gfx-backend-empty = { git = "https://github.com/gfx-rs/gfx", rev = "1d14789011cb892f4c1a205d3f8a87d479c2e354" }
|
||||
parking_lot = "0.11"
|
||||
raw-window-handle = { version = "0.3", optional = true }
|
||||
ron = { version = "0.6", optional = true }
|
||||
@ -35,12 +33,27 @@ smallvec = "1"
|
||||
tracing = { version = "0.1", default-features = false, features = ["std"] }
|
||||
thiserror = "1"
|
||||
gpu-alloc = { git = "https://github.com/zakarumych/gpu-alloc", rev = "d07be73f9439a37c89f5b72f2500cbf0eb4ff613" }
|
||||
gpu-descriptor = { git = "https://github.com/zakarumych/gpu-descriptor", rev = "831460c4b5120d9a74744d542f39a95b9816b5ab"}
|
||||
gpu-descriptor = { git = "https://github.com/zakarumych/gpu-descriptor", rev = "df74fd8c7bea03149058a41aab0e4fe04077b266"}
|
||||
|
||||
hal = { package = "gfx-hal", git = "https://github.com/gfx-rs/gfx", rev = "654ad48ee39ce2a341407ae2857ddf4db639ea54" }
|
||||
gfx-backend-empty = { git = "https://github.com/gfx-rs/gfx", rev = "654ad48ee39ce2a341407ae2857ddf4db639ea54" }
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))'.dependencies]
|
||||
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "654ad48ee39ce2a341407ae2857ddf4db639ea54" }
|
||||
gfx-backend-gl = { git = "https://github.com/gfx-rs/gfx", rev = "654ad48ee39ce2a341407ae2857ddf4db639ea54" }
|
||||
|
||||
[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
|
||||
gfx-backend-metal = { git = "https://github.com/gfx-rs/gfx", rev = "654ad48ee39ce2a341407ae2857ddf4db639ea54", features = ["naga"] }
|
||||
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "654ad48ee39ce2a341407ae2857ddf4db639ea54", optional = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
gfx-backend-dx12 = { git = "https://github.com/gfx-rs/gfx", rev = "654ad48ee39ce2a341407ae2857ddf4db639ea54" }
|
||||
gfx-backend-dx11 = { git = "https://github.com/gfx-rs/gfx", rev = "654ad48ee39ce2a341407ae2857ddf4db639ea54" }
|
||||
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "654ad48ee39ce2a341407ae2857ddf4db639ea54" }
|
||||
|
||||
[dependencies.naga]
|
||||
version = "0.2"
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "96c80738650822de35f77ab6a589f309460c8f39"
|
||||
tag = "gfx-2"
|
||||
features = ["spv-in", "spv-out", "wgsl-in"]
|
||||
|
||||
[dependencies.wgt]
|
||||
@ -48,19 +61,6 @@ path = "../wgpu-types"
|
||||
package = "wgpu-types"
|
||||
version = "0.6"
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))'.dependencies]
|
||||
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "1d14789011cb892f4c1a205d3f8a87d479c2e354" }
|
||||
gfx-backend-gl = { git = "https://github.com/gfx-rs/gfx", rev = "1d14789011cb892f4c1a205d3f8a87d479c2e354" }
|
||||
|
||||
[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
|
||||
gfx-backend-metal = { git = "https://github.com/gfx-rs/gfx", rev = "1d14789011cb892f4c1a205d3f8a87d479c2e354" }
|
||||
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "1d14789011cb892f4c1a205d3f8a87d479c2e354", optional = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
gfx-backend-dx12 = { git = "https://github.com/gfx-rs/gfx", rev = "1d14789011cb892f4c1a205d3f8a87d479c2e354" }
|
||||
gfx-backend-dx11 = { git = "https://github.com/gfx-rs/gfx", rev = "1d14789011cb892f4c1a205d3f8a87d479c2e354" }
|
||||
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "1d14789011cb892f4c1a205d3f8a87d479c2e354" }
|
||||
|
||||
[dev-dependencies]
|
||||
loom = "0.3"
|
||||
|
||||
|
@ -6,9 +6,7 @@ fn main() {
|
||||
// Setup cfg aliases
|
||||
cfg_aliases::cfg_aliases! {
|
||||
// Vendors/systems
|
||||
ios: { target_os = "ios" },
|
||||
macos: { target_os = "macos" },
|
||||
apple: { any(ios, macos) },
|
||||
apple: { any(target_os = "ios", target_os = "macos") },
|
||||
|
||||
// Backends
|
||||
vulkan: { any(windows, all(unix, not(apple)), feature = "gfx-backend-vulkan") },
|
||||
|
@ -500,7 +500,6 @@ impl RenderBundle {
|
||||
use hal::command::CommandBuffer as _;
|
||||
|
||||
let mut offsets = self.base.dynamic_offsets.as_slice();
|
||||
let mut index_type = hal::IndexType::U16;
|
||||
let mut pipeline_layout_id = None::<id::Valid<id::PipelineLayoutId>>;
|
||||
|
||||
for command in self.base.commands.iter() {
|
||||
@ -531,7 +530,7 @@ impl RenderBundle {
|
||||
offset,
|
||||
size,
|
||||
} => {
|
||||
index_type = conv::map_index_format(index_format);
|
||||
let index_type = conv::map_index_format(index_format);
|
||||
|
||||
let &(ref buffer, _) = buffer_guard
|
||||
.get(buffer_id)
|
||||
|
@ -17,7 +17,7 @@ struct DescriptorDevice<'a, B: hal::Backend>(&'a B::Device);
|
||||
|
||||
impl<B: hal::Backend> DescriptorAllocator<B> {
|
||||
pub fn new() -> Self {
|
||||
DescriptorAllocator(unsafe { gpu_descriptor::DescriptorAllocator::new(0) })
|
||||
DescriptorAllocator(gpu_descriptor::DescriptorAllocator::new(0))
|
||||
}
|
||||
|
||||
pub fn allocate(
|
||||
@ -27,18 +27,19 @@ impl<B: hal::Backend> DescriptorAllocator<B> {
|
||||
layout_descriptor_count: &DescriptorTotalCount,
|
||||
count: u32,
|
||||
) -> Result<Vec<DescriptorSet<B>>, DeviceError> {
|
||||
self.0
|
||||
.allocate(
|
||||
unsafe {
|
||||
self.0.allocate(
|
||||
&DescriptorDevice::<B>(device),
|
||||
layout,
|
||||
gpu_descriptor::DescriptorSetLayoutCreateFlags::empty(),
|
||||
layout_descriptor_count,
|
||||
count,
|
||||
)
|
||||
.map_err(|err| {
|
||||
tracing::warn!("Descriptor set allocation failed: {}", err);
|
||||
DeviceError::OutOfMemory
|
||||
})
|
||||
}
|
||||
.map_err(|err| {
|
||||
tracing::warn!("Descriptor set allocation failed: {}", err);
|
||||
DeviceError::OutOfMemory
|
||||
})
|
||||
}
|
||||
|
||||
pub fn free(&mut self, device: &B::Device, sets: impl IntoIterator<Item = DescriptorSet<B>>) {
|
||||
@ -46,7 +47,7 @@ impl<B: hal::Backend> DescriptorAllocator<B> {
|
||||
}
|
||||
|
||||
pub fn cleanup(&mut self, device: &B::Device) {
|
||||
self.0.cleanup(&DescriptorDevice::<B>(device))
|
||||
unsafe { self.0.cleanup(&DescriptorDevice::<B>(device)) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +122,7 @@ impl<B: hal::Backend>
|
||||
self.0,
|
||||
max_sets as usize,
|
||||
ranges,
|
||||
hal::pso::DescriptorPoolCreateFlags::from_bits_truncate(flags.bits() as u32),
|
||||
hal::pso::DescriptorPoolCreateFlags::from_bits_truncate(flags.bits()),
|
||||
) {
|
||||
Ok(pool) => Ok(pool),
|
||||
Err(hal::device::OutOfMemory::Host) => {
|
||||
|
@ -836,84 +836,105 @@ 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
|
||||
desc: &pipeline::ShaderModuleDescriptor<'a>,
|
||||
source: pipeline::ShaderModuleSource<'a>,
|
||||
) -> Result<pipeline::ShaderModule<B>, pipeline::CreateShaderModuleError> {
|
||||
// First, try to produce a Naga module.
|
||||
let (spv, module) = match source {
|
||||
pipeline::ShaderModuleSource::SpirV(spv) => {
|
||||
// Parse the given shader code and store its representation.
|
||||
let parser =
|
||||
naga::front::spv::Parser::new(spv.iter().cloned(), &Default::default());
|
||||
let module = match parser.parse() {
|
||||
Ok(module) => Some(module),
|
||||
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 or reflected");
|
||||
None
|
||||
}
|
||||
};
|
||||
(Cow::Borrowed(&**spv), module)
|
||||
(Some(spv), module)
|
||||
}
|
||||
pipeline::ShaderModuleSource::Wgsl(ref code) => {
|
||||
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 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
|
||||
},
|
||||
)
|
||||
}*/
|
||||
match naga::front::wgsl::parse_str(&code) {
|
||||
Ok(module) => (None, Some(module)),
|
||||
Err(err) => {
|
||||
tracing::error!("Failed to parse WGSL code: {}", err);
|
||||
return Err(pipeline::CreateShaderModuleError::Parsing);
|
||||
}
|
||||
}
|
||||
}
|
||||
pipeline::ShaderModuleSource::Naga(module) => (None, Some(module)),
|
||||
};
|
||||
|
||||
if let Some(ref module) = naga {
|
||||
naga::proc::Validator::new().validate(module)?;
|
||||
}
|
||||
let interface = module.as_ref().map(|m| validation::Interface::new(m));
|
||||
|
||||
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 naga_result = match module {
|
||||
// If succeeded, then validate it and attempt to give it to gfx-hal directly.
|
||||
Some(module) => {
|
||||
if self.private_features.shader_validation {
|
||||
naga::proc::Validator::new().validate(&module)?;
|
||||
}
|
||||
if desc.experimental_translation {
|
||||
match unsafe { self.raw.create_shader_module_from_naga(module) } {
|
||||
Ok(raw) => Ok(raw),
|
||||
Err((hal::device::ShaderError::CompilationFailed(msg), module)) => {
|
||||
tracing::warn!("Shader module compilation failed: {}", msg);
|
||||
Err(Some(module))
|
||||
}
|
||||
Err((_, module)) => Err(Some(module)),
|
||||
}
|
||||
} else {
|
||||
Err(Some(module))
|
||||
}
|
||||
}
|
||||
None => Err(None),
|
||||
};
|
||||
let shader = pipeline::ShaderModule {
|
||||
raw,
|
||||
|
||||
// Otherwise, fall back to SPIR-V.
|
||||
let spv_result = match naga_result {
|
||||
Ok(raw) => Ok(raw),
|
||||
Err(maybe_module) => {
|
||||
let spv = match spv {
|
||||
Some(data) => data,
|
||||
None => {
|
||||
// Produce a SPIR-V from the Naga module
|
||||
let module = maybe_module.unwrap();
|
||||
let mut flags = naga::back::spv::WriterFlags::empty();
|
||||
if cfg!(debug_assertions) {
|
||||
flags |= naga::back::spv::WriterFlags::DEBUG;
|
||||
}
|
||||
let data = naga::back::spv::write_vec(&module, flags);
|
||||
Cow::Owned(data)
|
||||
}
|
||||
};
|
||||
unsafe { self.raw.create_shader_module(&spv) }
|
||||
}
|
||||
};
|
||||
|
||||
Ok(pipeline::ShaderModule {
|
||||
raw: match spv_result {
|
||||
Ok(raw) => raw,
|
||||
Err(hal::device::ShaderError::OutOfMemory(_)) => {
|
||||
return Err(DeviceError::OutOfMemory.into());
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::error!("Shader error: {}", error);
|
||||
return Err(pipeline::CreateShaderModuleError::Parsing);
|
||||
}
|
||||
},
|
||||
device_id: Stored {
|
||||
value: id::Valid(self_id),
|
||||
ref_count: self.life_guard.add_ref(),
|
||||
},
|
||||
module: naga,
|
||||
interface,
|
||||
#[cfg(debug_assertions)]
|
||||
label: desc.label.to_string_or_default(),
|
||||
};
|
||||
Ok((shader, spv))
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a compatible render pass with a given key.
|
||||
@ -968,14 +989,12 @@ impl<B: GfxBackend> Device<B> {
|
||||
fn get_introspection_bind_group_layouts<'a>(
|
||||
pipeline_layout: &binding_model::PipelineLayout<B>,
|
||||
bgl_guard: &'a Storage<binding_model::BindGroupLayout<B>, id::BindGroupLayoutId>,
|
||||
) -> validation::IntrospectionBindGroupLayouts<'a> {
|
||||
validation::IntrospectionBindGroupLayouts::Given(
|
||||
pipeline_layout
|
||||
.bind_group_layout_ids
|
||||
.iter()
|
||||
.map(|&id| &bgl_guard[id].entries)
|
||||
.collect(),
|
||||
)
|
||||
) -> ArrayVec<[&'a binding_model::BindEntryMap; MAX_BIND_GROUPS]> {
|
||||
pipeline_layout
|
||||
.bind_group_layout_ids
|
||||
.iter()
|
||||
.map(|&id| &bgl_guard[id].entries)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn create_bind_group_layout(
|
||||
@ -1633,7 +1652,7 @@ impl<B: GfxBackend> Device<B> {
|
||||
let mut derived_group_layouts =
|
||||
ArrayVec::<[binding_model::BindEntryMap; MAX_BIND_GROUPS]>::new();
|
||||
|
||||
let interface = validation::StageInterface::default();
|
||||
let io = validation::StageIo::default();
|
||||
let pipeline_stage = &desc.compute_stage;
|
||||
let (shader_module_guard, _) = hub.shader_modules.read(&mut token);
|
||||
|
||||
@ -1645,24 +1664,30 @@ impl<B: GfxBackend> Device<B> {
|
||||
})?;
|
||||
|
||||
let flag = wgt::ShaderStage::COMPUTE;
|
||||
if let Some(ref module) = shader_module.module {
|
||||
let group_layouts = match desc.layout {
|
||||
Some(pipeline_layout_id) => Device::get_introspection_bind_group_layouts(
|
||||
if let Some(ref interface) = shader_module.interface {
|
||||
let provided_layouts = match desc.layout {
|
||||
Some(pipeline_layout_id) => Some(Device::get_introspection_bind_group_layouts(
|
||||
pipeline_layout_guard
|
||||
.get(pipeline_layout_id)
|
||||
.map_err(|_| pipeline::CreateComputePipelineError::InvalidLayout)?,
|
||||
&*bgl_guard,
|
||||
),
|
||||
)),
|
||||
None => {
|
||||
for _ in 0..self.limits.max_bind_groups {
|
||||
derived_group_layouts.push(binding_model::BindEntryMap::default());
|
||||
}
|
||||
validation::IntrospectionBindGroupLayouts::Derived(&mut derived_group_layouts)
|
||||
None
|
||||
}
|
||||
};
|
||||
let _ =
|
||||
validation::check_stage(module, group_layouts, &entry_point_name, flag, interface)
|
||||
.map_err(pipeline::CreateComputePipelineError::Stage)?;
|
||||
let _ = interface
|
||||
.check_stage(
|
||||
provided_layouts.as_ref().map(|p| p.as_slice()),
|
||||
&mut derived_group_layouts,
|
||||
&entry_point_name,
|
||||
flag,
|
||||
io,
|
||||
)
|
||||
.map_err(pipeline::CreateComputePipelineError::Stage)?;
|
||||
} else if desc.layout.is_none() {
|
||||
return Err(pipeline::ImplicitLayoutError::ReflectionError(flag).into());
|
||||
}
|
||||
@ -1768,7 +1793,7 @@ impl<B: GfxBackend> Device<B> {
|
||||
.unwrap_or_default();
|
||||
let rasterizer = conv::map_rasterization_state_descriptor(&rasterization_state);
|
||||
|
||||
let mut interface = validation::StageInterface::default();
|
||||
let mut io = validation::StageIo::default();
|
||||
let mut validated_stages = wgt::ShaderStage::empty();
|
||||
|
||||
let desc_vbs = &desc.vertex_state.vertex_buffers;
|
||||
@ -1814,9 +1839,9 @@ impl<B: GfxBackend> Device<B> {
|
||||
offset: attribute.offset as u32,
|
||||
},
|
||||
});
|
||||
interface.insert(
|
||||
io.insert(
|
||||
attribute.shader_location,
|
||||
validation::MaybeOwned::Owned(validation::map_vertex_format(attribute.format)),
|
||||
validation::NumericType::from_vertex_format(attribute.format),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1929,27 +1954,26 @@ impl<B: GfxBackend> Device<B> {
|
||||
error: validation::StageError::InvalidModule,
|
||||
})?;
|
||||
|
||||
if let Some(ref module) = shader_module.module {
|
||||
let group_layouts = match desc.layout {
|
||||
Some(pipeline_layout_id) => Device::get_introspection_bind_group_layouts(
|
||||
if let Some(ref interface) = shader_module.interface {
|
||||
let provided_layouts = match desc.layout {
|
||||
Some(pipeline_layout_id) => Some(Device::get_introspection_bind_group_layouts(
|
||||
pipeline_layout_guard
|
||||
.get(pipeline_layout_id)
|
||||
.map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?,
|
||||
&*bgl_guard,
|
||||
),
|
||||
None => validation::IntrospectionBindGroupLayouts::Derived(
|
||||
&mut derived_group_layouts,
|
||||
),
|
||||
)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
interface = validation::check_stage(
|
||||
module,
|
||||
group_layouts,
|
||||
&entry_point_name,
|
||||
flag,
|
||||
interface,
|
||||
)
|
||||
.map_err(|error| pipeline::CreateRenderPipelineError::Stage { flag, error })?;
|
||||
io = interface
|
||||
.check_stage(
|
||||
provided_layouts.as_ref().map(|p| p.as_slice()),
|
||||
&mut derived_group_layouts,
|
||||
&entry_point_name,
|
||||
flag,
|
||||
io,
|
||||
)
|
||||
.map_err(|error| pipeline::CreateRenderPipelineError::Stage { flag, error })?;
|
||||
validated_stages |= flag;
|
||||
}
|
||||
|
||||
@ -1972,30 +1996,30 @@ impl<B: GfxBackend> Device<B> {
|
||||
}
|
||||
})?;
|
||||
|
||||
let group_layouts = match desc.layout {
|
||||
Some(pipeline_layout_id) => Device::get_introspection_bind_group_layouts(
|
||||
let provided_layouts = match desc.layout {
|
||||
Some(pipeline_layout_id) => Some(Device::get_introspection_bind_group_layouts(
|
||||
pipeline_layout_guard
|
||||
.get(pipeline_layout_id)
|
||||
.map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?,
|
||||
&*bgl_guard,
|
||||
),
|
||||
None => validation::IntrospectionBindGroupLayouts::Derived(
|
||||
&mut derived_group_layouts,
|
||||
),
|
||||
)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
if validated_stages == wgt::ShaderStage::VERTEX {
|
||||
if let Some(ref module) = shader_module.module {
|
||||
interface = validation::check_stage(
|
||||
module,
|
||||
group_layouts,
|
||||
&entry_point_name,
|
||||
flag,
|
||||
interface,
|
||||
)
|
||||
.map_err(|error| {
|
||||
pipeline::CreateRenderPipelineError::Stage { flag, error }
|
||||
})?;
|
||||
if let Some(ref interface) = shader_module.interface {
|
||||
io = interface
|
||||
.check_stage(
|
||||
provided_layouts.as_ref().map(|p| p.as_slice()),
|
||||
&mut derived_group_layouts,
|
||||
&entry_point_name,
|
||||
flag,
|
||||
io,
|
||||
)
|
||||
.map_err(|error| pipeline::CreateRenderPipelineError::Stage {
|
||||
flag,
|
||||
error,
|
||||
})?;
|
||||
validated_stages |= flag;
|
||||
}
|
||||
}
|
||||
@ -2011,13 +2035,13 @@ impl<B: GfxBackend> Device<B> {
|
||||
|
||||
if validated_stages.contains(wgt::ShaderStage::FRAGMENT) {
|
||||
for (i, state) in color_states.iter().enumerate() {
|
||||
match interface.get(&(i as wgt::ShaderLocation)) {
|
||||
match io.get(&(i as wgt::ShaderLocation)) {
|
||||
Some(output) if validation::check_texture_format(state.format, output) => {}
|
||||
Some(output) => {
|
||||
tracing::warn!(
|
||||
"Incompatible fragment output[{}] from shader: {:?}, expected {:?}",
|
||||
i,
|
||||
&**output,
|
||||
output,
|
||||
state.format,
|
||||
);
|
||||
return Err(
|
||||
@ -2247,11 +2271,11 @@ pub enum DeviceError {
|
||||
OutOfMemory,
|
||||
}
|
||||
|
||||
impl From<hal::device::OomOrDeviceLost> for DeviceError {
|
||||
fn from(err: hal::device::OomOrDeviceLost) -> Self {
|
||||
impl From<hal::device::WaitError> for DeviceError {
|
||||
fn from(err: hal::device::WaitError) -> Self {
|
||||
match err {
|
||||
hal::device::OomOrDeviceLost::OutOfMemory(_) => Self::OutOfMemory,
|
||||
hal::device::OomOrDeviceLost::DeviceLost(_) => Self::Lost,
|
||||
hal::device::WaitError::OutOfMemory(_) => Self::OutOfMemory,
|
||||
hal::device::WaitError::DeviceLost(_) => Self::Lost,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3238,6 +3262,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
&self,
|
||||
device_id: id::DeviceId,
|
||||
desc: &pipeline::ShaderModuleDescriptor,
|
||||
source: pipeline::ShaderModuleSource,
|
||||
id_in: Input<G, id::ShaderModuleId>,
|
||||
) -> (
|
||||
id::ShaderModuleId,
|
||||
@ -3254,20 +3279,41 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
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,
|
||||
#[cfg(feature = "trace")]
|
||||
let data = match device.trace {
|
||||
Some(ref trace) => {
|
||||
let mut trace = trace.lock();
|
||||
match source {
|
||||
pipeline::ShaderModuleSource::SpirV(ref spv) => {
|
||||
trace.make_binary("spv", unsafe {
|
||||
std::slice::from_raw_parts(spv.as_ptr() as *const u8, spv.len() * 4)
|
||||
})
|
||||
}
|
||||
pipeline::ShaderModuleSource::Wgsl(ref code) => {
|
||||
trace.make_binary("wgsl", code.as_bytes())
|
||||
}
|
||||
pipeline::ShaderModuleSource::Naga(ref module) => {
|
||||
let config = ron::ser::PrettyConfig::new();
|
||||
let mut ron = Vec::new();
|
||||
ron::ser::to_writer_pretty(&mut ron, &module, config).unwrap();
|
||||
trace.make_binary("ron", &ron)
|
||||
}
|
||||
}
|
||||
}
|
||||
None => String::new(),
|
||||
};
|
||||
|
||||
let shader = match device.create_shader_module(device_id, desc, source) {
|
||||
Ok(shader) => shader,
|
||||
Err(e) => break e,
|
||||
};
|
||||
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,
|
||||
@ -3276,7 +3322,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
});
|
||||
}
|
||||
|
||||
let _ = spv;
|
||||
return (id.0, None);
|
||||
};
|
||||
|
||||
@ -3859,8 +3904,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
B::get_surface_mut(surface)
|
||||
.configure_swapchain(&device.raw, config)
|
||||
.map_err(|err| match err {
|
||||
hal::window::CreationError::OutOfMemory(_) => DeviceError::OutOfMemory,
|
||||
hal::window::CreationError::DeviceLost(_) => DeviceError::Lost,
|
||||
hal::window::SwapchainError::OutOfMemory(_) => DeviceError::OutOfMemory,
|
||||
hal::window::SwapchainError::DeviceLost(_) => DeviceError::Lost,
|
||||
_ => panic!("failed to configure swap chain on creation: {}", err),
|
||||
})?;
|
||||
}
|
||||
|
@ -7,37 +7,33 @@ use crate::{
|
||||
device::{DeviceError, RenderPassContext},
|
||||
hub::Resource,
|
||||
id::{DeviceId, PipelineLayoutId, ShaderModuleId},
|
||||
validation::StageError,
|
||||
Label, LifeGuard, Stored,
|
||||
validation, Label, LifeGuard, Stored,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
use thiserror::Error;
|
||||
use wgt::{BufferAddress, IndexFormat, InputStepMode};
|
||||
|
||||
#[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>),
|
||||
// Unable to serialize with `naga::Module` in here:
|
||||
// requires naga serialization feature.
|
||||
//Naga(naga::Module),
|
||||
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>,
|
||||
/// If enabled, `wgpu` will attempt to operate on `Naga` representation
|
||||
/// of the shader module for both validation and translation into the
|
||||
/// backend shader languages, where `gfx-hal` supports this.
|
||||
pub experimental_translation: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ShaderModule<B: hal::Backend> {
|
||||
pub(crate) raw: B::ShaderModule,
|
||||
pub(crate) device_id: Stored<DeviceId>,
|
||||
pub(crate) module: Option<naga::Module>,
|
||||
pub(crate) interface: Option<validation::Interface>,
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) label: String,
|
||||
}
|
||||
@ -59,6 +55,8 @@ impl<B: hal::Backend> Resource for ShaderModule<B> {
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateShaderModuleError {
|
||||
#[error("Failed to parse WGSL")]
|
||||
Parsing,
|
||||
#[error(transparent)]
|
||||
Device(#[from] DeviceError),
|
||||
#[error(transparent)]
|
||||
@ -113,7 +111,7 @@ pub enum CreateComputePipelineError {
|
||||
#[error("unable to derive an implicit layout")]
|
||||
Implicit(#[from] ImplicitLayoutError),
|
||||
#[error(transparent)]
|
||||
Stage(StageError),
|
||||
Stage(validation::StageError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -220,7 +218,7 @@ pub enum CreateRenderPipelineError {
|
||||
Stage {
|
||||
flag: wgt::ShaderStage,
|
||||
#[source]
|
||||
error: StageError,
|
||||
error: validation::StageError,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -160,9 +160,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
None,
|
||||
match err {
|
||||
hal::window::AcquireError::OutOfMemory(_) => Err(DeviceError::OutOfMemory)?,
|
||||
hal::window::AcquireError::NotReady => unreachable!(), // we always set a timeout
|
||||
hal::window::AcquireError::Timeout => SwapChainStatus::Timeout,
|
||||
hal::window::AcquireError::OutOfDate => SwapChainStatus::Outdated,
|
||||
hal::window::AcquireError::NotReady { .. } => SwapChainStatus::Timeout,
|
||||
hal::window::AcquireError::OutOfDate(_) => SwapChainStatus::Outdated,
|
||||
hal::window::AcquireError::SurfaceLost(_) => SwapChainStatus::Lost,
|
||||
hal::window::AcquireError::DeviceLost(_) => Err(DeviceError::Lost)?,
|
||||
},
|
||||
@ -283,7 +282,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
hal::window::PresentError::OutOfMemory(_) => {
|
||||
Err(SwapChainError::Device(DeviceError::OutOfMemory))
|
||||
}
|
||||
hal::window::PresentError::OutOfDate => Ok(SwapChainStatus::Outdated),
|
||||
hal::window::PresentError::OutOfDate(_) => Ok(SwapChainStatus::Outdated),
|
||||
hal::window::PresentError::SurfaceLost(_) => Ok(SwapChainStatus::Lost),
|
||||
hal::window::PresentError::DeviceLost(_) => {
|
||||
Err(SwapChainError::Device(DeviceError::Lost))
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user