Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for object and mesh shader #264

Merged
merged 2 commits into from
Apr 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions examples/mesh-shader/main.rs
Original file line number Diff line number Diff line change
@@ -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();
}
_ => {}
}
});
});
}
30 changes: 30 additions & 0 deletions examples/mesh-shader/shaders.metal
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <metal_stdlib>

using namespace metal;

struct VertexOut {
float4 position [[position]];
};

using mesh_t = mesh<VertexOut, void, 3, 1, topology::triangle>;

[[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);
}
Binary file added examples/mesh-shader/shaders.metallib
Binary file not shown.
39 changes: 39 additions & 0 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1899,6 +1899,45 @@ impl DeviceRef {
}
}

/// Only available on (macos(13.0), ios(16.0))
pub fn new_mesh_render_pipeline_state_with_reflection(
&self,
descriptor: &MeshRenderPipelineDescriptorRef,
reflection_options: MTLPipelineOption,
) -> 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<RenderPipelineState, String> {
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,
Expand Down
Loading