diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 745220a9e7..285e4303c9 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -841,7 +841,7 @@ impl Device { }; let raw = match unsafe { self.raw.create_shader_module(&hal_desc, hal_shader) } { Ok(raw) => raw, - Err((error, _shader)) => { + Err(error) => { return Err(match error { hal::ShaderError::Device(error) => { pipeline::CreateShaderModuleError::Device(error.into()) diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 56812c67c8..0477a03d38 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -631,8 +631,6 @@ impl NumericType { | Tf::Bc7RgbaUnormSrgb | Tf::Etc2RgbA1Unorm | Tf::Etc2RgbA1UnormSrgb - | Tf::Etc2RgbA8Unorm - | Tf::Etc2RgbA8UnormSrgb | Tf::Astc4x4RgbaUnorm | Tf::Astc4x4RgbaUnormSrgb | Tf::Astc5x4RgbaUnorm diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index 950f72b40e..2e156e8d47 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -236,13 +236,8 @@ impl crate::CommandBuffer for Encoder { unsafe fn fill_buffer(&mut self, buffer: &Resource, range: crate::MemoryRange, value: u8) {} - unsafe fn copy_buffer_to_buffer(&mut self, src: &Resource, dst: &Resource, regions: T) - where - T: Iterator, - { - } + unsafe fn copy_buffer_to_buffer(&mut self, src: &Resource, dst: &Resource, regions: T) {} - /// Note: `dst` current usage has to be `TextureUse::COPY_DST`. unsafe fn copy_texture_to_texture( &mut self, src: &Resource, @@ -252,7 +247,6 @@ impl crate::CommandBuffer for Encoder { ) { } - /// Note: `dst` current usage has to be `TextureUse::COPY_DST`. unsafe fn copy_buffer_to_texture(&mut self, src: &Resource, dst: &Resource, regions: T) {} unsafe fn copy_texture_to_buffer( diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index ab151ce556..1b9fa42a05 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -63,6 +63,8 @@ pub const MAX_BIND_GROUPS: usize = 8; pub const MAX_VERTEX_BUFFERS: usize = 16; pub const MAX_COLOR_TARGETS: usize = 4; pub const MAX_MIP_LEVELS: u32 = 16; +/// Size of a single occlusion/timestamp query, when copied into a buffer, in bytes. +pub const QUERY_SIZE: wgt::BufferAddress = 8; pub type Label<'a> = Option<&'a str>; pub type MemoryRange = Range; diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 45d745b40d..a3f34e8134 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -17,15 +17,12 @@ impl crate::Adapter for super::Adapter { &self, features: wgt::Features, ) -> Result, crate::DeviceError> { - let raw_device = self.shared.device.lock(); - Ok(crate::OpenDevice { device: super::Device { shared: Arc::clone(&self.shared), features, }, - queue: super::Queue { - }, + queue: super::Queue {}, }) } @@ -199,7 +196,9 @@ impl crate::Adapter for super::Adapter { | Tf::Bc4RUnorm | Tf::Bc4RSnorm | Tf::Bc5RgUnorm + | Tf::Bc5RgSnorm | Tf::Bc6hRgbSfloat + | Tf::Bc6hRgbUfloat | Tf::Bc7RgbaUnorm | Tf::Bc7RgbaUnormSrgb => { if pc.format_bc { @@ -946,7 +945,9 @@ impl super::PrivateCapabilities { Tf::Bc4RUnorm => BC4_RUnorm, Tf::Bc4RSnorm => BC4_RSnorm, Tf::Bc5RgUnorm => BC5_RGUnorm, + Tf::Bc5RgSnorm => BC5_RGSnorm, Tf::Bc6hRgbSfloat => BC6H_RGBFloat, + Tf::Bc6hRgbUfloat => BC6H_RGBUfloat, Tf::Bc7RgbaUnorm => BC7_RGBAUnorm, Tf::Bc7RgbaUnormSrgb => BC7_RGBAUnorm_sRGB, Tf::Etc2RgbUnorm => ETC2_RGB8, diff --git a/wgpu-hal/src/metal/command.rs b/wgpu-hal/src/metal/command.rs index b705bf8dfb..c861ef0586 100644 --- a/wgpu-hal/src/metal/command.rs +++ b/wgpu-hal/src/metal/command.rs @@ -1,98 +1,475 @@ -use std::ops::Range; +use super::{conv, AsNative}; +use std::{mem, ops::Range}; + +impl super::CommandBuffer { + fn enter_blit(&mut self) -> &mtl::BlitCommandEncoderRef { + if self.blit.is_none() { + debug_assert!(self.render.is_none() && self.compute.is_none()); + self.blit = Some(self.raw.new_blit_command_encoder().to_owned()); + } + self.blit.as_ref().unwrap() + } + + fn leave_blit(&mut self) { + if let Some(encoder) = self.blit.take() { + encoder.end_encoding(); + } + } + + fn enter_any(&mut self) -> &mtl::CommandEncoderRef { + if let Some(ref encoder) = self.render { + encoder + } else if let Some(ref encoder) = self.compute { + encoder + } else { + if self.blit.is_none() { + debug_assert!(self.render.is_none() && self.compute.is_none()); + self.blit = Some(self.raw.new_blit_command_encoder().to_owned()); + } + self.blit.as_ref().unwrap() + } + } +} impl crate::CommandBuffer for super::CommandBuffer { - unsafe fn finish(&mut self) {} + unsafe fn finish(&mut self) { + self.leave_blit(); + } - unsafe fn transition_buffers<'a, T>(&mut self, barriers: T) + unsafe fn transition_buffers<'a, T>(&mut self, _barriers: T) where T: Iterator>, { } - unsafe fn transition_textures<'a, T>(&mut self, barriers: T) + unsafe fn transition_textures<'a, T>(&mut self, _barriers: T) where T: Iterator>, { } - unsafe fn fill_buffer(&mut self, buffer: &Resource, range: crate::MemoryRange, value: u8) {} + unsafe fn fill_buffer(&mut self, buffer: &super::Buffer, range: crate::MemoryRange, value: u8) { + let encoder = self.enter_blit(); + encoder.fill_buffer(&buffer.raw, conv::map_range(&range), value); + } - unsafe fn copy_buffer_to_buffer(&mut self, src: &Resource, dst: &Resource, regions: T) - where + unsafe fn copy_buffer_to_buffer( + &mut self, + src: &super::Buffer, + dst: &super::Buffer, + regions: T, + ) where T: Iterator, { + let encoder = self.enter_blit(); + for copy in regions { + encoder.copy_from_buffer( + &src.raw, + copy.src_offset, + &dst.raw, + copy.dst_offset, + copy.size.get(), + ); + } } - /// Note: `dst` current usage has to be `TextureUse::COPY_DST`. unsafe fn copy_texture_to_texture( &mut self, - src: &Resource, - src_usage: crate::TextureUse, - dst: &Resource, + src: &super::Texture, + _src_usage: crate::TextureUse, + dst: &super::Texture, regions: T, - ) { + ) where + T: Iterator, + { + let encoder = self.enter_blit(); + for copy in regions { + let (src_slice, src_origin) = conv::map_origin(©.src_base.origin, src.raw_type); + let (dst_slice, dst_origin) = conv::map_origin(©.dst_base.origin, dst.raw_type); + let (slice_count, extent) = conv::map_extent(©.size, src.raw_type); + for slice in 0..slice_count { + encoder.copy_from_texture( + &src.raw, + src_slice + slice, + copy.src_base.mip_level as u64, + src_origin, + extent, + &dst.raw, + dst_slice + slice, + copy.dst_base.mip_level as u64, + dst_origin, + ); + } + } } - /// Note: `dst` current usage has to be `TextureUse::COPY_DST`. - unsafe fn copy_buffer_to_texture(&mut self, src: &Resource, dst: &Resource, regions: T) {} + unsafe fn copy_buffer_to_texture( + &mut self, + src: &super::Buffer, + dst: &super::Texture, + regions: T, + ) where + T: Iterator, + { + let encoder = self.enter_blit(); + for copy in regions { + let (dst_slice, dst_origin) = conv::map_origin(©.texture_base.origin, dst.raw_type); + let (slice_count, extent) = conv::map_extent(©.size, dst.raw_type); + let bytes_per_row = copy + .buffer_layout + .bytes_per_row + .map_or(0, |v| v.get() as u64); + let bytes_per_image = copy + .buffer_layout + .rows_per_image + .map_or(0, |v| v.get() as u64 * bytes_per_row); + for slice in 0..slice_count { + let offset = copy.buffer_layout.offset + bytes_per_image * slice; + encoder.copy_from_buffer_to_texture( + &src.raw, + offset, + bytes_per_row, + bytes_per_image, + extent, + &dst.raw, + dst_slice + slice_count, + copy.texture_base.mip_level as u64, + dst_origin, + mtl::MTLBlitOption::empty(), + ); + } + } + } unsafe fn copy_texture_to_buffer( &mut self, - src: &Resource, - src_usage: crate::TextureUse, - dst: &Resource, + src: &super::Texture, + _src_usage: crate::TextureUse, + dst: &super::Buffer, regions: T, - ) { + ) where + T: Iterator, + { + let encoder = self.enter_blit(); + for copy in regions { + let (src_slice, src_origin) = conv::map_origin(©.texture_base.origin, src.raw_type); + let (slice_count, extent) = conv::map_extent(©.size, src.raw_type); + let bytes_per_row = copy + .buffer_layout + .bytes_per_row + .map_or(0, |v| v.get() as u64); + let bytes_per_image = copy + .buffer_layout + .rows_per_image + .map_or(0, |v| v.get() as u64 * bytes_per_row); + for slice in 0..slice_count { + let offset = copy.buffer_layout.offset + bytes_per_image * slice; + encoder.copy_from_texture_to_buffer( + &src.raw, + src_slice + slice, + copy.texture_base.mip_level as u64, + src_origin, + extent, + &dst.raw, + offset, + bytes_per_row, + bytes_per_image, + mtl::MTLBlitOption::empty(), + ); + } + } } - unsafe fn begin_query(&mut self, set: &Resource, index: u32) {} - unsafe fn end_query(&mut self, set: &Resource, index: u32) {} - unsafe fn write_timestamp(&mut self, set: &Resource, index: u32) {} - unsafe fn reset_queries(&mut self, set: &Resource, range: Range) {} + unsafe fn begin_query(&mut self, set: &super::QuerySet, index: u32) { + match set.ty { + wgt::QueryType::Occlusion => { + self.render.as_ref().unwrap().set_visibility_result_mode( + mtl::MTLVisibilityResultMode::Boolean, + index as u64 * crate::QUERY_SIZE, + ); + } + _ => {} + } + } + unsafe fn end_query(&mut self, set: &super::QuerySet, _index: u32) { + match set.ty { + wgt::QueryType::Occlusion => { + self.render + .as_ref() + .unwrap() + .set_visibility_result_mode(mtl::MTLVisibilityResultMode::Disabled, 0); + } + _ => {} + } + } + unsafe fn write_timestamp(&mut self, _set: &super::QuerySet, _index: u32) {} + unsafe fn reset_queries(&mut self, set: &super::QuerySet, range: Range) { + let encoder = self.enter_blit(); + let raw_range = mtl::NSRange { + location: range.start as u64 * crate::QUERY_SIZE, + length: (range.end - range.start) as u64 * crate::QUERY_SIZE, + }; + encoder.fill_buffer(&set.raw_buffer, raw_range, 0); + } unsafe fn copy_query_results( &mut self, - set: &Resource, + set: &super::QuerySet, range: Range, - buffer: &Resource, + buffer: &super::Buffer, offset: wgt::BufferAddress, ) { + let encoder = self.enter_blit(); + let size = (range.end - range.start) as u64 * crate::QUERY_SIZE; + encoder.copy_from_buffer( + &set.raw_buffer, + range.start as u64 * crate::QUERY_SIZE, + &buffer.raw, + offset, + size, + ); } // render - unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor) {} - unsafe fn end_render_pass(&mut self) {} + unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor) { + self.leave_blit(); + let descriptor = mtl::RenderPassDescriptor::new(); + //TODO: set visibility results buffer + + for (i, at) in desc.color_attachments.iter().enumerate() { + let at_descriptor = descriptor.color_attachments().object_at(i as u64).unwrap(); + at_descriptor.set_texture(Some(&at.target.view.raw)); + if let Some(ref resolve) = at.resolve_target { + //Note: the selection of levels and slices is already handled by `TextureView` + at_descriptor.set_resolve_texture(Some(&resolve.view.raw)); + } + let load_action = if at.ops.contains(crate::AttachmentOp::LOAD) { + mtl::MTLLoadAction::Load + } else { + at_descriptor.set_clear_color(conv::map_clear_color(&at.clear_value)); + mtl::MTLLoadAction::Clear + }; + let store_action = conv::map_store_action( + at.ops.contains(crate::AttachmentOp::STORE), + at.resolve_target.is_some(), + ); + at_descriptor.set_load_action(load_action); + at_descriptor.set_store_action(store_action); + } + + if let Some(ref at) = desc.depth_stencil_attachment { + if at.target.view.aspects.contains(crate::FormatAspect::DEPTH) { + let at_descriptor = descriptor.depth_attachment().unwrap(); + at_descriptor.set_texture(Some(&at.target.view.raw)); + + let load_action = if at.depth_ops.contains(crate::AttachmentOp::LOAD) { + mtl::MTLLoadAction::Load + } else { + at_descriptor.set_clear_depth(at.clear_value.0 as f64); + mtl::MTLLoadAction::Clear + }; + let store_action = if at.depth_ops.contains(crate::AttachmentOp::STORE) { + mtl::MTLStoreAction::Store + } else { + mtl::MTLStoreAction::DontCare + }; + at_descriptor.set_load_action(load_action); + at_descriptor.set_store_action(store_action); + } + if at + .target + .view + .aspects + .contains(crate::FormatAspect::STENCIL) + { + let at_descriptor = descriptor.stencil_attachment().unwrap(); + at_descriptor.set_texture(Some(&at.target.view.raw)); + + let load_action = if at.depth_ops.contains(crate::AttachmentOp::LOAD) { + mtl::MTLLoadAction::Load + } else { + at_descriptor.set_clear_stencil(at.clear_value.1); + mtl::MTLLoadAction::Clear + }; + let store_action = if at.depth_ops.contains(crate::AttachmentOp::STORE) { + mtl::MTLStoreAction::Store + } else { + mtl::MTLStoreAction::DontCare + }; + at_descriptor.set_load_action(load_action); + at_descriptor.set_store_action(store_action); + } + } + + let encoder = self.raw.new_render_command_encoder(descriptor); + if let Some(label) = desc.label { + encoder.set_label(label); + } + self.render = Some(encoder.to_owned()); + } + + unsafe fn end_render_pass(&mut self) { + self.render.take().unwrap().end_encoding(); + } unsafe fn set_bind_group( &mut self, - layout: &Resource, + layout: &super::PipelineLayout, index: u32, - group: &Resource, + group: &super::BindGroup, dynamic_offsets: &[wgt::DynamicOffset], ) { + let bg_info = &layout.bind_group_infos[index as usize]; + + if let Some(ref encoder) = self.render { + for index in 0..group.counters.vs.buffers { + let buf = &group.buffers[index as usize]; + let mut offset = buf.offset; + if let Some(dyn_index) = buf.dynamic_index { + offset += dynamic_offsets[dyn_index as usize] as wgt::BufferAddress; + } + encoder.set_vertex_buffer( + (bg_info.base_resource_indices.vs.buffers + index) as u64, + Some(buf.ptr.as_native()), + offset, + ); + } + for index in 0..group.counters.fs.buffers { + let buf = &group.buffers[(group.counters.vs.buffers + index) as usize]; + let mut offset = buf.offset; + if let Some(dyn_index) = buf.dynamic_index { + offset += dynamic_offsets[dyn_index as usize] as wgt::BufferAddress; + } + encoder.set_fragment_buffer( + (bg_info.base_resource_indices.fs.buffers + index) as u64, + Some(buf.ptr.as_native()), + offset, + ); + } + + for index in 0..group.counters.vs.samplers { + let res = group.samplers[index as usize]; + encoder.set_vertex_sampler_state( + (bg_info.base_resource_indices.vs.samplers + index) as u64, + Some(res.as_native()), + ); + } + for index in 0..group.counters.fs.samplers { + let res = group.samplers[(group.counters.vs.samplers + index) as usize]; + encoder.set_fragment_sampler_state( + (bg_info.base_resource_indices.fs.samplers + index) as u64, + Some(res.as_native()), + ); + } + + for index in 0..group.counters.vs.textures { + let res = group.textures[index as usize]; + encoder.set_vertex_texture( + (bg_info.base_resource_indices.vs.textures + index) as u64, + Some(res.as_native()), + ); + } + for index in 0..group.counters.fs.textures { + let res = group.textures[(group.counters.vs.textures + index) as usize]; + encoder.set_fragment_texture( + (bg_info.base_resource_indices.fs.textures + index) as u64, + Some(res.as_native()), + ); + } + } + + if let Some(ref encoder) = self.compute { + let index_base = super::ResourceData { + buffers: group.counters.vs.buffers + group.counters.fs.buffers, + samplers: group.counters.vs.samplers + group.counters.fs.samplers, + textures: group.counters.vs.textures + group.counters.fs.textures, + }; + for index in 0..group.counters.cs.buffers { + let buf = &group.buffers[(index_base.buffers + index) as usize]; + let mut offset = buf.offset; + if let Some(dyn_index) = buf.dynamic_index { + offset += dynamic_offsets[dyn_index as usize] as wgt::BufferAddress; + } + encoder.set_buffer( + (bg_info.base_resource_indices.cs.buffers + index) as u64, + Some(buf.ptr.as_native()), + offset, + ); + } + for index in 0..group.counters.cs.samplers { + let res = group.samplers[(index_base.samplers + index) as usize]; + encoder.set_sampler_state( + (bg_info.base_resource_indices.cs.samplers + index) as u64, + Some(res.as_native()), + ); + } + for index in 0..group.counters.cs.textures { + let res = group.textures[(index_base.textures + index) as usize]; + encoder.set_texture( + (bg_info.base_resource_indices.cs.textures + index) as u64, + Some(res.as_native()), + ); + } + } } + unsafe fn set_push_constants( &mut self, - layout: &Resource, - stages: wgt::ShaderStage, - offset: u32, - data: &[u32], + _layout: &super::PipelineLayout, + _stages: wgt::ShaderStage, + _offset: u32, + _data: &[u32], ) { + //TODO } - unsafe fn insert_debug_marker(&mut self, label: &str) {} - unsafe fn begin_debug_marker(&mut self, group_label: &str) {} - unsafe fn end_debug_marker(&mut self) {} + unsafe fn insert_debug_marker(&mut self, label: &str) { + self.enter_any().insert_debug_signpost(label); + } + unsafe fn begin_debug_marker(&mut self, group_label: &str) { + self.enter_any().push_debug_group(group_label); + } + unsafe fn end_debug_marker(&mut self) { + self.enter_any().pop_debug_group(); + } - unsafe fn set_render_pipeline(&mut self, pipeline: &Resource) {} + unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) { + self.raw_primitive_type = pipeline.raw_primitive_type; + let encoder = self.render.as_ref().unwrap(); + encoder.set_render_pipeline_state(&pipeline.raw); + encoder.set_front_facing_winding(pipeline.raw_front_winding); + encoder.set_cull_mode(pipeline.raw_cull_mode); + if let Some(depth_clip) = pipeline.raw_depth_clip_mode { + encoder.set_depth_clip_mode(depth_clip); + } + if let Some((ref state, bias)) = pipeline.depth_stencil { + encoder.set_depth_stencil_state(state); + encoder.set_depth_bias(bias.constant as f32, bias.slope_scale, bias.clamp); + } + } unsafe fn set_index_buffer<'a>( &mut self, binding: crate::BufferBinding<'a, super::Api>, format: wgt::IndexFormat, ) { + let (stride, raw_type) = match format { + wgt::IndexFormat::Uint16 => (2, mtl::MTLIndexType::UInt16), + wgt::IndexFormat::Uint32 => (4, mtl::MTLIndexType::UInt32), + }; + self.index_state = Some(super::IndexState { + buffer_ptr: AsNative::from(binding.buffer.raw.as_ref()), + offset: binding.offset, + stride, + raw_type, + }); } - unsafe fn set_vertex_buffer<'a>(&mut self, index: u32, binding: crate::BufferBinding<'a, super::Api>) { + + unsafe fn set_vertex_buffer<'a>( + &mut self, + index: u32, + binding: crate::BufferBinding<'a, super::Api>, + ) { } unsafe fn set_viewport(&mut self, rect: &crate::Rect, depth_range: Range) {} unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect) {} @@ -106,7 +483,31 @@ impl crate::CommandBuffer for super::CommandBuffer { start_instance: u32, instance_count: u32, ) { + let encoder = self.render.as_ref().unwrap(); + if start_instance != 0 { + encoder.draw_primitives_instanced_base_instance( + self.raw_primitive_type, + start_vertex as _, + vertex_count as _, + instance_count as _, + start_instance as _, + ); + } else if instance_count != 1 { + encoder.draw_primitives_instanced( + self.raw_primitive_type, + start_vertex as _, + vertex_count as _, + instance_count as _, + ); + } else { + encoder.draw_primitives( + self.raw_primitive_type, + start_vertex as _, + vertex_count as _, + ); + } } + unsafe fn draw_indexed( &mut self, start_index: u32, @@ -115,47 +516,124 @@ impl crate::CommandBuffer for super::CommandBuffer { start_instance: u32, instance_count: u32, ) { + let encoder = self.render.as_ref().unwrap(); + let index = self.index_state.as_ref().unwrap(); + let offset = index.offset + index.stride * start_index as wgt::BufferAddress; + if base_vertex != 0 || start_instance != 0 { + encoder.draw_indexed_primitives_instanced_base_instance( + self.raw_primitive_type, + index_count as _, + index.raw_type, + index.buffer_ptr.as_native(), + offset, + instance_count as _, + base_vertex as _, + start_instance as _, + ); + } else if instance_count != 1 { + encoder.draw_indexed_primitives_instanced( + self.raw_primitive_type, + index_count as _, + index.raw_type, + index.buffer_ptr.as_native(), + offset, + instance_count as _, + ); + } else { + encoder.draw_indexed_primitives( + self.raw_primitive_type, + index_count as _, + index.raw_type, + index.buffer_ptr.as_native(), + offset, + ); + } } + unsafe fn draw_indirect( &mut self, - buffer: &Resource, - offset: wgt::BufferAddress, + buffer: &super::Buffer, + mut offset: wgt::BufferAddress, draw_count: u32, ) { + let encoder = self.render.as_ref().unwrap(); + for _ in 0..draw_count { + encoder.draw_primitives_indirect(self.raw_primitive_type, &buffer.raw, offset); + offset += mem::size_of::() as wgt::BufferAddress; + } } + unsafe fn draw_indexed_indirect( &mut self, - buffer: &Resource, - offset: wgt::BufferAddress, + buffer: &super::Buffer, + mut offset: wgt::BufferAddress, draw_count: u32, ) { + let encoder = self.render.as_ref().unwrap(); + let index = self.index_state.as_ref().unwrap(); + for _ in 0..draw_count { + encoder.draw_indexed_primitives_indirect( + self.raw_primitive_type, + index.raw_type, + index.buffer_ptr.as_native(), + index.offset, + &buffer.raw, + offset, + ); + offset += mem::size_of::() as wgt::BufferAddress; + } } + unsafe fn draw_indirect_count( &mut self, - buffer: &Resource, - offset: wgt::BufferAddress, - count_buffer: &Resource, - count_offset: wgt::BufferAddress, - max_count: u32, + _buffer: &super::Buffer, + _offset: wgt::BufferAddress, + _count_buffer: &super::Buffer, + _count_offset: wgt::BufferAddress, + _max_count: u32, ) { + //TODO } unsafe fn draw_indexed_indirect_count( &mut self, - buffer: &Resource, - offset: wgt::BufferAddress, - count_buffer: &Resource, - count_offset: wgt::BufferAddress, - max_count: u32, + _buffer: &super::Buffer, + _offset: wgt::BufferAddress, + _count_buffer: &super::Buffer, + _count_offset: wgt::BufferAddress, + _max_count: u32, ) { + //TODO } // compute - unsafe fn begin_compute_pass(&mut self) {} - unsafe fn end_compute_pass(&mut self) {} + unsafe fn begin_compute_pass(&mut self) { + self.leave_blit(); + let encoder = self.raw.new_compute_command_encoder(); + self.compute = Some(encoder.to_owned()); + } + unsafe fn end_compute_pass(&mut self) { + self.compute.take().unwrap().end_encoding(); + } - unsafe fn set_compute_pipeline(&mut self, pipeline: &Resource) {} + unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) { + self.raw_wg_size = pipeline.work_group_size; + let encoder = self.compute.as_ref().unwrap(); + encoder.set_compute_pipeline_state(&pipeline.raw); + } - unsafe fn dispatch(&mut self, count: [u32; 3]) {} - unsafe fn dispatch_indirect(&mut self, buffer: &Resource, offset: wgt::BufferAddress) {} + unsafe fn dispatch(&mut self, count: [u32; 3]) { + let encoder = self.compute.as_ref().unwrap(); + let raw_count = mtl::MTLSize { + width: count[0] as u64, + height: count[1] as u64, + depth: count[2] as u64, + }; + encoder.dispatch_thread_groups(raw_count, self.raw_wg_size); + } + + unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) { + let encoder = self.compute.as_ref().unwrap(); + encoder.dispatch_thread_groups_indirect(&buffer.raw, offset, self.raw_wg_size); + } } diff --git a/wgpu-hal/src/metal/conv.rs b/wgpu-hal/src/metal/conv.rs index b099edf949..9fc7727b26 100644 --- a/wgpu-hal/src/metal/conv.rs +++ b/wgpu-hal/src/metal/conv.rs @@ -212,6 +212,7 @@ pub fn map_vertex_format(format: wgt::VertexFormat) -> mtl::MTLVertexFormat { Vf::Uint32x4 => UInt4, Vf::Sint32x4 => Int4, Vf::Float32x4 => Float4, + Vf::Float64 | Vf::Float64x2 | Vf::Float64x3 | Vf::Float64x4 => unimplemented!(), } } @@ -252,3 +253,59 @@ pub fn map_cull_mode(face: Option) -> mtl::MTLCullMode { Some(wgt::Face::Back) => mtl::MTLCullMode::Back, } } + +pub fn map_range(range: &crate::MemoryRange) -> mtl::NSRange { + mtl::NSRange { + location: range.start, + length: range.end - range.start, + } +} + +pub fn map_extent(extent: &wgt::Extent3d, raw_type: mtl::MTLTextureType) -> (u64, mtl::MTLSize) { + let (depth, array_layers) = match raw_type { + mtl::MTLTextureType::D3 => (extent.depth_or_array_layers as u64, 1), + _ => (1, extent.depth_or_array_layers as u64), + }; + ( + array_layers, + mtl::MTLSize { + width: extent.width as u64, + height: extent.height as u64, + depth, + }, + ) +} + +pub fn map_origin(origin: &wgt::Origin3d, raw_type: mtl::MTLTextureType) -> (u64, mtl::MTLOrigin) { + let (z, slice) = match raw_type { + mtl::MTLTextureType::D3 => (origin.z as u64, 0), + _ => (0, origin.z as u64), + }; + ( + slice, + mtl::MTLOrigin { + x: origin.x as u64, + y: origin.y as u64, + z, + }, + ) +} + +pub fn map_store_action(store: bool, resolve: bool) -> mtl::MTLStoreAction { + use mtl::MTLStoreAction::*; + match (store, resolve) { + (true, true) => StoreAndMultisampleResolve, + (false, true) => MultisampleResolve, + (true, false) => Store, + (false, false) => DontCare, + } +} + +pub fn map_clear_color(color: &wgt::Color) -> mtl::MTLClearColor { + mtl::MTLClearColor { + red: color.r, + green: color.g, + blue: color.b, + alpha: color.a, + } +} diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 975993c25b..fe9fde8b65 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -280,7 +280,8 @@ impl crate::Device for super::Device { ) }; - Ok(super::TextureView { raw }) + let aspects = crate::FormatAspect::from(desc.format); + Ok(super::TextureView { raw, aspects }) } unsafe fn destroy_texture_view(&self, _view: super::TextureView) {} @@ -336,8 +337,20 @@ impl crate::Device for super::Device { &self, desc: &crate::CommandBufferDescriptor, ) -> DeviceResult { - let raw = self.shared.create_command_buffer().to_owned(); - Ok(super::CommandBuffer { raw }) + let raw = self.shared.create_command_buffer(); + if let Some(label) = desc.label { + raw.set_label(label); + } + + Ok(super::CommandBuffer { + raw, + blit: None, + render: None, + compute: None, + raw_primitive_type: mtl::MTLPrimitiveType::Point, + index_state: None, + raw_wg_size: mtl::MTLSize::new(0, 0, 0), + }) } unsafe fn destroy_command_buffer(&self, _cmd_buf: super::CommandBuffer) {} @@ -411,33 +424,29 @@ impl crate::Device for super::Device { let base_resource_indices = stage_data.map(|info| info.counters.clone()); for entry in bgl.entries.iter() { - match entry.ty { - wgt::BindingType::Buffer { - ty, - has_dynamic_offset, - min_binding_size: _, - } => { - if has_dynamic_offset { - dynamic_buffers.push(stage_data.map(|info| { - if entry.visibility.contains(map_naga_stage(info.stage)) { - info.counters.buffers - } else { - !0 - } - })); - } - match ty { - wgt::BufferBindingType::Storage { .. } => { - sized_buffer_bindings.push((entry.binding, entry.visibility)); - for info in stage_data.iter_mut() { - if entry.visibility.contains(map_naga_stage(info.stage)) { - info.sizes_count += 1; - } - } + if let wgt::BindingType::Buffer { + ty, + has_dynamic_offset, + min_binding_size: _, + } = entry.ty + { + if has_dynamic_offset { + dynamic_buffers.push(stage_data.map(|info| { + if entry.visibility.contains(map_naga_stage(info.stage)) { + info.counters.buffers + } else { + !0 + } + })); + } + if let wgt::BufferBindingType::Storage { .. } = ty { + sized_buffer_bindings.push((entry.binding, entry.visibility)); + for info in stage_data.iter_mut() { + if entry.visibility.contains(map_naga_stage(info.stage)) { + info.sizes_count += 1; } } } - _ => {} } for info in stage_data.iter_mut() { @@ -486,7 +495,7 @@ impl crate::Device for super::Device { bind_group_infos.push(super::BindGroupLayoutInfo { base_resource_indices, - dynamic_buffers, + //dynamic_buffers, sized_buffer_bindings, }); } @@ -558,16 +567,31 @@ impl crate::Device for super::Device { let mut bg = super::BindGroup::default(); for (&stage, counter) in super::NAGA_STAGES.iter().zip(bg.counters.iter_mut()) { let stage_bit = map_naga_stage(stage); + let mut dynamic_offsets_count = 0u32; for (entry, layout) in desc.entries.iter().zip(desc.layout.entries.iter()) { + if let wgt::BindingType::Buffer { + has_dynamic_offset: true, + .. + } = layout.ty + { + dynamic_offsets_count += 1; + } if !layout.visibility.contains(stage_bit) { continue; } match layout.ty { - wgt::BindingType::Buffer { .. } => { + wgt::BindingType::Buffer { + has_dynamic_offset, .. + } => { let source = &desc.buffers[entry.resource_index as usize]; bg.buffers.push(super::BufferResource { ptr: source.buffer.as_raw(), offset: source.offset, + dynamic_index: if has_dynamic_offset { + Some(dynamic_offsets_count - 1) + } else { + None + }, }); counter.buffers += 1; } @@ -592,7 +616,7 @@ impl crate::Device for super::Device { unsafe fn create_shader_module( &self, - desc: &crate::ShaderModuleDescriptor, + _desc: &crate::ShaderModuleDescriptor, shader: crate::NagaShader, ) -> Result { Ok(super::ShaderModule { raw: shader }) @@ -660,7 +684,7 @@ impl crate::Device for super::Device { } } - let (raw_depth_stencil, depth_bias) = match desc.depth_stencil { + let depth_stencil = match desc.depth_stencil { Some(ref ds) => { let raw_format = self.shared.private_caps.map_format(ds.format); let aspects = crate::FormatAspect::from(ds.format); @@ -677,9 +701,9 @@ impl crate::Device for super::Device { .device .lock() .new_depth_stencil_state(&ds_descriptor); - (Some(raw), ds.bias) + Some((raw, ds.bias)) } - None => (None, wgt::DepthBiasState::default()), + None => None, }; if desc.layout.total_counters.vs.buffers + (desc.vertex_buffers.len() as u32) @@ -703,9 +727,11 @@ impl crate::Device for super::Device { buffer_desc.set_stride(vb.array_stride); buffer_desc.set_step_function(conv::map_step_mode(vb.step_mode)); - for (j, at) in vb.attributes.iter().enumerate() { - let attribute_desc = - vertex_descriptor.attributes().object_at(i as u64).unwrap(); + for at in vb.attributes { + let attribute_desc = vertex_descriptor + .attributes() + .object_at(at.shader_location as u64) + .unwrap(); attribute_desc.set_format(conv::map_vertex_format(at.format)); attribute_desc.set_buffer_index(buffer_index); attribute_desc.set_offset(at.offset); @@ -763,8 +789,7 @@ impl crate::Device for super::Device { } else { None }, - raw_depth_stencil, - depth_bias, + depth_stencil, }) } unsafe fn destroy_render_pipeline(&self, _pipeline: super::RenderPipeline) {} @@ -817,12 +842,15 @@ impl crate::Device for super::Device { ) -> DeviceResult { match desc.ty { wgt::QueryType::Occlusion => { - let size = desc.count as u64 * 8; + let size = desc.count as u64 * crate::QUERY_SIZE; let options = mtl::MTLResourceOptions::empty(); //TODO: HazardTrackingModeUntracked let raw_buffer = self.shared.device.lock().new_buffer(size, options); raw_buffer.set_label("_QuerySet"); - Ok(super::QuerySet { raw_buffer }) + Ok(super::QuerySet { + raw_buffer, + ty: desc.ty.clone(), + }) } wgt::QueryType::Timestamp | wgt::QueryType::PipelineStatistics(_) => { Err(crate::DeviceError::OutOfMemory) diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index 6a41ff2d3d..d25344bb8d 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -68,7 +68,9 @@ impl crate::Instance for Instance { } } - unsafe fn destroy_surface(&self, surface: Surface) {} + unsafe fn destroy_surface(&self, surface: Surface) { + surface.dispose(); + } unsafe fn enumerate_adapters(&self) -> Vec> { let devices = mtl::Device::all(); @@ -224,30 +226,31 @@ impl AdapterShared { } } - fn create_command_buffer(&self) -> &mtl::CommandBufferRef { + fn create_command_buffer(&self) -> mtl::CommandBuffer { let queue = self.queue.lock(); - objc::rc::autoreleasepool(|| { - if self.settings.retain_command_buffer_references { + objc::rc::autoreleasepool(move || { + let cmd_buf_ref = if self.settings.retain_command_buffer_references { queue.new_command_buffer() } else { queue.new_command_buffer_with_unretained_references() - } + }; + cmd_buf_ref.to_owned() }) } } -struct Adapter { +pub struct Adapter { shared: Arc, } -struct Queue {} +pub struct Queue {} -struct Device { +pub struct Device { shared: Arc, features: wgt::Features, } -struct Surface { +pub struct Surface { view: Option>, render_layer: Mutex, raw_swapchain_format: mtl::MTLPixelFormat, @@ -258,7 +261,7 @@ struct Surface { } #[derive(Debug)] -struct SurfaceTexture { +pub struct SurfaceTexture { texture: Texture, drawable: mtl::MetalDrawable, present_with_transaction: bool, @@ -321,6 +324,7 @@ unsafe impl Sync for Texture {} #[derive(Debug)] pub struct TextureView { raw: mtl::Texture, + aspects: crate::FormatAspect, } unsafe impl Send for TextureView {} @@ -408,7 +412,7 @@ type MultiStageResourceCounters = MultiStageData>; #[derive(Debug)] struct BindGroupLayoutInfo { base_resource_indices: MultiStageResourceCounters, - dynamic_buffers: Vec>, + //dynamic_buffers: Vec>, sized_buffer_bindings: Vec<(u32, wgt::ShaderStage)>, } @@ -435,7 +439,6 @@ trait AsNative { type BufferPtr = NonNull; type TexturePtr = NonNull; type SamplerPtr = NonNull; -type ResourcePtr = NonNull; impl AsNative for BufferPtr { type Native = mtl::BufferRef; @@ -477,6 +480,7 @@ impl AsNative for SamplerPtr { struct BufferResource { ptr: BufferPtr, offset: wgt::BufferAddress, + dynamic_index: Option, } #[derive(Debug, Default)] @@ -502,21 +506,7 @@ struct PipelineStageInfo { sized_bindings: Vec, } -impl PipelineStageInfo { - fn clear(&mut self) { - self.push_constants = None; - self.sizes_slot = None; - self.sized_bindings.clear(); - } - - fn assign_from(&mut self, other: &Self) { - self.push_constants = other.push_constants; - self.sizes_slot = other.sizes_slot; - self.sized_bindings.clear(); - self.sized_bindings.extend_from_slice(&other.sized_bindings); - } -} - +#[allow(dead_code)] // silence xx_lib and xx_info warnings pub struct RenderPipeline { raw: mtl::RenderPipelineState, vs_lib: mtl::Library, @@ -527,10 +517,10 @@ pub struct RenderPipeline { raw_front_winding: mtl::MTLWinding, raw_cull_mode: mtl::MTLCullMode, raw_depth_clip_mode: Option, - raw_depth_stencil: Option, - depth_bias: wgt::DepthBiasState, + depth_stencil: Option<(mtl::DepthStencilState, wgt::DepthBiasState)>, } +#[allow(dead_code)] // silence xx_lib and xx_info warnings pub struct ComputePipeline { raw: mtl::ComputePipelineState, cs_lib: mtl::Library, @@ -541,6 +531,7 @@ pub struct ComputePipeline { #[derive(Debug)] pub struct QuerySet { raw_buffer: mtl::Buffer, + ty: wgt::QueryType, } unsafe impl Send for QuerySet {} @@ -555,6 +546,19 @@ pub struct Fence { unsafe impl Send for Fence {} unsafe impl Sync for Fence {} +struct IndexState { + buffer_ptr: BufferPtr, + offset: wgt::BufferAddress, + stride: wgt::BufferAddress, + raw_type: mtl::MTLIndexType, +} + pub struct CommandBuffer { raw: mtl::CommandBuffer, + blit: Option, + render: Option, + compute: Option, + raw_primitive_type: mtl::MTLPrimitiveType, + index_state: Option, + raw_wg_size: mtl::MTLSize, } diff --git a/wgpu-hal/src/metal/surface.rs b/wgpu-hal/src/metal/surface.rs index 6ac31ec0ff..1f2e18ac55 100644 --- a/wgpu-hal/src/metal/surface.rs +++ b/wgpu-hal/src/metal/surface.rs @@ -21,13 +21,6 @@ pub struct CGPoint { pub y: mtl::CGFloat, } -impl CGPoint { - #[inline] - pub fn new(x: mtl::CGFloat, y: mtl::CGFloat) -> CGPoint { - CGPoint { x, y } - } -} - #[repr(C)] #[derive(Clone, Copy, Debug, Default)] pub struct CGRect { @@ -35,13 +28,6 @@ pub struct CGRect { pub size: mtl::CGSize, } -impl CGRect { - #[inline] - pub fn new(origin: CGPoint, size: mtl::CGSize) -> CGRect { - CGRect { origin, size } - } -} - impl super::Surface { fn new(view: Option>, layer: mtl::MetalLayer) -> Self { Self { @@ -53,6 +39,12 @@ impl super::Surface { } } + pub unsafe fn dispose(self) { + if let Some(view) = self.view { + let () = msg_send![view.as_ptr(), release]; + } + } + #[cfg(target_os = "ios")] pub unsafe fn from_uiview(uiview: *mut c_void) -> Self { let view: cocoa_foundation::base::id = mem::transmute(uiview); @@ -200,36 +192,33 @@ impl crate::Surface for super::Surface { } let device_raw = device.shared.device.lock(); - unsafe { - // On iOS, unless the user supplies a view with a CAMetalLayer, we - // create one as a sublayer. However, when the view changes size, - // its sublayers are not automatically resized, and we must resize - // it here. The drawable size and the layer size don't correlate - #[cfg(target_os = "ios")] - { - if let Some(view) = self.view { - let main_layer: *mut Object = msg_send![view.as_ptr(), layer]; - let bounds: CGRect = msg_send![main_layer, bounds]; - let () = msg_send![*render_layer, setFrame: bounds]; - } + // On iOS, unless the user supplies a view with a CAMetalLayer, we + // create one as a sublayer. However, when the view changes size, + // its sublayers are not automatically resized, and we must resize + // it here. The drawable size and the layer size don't correlate + #[cfg(target_os = "ios")] + { + if let Some(view) = self.view { + let main_layer: *mut Object = msg_send![view.as_ptr(), layer]; + let bounds: CGRect = msg_send![main_layer, bounds]; + let () = msg_send![*render_layer, setFrame: bounds]; } - render_layer.set_device(&*device_raw); - render_layer.set_pixel_format(mtl_format); - render_layer.set_framebuffer_only(framebuffer_only); - render_layer.set_presents_with_transaction(self.present_with_transaction); + } + render_layer.set_device(&*device_raw); + render_layer.set_pixel_format(mtl_format); + render_layer.set_framebuffer_only(framebuffer_only); + render_layer.set_presents_with_transaction(self.present_with_transaction); - // this gets ignored on iOS for certain OS/device combinations (iphone5s iOS 10.3) - let () = - msg_send![*render_layer, setMaximumDrawableCount: config.swap_chain_size as u64]; + // this gets ignored on iOS for certain OS/device combinations (iphone5s iOS 10.3) + let () = msg_send![*render_layer, setMaximumDrawableCount: config.swap_chain_size as u64]; - render_layer.set_drawable_size(drawable_size); - if caps.can_set_next_drawable_timeout { - let () = msg_send![*render_layer, setAllowsNextDrawableTimeout:false]; - } - if caps.can_set_display_sync { - let () = msg_send![*render_layer, setDisplaySyncEnabled: display_sync]; - } - }; + render_layer.set_drawable_size(drawable_size); + if caps.can_set_next_drawable_timeout { + let () = msg_send![*render_layer, setAllowsNextDrawableTimeout:false]; + } + if caps.can_set_display_sync { + let () = msg_send![*render_layer, setDisplaySyncEnabled: display_sync]; + } Ok(()) } @@ -247,7 +236,6 @@ impl crate::Surface for super::Surface { let drawable = render_layer.next_drawable().unwrap(); (drawable.to_owned(), drawable.texture().to_owned()) }); - let size = render_layer.drawable_size(); let suf_texture = super::SurfaceTexture { texture: super::Texture {