mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Fix memory leak on macOS (#3056)
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user