diff --git a/CHANGELOG.md b/CHANGELOG.md index 24f9c31a726..9159871bd33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -218,6 +218,7 @@ By @beholdnec in [#8505](https://github.com/gfx-rs/wgpu/pull/8505). #### Vulkan +- Use the imported queue family's supported shader stages when building buffer barriers for raw Vulkan devices. - Fixed `SHADER_I16` not enabling `storage_buffer16_bit_access` or `storage_input_output16`, causing Vulkan validation errors when using 16-bit integers in buffers. By @JMS55 in [#9412](https://github.com/gfx-rs/wgpu/pull/9412). - Fixed validation errors when frames take longer than the specified swapchain acquire timeout. By @atlv24 in [#9405](https://github.com/gfx-rs/wgpu/pull/9405). - Fixed limits on Mesa's Honeykrisp / Asahi Linux. By @im-0 in [#9393](https://github.com/gfx-rs/wgpu/pull/9393). diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 211e53e3731..94a9db89efc 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -2473,6 +2473,14 @@ impl super::Adapter { .get_physical_device_memory_properties(self.raw) } }; + let queue_flags = unsafe { + self.instance + .raw + .get_physical_device_queue_family_properties(self.raw) + .get(family_index as usize) + .map(|queue_family_properties| queue_family_properties.queue_flags) + .ok_or(crate::DeviceError::Unexpected)? + }; let memory_types = &mem_properties.memory_types_as_slice(); let valid_ash_memory_types = memory_types.iter().enumerate().fold(0, |u, (i, mem)| { if self.known_memory_flags.contains(mem.property_flags) { @@ -2778,6 +2786,7 @@ impl super::Adapter { let shared = Arc::new(super::DeviceShared { raw: raw_device, family_index, + queue_flags, queue_index, raw_queue, drop_guard, diff --git a/wgpu-hal/src/vulkan/command.rs b/wgpu-hal/src/vulkan/command.rs index ec99f856ed6..ab0b5b85bfd 100644 --- a/wgpu-hal/src/vulkan/command.rs +++ b/wgpu-hal/src/vulkan/command.rs @@ -202,9 +202,11 @@ impl crate::CommandEncoder for super::CommandEncoder { vk_barriers.clear(); for bar in barriers { - let (src_stage, src_access) = conv::map_buffer_usage_to_barrier(bar.usage.from); + let (src_stage, src_access) = + conv::map_buffer_usage_to_barrier(bar.usage.from, self.device.queue_flags); src_stages |= src_stage; - let (dst_stage, dst_access) = conv::map_buffer_usage_to_barrier(bar.usage.to); + let (dst_stage, dst_access) = + conv::map_buffer_usage_to_barrier(bar.usage.to, self.device.queue_flags); dst_stages |= dst_stage; vk_barriers.push( diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index 24c3a5ba408..f5fa04f92c5 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -572,12 +572,11 @@ pub fn map_buffer_usage(usage: wgt::BufferUses) -> vk::BufferUsageFlags { pub fn map_buffer_usage_to_barrier( usage: wgt::BufferUses, + queue_flags: vk::QueueFlags, ) -> (vk::PipelineStageFlags, vk::AccessFlags) { let mut stages = vk::PipelineStageFlags::empty(); let mut access = vk::AccessFlags::empty(); - let shader_stages = vk::PipelineStageFlags::VERTEX_SHADER - | vk::PipelineStageFlags::FRAGMENT_SHADER - | vk::PipelineStageFlags::COMPUTE_SHADER; + let shader_stages = buffer_shader_stages(queue_flags); if usage.contains(wgt::BufferUses::MAP_READ) { stages |= vk::PipelineStageFlags::HOST; @@ -637,6 +636,19 @@ pub fn map_buffer_usage_to_barrier( (stages, access) } +fn buffer_shader_stages(queue_flags: vk::QueueFlags) -> vk::PipelineStageFlags { + let mut stages = vk::PipelineStageFlags::empty(); + + if queue_flags.contains(vk::QueueFlags::GRAPHICS) { + stages |= vk::PipelineStageFlags::VERTEX_SHADER | vk::PipelineStageFlags::FRAGMENT_SHADER; + } + if queue_flags.contains(vk::QueueFlags::COMPUTE) { + stages |= vk::PipelineStageFlags::COMPUTE_SHADER; + } + + stages +} + pub fn map_view_dimension(dim: wgt::TextureViewDimension) -> vk::ImageViewType { match dim { wgt::TextureViewDimension::D1 => vk::ImageViewType::TYPE_1D, @@ -1035,3 +1047,51 @@ pub fn map_acceleration_structure_usage_to_barrier( (stages, access) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn buffer_shader_stages_follow_queue_flags() { + let usage = wgt::BufferUses::UNIFORM; + + let (stages, access) = map_buffer_usage_to_barrier(usage, vk::QueueFlags::GRAPHICS); + assert_eq!( + stages, + vk::PipelineStageFlags::VERTEX_SHADER | vk::PipelineStageFlags::FRAGMENT_SHADER + ); + assert_eq!(access, vk::AccessFlags::UNIFORM_READ); + + let (stages, access) = map_buffer_usage_to_barrier(usage, vk::QueueFlags::COMPUTE); + assert_eq!(stages, vk::PipelineStageFlags::COMPUTE_SHADER); + assert_eq!(access, vk::AccessFlags::UNIFORM_READ); + + let (stages, access) = + map_buffer_usage_to_barrier(usage, vk::QueueFlags::GRAPHICS | vk::QueueFlags::COMPUTE); + assert_eq!( + stages, + vk::PipelineStageFlags::VERTEX_SHADER + | vk::PipelineStageFlags::FRAGMENT_SHADER + | vk::PipelineStageFlags::COMPUTE_SHADER + ); + assert_eq!(access, vk::AccessFlags::UNIFORM_READ); + } + + #[test] + fn non_shader_buffer_usage_is_unchanged() { + let (stages, access) = map_buffer_usage_to_barrier( + wgt::BufferUses::COPY_SRC | wgt::BufferUses::VERTEX, + vk::QueueFlags::empty(), + ); + + assert_eq!( + stages, + vk::PipelineStageFlags::TRANSFER | vk::PipelineStageFlags::VERTEX_INPUT + ); + assert_eq!( + access, + vk::AccessFlags::TRANSFER_READ | vk::AccessFlags::VERTEX_ATTRIBUTE_READ + ); + } +} diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index 124df07c8aa..92534291e86 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -467,6 +467,7 @@ struct RenderPassKey { struct DeviceShared { raw: ash::Device, family_index: u32, + queue_flags: vk::QueueFlags, queue_index: u32, raw_queue: vk::Queue, instance: Arc,