From 0a609e74c00592dfd868fca33d5c428c2ef618bc Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sun, 11 Jul 2021 23:45:49 -0400 Subject: [PATCH] hal/dx12: compute pipelines, update naga --- Cargo.lock | 2 +- wgpu-core/Cargo.toml | 2 +- wgpu-hal/Cargo.toml | 4 +- wgpu-hal/src/dx12/adapter.rs | 12 ++- wgpu-hal/src/dx12/command.rs | 6 +- wgpu-hal/src/dx12/device.rs | 137 ++++++++++++++++++++++++++++++---- wgpu-hal/src/dx12/instance.rs | 3 +- wgpu-hal/src/dx12/mod.rs | 36 +++++++-- wgpu-hal/src/metal/device.rs | 2 +- wgpu/Cargo.toml | 6 +- 10 files changed, 175 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61df75bd57..c1a33fb97b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1051,7 +1051,7 @@ dependencies = [ [[package]] name = "naga" version = "0.5.0" -source = "git+https://github.com/gfx-rs/naga?rev=0b9af95793e319817e74a30601cbcd4bad9bb3e6#0b9af95793e319817e74a30601cbcd4bad9bb3e6" +source = "git+https://github.com/gfx-rs/naga?rev=458db0b#458db0b5228854dc417283f4b9742e03f25bc492" dependencies = [ "bit-set", "bitflags", diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index af10fbb528..93583303d5 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -36,7 +36,7 @@ thiserror = "1" [dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "0b9af95793e319817e74a30601cbcd4bad9bb3e6" +rev = "458db0b" features = ["wgsl-in"] [dependencies.wgt] diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 1084ecbea0..dd968b33fe 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -59,11 +59,11 @@ core-graphics-types = "0.1" [dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "0b9af95793e319817e74a30601cbcd4bad9bb3e6" +rev = "458db0b" [dev-dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "0b9af95793e319817e74a30601cbcd4bad9bb3e6" +rev = "458db0b" features = ["wgsl-in"] [dev-dependencies] diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index 8b17767747..175d1524e6 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -18,6 +18,7 @@ impl super::Adapter { pub(super) fn expose( adapter: native::WeakPtr, library: &Arc, + instance_flags: crate::InstanceFlags, ) -> Option> { // Create the device so that we can get the capabilities. let device = match library.create_device(adapter, native::FeatureLevel::L11_0) { @@ -106,6 +107,7 @@ impl super::Adapter { } else { super::MemoryArchitecture::NonUnified }, + shader_debug_info: instance_flags.contains(crate::InstanceFlags::DEBUG), }; // Theoretically vram limited, but in practice 2^20 is the limit @@ -226,7 +228,7 @@ impl super::Adapter { impl crate::Adapter for super::Adapter { unsafe fn open( &self, - _features: wgt::Features, + features: wgt::Features, ) -> Result, crate::DeviceError> { let queue = self .device @@ -238,7 +240,13 @@ impl crate::Adapter for super::Adapter { ) .into_device_result("Queue creation")?; - let device = super::Device::new(self.device, queue, self.private_caps, &self.library)?; + let device = super::Device::new( + self.device, + queue, + features, + self.private_caps, + &self.library, + )?; Ok(crate::OpenDevice { device, queue: super::Queue { raw: queue }, diff --git a/wgpu-hal/src/dx12/command.rs b/wgpu-hal/src/dx12/command.rs index bec9a743b6..e93989981e 100644 --- a/wgpu-hal/src/dx12/command.rs +++ b/wgpu-hal/src/dx12/command.rs @@ -1,4 +1,4 @@ -use super::{conv, HResult as _, Resource}; +use super::{conv, HResult as _}; use std::{mem, ops::Range, ptr}; use winapi::um::d3d12; @@ -637,7 +637,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.list.unwrap().EndEvent() } - unsafe fn set_render_pipeline(&mut self, pipeline: &Resource) {} + unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) {} unsafe fn set_index_buffer<'a>( &mut self, @@ -795,7 +795,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.end_pass(); } - unsafe fn set_compute_pipeline(&mut self, pipeline: &Resource) {} + unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {} unsafe fn dispatch(&mut self, count: [u32; 3]) { self.list.unwrap().dispatch(count); diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index ef43e0f84e..cd636fdf8a 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -1,21 +1,19 @@ use super::{conv, descriptor, HResult as _}; use parking_lot::Mutex; -use std::{mem, ptr, slice, sync::Arc}; +use std::{ffi, mem, ptr, slice, sync::Arc}; use winapi::{ shared::{dxgiformat, dxgitype, winerror}, - um::{d3d12, d3d12sdklayers, synchapi, winbase}, + um::{d3d12, d3d12sdklayers, d3dcompiler, synchapi, winbase}, Interface, }; -//TODO: remove this -use super::Resource; - const D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING: u32 = 0x1688; impl super::Device { pub(super) fn new( raw: native::Device, present_queue: native::CommandQueue, + features: wgt::Features, private_caps: super::PrivateCapabilities, library: &Arc, ) -> Result { @@ -82,6 +80,7 @@ impl super::Device { let capacity_samplers = 2_048; let shared = super::DeviceShared { + features, zero_buffer, cmd_signatures: super::CommandSignatures { draw: raw @@ -508,6 +507,79 @@ impl super::Device { .CreateDepthStencilView(texture.resource.as_mut_ptr(), &raw_desc, handle.raw); handle } + + fn load_shader( + &self, + stage: &crate::ProgrammableStage, + layout: &super::PipelineLayout, + naga_stage: naga::ShaderStage, + ) -> Result { + use naga::back::hlsl; + + let stage_bit = crate::util::map_naga_stage(naga_stage); + let module = &stage.module.naga.module; + //TODO: reuse the writer + let mut source = String::new(); + let mut writer = hlsl::Writer::new(&mut source, &layout.naga_options); + let reflection_info = writer + .write(module, &stage.module.naga.info) + .map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("HLSL: {:?}", e)))?; + + let full_stage = format!( + "{}_{}\0", + naga_stage.to_hlsl_str(), + layout.naga_options.shader_model.to_str() + ); + let raw_ep = ffi::CString::new(stage.entry_point).unwrap(); + + let mut shader_data = native::Blob::null(); + let mut error = native::Blob::null(); + let mut compile_flags = d3dcompiler::D3DCOMPILE_ENABLE_STRICTNESS; + if self.private_caps.shader_debug_info { + compile_flags |= d3dcompiler::D3DCOMPILE_DEBUG; + } + if self + .shared + .features + .contains(wgt::Features::UNSIZED_BINDING_ARRAY) + { + compile_flags |= d3dcompiler::D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES; + } + + let hr = unsafe { + d3dcompiler::D3DCompile( + source.as_ptr() as *const _, + source.len(), + ptr::null(), + ptr::null(), + ptr::null_mut(), + raw_ep.as_ptr(), + full_stage.as_ptr() as *const i8, + compile_flags, + 0, + shader_data.mut_void() as *mut *mut _, + error.mut_void() as *mut *mut _, + ) + }; + + match hr.into_result() { + Ok(()) => Ok(shader_data), + Err(e) => { + let message = unsafe { + let slice = slice::from_raw_parts( + error.GetBufferPointer() as *const u8, + error.GetBufferSize(), + ); + String::from_utf8_lossy(slice) + }; + let full_msg = format!("D3DCompile error ({}): {}", e, message); + unsafe { + error.destroy(); + } + Err(crate::PipelineError::Linkage(stage_bit, full_msg)) + } + } + } } impl crate::Device for super::Device { @@ -1087,6 +1159,9 @@ impl crate::Device for super::Device { Ok(super::PipelineLayout { raw, bind_group_infos, + naga_options: naga::back::hlsl::Options { + shader_model: naga::back::hlsl::ShaderModel::V5_1, + }, }) } unsafe fn destroy_pipeline_layout(&self, pipeline_layout: super::PipelineLayout) { @@ -1247,24 +1322,58 @@ impl crate::Device for super::Device { &self, desc: &crate::ShaderModuleDescriptor, shader: crate::ShaderInput, - ) -> Result { - Ok(Resource) + ) -> Result { + match shader { + crate::ShaderInput::Naga(naga) => Ok(super::ShaderModule { naga }), + crate::ShaderInput::SpirV(_) => { + panic!("SPIRV_SHADER_PASSTHROUGH is not enabled for this backend") + } + } } - unsafe fn destroy_shader_module(&self, module: Resource) {} + unsafe fn destroy_shader_module(&self, _module: super::ShaderModule) { + // just drop + } + unsafe fn create_render_pipeline( &self, desc: &crate::RenderPipelineDescriptor, - ) -> Result { - Ok(Resource) + ) -> Result { + unimplemented!() } - unsafe fn destroy_render_pipeline(&self, pipeline: Resource) {} + unsafe fn destroy_render_pipeline(&self, pipeline: super::RenderPipeline) { + pipeline.raw.destroy(); + } + unsafe fn create_compute_pipeline( &self, desc: &crate::ComputePipelineDescriptor, - ) -> Result { - Ok(Resource) + ) -> Result { + let cs = self.load_shader(&desc.stage, desc.layout, naga::ShaderStage::Compute)?; + + let pair = self.raw.create_compute_pipeline_state( + desc.layout.raw, + native::Shader::from_blob(cs), + 0, + native::CachedPSO::null(), + native::PipelineStateFlags::empty(), + ); + + cs.destroy(); + + let raw = pair.into_result().map_err(|err| { + crate::PipelineError::Linkage(wgt::ShaderStages::COMPUTE, err.into_owned()) + })?; + + if let Some(name) = desc.label { + let cwstr = conv::map_label(name); + raw.SetName(cwstr.as_ptr()); + } + + Ok(super::ComputePipeline { raw }) + } + unsafe fn destroy_compute_pipeline(&self, pipeline: super::ComputePipeline) { + pipeline.raw.destroy(); } - unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {} unsafe fn create_query_set( &self, diff --git a/wgpu-hal/src/dx12/instance.rs b/wgpu-hal/src/dx12/instance.rs index c493444fd8..001033ca31 100644 --- a/wgpu-hal/src/dx12/instance.rs +++ b/wgpu-hal/src/dx12/instance.rs @@ -133,6 +133,7 @@ impl crate::Instance for super::Instance { factory, library: Arc::new(lib_main), lib_dxgi, + flags: desc.flags, }) } @@ -218,7 +219,7 @@ impl crate::Instance for super::Instance { } }; - adapters.extend(super::Adapter::expose(raw, &self.library)); + adapters.extend(super::Adapter::expose(raw, &self.library, self.flags)); } adapters } diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index e08a6f1563..23af6212f1 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -16,7 +16,7 @@ mod instance; use arrayvec::ArrayVec; use parking_lot::Mutex; -use std::{borrow::Cow, mem, ptr, sync::Arc}; +use std::{borrow::Cow, mem, num::NonZeroU32, ptr, sync::Arc}; use winapi::{ shared::{dxgi, dxgi1_2, dxgi1_4, dxgiformat, dxgitype, windef, winerror}, um::{d3d12, synchapi, winbase, winnt}, @@ -25,9 +25,6 @@ use winapi::{ #[derive(Clone)] pub struct Api; -//TODO: remove these temporaries -#[derive(Debug)] -pub struct Resource; impl crate::Api for Api { type Instance = Instance; @@ -50,9 +47,9 @@ impl crate::Api for Api { type BindGroupLayout = BindGroupLayout; type BindGroup = BindGroup; type PipelineLayout = PipelineLayout; - type ShaderModule = Resource; - type RenderPipeline = Resource; - type ComputePipeline = Resource; + type ShaderModule = ShaderModule; + type RenderPipeline = RenderPipeline; + type ComputePipeline = ComputePipeline; } trait HResult { @@ -100,6 +97,7 @@ pub struct Instance { factory: native::Factory4, library: Arc, lib_dxgi: native::DxgiLib, + flags: crate::InstanceFlags, } unsafe impl Send for Instance {} @@ -133,6 +131,7 @@ enum MemoryArchitecture { struct PrivateCapabilities { heterogeneous_resource_heaps: bool, memory_architecture: MemoryArchitecture, + shader_debug_info: bool, } #[derive(Default)] @@ -176,6 +175,7 @@ impl CommandSignatures { } struct DeviceShared { + features: wgt::Features, zero_buffer: native::Resource, cmd_signatures: CommandSignatures, heap_views: descriptor::GeneralHeap, @@ -420,11 +420,33 @@ pub struct PipelineLayout { // Storing for each associated bind group, which tables we created // in the root signature. This is required for binding descriptor sets. bind_group_infos: ArrayVec, + naga_options: naga::back::hlsl::Options, } unsafe impl Send for PipelineLayout {} unsafe impl Sync for PipelineLayout {} +#[derive(Debug)] +pub struct ShaderModule { + naga: crate::NagaShader, +} + +pub struct RenderPipeline { + raw: native::PipelineState, + topology: d3d12::D3D12_PRIMITIVE_TOPOLOGY, + vertex_strides: [Option; crate::MAX_VERTEX_BUFFERS], +} + +unsafe impl Send for RenderPipeline {} +unsafe impl Sync for RenderPipeline {} + +pub struct ComputePipeline { + raw: native::PipelineState, +} + +unsafe impl Send for ComputePipeline {} +unsafe impl Sync for ComputePipeline {} + impl SwapChain { unsafe fn release_resources(self) -> native::WeakPtr { for resource in self.resources { diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 23caea67e6..358de98e5f 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -676,7 +676,7 @@ impl crate::Device for super::Device { match shader { crate::ShaderInput::Naga(naga) => Ok(super::ShaderModule { naga }), crate::ShaderInput::SpirV(_) => { - unreachable!("SPIRV_SHADER_PASSTHROUGH is not enabled for this backend") + panic!("SPIRV_SHADER_PASSTHROUGH is not enabled for this backend") } } } diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index e521508b49..b2252bccd6 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -73,19 +73,19 @@ env_logger = "0.8" [dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "0b9af95793e319817e74a30601cbcd4bad9bb3e6" +rev = "458db0b" optional = true # used to test all the example shaders [dev-dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "0b9af95793e319817e74a30601cbcd4bad9bb3e6" +rev = "458db0b" features = ["wgsl-in"] # used to generate SPIR-V for the Web target [target.'cfg(target_arch = "wasm32")'.dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "0b9af95793e319817e74a30601cbcd4bad9bb3e6" +rev = "458db0b" features = ["wgsl-in", "spv-out"] [[example]]