Skip to main content

05_render_and_explicit_encoders/
05_render_and_explicit_encoders.rs

1#![allow(clippy::too_many_lines)]
2
3#[path = "common/mod.rs"]
4mod common;
5
6use apple_metal::{
7    load_action, pixel_format, primitive_type, resource_options, store_action, MetalDevice,
8    TextureDescriptor,
9};
10
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    println!(
14        "device: {} (registry id {})",
15        device.name(),
16        device.registry_id()
17    );
18
19    let queue = device.new_command_queue().expect("command queue");
20    let status_buffer = unsafe {
21        queue
22            .new_command_buffer_with_unretained_references()
23            .expect("scratch command buffer")
24    };
25    println!("scratch command buffer status={}", status_buffer.status());
26
27    let src = device
28        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
29        .expect("source buffer");
30    let dst = device
31        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
32        .expect("destination buffer");
33    let blit_cb = queue.new_command_buffer().expect("blit command buffer");
34    let mut blit = blit_cb
35        .new_blit_command_encoder()
36        .expect("blit command encoder");
37    blit.fill_buffer(&src, 0..64, b'Z').expect("fill source");
38    blit.copy_buffer(&src, 0, &dst, 0, 64)
39        .expect("copy buffers");
40    blit.end_encoding().expect("end blit encoder");
41    blit_cb.commit().expect("commit blit");
42    blit_cb.wait_until_completed().expect("complete blit");
43    let copied = {
44        let mapping = unsafe { dst.map_read().expect("map destination") };
45        let copied = mapping[..8].to_vec();
46        drop(mapping);
47        copied
48    };
49    println!("blit copied bytes: {copied:?}");
50
51    let library = device
52        .new_library_with_source(common::COMPUTE_SRC)
53        .expect("compile compute library");
54    let increment = library
55        .new_function("increment")
56        .expect("increment function");
57    let pipeline = device
58        .new_compute_pipeline_state(&increment)
59        .expect("compute pipeline");
60
61    let buffer = device
62        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
63        .expect("compute buffer");
64    common::write_u32_words(&buffer, &[10, 20, 30, 40]);
65    let compute_cb = queue.new_command_buffer().expect("compute command buffer");
66    let mut compute = compute_cb
67        .new_compute_command_encoder()
68        .expect("compute command encoder");
69    compute
70        .set_compute_pipeline_state(&pipeline)
71        .expect("bind compute pipeline");
72    compute
73        .set_buffer(&buffer, 0, 0)
74        .expect("bind compute buffer");
75    compute
76        .dispatch_threads((4, 1, 1), (1, 1, 1))
77        .expect("dispatch compute");
78    compute.end_encoding().expect("end compute encoder");
79    compute_cb.commit().expect("commit compute");
80    compute_cb.wait_until_completed().expect("complete compute");
81    println!("compute output: {:?}", common::read_u32_words(&buffer, 4));
82
83    let render_library = device
84        .new_library_with_source(common::RENDER_SRC)
85        .expect("compile render library");
86    let vertex = render_library
87        .new_function("fullscreen_vertex")
88        .expect("vertex function");
89    let fragment = render_library
90        .new_function("solid_fragment")
91        .expect("fragment function");
92    let render_pipeline = device
93        .new_render_pipeline_state(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
94        .expect("render pipeline");
95    println!("render pipeline label: {:?}", render_pipeline.label());
96
97    let render_target = device
98        .new_texture(common::shared_render_target(4, 4))
99        .expect("render target");
100    let vertex_buffer = device
101        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
102        .expect("vertex buffer");
103    let render_cb = queue.new_command_buffer().expect("render command buffer");
104    let mut render = render_cb
105        .new_render_command_encoder(
106            &render_target,
107            load_action::CLEAR,
108            store_action::STORE,
109            [0.0, 0.0, 0.0, 1.0],
110        )
111        .expect("render command encoder");
112    render
113        .set_render_pipeline_state(&render_pipeline)
114        .expect("bind render pipeline");
115    render
116        .set_vertex_buffer(&vertex_buffer, 0, 0)
117        .expect("bind vertex buffer");
118    render
119        .draw_primitives(primitive_type::TRIANGLE, 0, 3)
120        .expect("draw triangle");
121    render.end_encoding().expect("end render encoder");
122    render_cb.commit().expect("commit render");
123    render_cb.wait_until_completed().expect("complete render");
124
125    let mut rendered = vec![0_u8; 4 * 4 * 4];
126    unsafe {
127        render_target
128            .read_bytes_2d(&mut rendered, 16, (0, 0), (4, 4), 0)
129            .expect("read render target");
130    }
131    println!("first rendered pixel: {:?}", &rendered[..4]);
132
133    let shared_texture = device
134        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
135        .expect("shared texture");
136    let upload = vec![0x22_u8; 4 * 4 * 4];
137    unsafe {
138        shared_texture
139            .replace_region_2d(&upload, 16, (0, 0), (4, 4), 0)
140            .expect("upload texture");
141    }
142    let mut download = vec![0_u8; upload.len()];
143    unsafe {
144        shared_texture
145            .read_bytes_2d(&mut download, 16, (0, 0), (4, 4), 0)
146            .expect("read texture");
147    }
148    let view = shared_texture
149        .new_view(pixel_format::BGRA8UNORM)
150        .expect("texture view");
151    println!(
152        "texture {}x{} usage={} storage_mode={} view_width={}",
153        shared_texture.width(),
154        shared_texture.height(),
155        shared_texture.usage(),
156        shared_texture.storage_mode(),
157        view.width(),
158    );
159}