diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 239d0f04e..a7cd8d38b 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -60,7 +60,7 @@ impl CommandEncoder { fn open(&mut self) -> &mut A::CommandEncoder { if !self.is_open { self.is_open = true; - let label = self.label.as_ref().map(|s| s.as_str()); + let label = self.label.as_deref(); unsafe { self.raw.begin_encoding(label).unwrap() }; } &mut self.raw diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index ea08728dd..46acef821 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -592,8 +592,12 @@ impl Example { } } -#[cfg(feature = "metal")] +#[cfg(all(feature = "metal"))] type Api = hal::api::Metal; +#[cfg(all(feature = "vulkan", not(feature = "metal")))] +type Api = hal::api::Vulkan; +#[cfg(all(not(feature = "vulkan"), not(feature = "metal")))] +type Api = hal::api::Empty; fn main() { let event_loop = winit::event_loop::EventLoop::new(); diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 12e01b7ad..2ee3dabb2 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -756,6 +756,7 @@ impl crate::Adapter for super::Adapter { downlevel_flags: self.downlevel_flags, private_caps: self.private_caps.clone(), timestamp_period: self.phd_capabilities.properties.limits.timestamp_period, + render_passes: Mutex::new(Default::default()), }), mem_allocator: Mutex::new(mem_allocator), desc_allocator: Mutex::new(desc_allocator), @@ -767,6 +768,9 @@ impl crate::Adapter for super::Adapter { } unsafe fn close(&self, device: super::Device) { + for &raw in device.shared.render_passes.lock().values() { + device.shared.raw.destroy_render_pass(raw, None); + } device.shared.raw.destroy_device(None); } diff --git a/wgpu-hal/src/vulkan/command.rs b/wgpu-hal/src/vulkan/command.rs index b64791eff..23446bedb 100644 --- a/wgpu-hal/src/vulkan/command.rs +++ b/wgpu-hal/src/vulkan/command.rs @@ -139,7 +139,13 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn begin_debug_marker(&mut self, group_label: &str) {} unsafe fn end_debug_marker(&mut self) {} - unsafe fn set_render_pipeline(&mut self, pipeline: &Resource) {} + unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) { + self.device.raw.cmd_bind_pipeline( + self.active, + vk::PipelineBindPoint::GRAPHICS, + pipeline.raw, + ); + } unsafe fn set_index_buffer<'a>( &mut self, @@ -213,7 +219,13 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn begin_compute_pass(&mut self, desc: &crate::ComputePassDescriptor) {} unsafe fn end_compute_pass(&mut self) {} - unsafe fn set_compute_pipeline(&mut self, pipeline: &Resource) {} + unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) { + self.device.raw.cmd_bind_pipeline( + self.active, + vk::PipelineBindPoint::COMPUTE, + pipeline.raw, + ); + } unsafe fn dispatch(&mut self, count: [u32; 3]) {} unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) {} diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index 8141f81c3..09ab04103 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -110,6 +110,23 @@ impl super::PrivateCapabilities { } } +pub fn derive_image_layout(usage: crate::TextureUse) -> vk::ImageLayout { + match usage { + crate::TextureUse::COPY_SRC => vk::ImageLayout::TRANSFER_SRC_OPTIMAL, + crate::TextureUse::COPY_DST => vk::ImageLayout::TRANSFER_DST_OPTIMAL, + crate::TextureUse::SAMPLED => vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + crate::TextureUse::COLOR_TARGET => vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL, + crate::TextureUse::DEPTH_STENCIL_WRITE => vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + _ => { + if usage.contains(crate::TextureUse::DEPTH_STENCIL_READ) { + vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL + } else { + vk::ImageLayout::GENERAL + } + } + } +} + pub fn map_texture_usage(usage: crate::TextureUse) -> vk::ImageUsageFlags { let mut flags = vk::ImageUsageFlags::empty(); if usage.contains(crate::TextureUse::COPY_SRC) { @@ -173,6 +190,46 @@ pub fn map_index_format(index_format: wgt::IndexFormat) -> vk::IndexType { } } +pub fn map_vertex_format(vertex_format: wgt::VertexFormat) -> vk::Format { + use wgt::VertexFormat as Vf; + match vertex_format { + Vf::Uint8x2 => vk::Format::R8G8_UINT, + Vf::Uint8x4 => vk::Format::R8G8B8A8_UINT, + Vf::Sint8x2 => vk::Format::R8G8_SINT, + Vf::Sint8x4 => vk::Format::R8G8B8A8_SINT, + Vf::Unorm8x2 => vk::Format::R8G8_UNORM, + Vf::Unorm8x4 => vk::Format::R8G8B8A8_UNORM, + Vf::Snorm8x2 => vk::Format::R8G8_SNORM, + Vf::Snorm8x4 => vk::Format::R8G8B8A8_SNORM, + Vf::Uint16x2 => vk::Format::R16G16_UINT, + Vf::Uint16x4 => vk::Format::R16G16B16A16_UINT, + Vf::Sint16x2 => vk::Format::R16G16_SINT, + Vf::Sint16x4 => vk::Format::R16G16B16A16_SINT, + Vf::Unorm16x2 => vk::Format::R16G16_UNORM, + Vf::Unorm16x4 => vk::Format::R16G16B16A16_UNORM, + Vf::Snorm16x2 => vk::Format::R16G16_SNORM, + Vf::Snorm16x4 => vk::Format::R16G16B16A16_SNORM, + Vf::Float16x2 => vk::Format::R16G16_SFLOAT, + Vf::Float16x4 => vk::Format::R16G16B16A16_SFLOAT, + Vf::Float32 => vk::Format::R32_SFLOAT, + Vf::Float32x2 => vk::Format::R32G32_SFLOAT, + Vf::Float32x3 => vk::Format::R32G32B32_SFLOAT, + Vf::Float32x4 => vk::Format::R32G32B32A32_SFLOAT, + Vf::Uint32 => vk::Format::R32_UINT, + Vf::Uint32x2 => vk::Format::R32G32_UINT, + Vf::Uint32x3 => vk::Format::R32G32B32_UINT, + Vf::Uint32x4 => vk::Format::R32G32B32A32_UINT, + Vf::Sint32 => vk::Format::R32_SINT, + Vf::Sint32x2 => vk::Format::R32G32_SINT, + Vf::Sint32x3 => vk::Format::R32G32B32_SINT, + Vf::Sint32x4 => vk::Format::R32G32B32A32_SINT, + Vf::Float64 => vk::Format::R64_SFLOAT, + Vf::Float64x2 => vk::Format::R64G64_SFLOAT, + Vf::Float64x3 => vk::Format::R64G64B64_SFLOAT, + Vf::Float64x4 => vk::Format::R64G64B64A64_SFLOAT, + } +} + pub fn map_aspects(aspects: crate::FormatAspect) -> vk::ImageAspectFlags { let mut flags = vk::ImageAspectFlags::empty(); if aspects.contains(crate::FormatAspect::COLOR) { @@ -414,3 +471,93 @@ pub fn map_binding_type(ty: wgt::BindingType) -> vk::DescriptorType { wgt::BindingType::StorageTexture { .. } => vk::DescriptorType::STORAGE_IMAGE, } } + +pub fn map_topology(topology: wgt::PrimitiveTopology) -> vk::PrimitiveTopology { + use wgt::PrimitiveTopology as Pt; + match topology { + Pt::PointList => vk::PrimitiveTopology::POINT_LIST, + Pt::LineList => vk::PrimitiveTopology::LINE_LIST, + Pt::LineStrip => vk::PrimitiveTopology::LINE_STRIP, + Pt::TriangleList => vk::PrimitiveTopology::TRIANGLE_LIST, + Pt::TriangleStrip => vk::PrimitiveTopology::TRIANGLE_STRIP, + } +} + +pub fn map_front_face(front_face: wgt::FrontFace) -> vk::FrontFace { + match front_face { + wgt::FrontFace::Cw => vk::FrontFace::CLOCKWISE, + wgt::FrontFace::Ccw => vk::FrontFace::COUNTER_CLOCKWISE, + } +} + +pub fn map_cull_face(face: wgt::Face) -> vk::CullModeFlags { + match face { + wgt::Face::Front => vk::CullModeFlags::FRONT, + wgt::Face::Back => vk::CullModeFlags::BACK, + } +} + +pub fn map_stencil_op(op: wgt::StencilOperation) -> vk::StencilOp { + use wgt::StencilOperation as So; + match op { + So::Keep => vk::StencilOp::KEEP, + So::Zero => vk::StencilOp::ZERO, + So::Replace => vk::StencilOp::REPLACE, + So::Invert => vk::StencilOp::INVERT, + So::IncrementClamp => vk::StencilOp::INCREMENT_AND_CLAMP, + So::IncrementWrap => vk::StencilOp::INCREMENT_AND_WRAP, + So::DecrementClamp => vk::StencilOp::DECREMENT_AND_CLAMP, + So::DecrementWrap => vk::StencilOp::DECREMENT_AND_WRAP, + } +} + +pub fn map_stencil_face(face: &wgt::StencilFaceState) -> vk::StencilOpState { + vk::StencilOpState { + fail_op: map_stencil_op(face.fail_op), + pass_op: map_stencil_op(face.pass_op), + depth_fail_op: map_stencil_op(face.depth_fail_op), + compare_op: map_comparison(face.compare), + compare_mask: !0, + write_mask: !0, + reference: 0, + } +} + +fn map_blend_factor(factor: wgt::BlendFactor) -> vk::BlendFactor { + use wgt::BlendFactor as Bf; + match factor { + Bf::Zero => vk::BlendFactor::ZERO, + Bf::One => vk::BlendFactor::ONE, + Bf::Src => vk::BlendFactor::SRC_COLOR, + Bf::OneMinusSrc => vk::BlendFactor::ONE_MINUS_SRC_COLOR, + Bf::SrcAlpha => vk::BlendFactor::SRC_ALPHA, + Bf::OneMinusSrcAlpha => vk::BlendFactor::ONE_MINUS_SRC_ALPHA, + Bf::Dst => vk::BlendFactor::DST_COLOR, + Bf::OneMinusDst => vk::BlendFactor::ONE_MINUS_DST_COLOR, + Bf::DstAlpha => vk::BlendFactor::DST_ALPHA, + Bf::OneMinusDstAlpha => vk::BlendFactor::ONE_MINUS_DST_ALPHA, + Bf::SrcAlphaSaturated => vk::BlendFactor::SRC_ALPHA_SATURATE, + Bf::Constant => vk::BlendFactor::CONSTANT_COLOR, + Bf::OneMinusConstant => vk::BlendFactor::ONE_MINUS_CONSTANT_COLOR, + } +} + +fn map_blend_op(operation: wgt::BlendOperation) -> vk::BlendOp { + use wgt::BlendOperation as Bo; + match operation { + Bo::Add => vk::BlendOp::ADD, + Bo::Subtract => vk::BlendOp::SUBTRACT, + Bo::ReverseSubtract => vk::BlendOp::REVERSE_SUBTRACT, + Bo::Min => vk::BlendOp::MIN, + Bo::Max => vk::BlendOp::MAX, + } +} + +pub fn map_blend_component( + component: &wgt::BlendComponent, +) -> (vk::BlendOp, vk::BlendFactor, vk::BlendFactor) { + let op = map_blend_op(component.operation); + let src = map_blend_factor(component.src_factor); + let dst = map_blend_factor(component.dst_factor); + (op, src, dst) +} diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index ba1b25b18..9bb9fee96 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -5,7 +5,7 @@ use ash::{extensions::khr, version::DeviceV1_0, vk}; use inplace_it::inplace_or_alloc_from_iter; use parking_lot::Mutex; -use std::{ptr, sync::Arc}; +use std::{collections::hash_map::Entry, ffi::CString, ptr, sync::Arc}; impl super::DeviceShared { unsafe fn set_object_name( @@ -53,6 +53,101 @@ impl super::DeviceShared { .object_name(CStr::from_bytes_with_nul_unchecked(name_bytes)), ); } + + pub fn make_render_pass( + &self, + key: super::RenderPassKey, + ) -> Result { + Ok(match self.render_passes.lock().entry(key) { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(e) => { + let mut vk_attachments = Vec::new(); + let mut color_refs = Vec::with_capacity(e.key().colors.len()); + let mut resolve_refs = Vec::with_capacity(color_refs.capacity()); + let mut ds_ref = None; + let samples = vk::SampleCountFlags::from_raw(e.key().sample_count); + + for cat in e.key().colors.iter() { + color_refs.push(vk::AttachmentReference { + attachment: vk_attachments.len() as u32, + layout: cat.base.layout_in, + }); + vk_attachments.push({ + let (load_op, store_op) = conv::map_attachment_ops(cat.base.ops); + vk::AttachmentDescription::builder() + .format(cat.base.format) + .samples(samples) + .load_op(load_op) + .store_op(store_op) + .initial_layout(cat.base.layout_pre) + .final_layout(cat.base.layout_post) + .build() + }); + let at_ref = if let Some(ref rat) = cat.resolve { + let at_ref = vk::AttachmentReference { + attachment: vk_attachments.len() as u32, + layout: rat.layout_in, + }; + let (load_op, store_op) = conv::map_attachment_ops(rat.ops); + let vk_attachment = vk::AttachmentDescription::builder() + .format(rat.format) + .samples(vk::SampleCountFlags::TYPE_1) + .load_op(load_op) + .store_op(store_op) + .initial_layout(rat.layout_pre) + .final_layout(rat.layout_post) + .build(); + vk_attachments.push(vk_attachment); + at_ref + } else { + vk::AttachmentReference { + attachment: vk::ATTACHMENT_UNUSED, + layout: vk::ImageLayout::UNDEFINED, + } + }; + resolve_refs.push(at_ref); + } + + if let Some(ref ds) = e.key().depth_stencil { + ds_ref = Some(vk::AttachmentReference { + attachment: vk_attachments.len() as u32, + layout: ds.base.layout_in, + }); + let (load_op, store_op) = conv::map_attachment_ops(ds.base.ops); + let (stencil_load_op, stencil_store_op) = + conv::map_attachment_ops(ds.stencil_ops); + let vk_attachment = vk::AttachmentDescription::builder() + .format(ds.base.format) + .samples(samples) + .load_op(load_op) + .store_op(store_op) + .initial_layout(ds.base.layout_pre) + .final_layout(ds.base.layout_post) + .build(); + vk_attachments.push(vk_attachment); + } + + let vk_subpasses = [{ + let mut vk_subpass = vk::SubpassDescription::builder() + .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) + .color_attachments(&color_refs) + .resolve_attachments(&resolve_refs); + if let Some(ref reference) = ds_ref { + vk_subpass = vk_subpass.depth_stencil_attachment(reference) + } + vk_subpass.build() + }]; + + let vk_info = vk::RenderPassCreateInfo::builder() + .attachments(&vk_attachments) + .subpasses(&vk_subpasses); + + let raw = unsafe { self.raw.create_render_pass(&vk_info, None)? }; + + *e.insert(raw) + } + }) + } } impl gpu_alloc::MemoryDevice for super::DeviceShared { @@ -636,8 +731,17 @@ impl crate::Device for super::Device { desc: &crate::BindGroupLayoutDescriptor, ) -> Result { let mut desc_count = gpu_descriptor::DescriptorTotalCount::default(); + let mut types = Vec::new(); for entry in desc.entries { let count = entry.count.map_or(1, |c| c.get()); + if entry.binding as usize > types.len() { + types.resize( + entry.binding as usize + 1, + vk::DescriptorType::INPUT_ATTACHMENT, + ); + } + types[entry.binding as usize] = conv::map_binding_type(entry.ty); + match entry.ty { wgt::BindingType::Buffer { ty, @@ -677,7 +781,7 @@ impl crate::Device for super::Device { .iter() .map(|entry| vk::DescriptorSetLayoutBinding { binding: entry.binding, - descriptor_type: conv::map_binding_type(entry.ty), + descriptor_type: types[entry.binding as usize], descriptor_count: entry.count.map_or(1, |c| c.get()), stage_flags: conv::map_shader_stage(entry.visibility), p_immutable_samplers: ptr::null(), @@ -698,7 +802,11 @@ impl crate::Device for super::Device { .set_object_name(vk::ObjectType::DESCRIPTOR_SET_LAYOUT, raw, label); } - Ok(super::BindGroupLayout { raw, desc_count }) + Ok(super::BindGroupLayout { + raw, + desc_count, + types, + }) } unsafe fn destroy_bind_group_layout(&self, bg_layout: super::BindGroupLayout) { self.shared @@ -757,9 +865,57 @@ impl crate::Device for super::Device { &desc.layout.desc_count, 1, )?; - Ok(super::BindGroup { - raw: vk_sets.pop().unwrap(), - }) + + let set = vk_sets.pop().unwrap(); + let mut writes = Vec::with_capacity(desc.entries.len()); + let mut buffer_infos = Vec::with_capacity(desc.buffers.len()); + let mut sampler_infos = Vec::with_capacity(desc.samplers.len()); + let mut image_infos = Vec::with_capacity(desc.textures.len()); + for entry in desc.entries { + let ty = desc.layout.types[entry.binding as usize]; + let mut write = vk::WriteDescriptorSet::builder() + .dst_set(*set.raw()) + .dst_binding(entry.binding) + .descriptor_type(ty); + write = match ty { + vk::DescriptorType::SAMPLER => { + let index = sampler_infos.len(); + let binding = desc.samplers[index]; + let info = vk::DescriptorImageInfo::builder() + .sampler(binding.raw) + .build(); + sampler_infos.push(info); + write.image_info(&sampler_infos[index..]) + } + vk::DescriptorType::SAMPLED_IMAGE | vk::DescriptorType::STORAGE_IMAGE => { + let index = image_infos.len(); + let binding = &desc.textures[index]; + let layout = conv::derive_image_layout(binding.usage); + let info = vk::DescriptorImageInfo::builder() + .image_view(binding.view.raw) + .image_layout(layout) + .build(); + image_infos.push(info); + write.image_info(&image_infos[index..]) + } + _ => { + let index = buffer_infos.len(); + let binding = &desc.buffers[index]; + let mut info = vk::DescriptorBufferInfo::builder() + .buffer(binding.buffer.raw) + .offset(binding.offset); + if let Some(size) = binding.size { + info = info.range(size.get()); + } + buffer_infos.push(info.build()); + write.buffer_info(&buffer_infos[index..]) + } + }; + writes.push(write.build()); + } + + self.shared.raw.update_descriptor_sets(&writes, &[]); + Ok(super::BindGroup { raw: set }) } unsafe fn destroy_bind_group(&self, group: super::BindGroup) { self.desc_allocator @@ -771,24 +927,251 @@ impl crate::Device for super::Device { &self, desc: &crate::ShaderModuleDescriptor, shader: crate::NagaShader, - ) -> Result { - Ok(Resource) + ) -> Result { + let spv = naga::back::spv::write_vec(&shader.module, &shader.info, &self.naga_options) + .map_err(|e| crate::ShaderError::Compilation(format!("{}", e)))?; + + 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)?; + + Ok(super::ShaderModule { raw }) } - unsafe fn destroy_shader_module(&self, module: Resource) {} + unsafe fn destroy_shader_module(&self, module: super::ShaderModule) { + let _ = self.shared.raw.destroy_shader_module(module.raw, None); + } + unsafe fn create_render_pipeline( &self, desc: &crate::RenderPipelineDescriptor, - ) -> Result { - Ok(Resource) + ) -> Result { + let dynamic_states = [ + vk::DynamicState::VIEWPORT, + vk::DynamicState::SCISSOR, + vk::DynamicState::BLEND_CONSTANTS, + vk::DynamicState::STENCIL_REFERENCE, + ]; + let mut compatible_rp_key = super::RenderPassKey { + sample_count: desc.multisample.count, + ..Default::default() + }; + let mut stages = ArrayVec::<[_; 2]>::new(); + let mut vertex_buffers = Vec::with_capacity(desc.vertex_buffers.len()); + let mut vertex_attributes = Vec::new(); + + for (i, vb) in desc.vertex_buffers.iter().enumerate() { + vertex_buffers.push(vk::VertexInputBindingDescription { + binding: i as u32, + stride: vb.array_stride as u32, + input_rate: match vb.step_mode { + wgt::InputStepMode::Vertex => vk::VertexInputRate::VERTEX, + wgt::InputStepMode::Instance => vk::VertexInputRate::INSTANCE, + }, + }); + for at in vb.attributes { + vertex_attributes.push(vk::VertexInputAttributeDescription { + location: at.shader_location, + binding: i as u32, + format: conv::map_vertex_format(at.format), + offset: at.offset as u32, + }); + } + } + + let vk_vertex_input = vk::PipelineVertexInputStateCreateInfo::builder() + .vertex_binding_descriptions(&vertex_buffers) + .vertex_attribute_descriptions(&vertex_attributes) + .build(); + + let vk_input_assembly = vk::PipelineInputAssemblyStateCreateInfo::builder() + .topology(conv::map_topology(desc.primitive.topology)) + .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 mut vk_rasterization = vk::PipelineRasterizationStateCreateInfo::builder() + .depth_clamp_enable(desc.primitive.clamp_depth) + .polygon_mode(vk::PolygonMode::FILL) + .front_face(conv::map_front_face(desc.primitive.front_face)); + if let Some(face) = desc.primitive.cull_mode { + vk_rasterization = vk_rasterization.cull_mode(conv::map_cull_face(face)) + } + + let mut vk_depth_stencil = vk::PipelineDepthStencilStateCreateInfo::builder(); + if let Some(ref ds) = desc.depth_stencil { + let vk_format = self.shared.private_caps.map_texture_format(ds.format); + compatible_rp_key.depth_stencil = Some(super::DepthStencilAttachmentKey { + base: super::AttachmentKey::compatible(vk_format), + stencil_ops: crate::AttachmentOp::empty(), + }); + + if ds.is_depth_enabled() { + vk_depth_stencil = vk_depth_stencil + .depth_test_enable(true) + .depth_write_enable(ds.depth_write_enabled) + .depth_compare_op(conv::map_comparison(ds.depth_compare)); + } + if ds.stencil.is_enabled() { + let front = conv::map_stencil_face(&ds.stencil.front); + let back = conv::map_stencil_face(&ds.stencil.back); + vk_depth_stencil = vk_depth_stencil + .stencil_test_enable(true) + .front(front) + .back(back); + } + + if ds.bias.is_enabled() { + vk_rasterization = vk_rasterization + .depth_bias_enable(true) + .depth_bias_constant_factor(ds.bias.constant as f32) + .depth_bias_clamp(ds.bias.clamp) + .depth_bias_slope_factor(ds.bias.slope_scale); + } + } + + let vk_viewport = vk::PipelineViewportStateCreateInfo::builder() + .flags(vk::PipelineViewportStateCreateFlags::empty()) + .scissor_count(1) + .viewport_count(1) + .build(); + + let vk_sample_mask = [ + desc.multisample.mask as u32, + (desc.multisample.mask >> 32) as u32, + ]; + let vk_multisample = vk::PipelineMultisampleStateCreateInfo::builder() + .rasterization_samples(vk::SampleCountFlags::from_raw(desc.multisample.count)) + .alpha_to_coverage_enable(desc.multisample.alpha_to_coverage_enabled) + .sample_mask(&vk_sample_mask) + .build(); + + let mut vk_attachments = Vec::with_capacity(desc.color_targets.len()); + for cat in desc.color_targets { + let vk_format = self.shared.private_caps.map_texture_format(cat.format); + compatible_rp_key.colors.push(super::ColorAttachmentKey { + base: super::AttachmentKey::compatible(vk_format), + resolve: None, + }); + + let mut vk_attachment = vk::PipelineColorBlendAttachmentState::builder() + .color_write_mask(vk::ColorComponentFlags::from_raw(cat.write_mask.bits())); + if let Some(ref blend) = cat.blend { + let (color_op, color_src, color_dst) = conv::map_blend_component(&blend.color); + let (alpha_op, alpha_src, alpha_dst) = conv::map_blend_component(&blend.alpha); + vk_attachment = vk_attachment + .color_blend_op(color_op) + .src_color_blend_factor(color_src) + .dst_color_blend_factor(color_dst) + .alpha_blend_op(alpha_op) + .src_alpha_blend_factor(color_src) + .dst_alpha_blend_factor(color_dst); + } + vk_attachments.push(vk_attachment.build()); + } + + let vk_color_blend = vk::PipelineColorBlendStateCreateInfo::builder() + .attachments(&vk_attachments) + .build(); + + let vk_dynamic_state = vk::PipelineDynamicStateCreateInfo::builder() + .dynamic_states(&dynamic_states) + .build(); + + let raw_pass = self + .shared + .make_render_pass(compatible_rp_key) + .map_err(crate::DeviceError::from)?; + + let vk_infos = [{ + vk::GraphicsPipelineCreateInfo::builder() + .layout(desc.layout.raw) + .stages(&stages) + .vertex_input_state(&vk_vertex_input) + .input_assembly_state(&vk_input_assembly) + .rasterization_state(&vk_rasterization) + .viewport_state(&vk_viewport) + .multisample_state(&vk_multisample) + .depth_stencil_state(&vk_depth_stencil) + .color_blend_state(&vk_color_blend) + .dynamic_state(&vk_dynamic_state) + .render_pass(raw_pass) + .build() + }]; + + let mut raw_vec = self + .shared + .raw + .create_graphics_pipelines(vk::PipelineCache::null(), &vk_infos, None) + .map_err(|(_, e)| crate::DeviceError::from(e))?; + + Ok(super::RenderPipeline { + raw: raw_vec.pop().unwrap(), + }) } - unsafe fn destroy_render_pipeline(&self, pipeline: Resource) {} + unsafe fn destroy_render_pipeline(&self, pipeline: super::RenderPipeline) { + self.shared.raw.destroy_pipeline(pipeline.raw, None); + } + unsafe fn create_compute_pipeline( &self, desc: &crate::ComputePipelineDescriptor, - ) -> Result { - Ok(Resource) + ) -> Result { + 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 vk_infos = [{ + vk::ComputePipelineCreateInfo::builder() + .layout(desc.layout.raw) + .stage(vk_stage) + .build() + }]; + + let mut raw_vec = self + .shared + .raw + .create_compute_pipelines(vk::PipelineCache::null(), &vk_infos, None) + .map_err(|(_, e)| crate::DeviceError::from(e))?; + + Ok(super::ComputePipeline { + raw: raw_vec.pop().unwrap(), + }) + } + unsafe fn destroy_compute_pipeline(&self, pipeline: super::ComputePipeline) { + self.shared.raw.destroy_pipeline(pipeline.raw, None); } - unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {} unsafe fn create_query_set(&self, desc: &wgt::QuerySetDescriptor) -> DeviceResult { Ok(Resource) diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index e14c73116..66fece011 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -8,6 +8,7 @@ mod instance; use std::{borrow::Borrow, ffi::CStr, sync::Arc}; +use arrayvec::ArrayVec; use ash::{ extensions::{ext, khr}, vk, @@ -44,9 +45,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; } struct DebugUtils { @@ -133,6 +134,47 @@ struct PrivateCapabilities { texture_d24_s8: bool, } +#[derive(Clone, Eq, Hash, PartialEq)] +struct AttachmentKey { + format: vk::Format, + layout_pre: vk::ImageLayout, + layout_in: vk::ImageLayout, + layout_post: vk::ImageLayout, + ops: crate::AttachmentOp, +} + +impl AttachmentKey { + /// Returns an attachment key for a compatible attachment. + fn compatible(format: vk::Format) -> Self { + Self { + format, + layout_pre: vk::ImageLayout::UNDEFINED, + layout_in: vk::ImageLayout::UNDEFINED, + layout_post: vk::ImageLayout::UNDEFINED, + ops: crate::AttachmentOp::empty(), + } + } +} + +#[derive(Clone, Eq, Hash, PartialEq)] +struct ColorAttachmentKey { + base: AttachmentKey, + resolve: Option, +} + +#[derive(Clone, Eq, Hash, PartialEq)] +struct DepthStencilAttachmentKey { + base: AttachmentKey, + stencil_ops: crate::AttachmentOp, +} + +#[derive(Clone, Eq, Default, Hash, PartialEq)] +struct RenderPassKey { + colors: ArrayVec<[ColorAttachmentKey; crate::MAX_COLOR_TARGETS]>, + depth_stencil: Option, + sample_count: u32, +} + struct DeviceShared { raw: ash::Device, instance: Arc, @@ -142,6 +184,7 @@ struct DeviceShared { timestamp_period: f32, downlevel_flags: wgt::DownlevelFlags, private_caps: PrivateCapabilities, + render_passes: Mutex>, } pub struct Device { @@ -187,6 +230,7 @@ pub struct Sampler { pub struct BindGroupLayout { raw: vk::DescriptorSetLayout, desc_count: gpu_descriptor::DescriptorTotalCount, + types: Vec, } #[derive(Debug)] @@ -211,6 +255,21 @@ pub struct CommandBuffer { raw: vk::CommandBuffer, } +#[derive(Debug)] +pub struct ShaderModule { + raw: vk::ShaderModule, +} + +#[derive(Debug)] +pub struct RenderPipeline { + raw: vk::Pipeline, +} + +#[derive(Debug)] +pub struct ComputePipeline { + raw: vk::Pipeline, +} + impl crate::Queue for Queue { unsafe fn submit( &mut self,