diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/rust/metal/examples/window/README.md | 11 | ||||
-rw-r--r-- | third_party/rust/metal/examples/window/main.rs | 261 | ||||
-rw-r--r-- | third_party/rust/metal/examples/window/screenshot.png | bin | 0 -> 55104 bytes | |||
-rw-r--r-- | third_party/rust/metal/examples/window/shaders.metal | 97 | ||||
-rw-r--r-- | third_party/rust/metal/examples/window/shaders.metallib | bin | 0 -> 12332 bytes |
5 files changed, 369 insertions, 0 deletions
diff --git a/third_party/rust/metal/examples/window/README.md b/third_party/rust/metal/examples/window/README.md new file mode 100644 index 0000000000..62233be356 --- /dev/null +++ b/third_party/rust/metal/examples/window/README.md @@ -0,0 +1,11 @@ +## window + +Renders a spinning triangle to a [winit](https://github.com/rust-windowing/winit) window. + +![Screenshot of the final render](./screenshot.png) + +## To Run + +``` +cargo run --example window +``` diff --git a/third_party/rust/metal/examples/window/main.rs b/third_party/rust/metal/examples/window/main.rs new file mode 100644 index 0000000000..08936e82fc --- /dev/null +++ b/third_party/rust/metal/examples/window/main.rs @@ -0,0 +1,261 @@ +// Copyright 2016 metal-rs developers +// +// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or +// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or +// http://opensource.org/licenses/MIT>, at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +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, +}; + +#[repr(C)] +struct Rect { + pub x: f32, + pub y: f32, + pub w: f32, + pub h: f32, +} + +#[repr(C)] +struct Color { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} + +#[repr(C)] +struct ClearRect { + pub rect: Rect, + pub color: Color, +} + +fn prepare_pipeline_state<'a>( + device: &DeviceRef, + library: &LibraryRef, + vertex_shader: &str, + fragment_shader: &str, +) -> RenderPipelineState { + let vert = library.get_function(vertex_shader, None).unwrap(); + let frag = library.get_function(fragment_shader, None).unwrap(); + + let pipeline_state_descriptor = RenderPipelineDescriptor::new(); + pipeline_state_descriptor.set_vertex_function(Some(&vert)); + pipeline_state_descriptor.set_fragment_function(Some(&frag)); + let attachment = pipeline_state_descriptor + .color_attachments() + .object_at(0) + .unwrap(); + attachment.set_pixel_format(MTLPixelFormat::BGRA8Unorm); + + attachment.set_blending_enabled(true); + attachment.set_rgb_blend_operation(metal::MTLBlendOperation::Add); + attachment.set_alpha_blend_operation(metal::MTLBlendOperation::Add); + attachment.set_source_rgb_blend_factor(metal::MTLBlendFactor::SourceAlpha); + attachment.set_source_alpha_blend_factor(metal::MTLBlendFactor::SourceAlpha); + attachment.set_destination_rgb_blend_factor(metal::MTLBlendFactor::OneMinusSourceAlpha); + attachment.set_destination_alpha_blend_factor(metal::MTLBlendFactor::OneMinusSourceAlpha); + + device + .new_render_pipeline_state(&pipeline_state_descriptor) + .unwrap() +} + +fn prepare_render_pass_descriptor(descriptor: &RenderPassDescriptorRef, texture: &TextureRef) { + //descriptor.color_attachments().set_object_at(0, MTLRenderPassColorAttachmentDescriptor::alloc()); + //let color_attachment: MTLRenderPassColorAttachmentDescriptor = unsafe { msg_send![descriptor.color_attachments().0, _descriptorAtIndex:0] };//descriptor.color_attachments().object_at(0); + 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 Window 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/window/shaders.metallib"); + + let library = device.new_library_with_file(library_path).unwrap(); + let triangle_pipeline_state = + prepare_pipeline_state(&device, &library, "triangle_vertex", "triangle_fragment"); + let clear_rect_pipeline_state = prepare_pipeline_state( + &device, + &library, + "clear_rect_vertex", + "clear_rect_fragment", + ); + + let command_queue = device.new_command_queue(); + //let nc: () = msg_send![command_queue.0, setExecutionEnabled:true]; + + let vbuf = { + let vertex_data = [ + 0.0f32, 0.5, 1.0, 0.0, 0.0, -0.5, -0.5, 0.0, 1.0, 0.0, 0.5, 0.5, 0.0, 0.0, 1.0, + ]; + + device.new_buffer_with_data( + vertex_data.as_ptr() as *const _, + (vertex_data.len() * mem::size_of::<f32>()) as u64, + MTLResourceOptions::CPUCacheModeDefaultCache | MTLResourceOptions::StorageModeManaged, + ) + }; + + let mut r = 0.0f32; + + let clear_rect = vec![ClearRect { + rect: Rect { + x: -1.0, + y: -1.0, + w: 2.0, + h: 2.0, + }, + color: Color { + r: 0.5, + g: 0.8, + b: 0.5, + a: 1.0, + }, + }]; + + let clear_rect_buffer = device.new_buffer_with_data( + clear_rect.as_ptr() as *const _, + mem::size_of::<ClearRect>() as u64, + MTLResourceOptions::CPUCacheModeDefaultCache | MTLResourceOptions::StorageModeManaged, + ); + + 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 p = vbuf.contents(); + let vertex_data = [ + 0.0f32, + 0.5, + 1.0, + 0.0, + 0.0, + -0.5 + (r.cos() / 2. + 0.5), + -0.5, + 0.0, + 1.0, + 0.0, + 0.5 - (r.cos() / 2. + 0.5), + -0.5, + 0.0, + 0.0, + 1.0, + ]; + + unsafe { + std::ptr::copy( + vertex_data.as_ptr(), + p as *mut f32, + (vertex_data.len() * mem::size_of::<f32>()) as usize, + ); + } + + vbuf.did_modify_range(crate::NSRange::new( + 0 as u64, + (vertex_data.len() * mem::size_of::<f32>()) as u64, + )); + + 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_scissor_rect(MTLScissorRect { + x: 20, + y: 20, + width: 100, + height: 100, + }); + encoder.set_render_pipeline_state(&clear_rect_pipeline_state); + encoder.set_vertex_buffer(0, Some(&clear_rect_buffer), 0); + encoder.draw_primitives_instanced( + metal::MTLPrimitiveType::TriangleStrip, + 0, + 4, + 1, + ); + let physical_size = window.inner_size(); + encoder.set_scissor_rect(MTLScissorRect { + x: 0, + y: 0, + width: physical_size.width as _, + height: physical_size.height as _, + }); + + encoder.set_render_pipeline_state(&triangle_pipeline_state); + encoder.set_vertex_buffer(0, Some(&vbuf), 0); + encoder.draw_primitives(MTLPrimitiveType::Triangle, 0, 3); + encoder.end_encoding(); + + command_buffer.present_drawable(&drawable); + command_buffer.commit(); + + r += 0.01f32; + } + _ => {} + } + }); + }); +} diff --git a/third_party/rust/metal/examples/window/screenshot.png b/third_party/rust/metal/examples/window/screenshot.png Binary files differnew file mode 100644 index 0000000000..9f5eba8ccf --- /dev/null +++ b/third_party/rust/metal/examples/window/screenshot.png diff --git a/third_party/rust/metal/examples/window/shaders.metal b/third_party/rust/metal/examples/window/shaders.metal new file mode 100644 index 0000000000..cc05f5d57e --- /dev/null +++ b/third_party/rust/metal/examples/window/shaders.metal @@ -0,0 +1,97 @@ +#include <metal_stdlib> + +using namespace metal; + +typedef struct { + packed_float2 position; + packed_float3 color; +} vertex_t; + +struct ColorInOut { + float4 position [[position]]; + float4 color; +}; +// vertex shader function +vertex ColorInOut triangle_vertex(const device vertex_t* vertex_array [[ buffer(0) ]], + unsigned int vid [[ vertex_id ]]) +{ + ColorInOut out; + + auto device const &v = vertex_array[vid]; + out.position = float4(v.position.x, v.position.y, 0.0, 1.0); + out.color = float4(v.color.x, v.color.y, v.color.z, 0.2); + + return out; +} + +// fragment shader function +fragment float4 triangle_fragment(ColorInOut in [[stage_in]]) +{ + return in.color; +}; + + +struct Rect { + float x; + float y; + float w; + float h; +}; + +struct Color { + float r; + float g; + float b; + float a; +}; + +struct ClearRect { + Rect rect; + Color color; +}; + +float2 rect_vert( + Rect rect, + uint vid +) { + float2 pos; + + float left = rect.x; + float right = rect.x + rect.w; + float bottom = rect.y; + float top = rect.y + rect.h; + + switch (vid) { + case 0: + pos = float2(right, top); + break; + case 1: + pos = float2(left, top); + break; + case 2: + pos = float2(right, bottom); + break; + case 3: + pos = float2(left, bottom); + break; + } + return pos; +} + +vertex ColorInOut clear_rect_vertex( + const device ClearRect *clear_rect [[ buffer(0) ]], + unsigned int vid [[ vertex_id ]] +) { + ColorInOut out; + float4 pos = float4(rect_vert(clear_rect->rect, vid), 0, 1); + auto col = clear_rect->color; + + out.position = pos; + out.color = float4(col.r, col.g, col.b, col.a); + return out; +} + +fragment float4 clear_rect_fragment(ColorInOut in [[stage_in]]) +{ + return in.color; +}; diff --git a/third_party/rust/metal/examples/window/shaders.metallib b/third_party/rust/metal/examples/window/shaders.metallib Binary files differnew file mode 100644 index 0000000000..a6388fc9bc --- /dev/null +++ b/third_party/rust/metal/examples/window/shaders.metallib |