From 917a5bdf33f4fef058b734783b38bbaeb427237b Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sun, 21 Apr 2019 13:20:48 -0400 Subject: [PATCH] Fix bind groups for samplers and dynamic types - Add additional logging for instance and device creation - Fix set_bind_group and add tests - Add missing SurfaceDescriptorUnix typedef - Exclude target dir when compiling shaders --- compile_shaders.sh | 3 +- examples/particle_simulator.rs | 1 - src/imp/adapter.rs | 13 +- src/imp/command_encoder.rs | 12 +- src/imp/instance.rs | 19 +- src/lib.rs | 3 + tests/pipeline.rs | 308 +++++++++++++++++- .../shaders/pipeline.set_bind_group.comp.glsl | 24 ++ .../shaders/pipeline.set_bind_group.comp.spv | Bin 0 -> 1684 bytes 9 files changed, 361 insertions(+), 22 deletions(-) create mode 100644 tests/shaders/pipeline.set_bind_group.comp.glsl create mode 100644 tests/shaders/pipeline.set_bind_group.comp.spv diff --git a/compile_shaders.sh b/compile_shaders.sh index 9cffa66..957b219 100644 --- a/compile_shaders.sh +++ b/compile_shaders.sh @@ -5,7 +5,8 @@ set -e DIR=$(dirname ${BASH_SOURCE[0]}) -FILES=$(find $DIR -name "*.glsl") +# find all glsl files except for anything nested under ./target +FILES=$(find $DIR -path ./target -prune -o -name "*.glsl" -print) for FILE in ${FILES}; do NAME_GLSL=$(basename ${FILE}) diff --git a/examples/particle_simulator.rs b/examples/particle_simulator.rs index c3ab6e0..a152ae7 100644 --- a/examples/particle_simulator.rs +++ b/examples/particle_simulator.rs @@ -26,7 +26,6 @@ use rand::Rng; use std::time::{Duration, Instant}; - #[repr(C)] #[derive(Copy, Clone, Debug)] struct PositionColor { diff --git a/src/imp/adapter.rs b/src/imp/adapter.rs index ec94e9b..3f2ab10 100644 --- a/src/imp/adapter.rs +++ b/src/imp/adapter.rs @@ -105,10 +105,19 @@ impl AdapterInner { }; unsafe { - let physical_devices = instance.raw.enumerate_physical_devices()?; + let physical_devices = match instance.raw.enumerate_physical_devices() { + Ok(physical_devices) => physical_devices, + Err(e) => { + log::error!("failed to enumerate physical devices: {:?}", e); + return Err(e)?; + } + }; let physical_device_properties = &mut Vec::with_capacity(physical_devices.len()); for physical_device in physical_devices.iter().cloned() { - physical_device_properties.push(instance.raw.get_physical_device_properties(physical_device)); + let properties = instance.raw.get_physical_device_properties(physical_device); + let name = CStr::from_ptr(properties.device_name.as_ptr()); + log::debug!("found physical device: {:?} ({})", name, properties.device_type); + physical_device_properties.push(properties); } match options.power_preference { PowerPreference::HighPerformance => { diff --git a/src/imp/command_encoder.rs b/src/imp/command_encoder.rs index 1fd9d1a..fa9d348 100644 --- a/src/imp/command_encoder.rs +++ b/src/imp/command_encoder.rs @@ -105,18 +105,18 @@ impl CommandEncoderInner { ) { for (index, layout_binding) in bind_group.inner.layout.bindings.iter().enumerate() { match layout_binding.binding_type { - BindingType::UniformBuffer => { + BindingType::UniformBuffer | BindingType::DynamicUniformBuffer => { let (buffer, _) = bind_group.inner.bindings[index] .resource .as_buffer() - .expect("BindingType::UniformBuffer => BindingResource::Buffer"); + .expect("BindingType::[Dynamic]UniformBuffer => BindingResource::Buffer"); usage_tracker.buffer_used_as(buffer.inner.clone(), BufferUsageFlags::UNIFORM); } - BindingType::StorageBuffer => { + BindingType::StorageBuffer | BindingType::DynamicStorageBuffer => { let (buffer, _) = bind_group.inner.bindings[index] .resource .as_buffer() - .expect("BindingType::StorageBuffer => BindingResource::Buffer"); + .expect("BindingType::[Dynamic]StorageBuffer => BindingResource::Buffer"); usage_tracker.buffer_used_as(buffer.inner.clone(), BufferUsageFlags::STORAGE); } BindingType::SampledTexture => { @@ -133,8 +133,8 @@ impl CommandEncoderInner { .expect("BindingType::StorageTexelBuffer => BindingResource::BufferView"); usage_tracker.buffer_used_as(buffer_view.inner.buffer.clone(), BufferUsageFlags::STORAGE); } - _ => { - unimplemented!("binding type: {:?}", layout_binding.binding_type); + BindingType::Sampler => { + // no usage to track } } } diff --git a/src/imp/instance.rs b/src/imp/instance.rs index 4b89650..0f547d4 100644 --- a/src/imp/instance.rs +++ b/src/imp/instance.rs @@ -64,7 +64,7 @@ impl InstanceInner { let name = CStr::from_ptr(p.extension_name.as_ptr()); let name_cow = name.to_string_lossy(); log::trace!("found instance extension: {}", name_cow); - if name_cow.contains("surface") { + if name_cow.ends_with("surface") { include_extension = true; } if name_cow == "VK_EXT_debug_report" && init_debug_report { @@ -76,7 +76,9 @@ impl InstanceInner { } } - for p in entry.enumerate_instance_layer_properties()?.iter() { + let instance_layer_properties = entry.enumerate_instance_layer_properties()?; + + for p in instance_layer_properties.iter() { let name = CStr::from_ptr(p.layer_name.as_ptr()); log::trace!("found instance layer: {}", name.to_string_lossy()); } @@ -84,11 +86,22 @@ impl InstanceInner { let app_info = vk::ApplicationInfo::builder() .api_version(ash::vk_make_version!(1, 0, 0)); - let layer_names = [ + let layer_names = vec![ #[cfg(debug_assertions)] c_str!("VK_LAYER_LUNARG_standard_validation") ]; + for layer_name in layer_names.iter() { + let requested_layer_name = CStr::from_ptr(*layer_name); + let is_available = instance_layer_properties.iter().any(|p| { + let name = CStr::from_ptr(p.layer_name.as_ptr()); + name == requested_layer_name + }); + if !is_available { + log::error!("requested layer unavailable: {:?}", requested_layer_name.to_string_lossy()); + } + } + let extension_names_ptrs: Vec<_> = extension_names.iter().map(|name| name.as_ptr()).collect(); let create_info = vk::InstanceCreateInfo::builder() diff --git a/src/lib.rs b/src/lib.rs index bb72f42..726c754 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,6 +119,9 @@ pub struct SurfaceDescriptorUnix { #[cfg(windows)] pub type SurfaceDescriptor = SurfaceDescriptorWin32; +#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))] +pub type SurfaceDescriptor = SurfaceDescriptorUnix; + #[derive(Clone, Debug)] pub struct Surface { inner: Arc, diff --git a/tests/pipeline.rs b/tests/pipeline.rs index c567769..3d1b69b 100644 --- a/tests/pipeline.rs +++ b/tests/pipeline.rs @@ -2,15 +2,15 @@ use std::borrow::Cow; use vki::{ - BindGroupBinding, BindGroupDescriptor, BindGroupLayoutBinding, BindGroupLayoutDescriptor, BindingResource, - BindingType, BlendDescriptor, BlendFactor, BlendOperation, BufferDescriptor, BufferUsageFlags, Color, - ColorStateDescriptor, ColorWriteFlags, CompareFunction, ComputePipelineDescriptor, CullMode, - DepthStencilStateDescriptor, Extent3D, FrontFace, IndexFormat, InputStateDescriptor, InputStepMode, LoadOp, - PipelineLayoutDescriptor, PipelineStageDescriptor, PrimitiveTopology, RasterizationStateDescriptor, - RenderPassColorAttachmentDescriptor, RenderPassDescriptor, RenderPipelineDescriptor, SamplerDescriptor, - ShaderModuleDescriptor, ShaderStageFlags, StencilOperation, StencilStateFaceDescriptor, StoreOp, Texture, - TextureDescriptor, TextureDimension, TextureFormat, TextureUsageFlags, TextureView, VertexAttributeDescriptor, - VertexFormat, VertexInputDescriptor, + AddressMode, BindGroupBinding, BindGroupDescriptor, BindGroupLayoutBinding, BindGroupLayoutDescriptor, + BindingResource, BindingType, BlendDescriptor, BlendFactor, BlendOperation, BufferDescriptor, BufferUsageFlags, + BufferViewDescriptor, Color, ColorStateDescriptor, ColorWriteFlags, CompareFunction, ComputePipelineDescriptor, + CullMode, DepthStencilStateDescriptor, Extent3D, FilterMode, FrontFace, IndexFormat, InputStateDescriptor, + InputStepMode, LoadOp, PipelineLayoutDescriptor, PipelineStageDescriptor, PrimitiveTopology, + RasterizationStateDescriptor, RenderPassColorAttachmentDescriptor, RenderPassDescriptor, RenderPipelineDescriptor, + SamplerDescriptor, ShaderModuleDescriptor, ShaderStageFlags, StencilOperation, StencilStateFaceDescriptor, StoreOp, + Texture, TextureDescriptor, TextureDimension, TextureFormat, TextureUsageFlags, TextureView, + VertexAttributeDescriptor, VertexFormat, VertexInputDescriptor, }; pub mod support; @@ -423,3 +423,293 @@ fn create_multi_sample_render_pipeline() { Ok(instance) }); } + +#[test] +fn set_bind_group() { + vki::validate(|| { + let (instance, _adapter, device) = support::init()?; + + let shader_module_descriptor = ShaderModuleDescriptor { + code: Cow::Borrowed(include_bytes!("shaders/pipeline.set_bind_group.comp.spv")), + }; + let shader_module = device.create_shader_module(shader_module_descriptor)?; + + let bind_group_layout_descriptor = BindGroupLayoutDescriptor { + bindings: &[ + BindGroupLayoutBinding { + binding: 0, + visibility: ShaderStageFlags::COMPUTE, + binding_type: BindingType::UniformBuffer, + }, + BindGroupLayoutBinding { + binding: 1, + visibility: ShaderStageFlags::COMPUTE, + binding_type: BindingType::StorageBuffer, + }, + BindGroupLayoutBinding { + binding: 2, + visibility: ShaderStageFlags::COMPUTE, + binding_type: BindingType::StorageTexelBuffer, + }, + BindGroupLayoutBinding { + binding: 3, + visibility: ShaderStageFlags::COMPUTE, + binding_type: BindingType::Sampler, + }, + BindGroupLayoutBinding { + binding: 4, + visibility: ShaderStageFlags::COMPUTE, + binding_type: BindingType::SampledTexture, + }, + ], + }; + let bind_group_layout = device.create_bind_group_layout(bind_group_layout_descriptor)?; + + let pipeline_layout_descriptor = PipelineLayoutDescriptor { + bind_group_layouts: vec![bind_group_layout.clone()], + }; + + let pipeline_layout = device.create_pipeline_layout(pipeline_layout_descriptor)?; + + let pipeline_stage_descriptor = PipelineStageDescriptor { + entry_point: Cow::Borrowed("main"), + module: shader_module, + }; + + let compute_pipeline_descriptor = ComputePipelineDescriptor { + layout: pipeline_layout, + compute_stage: pipeline_stage_descriptor, + }; + + let compute_pipeline = device.create_compute_pipeline(compute_pipeline_descriptor)?; + + let uniform_buffer = device.create_buffer(BufferDescriptor { + size: 1024, + usage: BufferUsageFlags::UNIFORM, + })?; + let storage_buffer = device.create_buffer(BufferDescriptor { + size: 1024, + usage: BufferUsageFlags::STORAGE, + })?; + let image_buffer = device.create_buffer(BufferDescriptor { + size: 1024, + usage: BufferUsageFlags::STORAGE, // TODO: texel storage + })?; + let image_buffer_view = image_buffer.create_view(BufferViewDescriptor { + size: 1024, + offset: 0, + format: either::Left(TextureFormat::RGBA32Float), + })?; + let sampler = device.create_sampler(SamplerDescriptor { + mag_filter: FilterMode::Nearest, + min_filter: FilterMode::Nearest, + mipmap_filter: FilterMode::Nearest, + lod_min_clamp: 0.0, + lod_max_clamp: 1000.0, + address_mode_u: AddressMode::ClampToEdge, + address_mode_v: AddressMode::ClampToEdge, + address_mode_w: AddressMode::ClampToEdge, + compare_function: CompareFunction::Never, + })?; + let texture = device.create_texture(TextureDescriptor { + size: Extent3D { + width: 256, + height: 256, + depth: 1, + }, + format: TextureFormat::R8G8B8A8Unorm, + dimension: TextureDimension::D2, + usage: TextureUsageFlags::SAMPLED, + sample_count: 1, + mip_level_count: 1, + array_layer_count: 1, + })?; + let texture_view = texture.create_default_view()?; + + let bind_group = device.create_bind_group(BindGroupDescriptor { + layout: bind_group_layout, + bindings: vec![ + BindGroupBinding { + binding: 0, + resource: BindingResource::Buffer(uniform_buffer, 0..1024), + }, + BindGroupBinding { + binding: 1, + resource: BindingResource::Buffer(storage_buffer, 0..1024), + }, + BindGroupBinding { + binding: 2, + resource: BindingResource::BufferView(image_buffer_view), + }, + BindGroupBinding { + binding: 3, + resource: BindingResource::Sampler(sampler), + }, + BindGroupBinding { + binding: 4, + resource: BindingResource::TextureView(texture_view), + }, + ], + })?; + + let mut encoder = device.create_command_encoder()?; + + let mut compute_pass = encoder.begin_compute_pass(); + compute_pass.set_pipeline(&compute_pipeline); + compute_pass.set_bind_group(0, &bind_group, None); + compute_pass.dispatch(1, 1, 1); + compute_pass.end_pass(); + + let command_buffer = encoder.finish()?; + device.get_queue().submit(&[command_buffer])?; + + Ok(instance) + }); +} + +#[test] +fn set_bind_group_dynamic_offsets() { + vki::validate(|| { + let (instance, _adapter, device) = support::init()?; + + let shader_module_descriptor = ShaderModuleDescriptor { + code: Cow::Borrowed(include_bytes!("shaders/pipeline.set_bind_group.comp.spv")), + }; + let shader_module = device.create_shader_module(shader_module_descriptor)?; + + let bind_group_layout_descriptor = BindGroupLayoutDescriptor { + bindings: &[ + BindGroupLayoutBinding { + binding: 0, + visibility: ShaderStageFlags::COMPUTE, + binding_type: BindingType::DynamicUniformBuffer, + }, + BindGroupLayoutBinding { + binding: 1, + visibility: ShaderStageFlags::COMPUTE, + binding_type: BindingType::DynamicStorageBuffer, + }, + BindGroupLayoutBinding { + binding: 2, + visibility: ShaderStageFlags::COMPUTE, + binding_type: BindingType::StorageTexelBuffer, + }, + BindGroupLayoutBinding { + binding: 3, + visibility: ShaderStageFlags::COMPUTE, + binding_type: BindingType::Sampler, + }, + BindGroupLayoutBinding { + binding: 4, + visibility: ShaderStageFlags::COMPUTE, + binding_type: BindingType::SampledTexture, + }, + ], + }; + let bind_group_layout = device.create_bind_group_layout(bind_group_layout_descriptor)?; + + let pipeline_layout_descriptor = PipelineLayoutDescriptor { + bind_group_layouts: vec![bind_group_layout.clone()], + }; + + let pipeline_layout = device.create_pipeline_layout(pipeline_layout_descriptor)?; + + let pipeline_stage_descriptor = PipelineStageDescriptor { + entry_point: Cow::Borrowed("main"), + module: shader_module, + }; + + let compute_pipeline_descriptor = ComputePipelineDescriptor { + layout: pipeline_layout, + compute_stage: pipeline_stage_descriptor, + }; + + let compute_pipeline = device.create_compute_pipeline(compute_pipeline_descriptor)?; + + let uniform_buffer = device.create_buffer(BufferDescriptor { + size: 1024, + usage: BufferUsageFlags::UNIFORM, + })?; + let storage_buffer = device.create_buffer(BufferDescriptor { + size: 1024, + usage: BufferUsageFlags::STORAGE, + })?; + let image_buffer = device.create_buffer(BufferDescriptor { + size: 1024, + usage: BufferUsageFlags::STORAGE, // TODO: texel storage + })?; + let image_buffer_view = image_buffer.create_view(BufferViewDescriptor { + size: 1024, + offset: 0, + format: either::Left(TextureFormat::RGBA32Float), + })?; + let sampler = device.create_sampler(SamplerDescriptor { + mag_filter: FilterMode::Nearest, + min_filter: FilterMode::Nearest, + mipmap_filter: FilterMode::Nearest, + lod_min_clamp: 0.0, + lod_max_clamp: 1000.0, + address_mode_u: AddressMode::ClampToEdge, + address_mode_v: AddressMode::ClampToEdge, + address_mode_w: AddressMode::ClampToEdge, + compare_function: CompareFunction::Never, + })?; + let texture = device.create_texture(TextureDescriptor { + size: Extent3D { + width: 256, + height: 256, + depth: 1, + }, + format: TextureFormat::R8G8B8A8Unorm, + dimension: TextureDimension::D2, + usage: TextureUsageFlags::SAMPLED, + sample_count: 1, + mip_level_count: 1, + array_layer_count: 1, + })?; + let texture_view = texture.create_default_view()?; + + let bind_group = device.create_bind_group(BindGroupDescriptor { + layout: bind_group_layout, + bindings: vec![ + BindGroupBinding { + binding: 0, + resource: BindingResource::Buffer(uniform_buffer, 0..1024), + }, + BindGroupBinding { + binding: 1, + resource: BindingResource::Buffer(storage_buffer, 0..1024), + }, + BindGroupBinding { + binding: 2, + resource: BindingResource::BufferView(image_buffer_view), + }, + BindGroupBinding { + binding: 3, + resource: BindingResource::Sampler(sampler), + }, + BindGroupBinding { + binding: 4, + resource: BindingResource::TextureView(texture_view), + }, + ], + })?; + + let mut encoder = device.create_command_encoder()?; + + let mut compute_pass = encoder.begin_compute_pass(); + compute_pass.set_pipeline(&compute_pipeline); + + let dynamic_offsets: Option<&[u32]> = Some(&[0, 0]); + + compute_pass.set_bind_group(0, &bind_group, dynamic_offsets); + + compute_pass.dispatch(1, 1, 1); + compute_pass.end_pass(); + + let command_buffer = encoder.finish()?; + device.get_queue().submit(&[command_buffer])?; + + Ok(instance) + }); +} diff --git a/tests/shaders/pipeline.set_bind_group.comp.glsl b/tests/shaders/pipeline.set_bind_group.comp.glsl new file mode 100644 index 0000000..e4953d3 --- /dev/null +++ b/tests/shaders/pipeline.set_bind_group.comp.glsl @@ -0,0 +1,24 @@ +#version 450 + +layout (local_size_x = 1, local_size_y = 1) in; + +layout(set = 0, binding = 0) uniform UBO { + mat4 u_DataRead; +}; + +layout(set = 0, binding = 1) buffer SSB { + mat4 u_DataWrite; +}; + +layout(set = 0, binding = 2, rgba32f) uniform imageBuffer u_ImageBuffer; + +layout(set = 0, binding = 3) uniform sampler u_Sampler; + +layout(set = 0, binding = 4) uniform texture2D u_Texture; + +void main() { + u_DataWrite = u_DataRead; + vec2 texcoord = vec2(0.0, 0.0); + vec4 color = texture(sampler2D(u_Texture, u_Sampler), texcoord); + imageStore(u_ImageBuffer, int(gl_GlobalInvocationID.x), color); +} \ No newline at end of file diff --git a/tests/shaders/pipeline.set_bind_group.comp.spv b/tests/shaders/pipeline.set_bind_group.comp.spv new file mode 100644 index 0000000000000000000000000000000000000000..388548c3329ae7bb03b1326e89e8a39f7ea410fe GIT binary patch literal 1684 zcmY+EX=@W<5XYaKjkTw>x3-(cyERsAiy#V?$~F)P7_WEBy4jY6O*W*PQo&E>r}B;9 z|F;LM1JjxL&-u)3Qz^G*j47EJGjC2zO3S7!#2DlY$=jx$*mk$yZC}NM_R;Ynkqf4R zNPLTmsY$Pjhi)(eCwECW*s_?KIaichmi=2m)yx{Z>)5@X-Tmlz7^1|t$7*JD0v42fHZmCDVf2t|!i7wMjoijIfzfFSJ*US~YFD3K^ zsb5ZeNjy4~#((nNfl1<*QdoM;tV@sm8!w6`^5U9z*aM6^Q}`NDYwbFpE-zSPHb)l zZD|@ylDH;-$PyEWy(fmY_4Wsn)S&MZN&51g6^XZ%#MFD5If$hmHn)b@^?{^?A!0wz zCBe8e`E5yRfs>ETw*kh!h&>cT#J`lp2Y#Z-n1ycuqUIkV%u6kH&u;>I#AdJj9$Fp>}^-f-mxvomYDs1RX=w7P)rOs zG2H)=m^$Az8M8eW69>-w_%7(h?D)uI-}_>A&7ADzm6+YJFJjoyYccpQ*>jRd8HS%; T$KvESQa1JQgZ