diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /third_party/rust/metal/examples/shader-dylib | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/metal/examples/shader-dylib')
3 files changed, 199 insertions, 0 deletions
diff --git a/third_party/rust/metal/examples/shader-dylib/main.rs b/third_party/rust/metal/examples/shader-dylib/main.rs new file mode 100644 index 0000000000..b713e20e06 --- /dev/null +++ b/third_party/rust/metal/examples/shader-dylib/main.rs @@ -0,0 +1,177 @@ +use cocoa::{appkit::NSView, base::id as cocoa_id}; +use core_graphics_types::geometry::CGSize; + +use metal::*; +use objc::{rc::autoreleasepool, runtime::YES}; + +use winit::{ + event::{Event, WindowEvent}, + event_loop::ControlFlow, + platform::macos::WindowExtMacOS, +}; + +use std::mem; + +struct App { + pub device: Device, + pub command_queue: CommandQueue, + pub layer: MetalLayer, + pub image_fill_cps: ComputePipelineState, + pub width: u32, + pub height: u32, +} + +fn select_device() -> Option<Device> { + let devices = Device::all(); + for device in devices { + if device.supports_dynamic_libraries() { + return Some(device); + } + } + + None +} + +impl App { + fn new(window: &winit::window::Window) -> Self { + let device = select_device().expect("no device found that supports dynamic libraries"); + let command_queue = device.new_command_queue(); + + let layer = MetalLayer::new(); + layer.set_device(&device); + layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm); + layer.set_presents_with_transaction(false); + layer.set_framebuffer_only(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)); + + // compile dynamic lib shader + let dylib_src_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("examples/shader-dylib/test_dylib.metal"); + let install_path = + std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("target/test_dylib.metallib"); + + let dylib_src = std::fs::read_to_string(dylib_src_path).expect("bad shit"); + let opts = metal::CompileOptions::new(); + opts.set_library_type(MTLLibraryType::Dynamic); + opts.set_install_name(install_path.to_str().unwrap()); + + let lib = device + .new_library_with_source(dylib_src.as_str(), &opts) + .unwrap(); + + // create dylib + let dylib = device.new_dynamic_library(&lib).unwrap(); + dylib.set_label("test_dylib"); + + // optional: serialize binary blob that can be loaded later + let blob_url = String::from("file://") + install_path.to_str().unwrap(); + let url = URL::new_with_string(&blob_url); + dylib.serialize_to_url(&url).unwrap(); + + // create shader that links with dylib + let shader_src_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("examples/shader-dylib/test_shader.metal"); + + let shader_src = std::fs::read_to_string(shader_src_path).expect("bad shit"); + let opts = metal::CompileOptions::new(); + // add dynamic library to link with + let libraries = [dylib.as_ref()]; + opts.set_libraries(&libraries); + + // compile + let shader_lib = device + .new_library_with_source(shader_src.as_str(), &opts) + .unwrap(); + + let func = shader_lib.get_function("test_kernel", None).unwrap(); + + // create pipeline state + // linking occurs here + let image_fill_cps = device + .new_compute_pipeline_state_with_function(&func) + .unwrap(); + + Self { + device, + command_queue, + layer, + image_fill_cps, + width: draw_size.width, + height: draw_size.height, + } + } + + fn resize(&mut self, width: u32, height: u32) { + self.layer + .set_drawable_size(CGSize::new(width as f64, height as f64)); + self.width = width; + self.height = height; + } + + fn draw(&self) { + let drawable = match self.layer.next_drawable() { + Some(drawable) => drawable, + None => return, + }; + + let w = self.image_fill_cps.thread_execution_width(); + let h = self.image_fill_cps.max_total_threads_per_threadgroup() / w; + let threads_per_threadgroup = MTLSize::new(w, h, 1); + let threads_per_grid = MTLSize::new(self.width as _, self.height as _, 1); + + let command_buffer = self.command_queue.new_command_buffer(); + + { + let encoder = command_buffer.new_compute_command_encoder(); + encoder.set_compute_pipeline_state(&self.image_fill_cps); + encoder.set_texture(0, Some(&drawable.texture())); + encoder.dispatch_threads(threads_per_grid, threads_per_threadgroup); + encoder.end_encoding(); + } + + command_buffer.present_drawable(&drawable); + command_buffer.commit(); + } +} + +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 Shader Dylib Example".to_string()) + .build(&events_loop) + .unwrap(); + + let mut app = App::new(&window); + + 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) => { + app.resize(size.width, size.height); + } + _ => (), + }, + Event::MainEventsCleared => { + window.request_redraw(); + } + Event::RedrawRequested(_) => { + app.draw(); + } + _ => {} + } + }); + }); +} diff --git a/third_party/rust/metal/examples/shader-dylib/test_dylib.metal b/third_party/rust/metal/examples/shader-dylib/test_dylib.metal new file mode 100644 index 0000000000..5faa4a803a --- /dev/null +++ b/third_party/rust/metal/examples/shader-dylib/test_dylib.metal @@ -0,0 +1,8 @@ +#include <metal_stdlib> + +using namespace metal; + +float4 get_color_test(float4 inColor) +{ + return float4(inColor.r, inColor.g, inColor.b, 0); +} diff --git a/third_party/rust/metal/examples/shader-dylib/test_shader.metal b/third_party/rust/metal/examples/shader-dylib/test_shader.metal new file mode 100644 index 0000000000..38203a64a5 --- /dev/null +++ b/third_party/rust/metal/examples/shader-dylib/test_shader.metal @@ -0,0 +1,14 @@ +#include <metal_stdlib> + +using namespace metal; + +extern float4 get_color_test(float4 inColor); + +kernel void test_kernel( + texture2d<float, access::write> image [[texture(0)]], + uint2 coordinates [[thread_position_in_grid]], + uint2 size [[threads_per_grid]]) +{ + float2 uv = float2(coordinates) / float2(size - 1); + image.write(get_color_test(float4(uv, 0.0, 1.0)), coordinates); +} |