summaryrefslogtreecommitdiffstats
path: root/third_party/rust/metal/examples/window
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/metal/examples/window/README.md11
-rw-r--r--third_party/rust/metal/examples/window/main.rs261
-rw-r--r--third_party/rust/metal/examples/window/screenshot.pngbin0 -> 55104 bytes
-rw-r--r--third_party/rust/metal/examples/window/shaders.metal97
-rw-r--r--third_party/rust/metal/examples/window/shaders.metallibbin0 -> 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
new file mode 100644
index 0000000000..9f5eba8ccf
--- /dev/null
+++ b/third_party/rust/metal/examples/window/screenshot.png
Binary files differ
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
new file mode 100644
index 0000000000..a6388fc9bc
--- /dev/null
+++ b/third_party/rust/metal/examples/window/shaders.metallib
Binary files differ