mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 23:04:07 +00:00
vulkan: compile shader modules at pipeline creation time
This commit is contained in:
parent
ce35395910
commit
e00bfac6cf
@ -36,7 +36,7 @@ thiserror = "1"
|
||||
|
||||
[dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "93db57c"
|
||||
rev = "d4bedaf"
|
||||
#version = "0.6"
|
||||
features = ["wgsl-in"]
|
||||
|
||||
|
@ -69,12 +69,12 @@ core-graphics-types = "0.1"
|
||||
|
||||
[dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "93db57c"
|
||||
rev = "d4bedaf"
|
||||
#version = "0.6"
|
||||
|
||||
[dev-dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "93db57c"
|
||||
rev = "d4bedaf"
|
||||
#version = "0.6"
|
||||
features = ["wgsl-in"]
|
||||
|
||||
|
@ -53,13 +53,11 @@ impl PhysicalDeviceFeatures {
|
||||
downlevel_flags: wgt::DownlevelFlags,
|
||||
private_caps: &super::PrivateCapabilities,
|
||||
) -> Self {
|
||||
//TODO: make configurable
|
||||
let rba = !(cfg!(target_os = "macos") || cfg!(target_os = "ios"));
|
||||
Self {
|
||||
// vk::PhysicalDeviceFeatures is a struct composed of Bool32's while
|
||||
// Features is a bitfield so we need to map everything manually
|
||||
core: vk::PhysicalDeviceFeatures::builder()
|
||||
.robust_buffer_access(rba)
|
||||
.robust_buffer_access(private_caps.robust_buffer_access)
|
||||
.independent_blend(true)
|
||||
.sample_rate_shading(true)
|
||||
.image_cube_array(
|
||||
@ -631,6 +629,7 @@ impl super::Instance {
|
||||
};
|
||||
|
||||
let (available_features, downlevel_flags) = phd_features.to_wgpu(&phd_capabilities);
|
||||
let mut workarounds = super::Workarounds::empty();
|
||||
{
|
||||
use crate::auxil::db;
|
||||
// see https://github.com/gfx-rs/gfx/issues/1930
|
||||
@ -640,6 +639,8 @@ impl super::Instance {
|
||||
== db::intel::DEVICE_KABY_LAKE_MASK
|
||||
|| phd_capabilities.properties.device_id & db::intel::DEVICE_SKY_LAKE_MASK
|
||||
== db::intel::DEVICE_SKY_LAKE_MASK);
|
||||
// TODO: only enable for particular devices
|
||||
workarounds |= super::Workarounds::SEPARATE_ENTRY_POINTS;
|
||||
};
|
||||
|
||||
if phd_features.core.sample_rate_shading == 0 {
|
||||
@ -700,6 +701,8 @@ impl super::Instance {
|
||||
},
|
||||
non_coherent_map_mask: phd_capabilities.properties.limits.non_coherent_atom_size - 1,
|
||||
can_present: true,
|
||||
//TODO: make configurable
|
||||
robust_buffer_access: phd_features.core.robust_buffer_access != 0,
|
||||
};
|
||||
|
||||
let capabilities = crate::Capabilities {
|
||||
@ -725,6 +728,7 @@ impl super::Instance {
|
||||
//phd_features,
|
||||
downlevel_flags,
|
||||
private_caps,
|
||||
workarounds,
|
||||
};
|
||||
|
||||
Some(crate::ExposedAdapter {
|
||||
@ -845,8 +849,15 @@ impl super::Adapter {
|
||||
lang_version: (1, 0),
|
||||
flags,
|
||||
capabilities: Some(capabilities.iter().cloned().collect()),
|
||||
index_bounds_check_policy: naga::back::BoundsCheckPolicy::Restrict,
|
||||
image_bounds_check_policy: naga::back::BoundsCheckPolicy::Restrict,
|
||||
bounds_check_policies: naga::back::BoundsCheckPolicies {
|
||||
index: naga::back::BoundsCheckPolicy::Restrict,
|
||||
image: naga::back::BoundsCheckPolicy::Restrict,
|
||||
buffer: if self.private_caps.robust_buffer_access {
|
||||
naga::back::BoundsCheckPolicy::Unchecked
|
||||
} else {
|
||||
naga::back::BoundsCheckPolicy::Restrict
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@ -864,6 +875,7 @@ impl super::Adapter {
|
||||
vendor_id: self.phd_capabilities.properties.vendor_id,
|
||||
downlevel_flags: self.downlevel_flags,
|
||||
private_caps: self.private_caps.clone(),
|
||||
workarounds: self.workarounds,
|
||||
timestamp_period: self.phd_capabilities.properties.limits.timestamp_period,
|
||||
render_passes: Mutex::new(Default::default()),
|
||||
framebuffers: Mutex::new(Default::default()),
|
||||
|
@ -460,6 +460,12 @@ impl
|
||||
}
|
||||
}
|
||||
|
||||
struct CompiledStage {
|
||||
create_info: vk::PipelineShaderStageCreateInfo,
|
||||
_entry_point: CString,
|
||||
temp_raw_module: Option<vk::ShaderModule>,
|
||||
}
|
||||
|
||||
impl super::Device {
|
||||
pub(super) unsafe fn create_swapchain(
|
||||
&self,
|
||||
@ -555,6 +561,59 @@ impl super::Device {
|
||||
copy_size: conv::map_extent_to_copy_size(&desc.size, desc.dimension),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_shader_module_impl(
|
||||
&self,
|
||||
spv: &[u32],
|
||||
) -> Result<vk::ShaderModule, crate::DeviceError> {
|
||||
let vk_info = vk::ShaderModuleCreateInfo::builder()
|
||||
.flags(vk::ShaderModuleCreateFlags::empty())
|
||||
.code(spv);
|
||||
|
||||
let raw = unsafe { self.shared.raw.create_shader_module(&vk_info, None)? };
|
||||
Ok(raw)
|
||||
}
|
||||
|
||||
fn compile_stage(
|
||||
&self,
|
||||
stage: &crate::ProgrammableStage<super::Api>,
|
||||
naga_stage: naga::ShaderStage,
|
||||
) -> Result<CompiledStage, crate::PipelineError> {
|
||||
let stage_flags = crate::auxil::map_naga_stage(naga_stage);
|
||||
let vk_module = match *stage.module {
|
||||
super::ShaderModule::Raw(raw) => raw,
|
||||
super::ShaderModule::Intermediate(ref naga_shader) => {
|
||||
let pipeline_options = naga::back::spv::PipelineOptions {
|
||||
entry_point: stage.entry_point.to_string(),
|
||||
shader_stage: naga_stage,
|
||||
};
|
||||
let spv = naga::back::spv::write_vec(
|
||||
&naga_shader.module,
|
||||
&naga_shader.info,
|
||||
&self.naga_options,
|
||||
Some(&pipeline_options),
|
||||
)
|
||||
.map_err(|e| crate::PipelineError::Linkage(stage_flags, format!("{}", e)))?;
|
||||
self.create_shader_module_impl(&spv)?
|
||||
}
|
||||
};
|
||||
|
||||
let entry_point = CString::new(stage.entry_point).unwrap();
|
||||
let create_info = vk::PipelineShaderStageCreateInfo::builder()
|
||||
.stage(conv::map_shader_stage(stage_flags))
|
||||
.module(vk_module)
|
||||
.name(&entry_point)
|
||||
.build();
|
||||
|
||||
Ok(CompiledStage {
|
||||
create_info,
|
||||
_entry_point: entry_point,
|
||||
temp_raw_module: match *stage.module {
|
||||
super::ShaderModule::Raw(_) => None,
|
||||
super::ShaderModule::Intermediate(_) => Some(vk_module),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Device<super::Api> for super::Device {
|
||||
@ -1114,36 +1173,43 @@ impl crate::Device<super::Api> for super::Device {
|
||||
shader: crate::ShaderInput,
|
||||
) -> Result<super::ShaderModule, crate::ShaderError> {
|
||||
let spv = match shader {
|
||||
crate::ShaderInput::Naga(naga_shader) => Cow::Owned(
|
||||
crate::ShaderInput::Naga(naga_shader) => {
|
||||
if self
|
||||
.shared
|
||||
.workarounds
|
||||
.contains(super::Workarounds::SEPARATE_ENTRY_POINTS)
|
||||
{
|
||||
return Ok(super::ShaderModule::Intermediate(naga_shader));
|
||||
}
|
||||
Cow::Owned(
|
||||
naga::back::spv::write_vec(
|
||||
&naga_shader.module,
|
||||
&naga_shader.info,
|
||||
&self.naga_options,
|
||||
None,
|
||||
)
|
||||
.map_err(|e| crate::ShaderError::Compilation(format!("{}", e)))?,
|
||||
),
|
||||
)
|
||||
}
|
||||
crate::ShaderInput::SpirV(spv) => Cow::Borrowed(spv),
|
||||
};
|
||||
|
||||
let vk_info = vk::ShaderModuleCreateInfo::builder()
|
||||
.flags(vk::ShaderModuleCreateFlags::empty())
|
||||
.code(&spv);
|
||||
|
||||
let raw = self
|
||||
.shared
|
||||
.raw
|
||||
.create_shader_module(&vk_info, None)
|
||||
.map_err(crate::DeviceError::from)?;
|
||||
let raw = self.create_shader_module_impl(&*spv)?;
|
||||
|
||||
if let Some(label) = desc.label {
|
||||
self.shared
|
||||
.set_object_name(vk::ObjectType::SHADER_MODULE, raw, label);
|
||||
}
|
||||
|
||||
Ok(super::ShaderModule { raw })
|
||||
Ok(super::ShaderModule::Raw(raw))
|
||||
}
|
||||
unsafe fn destroy_shader_module(&self, module: super::ShaderModule) {
|
||||
let _ = self.shared.raw.destroy_shader_module(module.raw, None);
|
||||
match module {
|
||||
super::ShaderModule::Raw(raw) => {
|
||||
let _ = self.shared.raw.destroy_shader_module(raw, None);
|
||||
}
|
||||
super::ShaderModule::Intermediate(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn create_render_pipeline(
|
||||
@ -1193,29 +1259,16 @@ impl crate::Device<super::Api> for super::Device {
|
||||
.primitive_restart_enable(desc.primitive.strip_index_format.is_some())
|
||||
.build();
|
||||
|
||||
let vs_entry_point;
|
||||
{
|
||||
let stage = &desc.vertex_stage;
|
||||
vs_entry_point = CString::new(stage.entry_point).unwrap();
|
||||
stages.push(
|
||||
vk::PipelineShaderStageCreateInfo::builder()
|
||||
.stage(vk::ShaderStageFlags::VERTEX)
|
||||
.module(stage.module.raw)
|
||||
.name(&vs_entry_point)
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
let fs_entry_point;
|
||||
if let Some(ref stage) = desc.fragment_stage {
|
||||
fs_entry_point = CString::new(stage.entry_point).unwrap();
|
||||
stages.push(
|
||||
vk::PipelineShaderStageCreateInfo::builder()
|
||||
.stage(vk::ShaderStageFlags::FRAGMENT)
|
||||
.module(stage.module.raw)
|
||||
.name(&fs_entry_point)
|
||||
.build(),
|
||||
);
|
||||
let compiled_vs = self.compile_stage(&desc.vertex_stage, naga::ShaderStage::Vertex)?;
|
||||
stages.push(compiled_vs.create_info);
|
||||
let compiled_fs = match desc.fragment_stage {
|
||||
Some(ref stage) => {
|
||||
let compiled = self.compile_stage(stage, naga::ShaderStage::Fragment)?;
|
||||
stages.push(compiled.create_info);
|
||||
Some(compiled)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let mut vk_rasterization = vk::PipelineRasterizationStateCreateInfo::builder()
|
||||
.depth_clamp_enable(desc.primitive.clamp_depth)
|
||||
@ -1355,6 +1408,17 @@ impl crate::Device<super::Api> for super::Device {
|
||||
.set_object_name(vk::ObjectType::PIPELINE, raw, label);
|
||||
}
|
||||
|
||||
if let Some(raw_module) = compiled_vs.temp_raw_module {
|
||||
self.shared.raw.destroy_shader_module(raw_module, None);
|
||||
}
|
||||
if let Some(CompiledStage {
|
||||
temp_raw_module: Some(raw_module),
|
||||
..
|
||||
}) = compiled_fs
|
||||
{
|
||||
self.shared.raw.destroy_shader_module(raw_module, None);
|
||||
}
|
||||
|
||||
Ok(super::RenderPipeline { raw })
|
||||
}
|
||||
unsafe fn destroy_render_pipeline(&self, pipeline: super::RenderPipeline) {
|
||||
@ -1365,17 +1429,12 @@ impl crate::Device<super::Api> for super::Device {
|
||||
&self,
|
||||
desc: &crate::ComputePipelineDescriptor<super::Api>,
|
||||
) -> Result<super::ComputePipeline, crate::PipelineError> {
|
||||
let cs_entry_point = CString::new(desc.stage.entry_point).unwrap();
|
||||
let vk_stage = vk::PipelineShaderStageCreateInfo::builder()
|
||||
.stage(vk::ShaderStageFlags::COMPUTE)
|
||||
.module(desc.stage.module.raw)
|
||||
.name(&cs_entry_point)
|
||||
.build();
|
||||
let compiled = self.compile_stage(&desc.stage, naga::ShaderStage::Compute)?;
|
||||
|
||||
let vk_infos = [{
|
||||
vk::ComputePipelineCreateInfo::builder()
|
||||
.layout(desc.layout.raw)
|
||||
.stage(vk_stage)
|
||||
.stage(compiled.create_info)
|
||||
.build()
|
||||
}];
|
||||
|
||||
@ -1391,6 +1450,10 @@ impl crate::Device<super::Api> for super::Device {
|
||||
.set_object_name(vk::ObjectType::PIPELINE, raw, label);
|
||||
}
|
||||
|
||||
if let Some(raw_module) = compiled.temp_raw_module {
|
||||
self.shared.raw.destroy_shader_module(raw_module, None);
|
||||
}
|
||||
|
||||
Ok(super::ComputePipeline { raw })
|
||||
}
|
||||
unsafe fn destroy_compute_pipeline(&self, pipeline: super::ComputePipeline) {
|
||||
|
@ -130,6 +130,7 @@ pub struct Adapter {
|
||||
//phd_features: adapter::PhysicalDeviceFeatures,
|
||||
downlevel_flags: wgt::DownlevelFlags,
|
||||
private_caps: PrivateCapabilities,
|
||||
workarounds: Workarounds,
|
||||
}
|
||||
|
||||
// TODO there's no reason why this can't be unified--the function pointers should all be the same--it's not clear how to do this with `ash`.
|
||||
@ -161,8 +162,17 @@ struct PrivateCapabilities {
|
||||
/// Ability to present contents to any screen. Only needed to work around broken platform configurations.
|
||||
can_present: bool,
|
||||
non_coherent_map_mask: wgt::BufferAddress,
|
||||
robust_buffer_access: bool,
|
||||
}
|
||||
|
||||
bitflags::bitflags!(
|
||||
/// Workaround flags.
|
||||
pub struct Workarounds: u32 {
|
||||
/// Only generate SPIR-V for one entry point at a time.
|
||||
const SEPARATE_ENTRY_POINTS = 0x1;
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
struct AttachmentKey {
|
||||
format: vk::Format,
|
||||
@ -225,6 +235,7 @@ struct DeviceShared {
|
||||
timestamp_period: f32,
|
||||
downlevel_flags: wgt::DownlevelFlags,
|
||||
private_caps: PrivateCapabilities,
|
||||
workarounds: Workarounds,
|
||||
render_passes: Mutex<fxhash::FxHashMap<RenderPassKey, vk::RenderPass>>,
|
||||
framebuffers: Mutex<fxhash::FxHashMap<FramebufferKey, vk::Framebuffer>>,
|
||||
}
|
||||
@ -358,8 +369,9 @@ pub struct CommandBuffer {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ShaderModule {
|
||||
raw: vk::ShaderModule,
|
||||
pub enum ShaderModule {
|
||||
Raw(vk::ShaderModule),
|
||||
Intermediate(crate::NagaShader),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -90,14 +90,14 @@ env_logger = "0.8"
|
||||
|
||||
[dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "93db57c"
|
||||
rev = "d4bedaf"
|
||||
#version = "0.6"
|
||||
optional = true
|
||||
|
||||
# used to test all the example shaders
|
||||
[dev-dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "93db57c"
|
||||
rev = "d4bedaf"
|
||||
#version = "0.6"
|
||||
features = ["wgsl-in"]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user