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 = queue
21        .new_command_buffer_with_unretained_references()
22        .expect("scratch command buffer");
23    println!("scratch command buffer status={}", status_buffer.status());
24
25    let src = device
26        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
27        .expect("source buffer");
28    let dst = device
29        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
30        .expect("destination buffer");
31    let blit_cb = queue.new_command_buffer().expect("blit command buffer");
32    let blit = blit_cb
33        .new_blit_command_encoder()
34        .expect("blit command encoder");
35    assert!(blit.fill_buffer(&src, 0..64, b'Z'));
36    assert!(blit.copy_buffer(&src, 0, &dst, 0, 64));
37    blit.end_encoding();
38    blit_cb.commit();
39    blit_cb.wait_until_completed();
40    let copied = unsafe {
41        core::slice::from_raw_parts(dst.contents().expect("dst contents").cast::<u8>(), 8)
42    };
43    println!("blit copied bytes: {copied:?}");
44
45    let library = device
46        .new_library_with_source(common::COMPUTE_SRC)
47        .expect("compile compute library");
48    let increment = library
49        .new_function("increment")
50        .expect("increment function");
51    let pipeline = device
52        .new_compute_pipeline_state(&increment)
53        .expect("compute pipeline");
54
55    let buffer = device
56        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
57        .expect("compute buffer");
58    common::write_u32_words(&buffer, &[10, 20, 30, 40]);
59    let compute_cb = queue.new_command_buffer().expect("compute command buffer");
60    let compute = compute_cb
61        .new_compute_command_encoder()
62        .expect("compute command encoder");
63    compute.set_compute_pipeline_state(&pipeline);
64    compute.set_buffer(&buffer, 0, 0);
65    compute.dispatch_threads((4, 1, 1), (1, 1, 1));
66    compute.end_encoding();
67    compute_cb.commit();
68    compute_cb.wait_until_completed();
69    println!("compute output: {:?}", common::read_u32_words(&buffer, 4));
70
71    let render_library = device
72        .new_library_with_source(common::RENDER_SRC)
73        .expect("compile render library");
74    let vertex = render_library
75        .new_function("fullscreen_vertex")
76        .expect("vertex function");
77    let fragment = render_library
78        .new_function("solid_fragment")
79        .expect("fragment function");
80    let render_pipeline = device
81        .new_render_pipeline_state(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
82        .expect("render pipeline");
83    println!("render pipeline label: {:?}", render_pipeline.label());
84
85    let render_target = device
86        .new_texture(common::shared_render_target(4, 4))
87        .expect("render target");
88    let vertex_buffer = device
89        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
90        .expect("vertex buffer");
91    let render_cb = queue.new_command_buffer().expect("render command buffer");
92    let render = render_cb
93        .new_render_command_encoder(
94            &render_target,
95            load_action::CLEAR,
96            store_action::STORE,
97            [0.0, 0.0, 0.0, 1.0],
98        )
99        .expect("render command encoder");
100    render.set_render_pipeline_state(&render_pipeline);
101    render.set_vertex_buffer(&vertex_buffer, 0, 0);
102    render.draw_primitives(primitive_type::TRIANGLE, 0, 3);
103    render.end_encoding();
104    render_cb.commit();
105    render_cb.wait_until_completed();
106
107    let mut rendered = vec![0_u8; 4 * 4 * 4];
108    assert!(render_target.read_bytes_2d(&mut rendered, 16, (0, 0), (4, 4), 0));
109    println!("first rendered pixel: {:?}", &rendered[..4]);
110
111    let shared_texture = device
112        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
113        .expect("shared texture");
114    let upload = vec![0x22_u8; 4 * 4 * 4];
115    assert!(shared_texture.replace_region_2d(&upload, 16, (0, 0), (4, 4), 0));
116    let mut download = vec![0_u8; upload.len()];
117    assert!(shared_texture.read_bytes_2d(&mut download, 16, (0, 0), (4, 4), 0));
118    let view = shared_texture
119        .new_view(pixel_format::BGRA8UNORM)
120        .expect("texture view");
121    println!(
122        "texture {}x{} usage={} storage_mode={} view_width={}",
123        shared_texture.width(),
124        shared_texture.height(),
125        shared_texture.usage(),
126        shared_texture.storage_mode(),
127        view.width(),
128    );
129}