Fix memory leak on macOS (#3056)

This commit is contained in:
Xiaopeng Li
2022-10-13 14:13:31 +08:00
committed by GitHub
parent b72bcc54dc
commit 9272cc65cc
2 changed files with 386 additions and 367 deletions

View File

@@ -905,11 +905,13 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
self.begin_pass();
let raw = self.raw_cmd_buf.as_ref().unwrap();
let encoder = raw.new_compute_command_encoder();
if let Some(label) = desc.label {
encoder.set_label(label);
}
self.state.compute = Some(encoder.to_owned());
objc::rc::autoreleasepool(|| {
let encoder = raw.new_compute_command_encoder();
if let Some(label) = desc.label {
encoder.set_label(label);
}
self.state.compute = Some(encoder.to_owned());
});
}
unsafe fn end_compute_pass(&mut self) {
self.state.compute.take().unwrap().end_encoding();

View File

@@ -235,13 +235,15 @@ impl crate::Device<super::Api> for super::Device {
//TODO: HazardTrackingModeUntracked
let raw = self.shared.device.lock().new_buffer(desc.size, options);
if let Some(label) = desc.label {
raw.set_label(label);
}
Ok(super::Buffer {
raw,
size: desc.size,
objc::rc::autoreleasepool(|| {
let raw = self.shared.device.lock().new_buffer(desc.size, options);
if let Some(label) = desc.label {
raw.set_label(label);
}
Ok(super::Buffer {
raw,
size: desc.size,
})
})
}
unsafe fn destroy_buffer(&self, _buffer: super::Buffer) {}
@@ -271,61 +273,63 @@ impl crate::Device<super::Api> for super::Device {
) -> DeviceResult<super::Texture> {
let mtl_format = self.shared.private_caps.map_format(desc.format);
let descriptor = mtl::TextureDescriptor::new();
let mut array_layers = desc.size.depth_or_array_layers;
let mut copy_size = crate::CopyExtent {
width: desc.size.width,
height: desc.size.height,
depth: 1,
};
let mtl_type = match desc.dimension {
wgt::TextureDimension::D1 => {
if desc.size.depth_or_array_layers > 1 {
descriptor.set_array_length(desc.size.depth_or_array_layers as u64);
mtl::MTLTextureType::D1Array
} else {
mtl::MTLTextureType::D1
objc::rc::autoreleasepool(|| {
let descriptor = mtl::TextureDescriptor::new();
let mut array_layers = desc.size.depth_or_array_layers;
let mut copy_size = crate::CopyExtent {
width: desc.size.width,
height: desc.size.height,
depth: 1,
};
let mtl_type = match desc.dimension {
wgt::TextureDimension::D1 => {
if desc.size.depth_or_array_layers > 1 {
descriptor.set_array_length(desc.size.depth_or_array_layers as u64);
mtl::MTLTextureType::D1Array
} else {
mtl::MTLTextureType::D1
}
}
}
wgt::TextureDimension::D2 => {
if desc.sample_count > 1 {
descriptor.set_sample_count(desc.sample_count as u64);
mtl::MTLTextureType::D2Multisample
} else if desc.size.depth_or_array_layers > 1 {
descriptor.set_array_length(desc.size.depth_or_array_layers as u64);
mtl::MTLTextureType::D2Array
} else {
mtl::MTLTextureType::D2
wgt::TextureDimension::D2 => {
if desc.sample_count > 1 {
descriptor.set_sample_count(desc.sample_count as u64);
mtl::MTLTextureType::D2Multisample
} else if desc.size.depth_or_array_layers > 1 {
descriptor.set_array_length(desc.size.depth_or_array_layers as u64);
mtl::MTLTextureType::D2Array
} else {
mtl::MTLTextureType::D2
}
}
wgt::TextureDimension::D3 => {
descriptor.set_depth(desc.size.depth_or_array_layers as u64);
array_layers = 1;
copy_size.depth = desc.size.depth_or_array_layers;
mtl::MTLTextureType::D3
}
};
descriptor.set_texture_type(mtl_type);
descriptor.set_width(desc.size.width as u64);
descriptor.set_height(desc.size.height as u64);
descriptor.set_mipmap_level_count(desc.mip_level_count as u64);
descriptor.set_pixel_format(mtl_format);
descriptor.set_usage(conv::map_texture_usage(desc.usage));
descriptor.set_storage_mode(mtl::MTLStorageMode::Private);
let raw = self.shared.device.lock().new_texture(&descriptor);
if let Some(label) = desc.label {
raw.set_label(label);
}
wgt::TextureDimension::D3 => {
descriptor.set_depth(desc.size.depth_or_array_layers as u64);
array_layers = 1;
copy_size.depth = desc.size.depth_or_array_layers;
mtl::MTLTextureType::D3
}
};
descriptor.set_texture_type(mtl_type);
descriptor.set_width(desc.size.width as u64);
descriptor.set_height(desc.size.height as u64);
descriptor.set_mipmap_level_count(desc.mip_level_count as u64);
descriptor.set_pixel_format(mtl_format);
descriptor.set_usage(conv::map_texture_usage(desc.usage));
descriptor.set_storage_mode(mtl::MTLStorageMode::Private);
let raw = self.shared.device.lock().new_texture(&descriptor);
if let Some(label) = desc.label {
raw.set_label(label);
}
Ok(super::Texture {
raw,
raw_format: mtl_format,
raw_type: mtl_type,
mip_levels: desc.mip_level_count,
array_layers,
copy_size,
Ok(super::Texture {
raw,
raw_format: mtl_format,
raw_type: mtl_type,
mip_levels: desc.mip_level_count,
array_layers,
copy_size,
})
})
}
@@ -363,24 +367,24 @@ impl crate::Device<super::Api> for super::Device {
None => texture.array_layers - desc.range.base_array_layer,
};
let raw = texture.raw.new_texture_view_from_slice(
raw_format,
raw_type,
mtl::NSRange {
location: desc.range.base_mip_level as _,
length: mip_level_count as _,
},
mtl::NSRange {
location: desc.range.base_array_layer as _,
length: array_layer_count as _,
},
);
if let Some(label) = desc.label {
objc::rc::autoreleasepool(|| {
objc::rc::autoreleasepool(|| {
let raw = texture.raw.new_texture_view_from_slice(
raw_format,
raw_type,
mtl::NSRange {
location: desc.range.base_mip_level as _,
length: mip_level_count as _,
},
mtl::NSRange {
location: desc.range.base_array_layer as _,
length: array_layer_count as _,
},
);
if let Some(label) = desc.label {
raw.set_label(label);
});
}
raw
}
raw
})
};
let aspects = crate::FormatAspects::from(desc.format);
@@ -393,64 +397,66 @@ impl crate::Device<super::Api> for super::Device {
desc: &crate::SamplerDescriptor,
) -> DeviceResult<super::Sampler> {
let caps = &self.shared.private_caps;
let descriptor = mtl::SamplerDescriptor::new();
objc::rc::autoreleasepool(|| {
let descriptor = mtl::SamplerDescriptor::new();
descriptor.set_min_filter(conv::map_filter_mode(desc.min_filter));
descriptor.set_mag_filter(conv::map_filter_mode(desc.mag_filter));
descriptor.set_mip_filter(match desc.mipmap_filter {
wgt::FilterMode::Nearest if desc.lod_clamp.is_none() => {
mtl::MTLSamplerMipFilter::NotMipmapped
descriptor.set_min_filter(conv::map_filter_mode(desc.min_filter));
descriptor.set_mag_filter(conv::map_filter_mode(desc.mag_filter));
descriptor.set_mip_filter(match desc.mipmap_filter {
wgt::FilterMode::Nearest if desc.lod_clamp.is_none() => {
mtl::MTLSamplerMipFilter::NotMipmapped
}
wgt::FilterMode::Nearest => mtl::MTLSamplerMipFilter::Nearest,
wgt::FilterMode::Linear => mtl::MTLSamplerMipFilter::Linear,
});
let [s, t, r] = desc.address_modes;
descriptor.set_address_mode_s(conv::map_address_mode(s));
descriptor.set_address_mode_t(conv::map_address_mode(t));
descriptor.set_address_mode_r(conv::map_address_mode(r));
if let Some(aniso) = desc.anisotropy_clamp {
descriptor.set_max_anisotropy(aniso.get() as _);
}
wgt::FilterMode::Nearest => mtl::MTLSamplerMipFilter::Nearest,
wgt::FilterMode::Linear => mtl::MTLSamplerMipFilter::Linear,
});
let [s, t, r] = desc.address_modes;
descriptor.set_address_mode_s(conv::map_address_mode(s));
descriptor.set_address_mode_t(conv::map_address_mode(t));
descriptor.set_address_mode_r(conv::map_address_mode(r));
if let Some(aniso) = desc.anisotropy_clamp {
descriptor.set_max_anisotropy(aniso.get() as _);
}
if let Some(ref range) = desc.lod_clamp {
descriptor.set_lod_min_clamp(range.start);
descriptor.set_lod_max_clamp(range.end);
}
if caps.sampler_lod_average {
descriptor.set_lod_average(true); // optimization
}
if let Some(fun) = desc.compare {
descriptor.set_compare_function(conv::map_compare_function(fun));
}
if let Some(border_color) = desc.border_color {
if let wgt::SamplerBorderColor::Zero = border_color {
if s == wgt::AddressMode::ClampToBorder {
descriptor.set_address_mode_s(mtl::MTLSamplerAddressMode::ClampToZero);
}
if t == wgt::AddressMode::ClampToBorder {
descriptor.set_address_mode_t(mtl::MTLSamplerAddressMode::ClampToZero);
}
if r == wgt::AddressMode::ClampToBorder {
descriptor.set_address_mode_r(mtl::MTLSamplerAddressMode::ClampToZero);
}
} else {
descriptor.set_border_color(conv::map_border_color(border_color));
if let Some(ref range) = desc.lod_clamp {
descriptor.set_lod_min_clamp(range.start);
descriptor.set_lod_max_clamp(range.end);
}
}
if let Some(label) = desc.label {
descriptor.set_label(label);
}
let raw = self.shared.device.lock().new_sampler(&descriptor);
if caps.sampler_lod_average {
descriptor.set_lod_average(true); // optimization
}
Ok(super::Sampler { raw })
if let Some(fun) = desc.compare {
descriptor.set_compare_function(conv::map_compare_function(fun));
}
if let Some(border_color) = desc.border_color {
if let wgt::SamplerBorderColor::Zero = border_color {
if s == wgt::AddressMode::ClampToBorder {
descriptor.set_address_mode_s(mtl::MTLSamplerAddressMode::ClampToZero);
}
if t == wgt::AddressMode::ClampToBorder {
descriptor.set_address_mode_t(mtl::MTLSamplerAddressMode::ClampToZero);
}
if r == wgt::AddressMode::ClampToBorder {
descriptor.set_address_mode_r(mtl::MTLSamplerAddressMode::ClampToZero);
}
} else {
descriptor.set_border_color(conv::map_border_color(border_color));
}
}
if let Some(label) = desc.label {
descriptor.set_label(label);
}
let raw = self.shared.device.lock().new_sampler(&descriptor);
Ok(super::Sampler { raw })
})
}
unsafe fn destroy_sampler(&self, _sampler: super::Sampler) {}
@@ -784,201 +790,205 @@ impl crate::Device<super::Api> for super::Device {
&self,
desc: &crate::RenderPipelineDescriptor<super::Api>,
) -> Result<super::RenderPipeline, crate::PipelineError> {
let descriptor = mtl::RenderPipelineDescriptor::new();
objc::rc::autoreleasepool(|| {
let descriptor = mtl::RenderPipelineDescriptor::new();
let raw_triangle_fill_mode = match desc.primitive.polygon_mode {
wgt::PolygonMode::Fill => mtl::MTLTriangleFillMode::Fill,
wgt::PolygonMode::Line => mtl::MTLTriangleFillMode::Lines,
wgt::PolygonMode::Point => panic!(
"{:?} is not enabled for this backend",
wgt::Features::POLYGON_MODE_POINT
),
};
let (primitive_class, raw_primitive_type) =
conv::map_primitive_topology(desc.primitive.topology);
let vs = self.load_shader(
&desc.vertex_stage,
desc.layout,
primitive_class,
naga::ShaderStage::Vertex,
)?;
descriptor.set_vertex_function(Some(&vs.function));
if self.shared.private_caps.supports_mutability {
Self::set_buffers_mutability(
descriptor.vertex_buffers().unwrap(),
vs.immutable_buffer_mask,
);
}
// Fragment shader
let (fs_lib, fs_sized_bindings) = match desc.fragment_stage {
Some(ref stage) => {
let fs = self.load_shader(
stage,
desc.layout,
primitive_class,
naga::ShaderStage::Fragment,
)?;
descriptor.set_fragment_function(Some(&fs.function));
if self.shared.private_caps.supports_mutability {
Self::set_buffers_mutability(
descriptor.fragment_buffers().unwrap(),
fs.immutable_buffer_mask,
);
}
(Some(fs.library), fs.sized_bindings)
}
None => {
// TODO: This is a workaround for what appears to be a Metal validation bug
// A pixel format is required even though no attachments are provided
if desc.color_targets.is_empty() && desc.depth_stencil.is_none() {
descriptor.set_depth_attachment_pixel_format(mtl::MTLPixelFormat::Depth32Float);
}
(None, Vec::new())
}
};
for (i, ct) in desc.color_targets.iter().enumerate() {
let at_descriptor = descriptor.color_attachments().object_at(i as u64).unwrap();
let ct = if let Some(color_target) = ct.as_ref() {
color_target
} else {
at_descriptor.set_pixel_format(mtl::MTLPixelFormat::Invalid);
continue;
let raw_triangle_fill_mode = match desc.primitive.polygon_mode {
wgt::PolygonMode::Fill => mtl::MTLTriangleFillMode::Fill,
wgt::PolygonMode::Line => mtl::MTLTriangleFillMode::Lines,
wgt::PolygonMode::Point => panic!(
"{:?} is not enabled for this backend",
wgt::Features::POLYGON_MODE_POINT
),
};
let raw_format = self.shared.private_caps.map_format(ct.format);
at_descriptor.set_pixel_format(raw_format);
at_descriptor.set_write_mask(conv::map_color_write(ct.write_mask));
let (primitive_class, raw_primitive_type) =
conv::map_primitive_topology(desc.primitive.topology);
if let Some(ref blend) = ct.blend {
at_descriptor.set_blending_enabled(true);
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);
let vs = self.load_shader(
&desc.vertex_stage,
desc.layout,
primitive_class,
naga::ShaderStage::Vertex,
)?;
at_descriptor.set_rgb_blend_operation(color_op);
at_descriptor.set_source_rgb_blend_factor(color_src);
at_descriptor.set_destination_rgb_blend_factor(color_dst);
at_descriptor.set_alpha_blend_operation(alpha_op);
at_descriptor.set_source_alpha_blend_factor(alpha_src);
at_descriptor.set_destination_alpha_blend_factor(alpha_dst);
descriptor.set_vertex_function(Some(&vs.function));
if self.shared.private_caps.supports_mutability {
Self::set_buffers_mutability(
descriptor.vertex_buffers().unwrap(),
vs.immutable_buffer_mask,
);
}
}
let depth_stencil = match desc.depth_stencil {
Some(ref ds) => {
let raw_format = self.shared.private_caps.map_format(ds.format);
let aspects = crate::FormatAspects::from(ds.format);
if aspects.contains(crate::FormatAspects::DEPTH) {
descriptor.set_depth_attachment_pixel_format(raw_format);
// Fragment shader
let (fs_lib, fs_sized_bindings) = match desc.fragment_stage {
Some(ref stage) => {
let fs = self.load_shader(
stage,
desc.layout,
primitive_class,
naga::ShaderStage::Fragment,
)?;
descriptor.set_fragment_function(Some(&fs.function));
if self.shared.private_caps.supports_mutability {
Self::set_buffers_mutability(
descriptor.fragment_buffers().unwrap(),
fs.immutable_buffer_mask,
);
}
(Some(fs.library), fs.sized_bindings)
}
if aspects.contains(crate::FormatAspects::STENCIL) {
descriptor.set_stencil_attachment_pixel_format(raw_format);
None => {
// TODO: This is a workaround for what appears to be a Metal validation bug
// A pixel format is required even though no attachments are provided
if desc.color_targets.is_empty() && desc.depth_stencil.is_none() {
descriptor
.set_depth_attachment_pixel_format(mtl::MTLPixelFormat::Depth32Float);
}
(None, Vec::new())
}
};
let ds_descriptor = create_depth_stencil_desc(ds);
let raw = self
.shared
.device
.lock()
.new_depth_stencil_state(&ds_descriptor);
Some((raw, ds.bias))
}
None => None,
};
if desc.layout.total_counters.vs.buffers + (desc.vertex_buffers.len() as u32)
> self.shared.private_caps.max_vertex_buffers
{
let msg = format!(
"pipeline needs too many buffers in the vertex stage: {} vertex and {} layout",
desc.vertex_buffers.len(),
desc.layout.total_counters.vs.buffers
);
return Err(crate::PipelineError::Linkage(
wgt::ShaderStages::VERTEX,
msg,
));
}
if !desc.vertex_buffers.is_empty() {
let vertex_descriptor = mtl::VertexDescriptor::new();
for (i, vb) in desc.vertex_buffers.iter().enumerate() {
let buffer_index =
self.shared.private_caps.max_vertex_buffers as u64 - 1 - i as u64;
let buffer_desc = vertex_descriptor.layouts().object_at(buffer_index).unwrap();
buffer_desc.set_stride(vb.array_stride);
buffer_desc.set_step_function(conv::map_step_mode(vb.step_mode));
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);
}
}
descriptor.set_vertex_descriptor(Some(vertex_descriptor));
}
if desc.multisample.count != 1 {
//TODO: handle sample mask
descriptor.set_sample_count(desc.multisample.count as u64);
descriptor.set_alpha_to_coverage_enabled(desc.multisample.alpha_to_coverage_enabled);
//descriptor.set_alpha_to_one_enabled(desc.multisample.alpha_to_one_enabled);
}
if let Some(name) = desc.label {
descriptor.set_label(name);
}
let raw = self
.shared
.device
.lock()
.new_render_pipeline_state(&descriptor)
.map_err(|e| {
crate::PipelineError::Linkage(
wgt::ShaderStages::VERTEX | wgt::ShaderStages::FRAGMENT,
format!("new_render_pipeline_state: {:?}", e),
)
})?;
Ok(super::RenderPipeline {
raw,
vs_lib: vs.library,
fs_lib,
vs_info: super::PipelineStageInfo {
push_constants: desc.layout.push_constants_infos.vs,
sizes_slot: desc.layout.naga_options.per_stage_map.vs.sizes_buffer,
sized_bindings: vs.sized_bindings,
},
fs_info: super::PipelineStageInfo {
push_constants: desc.layout.push_constants_infos.fs,
sizes_slot: desc.layout.naga_options.per_stage_map.fs.sizes_buffer,
sized_bindings: fs_sized_bindings,
},
raw_primitive_type,
raw_triangle_fill_mode,
raw_front_winding: conv::map_winding(desc.primitive.front_face),
raw_cull_mode: conv::map_cull_mode(desc.primitive.cull_mode),
raw_depth_clip_mode: if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
Some(if desc.primitive.unclipped_depth {
mtl::MTLDepthClipMode::Clamp
for (i, ct) in desc.color_targets.iter().enumerate() {
let at_descriptor = descriptor.color_attachments().object_at(i as u64).unwrap();
let ct = if let Some(color_target) = ct.as_ref() {
color_target
} else {
mtl::MTLDepthClipMode::Clip
})
} else {
None
},
depth_stencil,
at_descriptor.set_pixel_format(mtl::MTLPixelFormat::Invalid);
continue;
};
let raw_format = self.shared.private_caps.map_format(ct.format);
at_descriptor.set_pixel_format(raw_format);
at_descriptor.set_write_mask(conv::map_color_write(ct.write_mask));
if let Some(ref blend) = ct.blend {
at_descriptor.set_blending_enabled(true);
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);
at_descriptor.set_rgb_blend_operation(color_op);
at_descriptor.set_source_rgb_blend_factor(color_src);
at_descriptor.set_destination_rgb_blend_factor(color_dst);
at_descriptor.set_alpha_blend_operation(alpha_op);
at_descriptor.set_source_alpha_blend_factor(alpha_src);
at_descriptor.set_destination_alpha_blend_factor(alpha_dst);
}
}
let depth_stencil = match desc.depth_stencil {
Some(ref ds) => {
let raw_format = self.shared.private_caps.map_format(ds.format);
let aspects = crate::FormatAspects::from(ds.format);
if aspects.contains(crate::FormatAspects::DEPTH) {
descriptor.set_depth_attachment_pixel_format(raw_format);
}
if aspects.contains(crate::FormatAspects::STENCIL) {
descriptor.set_stencil_attachment_pixel_format(raw_format);
}
let ds_descriptor = create_depth_stencil_desc(ds);
let raw = self
.shared
.device
.lock()
.new_depth_stencil_state(&ds_descriptor);
Some((raw, ds.bias))
}
None => None,
};
if desc.layout.total_counters.vs.buffers + (desc.vertex_buffers.len() as u32)
> self.shared.private_caps.max_vertex_buffers
{
let msg = format!(
"pipeline needs too many buffers in the vertex stage: {} vertex and {} layout",
desc.vertex_buffers.len(),
desc.layout.total_counters.vs.buffers
);
return Err(crate::PipelineError::Linkage(
wgt::ShaderStages::VERTEX,
msg,
));
}
if !desc.vertex_buffers.is_empty() {
let vertex_descriptor = mtl::VertexDescriptor::new();
for (i, vb) in desc.vertex_buffers.iter().enumerate() {
let buffer_index =
self.shared.private_caps.max_vertex_buffers as u64 - 1 - i as u64;
let buffer_desc = vertex_descriptor.layouts().object_at(buffer_index).unwrap();
buffer_desc.set_stride(vb.array_stride);
buffer_desc.set_step_function(conv::map_step_mode(vb.step_mode));
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);
}
}
descriptor.set_vertex_descriptor(Some(vertex_descriptor));
}
if desc.multisample.count != 1 {
//TODO: handle sample mask
descriptor.set_sample_count(desc.multisample.count as u64);
descriptor
.set_alpha_to_coverage_enabled(desc.multisample.alpha_to_coverage_enabled);
//descriptor.set_alpha_to_one_enabled(desc.multisample.alpha_to_one_enabled);
}
if let Some(name) = desc.label {
descriptor.set_label(name);
}
let raw = self
.shared
.device
.lock()
.new_render_pipeline_state(&descriptor)
.map_err(|e| {
crate::PipelineError::Linkage(
wgt::ShaderStages::VERTEX | wgt::ShaderStages::FRAGMENT,
format!("new_render_pipeline_state: {:?}", e),
)
})?;
Ok(super::RenderPipeline {
raw,
vs_lib: vs.library,
fs_lib,
vs_info: super::PipelineStageInfo {
push_constants: desc.layout.push_constants_infos.vs,
sizes_slot: desc.layout.naga_options.per_stage_map.vs.sizes_buffer,
sized_bindings: vs.sized_bindings,
},
fs_info: super::PipelineStageInfo {
push_constants: desc.layout.push_constants_infos.fs,
sizes_slot: desc.layout.naga_options.per_stage_map.fs.sizes_buffer,
sized_bindings: fs_sized_bindings,
},
raw_primitive_type,
raw_triangle_fill_mode,
raw_front_winding: conv::map_winding(desc.primitive.front_face),
raw_cull_mode: conv::map_cull_mode(desc.primitive.cull_mode),
raw_depth_clip_mode: if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) {
Some(if desc.primitive.unclipped_depth {
mtl::MTLDepthClipMode::Clamp
} else {
mtl::MTLDepthClipMode::Clip
})
} else {
None
},
depth_stencil,
})
})
}
unsafe fn destroy_render_pipeline(&self, _pipeline: super::RenderPipeline) {}
@@ -987,46 +997,51 @@ impl crate::Device<super::Api> for super::Device {
&self,
desc: &crate::ComputePipelineDescriptor<super::Api>,
) -> Result<super::ComputePipeline, crate::PipelineError> {
let descriptor = mtl::ComputePipelineDescriptor::new();
objc::rc::autoreleasepool(|| {
let descriptor = mtl::ComputePipelineDescriptor::new();
let cs = self.load_shader(
&desc.stage,
desc.layout,
mtl::MTLPrimitiveTopologyClass::Unspecified,
naga::ShaderStage::Compute,
)?;
descriptor.set_compute_function(Some(&cs.function));
let cs = self.load_shader(
&desc.stage,
desc.layout,
mtl::MTLPrimitiveTopologyClass::Unspecified,
naga::ShaderStage::Compute,
)?;
descriptor.set_compute_function(Some(&cs.function));
if self.shared.private_caps.supports_mutability {
Self::set_buffers_mutability(descriptor.buffers().unwrap(), cs.immutable_buffer_mask);
}
if self.shared.private_caps.supports_mutability {
Self::set_buffers_mutability(
descriptor.buffers().unwrap(),
cs.immutable_buffer_mask,
);
}
if let Some(name) = desc.label {
descriptor.set_label(name);
}
if let Some(name) = desc.label {
descriptor.set_label(name);
}
let raw = self
.shared
.device
.lock()
.new_compute_pipeline_state(&descriptor)
.map_err(|e| {
crate::PipelineError::Linkage(
wgt::ShaderStages::COMPUTE,
format!("new_compute_pipeline_state: {:?}", e),
)
})?;
let raw = self
.shared
.device
.lock()
.new_compute_pipeline_state(&descriptor)
.map_err(|e| {
crate::PipelineError::Linkage(
wgt::ShaderStages::COMPUTE,
format!("new_compute_pipeline_state: {:?}", e),
)
})?;
Ok(super::ComputePipeline {
raw,
cs_info: super::PipelineStageInfo {
push_constants: desc.layout.push_constants_infos.cs,
sizes_slot: desc.layout.naga_options.per_stage_map.cs.sizes_buffer,
sized_bindings: cs.sized_bindings,
},
cs_lib: cs.library,
work_group_size: cs.wg_size,
work_group_memory_sizes: cs.wg_memory_sizes,
Ok(super::ComputePipeline {
raw,
cs_info: super::PipelineStageInfo {
push_constants: desc.layout.push_constants_infos.cs,
sizes_slot: desc.layout.naga_options.per_stage_map.cs.sizes_buffer,
sized_bindings: cs.sized_bindings,
},
cs_lib: cs.library,
work_group_size: cs.wg_size,
work_group_memory_sizes: cs.wg_memory_sizes,
})
})
}
unsafe fn destroy_compute_pipeline(&self, _pipeline: super::ComputePipeline) {}
@@ -1035,24 +1050,26 @@ impl crate::Device<super::Api> for super::Device {
&self,
desc: &wgt::QuerySetDescriptor<crate::Label>,
) -> DeviceResult<super::QuerySet> {
match desc.ty {
wgt::QueryType::Occlusion => {
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);
if let Some(label) = desc.label {
raw_buffer.set_label(label);
objc::rc::autoreleasepool(|| {
match desc.ty {
wgt::QueryType::Occlusion => {
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);
if let Some(label) = desc.label {
raw_buffer.set_label(label);
}
Ok(super::QuerySet {
raw_buffer,
ty: desc.ty,
})
}
wgt::QueryType::Timestamp | wgt::QueryType::PipelineStatistics(_) => {
Err(crate::DeviceError::OutOfMemory)
}
Ok(super::QuerySet {
raw_buffer,
ty: desc.ty,
})
}
wgt::QueryType::Timestamp | wgt::QueryType::PipelineStatistics(_) => {
Err(crate::DeviceError::OutOfMemory)
}
}
})
}
unsafe fn destroy_query_set(&self, _set: super::QuerySet) {}