From 50fc105712f985690c9041d00646eacb59c1b743 Mon Sep 17 00:00:00 2001 From: Marlon Date: Sat, 1 Apr 2023 07:48:07 +0200 Subject: [PATCH] Add support for object and mesh shader (#264) * Add support for object and mesh shader * Remove unnecessary unsafe block --- examples/mesh-shader/main.rs | 118 ++++++++++ examples/mesh-shader/shaders.metal | 30 +++ examples/mesh-shader/shaders.metallib | Bin 0 -> 6314 bytes src/device.rs | 39 ++++ src/encoder.rs | 322 ++++++++++++++++++++++++++ src/pipeline/render.rs | 262 +++++++++++++++++++++ 6 files changed, 771 insertions(+) create mode 100644 examples/mesh-shader/main.rs create mode 100644 examples/mesh-shader/shaders.metal create mode 100644 examples/mesh-shader/shaders.metallib diff --git a/examples/mesh-shader/main.rs b/examples/mesh-shader/main.rs new file mode 100644 index 0000000..8edb30c --- /dev/null +++ b/examples/mesh-shader/main.rs @@ -0,0 +1,118 @@ +extern crate objc; + +use cocoa::{appkit::NSView, base::id as cocoa_id}; +use core_graphics_types::geometry::CGSize; + +use metal::*; +use objc::{rc::autoreleasepool, runtime::YES}; +use std::mem; +use winit::platform::macos::WindowExtMacOS; + +use winit::{ + event::{Event, WindowEvent}, + event_loop::ControlFlow, +}; + +fn prepare_render_pass_descriptor(descriptor: &RenderPassDescriptorRef, texture: &TextureRef) { + let color_attachment = descriptor.color_attachments().object_at(0).unwrap(); + + color_attachment.set_texture(Some(texture)); + color_attachment.set_load_action(MTLLoadAction::Clear); + color_attachment.set_clear_color(MTLClearColor::new(0.2, 0.2, 0.25, 1.0)); + color_attachment.set_store_action(MTLStoreAction::Store); +} + +fn main() { + let events_loop = winit::event_loop::EventLoop::new(); + let size = winit::dpi::LogicalSize::new(800, 600); + + let window = winit::window::WindowBuilder::new() + .with_inner_size(size) + .with_title("Metal Mesh Shader Example".to_string()) + .build(&events_loop) + .unwrap(); + + let device = Device::system_default().expect("no device found"); + + let layer = MetalLayer::new(); + layer.set_device(&device); + layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm); + layer.set_presents_with_transaction(false); + + unsafe { + let view = window.ns_view() as cocoa_id; + view.setWantsLayer(YES); + view.setLayer(mem::transmute(layer.as_ref())); + } + + let draw_size = window.inner_size(); + layer.set_drawable_size(CGSize::new(draw_size.width as f64, draw_size.height as f64)); + + let library_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("examples/mesh-shader/shaders.metallib"); + let library = device.new_library_with_file(library_path).unwrap(); + + let mesh = library.get_function("mesh_function", None).unwrap(); + let frag = library.get_function("fragment_function", None).unwrap(); + + let pipeline_state_desc = MeshRenderPipelineDescriptor::new(); + pipeline_state_desc + .color_attachments() + .object_at(0) + .unwrap() + .set_pixel_format(MTLPixelFormat::BGRA8Unorm); + pipeline_state_desc.set_mesh_function(Some(&mesh)); + pipeline_state_desc.set_fragment_function(Some(&frag)); + + let pipeline_state = device + .new_mesh_render_pipeline_state(&pipeline_state_desc) + .unwrap(); + + let command_queue = device.new_command_queue(); + + events_loop.run(move |event, _, control_flow| { + autoreleasepool(|| { + *control_flow = ControlFlow::Poll; + + match event { + Event::WindowEvent { event, .. } => match event { + WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, + WindowEvent::Resized(size) => { + layer.set_drawable_size(CGSize::new(size.width as f64, size.height as f64)); + } + _ => (), + }, + Event::MainEventsCleared => { + window.request_redraw(); + } + Event::RedrawRequested(_) => { + let drawable = match layer.next_drawable() { + Some(drawable) => drawable, + None => return, + }; + + let render_pass_descriptor = RenderPassDescriptor::new(); + + prepare_render_pass_descriptor(&render_pass_descriptor, drawable.texture()); + + let command_buffer = command_queue.new_command_buffer(); + let encoder = + command_buffer.new_render_command_encoder(&render_pass_descriptor); + + encoder.set_render_pipeline_state(&pipeline_state); + encoder.draw_mesh_threads( + MTLSize::new(1, 1, 1), + MTLSize::new(1, 1, 1), + MTLSize::new(1, 1, 1), + ); + + encoder.end_encoding(); + + command_buffer.present_drawable(&drawable); + command_buffer.commit(); + } + _ => {} + } + }); + }); +} diff --git a/examples/mesh-shader/shaders.metal b/examples/mesh-shader/shaders.metal new file mode 100644 index 0000000..1a82530 --- /dev/null +++ b/examples/mesh-shader/shaders.metal @@ -0,0 +1,30 @@ +#include + +using namespace metal; + +struct VertexOut { + float4 position [[position]]; +}; + +using mesh_t = mesh; + +[[mesh]] void mesh_function(mesh_t m) { + VertexOut v; + v.position = float4(-1.0, -1.0, 0.0, 1.0); + + m.set_primitive_count(1); + + m.set_vertex(0, v); + v.position = float4(0.0, 1.0, 0.0, 1.0); + m.set_vertex(1, v); + v.position = float4(1.0, -1.0, 0.0, 1.0); + m.set_vertex(2, v); + + m.set_index(0, 0); + m.set_index(1, 1); + m.set_index(2, 2); +} + +fragment half4 fragment_function() { + return half4(0.1, 1.0, 0.1, 1.0); +} \ No newline at end of file diff --git a/examples/mesh-shader/shaders.metallib b/examples/mesh-shader/shaders.metallib new file mode 100644 index 0000000000000000000000000000000000000000..4af8d60ddcf200aae627bc160c81bf9ee1c10a2f GIT binary patch literal 6314 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 Result<(RenderPipelineState, RenderPipelineReflection), String> { + unsafe { + let mut reflection: *mut Object = ptr::null_mut(); + let pipeline_state: *mut MTLRenderPipelineState = try_objc! { err => + msg_send![self, newRenderPipelineStateWithMeshDescriptor:descriptor + options:reflection_options + reflection:&mut reflection + error:&mut err] + }; + + let state = RenderPipelineState::from_ptr(pipeline_state); + + let () = msg_send![reflection, retain]; + let reflection = RenderPipelineReflection::from_ptr(reflection as _); + + Ok((state, reflection)) + } + } + + /// Only available on (macos(13.0), ios(16.0)) + pub fn new_mesh_render_pipeline_state( + &self, + descriptor: &MeshRenderPipelineDescriptorRef, + ) -> Result { + unsafe { + let pipeline_state: *mut MTLRenderPipelineState = try_objc! { err => + msg_send![self, newRenderPipelineStateWithMeshDescriptor:descriptor + error:&mut err] + }; + + Ok(RenderPipelineState::from_ptr(pipeline_state)) + } + } + pub fn new_compute_pipeline_state_with_function( &self, function: &FunctionRef, diff --git a/src/encoder.rs b/src/encoder.rs index 0616d2c..09e5e6e 100644 --- a/src/encoder.rs +++ b/src/encoder.rs @@ -440,6 +440,278 @@ impl RenderCommandEncoderRef { } } + // Specifying Resources for a Object Shader Function + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_object_buffer( + &self, + index: NSUInteger, + buffer: Option<&BufferRef>, + offset: NSUInteger, + ) { + unsafe { + msg_send![self, + setObjectBuffer:buffer + offset:offset + atIndex:index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_object_buffer_offset(&self, index: NSUInteger, offset: NSUInteger) { + unsafe { + msg_send![self, + setObjectBufferOffset:offset + atIndex:index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_object_bytes( + &self, + index: NSUInteger, + length: NSUInteger, + bytes: *const std::ffi::c_void, + ) { + unsafe { + msg_send![self, + setObjectBytes:bytes + length:length + atIndex:index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_object_sampler_state(&self, index: NSUInteger, sampler: Option<&SamplerStateRef>) { + unsafe { + msg_send![self, + setObjectSamplerState:sampler + atIndex:index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_object_sampler_state_with_lod( + &self, + index: NSUInteger, + sampler: Option<&SamplerStateRef>, + lod_clamp: Range, + ) { + unsafe { + msg_send![self, + setObjectSamplerState:sampler + lodMinClamp:lod_clamp.start + lodMaxClamp:lod_clamp.end + atIndex:index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_object_texture(&self, index: NSUInteger, texture: Option<&TextureRef>) { + unsafe { + msg_send![self, + setObjectTexture:texture + atIndex:index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_object_threadgroup_memory_length(&self, index: NSUInteger, length: NSUInteger) { + unsafe { + msg_send![self, + setObjectThreadgroupMemoryLength: length + atIndex: index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_object_buffers( + &self, + start_index: NSUInteger, + data: &[Option<&BufferRef>], + offsets: &[NSUInteger], + ) { + debug_assert_eq!(offsets.len(), data.len()); + unsafe { + msg_send![self, + setObjectBuffers: data.as_ptr() + offsets: offsets.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_object_sampler_states( + &self, + start_index: NSUInteger, + data: &[Option<&SamplerStateRef>], + ) { + unsafe { + msg_send![self, + setObjectSamplerStates: data.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_object_textures(&self, start_index: NSUInteger, data: &[Option<&TextureRef>]) { + unsafe { + msg_send![self, + setObjectTextures: data.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + // Specifying Resources for a Mesh Shader + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_mesh_buffer( + &self, + index: NSUInteger, + buffer: Option<&BufferRef>, + offset: NSUInteger, + ) { + unsafe { + msg_send![self, + setMeshBuffer:buffer + offset:offset + atIndex:index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_mesh_buffer_offset(&self, index: NSUInteger, offset: NSUInteger) { + unsafe { + msg_send![self, + setMeshBufferOffset:offset + atIndex:index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_mesh_bytes( + &self, + index: NSUInteger, + length: NSUInteger, + bytes: *const std::ffi::c_void, + ) { + unsafe { + msg_send![self, + setMeshBytes:bytes + length:length + atIndex:index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_mesh_sampler_state(&self, index: NSUInteger, sampler: Option<&SamplerStateRef>) { + unsafe { + msg_send![self, + setMeshSamplerState:sampler + atIndex:index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_mesh_sampler_state_with_lod( + &self, + index: NSUInteger, + sampler: Option<&SamplerStateRef>, + lod_clamp: Range, + ) { + unsafe { + msg_send![self, + setMeshSamplerState:sampler + lodMinClamp:lod_clamp.start + lodMaxClamp:lod_clamp.end + atIndex:index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_mesh_texture(&self, index: NSUInteger, texture: Option<&TextureRef>) { + unsafe { + msg_send![self, + setMeshTexture:texture + atIndex:index + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_mesh_buffers( + &self, + start_index: NSUInteger, + data: &[Option<&BufferRef>], + offsets: &[NSUInteger], + ) { + debug_assert_eq!(offsets.len(), data.len()); + unsafe { + msg_send![self, + setMeshBuffers: data.as_ptr() + offsets: offsets.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_mesh_sampler_states( + &self, + start_index: NSUInteger, + data: &[Option<&SamplerStateRef>], + ) { + unsafe { + msg_send![self, + setMeshSamplerStates: data.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn set_mesh_textures(&self, start_index: NSUInteger, data: &[Option<&TextureRef>]) { + unsafe { + msg_send![self, + setMeshTextures: data.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + // Specifying Resources for a Fragment Shader Function pub fn set_fragment_bytes( @@ -749,6 +1021,56 @@ impl RenderCommandEncoderRef { // fn setVertexBuffers_offsets_withRange(self, buffers: *const id, offsets: *const NSUInteger, range: NSRange); // fn setVertexSamplerStates_lodMinClamps_lodMaxClamps_withRange(self, samplers: *const id, lodMinClamps: *const f32, lodMaxClamps: *const f32, range: NSRange); + /// Only available in (macos(13.0), ios(16.0)) + pub fn draw_mesh_threadgroups( + &self, + threadgroups_per_grid: MTLSize, + threads_per_object_threadgroup: MTLSize, + threads_per_mesh_threadgroup: MTLSize, + ) { + unsafe { + msg_send![self, + drawMeshThreadgroups: threadgroups_per_grid + threadsPerObjectThreadgroup: threads_per_object_threadgroup + threadsPerMeshThreadgroup: threads_per_mesh_threadgroup + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn draw_mesh_threadgroups_with_indirect_buffer( + &self, + indirect_buffer: &BufferRef, + indirect_buffer_offset: NSUInteger, + threads_per_object_threadgroup: MTLSize, + threads_per_mesh_threadgroup: MTLSize, + ) { + unsafe { + msg_send![self, + drawMeshThreadgroupsWithIndirectBuffer: indirect_buffer + indirectBufferOffset: indirect_buffer_offset + threadsPerObjectThreadgroup: threads_per_object_threadgroup + threadsPerMeshThreadgroup: threads_per_mesh_threadgroup + ] + } + } + + /// Only available in (macos(13.0), ios(16.0)) + pub fn draw_mesh_threads( + &self, + threads_per_grid: MTLSize, + threads_per_object_threadgroup: MTLSize, + threads_per_mesh_threadgroup: MTLSize, + ) { + unsafe { + msg_send![self, + drawMeshThreads: threads_per_grid + threadsPerObjectThreadgroup: threads_per_object_threadgroup + threadsPerMeshThreadgroup: threads_per_mesh_threadgroup + ] + } + } + /// Adds an untracked resource to the render pass. /// /// Availability: iOS 11.0+, macOS 10.13+ diff --git a/src/pipeline/render.rs b/src/pipeline/render.rs index b6ecdd5..6731c15 100644 --- a/src/pipeline/render.rs +++ b/src/pipeline/render.rs @@ -246,6 +246,268 @@ impl ComputePipelineReflectionRef { } } +/// See +/// Only available in (macos(13.0), ios(16.0)) +pub enum MTLMeshRenderPipelineDescriptor {} + +foreign_obj_type! { + type CType = MTLMeshRenderPipelineDescriptor; + pub struct MeshRenderPipelineDescriptor; +} + +impl MeshRenderPipelineDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLMeshRenderPipelineDescriptor); + msg_send![class, new] + } + } +} + +impl MeshRenderPipelineDescriptorRef { + pub fn color_attachments(&self) -> &RenderPipelineColorAttachmentDescriptorArrayRef { + unsafe { msg_send![self, colorAttachments] } + } + + pub fn depth_attachment_pixel_format(&self) -> MTLPixelFormat { + unsafe { msg_send![self, depthAttachmentPixelFormat] } + } + + pub fn set_depth_attachment_pixel_format(&self, pixel_format: MTLPixelFormat) { + unsafe { msg_send![self, setDepthAttachmentPixelFormat: pixel_format] } + } + + pub fn fragment_buffers(&self) -> Option<&PipelineBufferDescriptorArrayRef> { + unsafe { msg_send![self, fragmentBuffers] } + } + + pub fn fragment_function(&self) -> Option<&FunctionRef> { + unsafe { msg_send![self, fragmentFunction] } + } + + pub fn set_fragment_function(&self, function: Option<&FunctionRef>) { + unsafe { msg_send![self, setFragmentFunction: function] } + } + + pub fn is_alpha_to_coverage_enabled(&self) -> bool { + unsafe { + match msg_send![self, isAlphaToCoverageEnabled] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_alpha_to_coverage_enabled(&self, enabled: bool) { + unsafe { msg_send![self, setAlphaToCoverageEnabled: enabled] } + } + + pub fn is_alpha_to_one_enabled(&self) -> bool { + unsafe { + match msg_send![self, isAlphaToOneEnabled] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_alpha_to_one_enabled(&self, enabled: bool) { + unsafe { msg_send![self, setAlphaToOneEnabled: enabled] } + } + + pub fn is_rasterization_enabled(&self) -> bool { + unsafe { + match msg_send![self, isRasterizationEnabled] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_rasterization_enabled(&self, enabled: bool) { + unsafe { msg_send![self, setRasterizationEnabled: enabled] } + } + + pub fn label(&self) -> &str { + unsafe { + let label = msg_send![self, label]; + crate::nsstring_as_str(label) + } + } + + pub fn set_label(&self, label: &str) { + unsafe { + let nslabel = crate::nsstring_from_str(label); + let () = msg_send![self, setLabel: nslabel]; + } + } + + pub fn max_total_threadgroups_per_mesh_grid(&self) -> NSUInteger { + unsafe { msg_send![self, maxTotalThreadgroupsPerMeshGrid] } + } + + pub fn set_max_total_threadgroups_per_mesh_grid( + &self, + max_total_threadgroups_per_mesh_grid: NSUInteger, + ) { + unsafe { + msg_send![ + self, + setMaxTotalThreadgroupsPerMeshGrid: max_total_threadgroups_per_mesh_grid + ] + } + } + + pub fn max_total_threads_per_mesh_threadgroup(&self) -> NSUInteger { + unsafe { msg_send![self, maxTotalThreadsPerMeshThreadgroup] } + } + + pub fn set_max_total_threads_per_mesh_threadgroup( + &self, + max_total_threads_per_mesh_threadgroup: NSUInteger, + ) { + unsafe { + msg_send![ + self, + setMaxTotalThreadsPerMeshThreadgroup: max_total_threads_per_mesh_threadgroup + ] + } + } + + pub fn max_total_threads_per_object_threadgroup(&self) -> NSUInteger { + unsafe { msg_send![self, maxTotalThreadsPerObjectThreadgroup] } + } + + pub fn set_max_total_threads_per_object_threadgroup( + &self, + max_total_threads_per_object_threadgroup: NSUInteger, + ) { + unsafe { + msg_send![ + self, + setMaxTotalThreadsPerObjectThreadgroup: max_total_threads_per_object_threadgroup + ] + } + } + + pub fn max_vertex_amplification_count(&self) -> NSUInteger { + unsafe { msg_send![self, maxVertexAmplificationCount] } + } + + pub fn set_max_vertex_amplification_count(&self, max_vertex_amplification_count: NSUInteger) { + unsafe { + msg_send![ + self, + setMaxVertexAmplificationCount: max_vertex_amplification_count + ] + } + } + + pub fn mesh_buffers(&self) -> Option<&PipelineBufferDescriptorArrayRef> { + unsafe { msg_send![self, meshBuffers] } + } + + pub fn mesh_function(&self) -> Option<&FunctionRef> { + unsafe { msg_send![self, meshFunction] } + } + + pub fn set_mesh_function(&self, function: Option<&FunctionRef>) { + unsafe { msg_send![self, setMeshFunction: function] } + } + + pub fn mesh_threadgroup_size_is_multiple_of_thread_execution_width(&self) -> bool { + unsafe { + match msg_send![self, isMeshThreadgroupSizeIsMultipleOfThreadExecutionWidth] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_mesh_threadgroup_size_is_multiple_of_thread_execution_width( + &self, + mesh_threadgroup_size_is_multiple_of_thread_execution_width: bool, + ) { + unsafe { + msg_send![ + self, + setMeshThreadgroupSizeIsMultipleOfThreadExecutionWidth: + mesh_threadgroup_size_is_multiple_of_thread_execution_width + ] + } + } + + pub fn object_buffers(&self) -> Option<&PipelineBufferDescriptorArrayRef> { + unsafe { msg_send![self, objectBuffers] } + } + + pub fn object_function(&self) -> Option<&FunctionRef> { + unsafe { msg_send![self, objectFunction] } + } + + pub fn set_object_function(&self, function: Option<&FunctionRef>) { + unsafe { msg_send![self, setObjectFunction: function] } + } + + pub fn object_threadgroup_size_is_multiple_of_thread_execution_width(&self) -> bool { + unsafe { + match msg_send![ + self, + isObjectThreadgroupSizeIsMultipleOfThreadExecutionWidth + ] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_object_threadgroup_size_is_multiple_of_thread_execution_width( + &self, + object_threadgroup_size_is_multiple_of_thread_execution_width: bool, + ) { + unsafe { + msg_send![ + self, + setObjectThreadgroupSizeIsMultipleOfThreadExecutionWidth: + object_threadgroup_size_is_multiple_of_thread_execution_width + ] + } + } + + pub fn payload_memory_length(&self) -> NSUInteger { + unsafe { msg_send![self, payloadMemoryLength] } + } + + pub fn set_payload_memory_length(&self, payload_memory_length: NSUInteger) { + unsafe { msg_send![self, setPayloadMemoryLength: payload_memory_length] } + } + + pub fn raster_sample_count(&self) -> NSUInteger { + unsafe { msg_send![self, rasterSampleCount] } + } + + pub fn set_raster_sample_count(&self, raster_sample_count: NSUInteger) { + unsafe { msg_send![self, setRasterSampleCount: raster_sample_count] } + } + + pub fn stencil_attachment_pixel_format(&self) -> MTLPixelFormat { + unsafe { msg_send![self, stencilAttachmentPixelFormat] } + } + + pub fn set_stencil_attachment_pixel_format(&self, pixel_format: MTLPixelFormat) { + unsafe { msg_send![self, setStencilAttachmentPixelFormat: pixel_format] } + } + + pub fn reset(&self) { + unsafe { msg_send![self, reset] } + } +} + /// See pub enum MTLRenderPipelineDescriptor {}