Skip to main content

ManuallyDropDevice

Struct ManuallyDropDevice 

Source
pub struct ManuallyDropDevice { /* private fields */ }
Expand description

Borrowed MetalDevice that does not release on drop.

Methods from Deref<Target = MetalDevice>§

Source

pub fn name(&self) -> String

Human-readable device name.

Examples found in repository?
examples/05_render_and_explicit_encoders.rs (line 15)
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}
More examples
Hide additional examples
examples/06_resources_and_archives.rs (line 12)
10fn main() {
11    let device = MetalDevice::system_default().expect("Metal device available");
12    println!("device: {}", device.name());
13
14    let queue = device
15        .new_command_queue_with_max_command_buffer_count(4)
16        .expect("bounded command queue");
17    let scratch = unsafe {
18        queue
19            .new_command_buffer_with_unretained_references()
20            .expect("bounded scratch command buffer")
21    };
22    println!("bounded queue scratch status={}", scratch.status());
23
24    let library = device
25        .new_library_with_source(common::COMPUTE_SRC)
26        .expect("compile compute library");
27    let args = library.new_function("use_args").expect("use_args function");
28    let mut argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
29    let argument_buffer = device
30        .new_buffer(
31            argument_encoder.encoded_length(),
32            resource_options::STORAGE_MODE_SHARED,
33        )
34        .expect("argument buffer");
35    let payload = device
36        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
37        .expect("payload buffer");
38    let texture = device
39        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
40        .expect("argument texture");
41    unsafe {
42        let mut binding = argument_encoder
43            .bind_argument_buffer(&argument_buffer, 0)
44            .expect("bind argument buffer");
45        binding
46            .set_buffer_unchecked(&payload, 0, 0)
47            .expect("bind payload");
48        binding
49            .set_texture_unchecked(&texture, 1)
50            .expect("bind texture");
51    }
52    println!(
53        "argument encoder length={} alignment={}",
54        argument_encoder.encoded_length(),
55        argument_encoder.alignment(),
56    );
57
58    let backing = device
59        .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
60        .expect("backing buffer");
61    let buffer_texture = backing
62        .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
63        .expect("buffer-backed texture");
64    println!(
65        "buffer-backed texture {}x{} fmt={}",
66        buffer_texture.width(),
67        buffer_texture.height(),
68        buffer_texture.pixel_format(),
69    );
70
71    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
72        let heap_buffer = heap
73            .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
74            .expect("heap buffer");
75        let heap_texture = heap
76            .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
77            .expect("heap texture");
78        println!(
79            "heap size={} used={} current={} max_available={}",
80            heap.size(),
81            heap.used_size(),
82            heap.current_allocated_size(),
83            heap.max_available_size(256),
84        );
85        println!(
86            "heap buffer len={} heap texture {}x{} purgeable={}",
87            heap_buffer.length(),
88            heap_texture.width(),
89            heap_texture.height(),
90            heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
91        );
92    } else {
93        println!("heaps are unavailable on this device");
94    }
95
96    match device.new_log_state(log_level::INFO, 1_024) {
97        Ok(log_state) => {
98            let _ = device
99                .new_command_queue_with_log_state(4, &log_state)
100                .expect("log-state queue");
101            println!("created queue with log state");
102        }
103        Err(error) => println!("log state unavailable on this OS: {error}"),
104    }
105
106    if device.supports_dynamic_libraries() {
107        let dynamic_path = common::artifact_path("example-dylib.metallib");
108        let dynamic_library = device
109            .new_dynamic_library_with_source(
110                common::DYNAMIC_LIB_SRC,
111                dynamic_path.to_string_lossy().as_ref(),
112            )
113            .expect("dynamic library from source");
114        dynamic_library
115            .serialize_to_file(&dynamic_path)
116            .expect("serialize dynamic library");
117        let reloaded = device
118            .load_dynamic_library(&dynamic_path)
119            .expect("reload dynamic library");
120        println!("dynamic library install name: {}", reloaded.install_name());
121
122        let render_library = device
123            .new_library_with_source(common::RENDER_SRC)
124            .expect("compile render library");
125        let vertex = render_library
126            .new_function("fullscreen_vertex")
127            .expect("vertex function");
128        let fragment = render_library
129            .new_function("solid_fragment")
130            .expect("fragment function");
131        let increment = library
132            .new_function("increment")
133            .expect("increment function");
134
135        let archive_path = common::artifact_path("example-archive.metalarc");
136        let archive = device.new_binary_archive(None).expect("binary archive");
137        archive
138            .add_compute_function(&increment)
139            .expect("archive compute pipeline");
140        archive
141            .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
142            .expect("archive render pipeline");
143        archive
144            .serialize_to_file(&archive_path)
145            .expect("serialize binary archive");
146        let _ = device
147            .new_binary_archive(Some(&archive_path))
148            .expect("reload binary archive");
149        println!("binary archive written to {}", archive_path.display());
150    } else {
151        println!("dynamic libraries unsupported; skipping archive serialization");
152    }
153}
Source

pub fn registry_id(&self) -> u64

Global IORegistry identifier for the device.

Examples found in repository?
examples/05_render_and_explicit_encoders.rs (line 16)
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}
Source

pub fn supports_dynamic_libraries(&self) -> bool

Whether this device supports Metal dynamic libraries.

Examples found in repository?
examples/06_resources_and_archives.rs (line 106)
10fn main() {
11    let device = MetalDevice::system_default().expect("Metal device available");
12    println!("device: {}", device.name());
13
14    let queue = device
15        .new_command_queue_with_max_command_buffer_count(4)
16        .expect("bounded command queue");
17    let scratch = unsafe {
18        queue
19            .new_command_buffer_with_unretained_references()
20            .expect("bounded scratch command buffer")
21    };
22    println!("bounded queue scratch status={}", scratch.status());
23
24    let library = device
25        .new_library_with_source(common::COMPUTE_SRC)
26        .expect("compile compute library");
27    let args = library.new_function("use_args").expect("use_args function");
28    let mut argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
29    let argument_buffer = device
30        .new_buffer(
31            argument_encoder.encoded_length(),
32            resource_options::STORAGE_MODE_SHARED,
33        )
34        .expect("argument buffer");
35    let payload = device
36        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
37        .expect("payload buffer");
38    let texture = device
39        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
40        .expect("argument texture");
41    unsafe {
42        let mut binding = argument_encoder
43            .bind_argument_buffer(&argument_buffer, 0)
44            .expect("bind argument buffer");
45        binding
46            .set_buffer_unchecked(&payload, 0, 0)
47            .expect("bind payload");
48        binding
49            .set_texture_unchecked(&texture, 1)
50            .expect("bind texture");
51    }
52    println!(
53        "argument encoder length={} alignment={}",
54        argument_encoder.encoded_length(),
55        argument_encoder.alignment(),
56    );
57
58    let backing = device
59        .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
60        .expect("backing buffer");
61    let buffer_texture = backing
62        .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
63        .expect("buffer-backed texture");
64    println!(
65        "buffer-backed texture {}x{} fmt={}",
66        buffer_texture.width(),
67        buffer_texture.height(),
68        buffer_texture.pixel_format(),
69    );
70
71    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
72        let heap_buffer = heap
73            .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
74            .expect("heap buffer");
75        let heap_texture = heap
76            .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
77            .expect("heap texture");
78        println!(
79            "heap size={} used={} current={} max_available={}",
80            heap.size(),
81            heap.used_size(),
82            heap.current_allocated_size(),
83            heap.max_available_size(256),
84        );
85        println!(
86            "heap buffer len={} heap texture {}x{} purgeable={}",
87            heap_buffer.length(),
88            heap_texture.width(),
89            heap_texture.height(),
90            heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
91        );
92    } else {
93        println!("heaps are unavailable on this device");
94    }
95
96    match device.new_log_state(log_level::INFO, 1_024) {
97        Ok(log_state) => {
98            let _ = device
99                .new_command_queue_with_log_state(4, &log_state)
100                .expect("log-state queue");
101            println!("created queue with log state");
102        }
103        Err(error) => println!("log state unavailable on this OS: {error}"),
104    }
105
106    if device.supports_dynamic_libraries() {
107        let dynamic_path = common::artifact_path("example-dylib.metallib");
108        let dynamic_library = device
109            .new_dynamic_library_with_source(
110                common::DYNAMIC_LIB_SRC,
111                dynamic_path.to_string_lossy().as_ref(),
112            )
113            .expect("dynamic library from source");
114        dynamic_library
115            .serialize_to_file(&dynamic_path)
116            .expect("serialize dynamic library");
117        let reloaded = device
118            .load_dynamic_library(&dynamic_path)
119            .expect("reload dynamic library");
120        println!("dynamic library install name: {}", reloaded.install_name());
121
122        let render_library = device
123            .new_library_with_source(common::RENDER_SRC)
124            .expect("compile render library");
125        let vertex = render_library
126            .new_function("fullscreen_vertex")
127            .expect("vertex function");
128        let fragment = render_library
129            .new_function("solid_fragment")
130            .expect("fragment function");
131        let increment = library
132            .new_function("increment")
133            .expect("increment function");
134
135        let archive_path = common::artifact_path("example-archive.metalarc");
136        let archive = device.new_binary_archive(None).expect("binary archive");
137        archive
138            .add_compute_function(&increment)
139            .expect("archive compute pipeline");
140        archive
141            .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
142            .expect("archive render pipeline");
143        archive
144            .serialize_to_file(&archive_path)
145            .expect("serialize binary archive");
146        let _ = device
147            .new_binary_archive(Some(&archive_path))
148            .expect("reload binary archive");
149        println!("binary archive written to {}", archive_path.display());
150    } else {
151        println!("dynamic libraries unsupported; skipping archive serialization");
152    }
153}
Source

pub fn supports_render_dynamic_libraries(&self) -> bool

Whether this device supports render-stage dynamic libraries.

Source

pub fn supports_raytracing(&self) -> bool

Whether this device supports compute ray tracing.

Examples found in repository?
examples/07_advanced_objects.rs (line 113)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn supports_counter_sampling(&self, sampling_point: usize) -> bool

Query support for a hardware counter sampling point.

Examples found in repository?
examples/07_advanced_objects.rs (line 47)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn counter_set_names(&self) -> Vec<String>

Return the names of all counter sets exposed by this device.

Examples found in repository?
examples/07_advanced_objects.rs (line 14)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn new_command_queue_with_max_command_buffer_count( &self, max_command_buffer_count: usize, ) -> Option<CommandQueue>

Create a command queue with an explicit maximum in-flight command-buffer count.

Examples found in repository?
examples/06_resources_and_archives.rs (line 15)
10fn main() {
11    let device = MetalDevice::system_default().expect("Metal device available");
12    println!("device: {}", device.name());
13
14    let queue = device
15        .new_command_queue_with_max_command_buffer_count(4)
16        .expect("bounded command queue");
17    let scratch = unsafe {
18        queue
19            .new_command_buffer_with_unretained_references()
20            .expect("bounded scratch command buffer")
21    };
22    println!("bounded queue scratch status={}", scratch.status());
23
24    let library = device
25        .new_library_with_source(common::COMPUTE_SRC)
26        .expect("compile compute library");
27    let args = library.new_function("use_args").expect("use_args function");
28    let mut argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
29    let argument_buffer = device
30        .new_buffer(
31            argument_encoder.encoded_length(),
32            resource_options::STORAGE_MODE_SHARED,
33        )
34        .expect("argument buffer");
35    let payload = device
36        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
37        .expect("payload buffer");
38    let texture = device
39        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
40        .expect("argument texture");
41    unsafe {
42        let mut binding = argument_encoder
43            .bind_argument_buffer(&argument_buffer, 0)
44            .expect("bind argument buffer");
45        binding
46            .set_buffer_unchecked(&payload, 0, 0)
47            .expect("bind payload");
48        binding
49            .set_texture_unchecked(&texture, 1)
50            .expect("bind texture");
51    }
52    println!(
53        "argument encoder length={} alignment={}",
54        argument_encoder.encoded_length(),
55        argument_encoder.alignment(),
56    );
57
58    let backing = device
59        .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
60        .expect("backing buffer");
61    let buffer_texture = backing
62        .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
63        .expect("buffer-backed texture");
64    println!(
65        "buffer-backed texture {}x{} fmt={}",
66        buffer_texture.width(),
67        buffer_texture.height(),
68        buffer_texture.pixel_format(),
69    );
70
71    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
72        let heap_buffer = heap
73            .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
74            .expect("heap buffer");
75        let heap_texture = heap
76            .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
77            .expect("heap texture");
78        println!(
79            "heap size={} used={} current={} max_available={}",
80            heap.size(),
81            heap.used_size(),
82            heap.current_allocated_size(),
83            heap.max_available_size(256),
84        );
85        println!(
86            "heap buffer len={} heap texture {}x{} purgeable={}",
87            heap_buffer.length(),
88            heap_texture.width(),
89            heap_texture.height(),
90            heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
91        );
92    } else {
93        println!("heaps are unavailable on this device");
94    }
95
96    match device.new_log_state(log_level::INFO, 1_024) {
97        Ok(log_state) => {
98            let _ = device
99                .new_command_queue_with_log_state(4, &log_state)
100                .expect("log-state queue");
101            println!("created queue with log state");
102        }
103        Err(error) => println!("log state unavailable on this OS: {error}"),
104    }
105
106    if device.supports_dynamic_libraries() {
107        let dynamic_path = common::artifact_path("example-dylib.metallib");
108        let dynamic_library = device
109            .new_dynamic_library_with_source(
110                common::DYNAMIC_LIB_SRC,
111                dynamic_path.to_string_lossy().as_ref(),
112            )
113            .expect("dynamic library from source");
114        dynamic_library
115            .serialize_to_file(&dynamic_path)
116            .expect("serialize dynamic library");
117        let reloaded = device
118            .load_dynamic_library(&dynamic_path)
119            .expect("reload dynamic library");
120        println!("dynamic library install name: {}", reloaded.install_name());
121
122        let render_library = device
123            .new_library_with_source(common::RENDER_SRC)
124            .expect("compile render library");
125        let vertex = render_library
126            .new_function("fullscreen_vertex")
127            .expect("vertex function");
128        let fragment = render_library
129            .new_function("solid_fragment")
130            .expect("fragment function");
131        let increment = library
132            .new_function("increment")
133            .expect("increment function");
134
135        let archive_path = common::artifact_path("example-archive.metalarc");
136        let archive = device.new_binary_archive(None).expect("binary archive");
137        archive
138            .add_compute_function(&increment)
139            .expect("archive compute pipeline");
140        archive
141            .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
142            .expect("archive render pipeline");
143        archive
144            .serialize_to_file(&archive_path)
145            .expect("serialize binary archive");
146        let _ = device
147            .new_binary_archive(Some(&archive_path))
148            .expect("reload binary archive");
149        println!("binary archive written to {}", archive_path.display());
150    } else {
151        println!("dynamic libraries unsupported; skipping archive serialization");
152    }
153}
Source

pub fn new_command_queue_with_log_state( &self, max_command_buffer_count: usize, log_state: &LogState, ) -> Option<CommandQueue>

Create a command queue that uses log_state for shader logging.

Examples found in repository?
examples/06_resources_and_archives.rs (line 99)
10fn main() {
11    let device = MetalDevice::system_default().expect("Metal device available");
12    println!("device: {}", device.name());
13
14    let queue = device
15        .new_command_queue_with_max_command_buffer_count(4)
16        .expect("bounded command queue");
17    let scratch = unsafe {
18        queue
19            .new_command_buffer_with_unretained_references()
20            .expect("bounded scratch command buffer")
21    };
22    println!("bounded queue scratch status={}", scratch.status());
23
24    let library = device
25        .new_library_with_source(common::COMPUTE_SRC)
26        .expect("compile compute library");
27    let args = library.new_function("use_args").expect("use_args function");
28    let mut argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
29    let argument_buffer = device
30        .new_buffer(
31            argument_encoder.encoded_length(),
32            resource_options::STORAGE_MODE_SHARED,
33        )
34        .expect("argument buffer");
35    let payload = device
36        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
37        .expect("payload buffer");
38    let texture = device
39        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
40        .expect("argument texture");
41    unsafe {
42        let mut binding = argument_encoder
43            .bind_argument_buffer(&argument_buffer, 0)
44            .expect("bind argument buffer");
45        binding
46            .set_buffer_unchecked(&payload, 0, 0)
47            .expect("bind payload");
48        binding
49            .set_texture_unchecked(&texture, 1)
50            .expect("bind texture");
51    }
52    println!(
53        "argument encoder length={} alignment={}",
54        argument_encoder.encoded_length(),
55        argument_encoder.alignment(),
56    );
57
58    let backing = device
59        .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
60        .expect("backing buffer");
61    let buffer_texture = backing
62        .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
63        .expect("buffer-backed texture");
64    println!(
65        "buffer-backed texture {}x{} fmt={}",
66        buffer_texture.width(),
67        buffer_texture.height(),
68        buffer_texture.pixel_format(),
69    );
70
71    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
72        let heap_buffer = heap
73            .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
74            .expect("heap buffer");
75        let heap_texture = heap
76            .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
77            .expect("heap texture");
78        println!(
79            "heap size={} used={} current={} max_available={}",
80            heap.size(),
81            heap.used_size(),
82            heap.current_allocated_size(),
83            heap.max_available_size(256),
84        );
85        println!(
86            "heap buffer len={} heap texture {}x{} purgeable={}",
87            heap_buffer.length(),
88            heap_texture.width(),
89            heap_texture.height(),
90            heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
91        );
92    } else {
93        println!("heaps are unavailable on this device");
94    }
95
96    match device.new_log_state(log_level::INFO, 1_024) {
97        Ok(log_state) => {
98            let _ = device
99                .new_command_queue_with_log_state(4, &log_state)
100                .expect("log-state queue");
101            println!("created queue with log state");
102        }
103        Err(error) => println!("log state unavailable on this OS: {error}"),
104    }
105
106    if device.supports_dynamic_libraries() {
107        let dynamic_path = common::artifact_path("example-dylib.metallib");
108        let dynamic_library = device
109            .new_dynamic_library_with_source(
110                common::DYNAMIC_LIB_SRC,
111                dynamic_path.to_string_lossy().as_ref(),
112            )
113            .expect("dynamic library from source");
114        dynamic_library
115            .serialize_to_file(&dynamic_path)
116            .expect("serialize dynamic library");
117        let reloaded = device
118            .load_dynamic_library(&dynamic_path)
119            .expect("reload dynamic library");
120        println!("dynamic library install name: {}", reloaded.install_name());
121
122        let render_library = device
123            .new_library_with_source(common::RENDER_SRC)
124            .expect("compile render library");
125        let vertex = render_library
126            .new_function("fullscreen_vertex")
127            .expect("vertex function");
128        let fragment = render_library
129            .new_function("solid_fragment")
130            .expect("fragment function");
131        let increment = library
132            .new_function("increment")
133            .expect("increment function");
134
135        let archive_path = common::artifact_path("example-archive.metalarc");
136        let archive = device.new_binary_archive(None).expect("binary archive");
137        archive
138            .add_compute_function(&increment)
139            .expect("archive compute pipeline");
140        archive
141            .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
142            .expect("archive render pipeline");
143        archive
144            .serialize_to_file(&archive_path)
145            .expect("serialize binary archive");
146        let _ = device
147            .new_binary_archive(Some(&archive_path))
148            .expect("reload binary archive");
149        println!("binary archive written to {}", archive_path.display());
150    } else {
151        println!("dynamic libraries unsupported; skipping archive serialization");
152    }
153}
Source

pub fn new_heap(&self, size: usize, storage_mode: usize) -> Option<Heap>

Create a heap with the requested size and storage mode.

Examples found in repository?
examples/06_resources_and_archives.rs (line 71)
10fn main() {
11    let device = MetalDevice::system_default().expect("Metal device available");
12    println!("device: {}", device.name());
13
14    let queue = device
15        .new_command_queue_with_max_command_buffer_count(4)
16        .expect("bounded command queue");
17    let scratch = unsafe {
18        queue
19            .new_command_buffer_with_unretained_references()
20            .expect("bounded scratch command buffer")
21    };
22    println!("bounded queue scratch status={}", scratch.status());
23
24    let library = device
25        .new_library_with_source(common::COMPUTE_SRC)
26        .expect("compile compute library");
27    let args = library.new_function("use_args").expect("use_args function");
28    let mut argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
29    let argument_buffer = device
30        .new_buffer(
31            argument_encoder.encoded_length(),
32            resource_options::STORAGE_MODE_SHARED,
33        )
34        .expect("argument buffer");
35    let payload = device
36        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
37        .expect("payload buffer");
38    let texture = device
39        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
40        .expect("argument texture");
41    unsafe {
42        let mut binding = argument_encoder
43            .bind_argument_buffer(&argument_buffer, 0)
44            .expect("bind argument buffer");
45        binding
46            .set_buffer_unchecked(&payload, 0, 0)
47            .expect("bind payload");
48        binding
49            .set_texture_unchecked(&texture, 1)
50            .expect("bind texture");
51    }
52    println!(
53        "argument encoder length={} alignment={}",
54        argument_encoder.encoded_length(),
55        argument_encoder.alignment(),
56    );
57
58    let backing = device
59        .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
60        .expect("backing buffer");
61    let buffer_texture = backing
62        .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
63        .expect("buffer-backed texture");
64    println!(
65        "buffer-backed texture {}x{} fmt={}",
66        buffer_texture.width(),
67        buffer_texture.height(),
68        buffer_texture.pixel_format(),
69    );
70
71    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
72        let heap_buffer = heap
73            .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
74            .expect("heap buffer");
75        let heap_texture = heap
76            .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
77            .expect("heap texture");
78        println!(
79            "heap size={} used={} current={} max_available={}",
80            heap.size(),
81            heap.used_size(),
82            heap.current_allocated_size(),
83            heap.max_available_size(256),
84        );
85        println!(
86            "heap buffer len={} heap texture {}x{} purgeable={}",
87            heap_buffer.length(),
88            heap_texture.width(),
89            heap_texture.height(),
90            heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
91        );
92    } else {
93        println!("heaps are unavailable on this device");
94    }
95
96    match device.new_log_state(log_level::INFO, 1_024) {
97        Ok(log_state) => {
98            let _ = device
99                .new_command_queue_with_log_state(4, &log_state)
100                .expect("log-state queue");
101            println!("created queue with log state");
102        }
103        Err(error) => println!("log state unavailable on this OS: {error}"),
104    }
105
106    if device.supports_dynamic_libraries() {
107        let dynamic_path = common::artifact_path("example-dylib.metallib");
108        let dynamic_library = device
109            .new_dynamic_library_with_source(
110                common::DYNAMIC_LIB_SRC,
111                dynamic_path.to_string_lossy().as_ref(),
112            )
113            .expect("dynamic library from source");
114        dynamic_library
115            .serialize_to_file(&dynamic_path)
116            .expect("serialize dynamic library");
117        let reloaded = device
118            .load_dynamic_library(&dynamic_path)
119            .expect("reload dynamic library");
120        println!("dynamic library install name: {}", reloaded.install_name());
121
122        let render_library = device
123            .new_library_with_source(common::RENDER_SRC)
124            .expect("compile render library");
125        let vertex = render_library
126            .new_function("fullscreen_vertex")
127            .expect("vertex function");
128        let fragment = render_library
129            .new_function("solid_fragment")
130            .expect("fragment function");
131        let increment = library
132            .new_function("increment")
133            .expect("increment function");
134
135        let archive_path = common::artifact_path("example-archive.metalarc");
136        let archive = device.new_binary_archive(None).expect("binary archive");
137        archive
138            .add_compute_function(&increment)
139            .expect("archive compute pipeline");
140        archive
141            .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
142            .expect("archive render pipeline");
143        archive
144            .serialize_to_file(&archive_path)
145            .expect("serialize binary archive");
146        let _ = device
147            .new_binary_archive(Some(&archive_path))
148            .expect("reload binary archive");
149        println!("binary archive written to {}", archive_path.display());
150    } else {
151        println!("dynamic libraries unsupported; skipping archive serialization");
152    }
153}
More examples
Hide additional examples
examples/07_advanced_objects.rs (line 195)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn new_fence(&self) -> Option<Fence>

Create a new fence.

Examples found in repository?
examples/07_advanced_objects.rs (line 44)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn new_shared_event(&self) -> Option<Event>

Create a new shared event.

Examples found in repository?
examples/07_advanced_objects.rs (line 17)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn new_dynamic_library_with_source( &self, source: &str, install_name: &str, ) -> Result<DynamicLibrary, String>

Compile source as a Metal dynamic library with the given install_name.

§Errors

Returns Metal’s localized compiler or linker error on failure.

Examples found in repository?
examples/06_resources_and_archives.rs (lines 109-112)
10fn main() {
11    let device = MetalDevice::system_default().expect("Metal device available");
12    println!("device: {}", device.name());
13
14    let queue = device
15        .new_command_queue_with_max_command_buffer_count(4)
16        .expect("bounded command queue");
17    let scratch = unsafe {
18        queue
19            .new_command_buffer_with_unretained_references()
20            .expect("bounded scratch command buffer")
21    };
22    println!("bounded queue scratch status={}", scratch.status());
23
24    let library = device
25        .new_library_with_source(common::COMPUTE_SRC)
26        .expect("compile compute library");
27    let args = library.new_function("use_args").expect("use_args function");
28    let mut argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
29    let argument_buffer = device
30        .new_buffer(
31            argument_encoder.encoded_length(),
32            resource_options::STORAGE_MODE_SHARED,
33        )
34        .expect("argument buffer");
35    let payload = device
36        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
37        .expect("payload buffer");
38    let texture = device
39        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
40        .expect("argument texture");
41    unsafe {
42        let mut binding = argument_encoder
43            .bind_argument_buffer(&argument_buffer, 0)
44            .expect("bind argument buffer");
45        binding
46            .set_buffer_unchecked(&payload, 0, 0)
47            .expect("bind payload");
48        binding
49            .set_texture_unchecked(&texture, 1)
50            .expect("bind texture");
51    }
52    println!(
53        "argument encoder length={} alignment={}",
54        argument_encoder.encoded_length(),
55        argument_encoder.alignment(),
56    );
57
58    let backing = device
59        .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
60        .expect("backing buffer");
61    let buffer_texture = backing
62        .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
63        .expect("buffer-backed texture");
64    println!(
65        "buffer-backed texture {}x{} fmt={}",
66        buffer_texture.width(),
67        buffer_texture.height(),
68        buffer_texture.pixel_format(),
69    );
70
71    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
72        let heap_buffer = heap
73            .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
74            .expect("heap buffer");
75        let heap_texture = heap
76            .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
77            .expect("heap texture");
78        println!(
79            "heap size={} used={} current={} max_available={}",
80            heap.size(),
81            heap.used_size(),
82            heap.current_allocated_size(),
83            heap.max_available_size(256),
84        );
85        println!(
86            "heap buffer len={} heap texture {}x{} purgeable={}",
87            heap_buffer.length(),
88            heap_texture.width(),
89            heap_texture.height(),
90            heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
91        );
92    } else {
93        println!("heaps are unavailable on this device");
94    }
95
96    match device.new_log_state(log_level::INFO, 1_024) {
97        Ok(log_state) => {
98            let _ = device
99                .new_command_queue_with_log_state(4, &log_state)
100                .expect("log-state queue");
101            println!("created queue with log state");
102        }
103        Err(error) => println!("log state unavailable on this OS: {error}"),
104    }
105
106    if device.supports_dynamic_libraries() {
107        let dynamic_path = common::artifact_path("example-dylib.metallib");
108        let dynamic_library = device
109            .new_dynamic_library_with_source(
110                common::DYNAMIC_LIB_SRC,
111                dynamic_path.to_string_lossy().as_ref(),
112            )
113            .expect("dynamic library from source");
114        dynamic_library
115            .serialize_to_file(&dynamic_path)
116            .expect("serialize dynamic library");
117        let reloaded = device
118            .load_dynamic_library(&dynamic_path)
119            .expect("reload dynamic library");
120        println!("dynamic library install name: {}", reloaded.install_name());
121
122        let render_library = device
123            .new_library_with_source(common::RENDER_SRC)
124            .expect("compile render library");
125        let vertex = render_library
126            .new_function("fullscreen_vertex")
127            .expect("vertex function");
128        let fragment = render_library
129            .new_function("solid_fragment")
130            .expect("fragment function");
131        let increment = library
132            .new_function("increment")
133            .expect("increment function");
134
135        let archive_path = common::artifact_path("example-archive.metalarc");
136        let archive = device.new_binary_archive(None).expect("binary archive");
137        archive
138            .add_compute_function(&increment)
139            .expect("archive compute pipeline");
140        archive
141            .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
142            .expect("archive render pipeline");
143        archive
144            .serialize_to_file(&archive_path)
145            .expect("serialize binary archive");
146        let _ = device
147            .new_binary_archive(Some(&archive_path))
148            .expect("reload binary archive");
149        println!("binary archive written to {}", archive_path.display());
150    } else {
151        println!("dynamic libraries unsupported; skipping archive serialization");
152    }
153}
Source

pub fn load_dynamic_library( &self, path: &Path, ) -> Result<DynamicLibrary, String>

Load a serialized Metal dynamic library from path.

§Errors

Returns Metal’s localized file or linker error on failure.

Examples found in repository?
examples/06_resources_and_archives.rs (line 118)
10fn main() {
11    let device = MetalDevice::system_default().expect("Metal device available");
12    println!("device: {}", device.name());
13
14    let queue = device
15        .new_command_queue_with_max_command_buffer_count(4)
16        .expect("bounded command queue");
17    let scratch = unsafe {
18        queue
19            .new_command_buffer_with_unretained_references()
20            .expect("bounded scratch command buffer")
21    };
22    println!("bounded queue scratch status={}", scratch.status());
23
24    let library = device
25        .new_library_with_source(common::COMPUTE_SRC)
26        .expect("compile compute library");
27    let args = library.new_function("use_args").expect("use_args function");
28    let mut argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
29    let argument_buffer = device
30        .new_buffer(
31            argument_encoder.encoded_length(),
32            resource_options::STORAGE_MODE_SHARED,
33        )
34        .expect("argument buffer");
35    let payload = device
36        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
37        .expect("payload buffer");
38    let texture = device
39        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
40        .expect("argument texture");
41    unsafe {
42        let mut binding = argument_encoder
43            .bind_argument_buffer(&argument_buffer, 0)
44            .expect("bind argument buffer");
45        binding
46            .set_buffer_unchecked(&payload, 0, 0)
47            .expect("bind payload");
48        binding
49            .set_texture_unchecked(&texture, 1)
50            .expect("bind texture");
51    }
52    println!(
53        "argument encoder length={} alignment={}",
54        argument_encoder.encoded_length(),
55        argument_encoder.alignment(),
56    );
57
58    let backing = device
59        .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
60        .expect("backing buffer");
61    let buffer_texture = backing
62        .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
63        .expect("buffer-backed texture");
64    println!(
65        "buffer-backed texture {}x{} fmt={}",
66        buffer_texture.width(),
67        buffer_texture.height(),
68        buffer_texture.pixel_format(),
69    );
70
71    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
72        let heap_buffer = heap
73            .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
74            .expect("heap buffer");
75        let heap_texture = heap
76            .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
77            .expect("heap texture");
78        println!(
79            "heap size={} used={} current={} max_available={}",
80            heap.size(),
81            heap.used_size(),
82            heap.current_allocated_size(),
83            heap.max_available_size(256),
84        );
85        println!(
86            "heap buffer len={} heap texture {}x{} purgeable={}",
87            heap_buffer.length(),
88            heap_texture.width(),
89            heap_texture.height(),
90            heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
91        );
92    } else {
93        println!("heaps are unavailable on this device");
94    }
95
96    match device.new_log_state(log_level::INFO, 1_024) {
97        Ok(log_state) => {
98            let _ = device
99                .new_command_queue_with_log_state(4, &log_state)
100                .expect("log-state queue");
101            println!("created queue with log state");
102        }
103        Err(error) => println!("log state unavailable on this OS: {error}"),
104    }
105
106    if device.supports_dynamic_libraries() {
107        let dynamic_path = common::artifact_path("example-dylib.metallib");
108        let dynamic_library = device
109            .new_dynamic_library_with_source(
110                common::DYNAMIC_LIB_SRC,
111                dynamic_path.to_string_lossy().as_ref(),
112            )
113            .expect("dynamic library from source");
114        dynamic_library
115            .serialize_to_file(&dynamic_path)
116            .expect("serialize dynamic library");
117        let reloaded = device
118            .load_dynamic_library(&dynamic_path)
119            .expect("reload dynamic library");
120        println!("dynamic library install name: {}", reloaded.install_name());
121
122        let render_library = device
123            .new_library_with_source(common::RENDER_SRC)
124            .expect("compile render library");
125        let vertex = render_library
126            .new_function("fullscreen_vertex")
127            .expect("vertex function");
128        let fragment = render_library
129            .new_function("solid_fragment")
130            .expect("fragment function");
131        let increment = library
132            .new_function("increment")
133            .expect("increment function");
134
135        let archive_path = common::artifact_path("example-archive.metalarc");
136        let archive = device.new_binary_archive(None).expect("binary archive");
137        archive
138            .add_compute_function(&increment)
139            .expect("archive compute pipeline");
140        archive
141            .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
142            .expect("archive render pipeline");
143        archive
144            .serialize_to_file(&archive_path)
145            .expect("serialize binary archive");
146        let _ = device
147            .new_binary_archive(Some(&archive_path))
148            .expect("reload binary archive");
149        println!("binary archive written to {}", archive_path.display());
150    } else {
151        println!("dynamic libraries unsupported; skipping archive serialization");
152    }
153}
Source

pub fn new_binary_archive( &self, path: Option<&Path>, ) -> Result<BinaryArchive, String>

Create a binary archive, optionally loading it from path first.

§Errors

Returns Metal’s localized archive creation error on failure.

Examples found in repository?
examples/06_resources_and_archives.rs (line 136)
10fn main() {
11    let device = MetalDevice::system_default().expect("Metal device available");
12    println!("device: {}", device.name());
13
14    let queue = device
15        .new_command_queue_with_max_command_buffer_count(4)
16        .expect("bounded command queue");
17    let scratch = unsafe {
18        queue
19            .new_command_buffer_with_unretained_references()
20            .expect("bounded scratch command buffer")
21    };
22    println!("bounded queue scratch status={}", scratch.status());
23
24    let library = device
25        .new_library_with_source(common::COMPUTE_SRC)
26        .expect("compile compute library");
27    let args = library.new_function("use_args").expect("use_args function");
28    let mut argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
29    let argument_buffer = device
30        .new_buffer(
31            argument_encoder.encoded_length(),
32            resource_options::STORAGE_MODE_SHARED,
33        )
34        .expect("argument buffer");
35    let payload = device
36        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
37        .expect("payload buffer");
38    let texture = device
39        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
40        .expect("argument texture");
41    unsafe {
42        let mut binding = argument_encoder
43            .bind_argument_buffer(&argument_buffer, 0)
44            .expect("bind argument buffer");
45        binding
46            .set_buffer_unchecked(&payload, 0, 0)
47            .expect("bind payload");
48        binding
49            .set_texture_unchecked(&texture, 1)
50            .expect("bind texture");
51    }
52    println!(
53        "argument encoder length={} alignment={}",
54        argument_encoder.encoded_length(),
55        argument_encoder.alignment(),
56    );
57
58    let backing = device
59        .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
60        .expect("backing buffer");
61    let buffer_texture = backing
62        .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
63        .expect("buffer-backed texture");
64    println!(
65        "buffer-backed texture {}x{} fmt={}",
66        buffer_texture.width(),
67        buffer_texture.height(),
68        buffer_texture.pixel_format(),
69    );
70
71    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
72        let heap_buffer = heap
73            .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
74            .expect("heap buffer");
75        let heap_texture = heap
76            .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
77            .expect("heap texture");
78        println!(
79            "heap size={} used={} current={} max_available={}",
80            heap.size(),
81            heap.used_size(),
82            heap.current_allocated_size(),
83            heap.max_available_size(256),
84        );
85        println!(
86            "heap buffer len={} heap texture {}x{} purgeable={}",
87            heap_buffer.length(),
88            heap_texture.width(),
89            heap_texture.height(),
90            heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
91        );
92    } else {
93        println!("heaps are unavailable on this device");
94    }
95
96    match device.new_log_state(log_level::INFO, 1_024) {
97        Ok(log_state) => {
98            let _ = device
99                .new_command_queue_with_log_state(4, &log_state)
100                .expect("log-state queue");
101            println!("created queue with log state");
102        }
103        Err(error) => println!("log state unavailable on this OS: {error}"),
104    }
105
106    if device.supports_dynamic_libraries() {
107        let dynamic_path = common::artifact_path("example-dylib.metallib");
108        let dynamic_library = device
109            .new_dynamic_library_with_source(
110                common::DYNAMIC_LIB_SRC,
111                dynamic_path.to_string_lossy().as_ref(),
112            )
113            .expect("dynamic library from source");
114        dynamic_library
115            .serialize_to_file(&dynamic_path)
116            .expect("serialize dynamic library");
117        let reloaded = device
118            .load_dynamic_library(&dynamic_path)
119            .expect("reload dynamic library");
120        println!("dynamic library install name: {}", reloaded.install_name());
121
122        let render_library = device
123            .new_library_with_source(common::RENDER_SRC)
124            .expect("compile render library");
125        let vertex = render_library
126            .new_function("fullscreen_vertex")
127            .expect("vertex function");
128        let fragment = render_library
129            .new_function("solid_fragment")
130            .expect("fragment function");
131        let increment = library
132            .new_function("increment")
133            .expect("increment function");
134
135        let archive_path = common::artifact_path("example-archive.metalarc");
136        let archive = device.new_binary_archive(None).expect("binary archive");
137        archive
138            .add_compute_function(&increment)
139            .expect("archive compute pipeline");
140        archive
141            .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
142            .expect("archive render pipeline");
143        archive
144            .serialize_to_file(&archive_path)
145            .expect("serialize binary archive");
146        let _ = device
147            .new_binary_archive(Some(&archive_path))
148            .expect("reload binary archive");
149        println!("binary archive written to {}", archive_path.display());
150    } else {
151        println!("dynamic libraries unsupported; skipping archive serialization");
152    }
153}
Source

pub fn new_indirect_command_buffer( &self, command_types: usize, max_command_count: usize, max_vertex_buffer_bind_count: usize, max_fragment_buffer_bind_count: usize, max_kernel_buffer_bind_count: usize, options: usize, ) -> Option<IndirectCommandBuffer>

Create a new indirect command buffer.

Examples found in repository?
examples/07_advanced_objects.rs (lines 183-190)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn new_acceleration_structure_with_size( &self, size: usize, ) -> Option<AccelerationStructure>

Allocate storage for a ray-tracing acceleration structure.

Examples found in repository?
examples/07_advanced_objects.rs (line 122)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn new_counter_sample_buffer( &self, counter_set_name: &str, sample_count: usize, storage_mode: usize, label: Option<&str>, ) -> Result<CounterSampleBuffer, String>

Create a counter sample buffer for the named counter set.

§Errors

Returns Metal’s localized counter-sample-buffer error on failure.

Examples found in repository?
examples/07_advanced_objects.rs (line 49)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn new_log_state( &self, level: usize, buffer_size: isize, ) -> Result<LogState, String>

Create a shader log state.

§Errors

Returns Metal’s localized log-state creation error on failure.

Examples found in repository?
examples/06_resources_and_archives.rs (line 96)
10fn main() {
11    let device = MetalDevice::system_default().expect("Metal device available");
12    println!("device: {}", device.name());
13
14    let queue = device
15        .new_command_queue_with_max_command_buffer_count(4)
16        .expect("bounded command queue");
17    let scratch = unsafe {
18        queue
19            .new_command_buffer_with_unretained_references()
20            .expect("bounded scratch command buffer")
21    };
22    println!("bounded queue scratch status={}", scratch.status());
23
24    let library = device
25        .new_library_with_source(common::COMPUTE_SRC)
26        .expect("compile compute library");
27    let args = library.new_function("use_args").expect("use_args function");
28    let mut argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
29    let argument_buffer = device
30        .new_buffer(
31            argument_encoder.encoded_length(),
32            resource_options::STORAGE_MODE_SHARED,
33        )
34        .expect("argument buffer");
35    let payload = device
36        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
37        .expect("payload buffer");
38    let texture = device
39        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
40        .expect("argument texture");
41    unsafe {
42        let mut binding = argument_encoder
43            .bind_argument_buffer(&argument_buffer, 0)
44            .expect("bind argument buffer");
45        binding
46            .set_buffer_unchecked(&payload, 0, 0)
47            .expect("bind payload");
48        binding
49            .set_texture_unchecked(&texture, 1)
50            .expect("bind texture");
51    }
52    println!(
53        "argument encoder length={} alignment={}",
54        argument_encoder.encoded_length(),
55        argument_encoder.alignment(),
56    );
57
58    let backing = device
59        .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
60        .expect("backing buffer");
61    let buffer_texture = backing
62        .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
63        .expect("buffer-backed texture");
64    println!(
65        "buffer-backed texture {}x{} fmt={}",
66        buffer_texture.width(),
67        buffer_texture.height(),
68        buffer_texture.pixel_format(),
69    );
70
71    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
72        let heap_buffer = heap
73            .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
74            .expect("heap buffer");
75        let heap_texture = heap
76            .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
77            .expect("heap texture");
78        println!(
79            "heap size={} used={} current={} max_available={}",
80            heap.size(),
81            heap.used_size(),
82            heap.current_allocated_size(),
83            heap.max_available_size(256),
84        );
85        println!(
86            "heap buffer len={} heap texture {}x{} purgeable={}",
87            heap_buffer.length(),
88            heap_texture.width(),
89            heap_texture.height(),
90            heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
91        );
92    } else {
93        println!("heaps are unavailable on this device");
94    }
95
96    match device.new_log_state(log_level::INFO, 1_024) {
97        Ok(log_state) => {
98            let _ = device
99                .new_command_queue_with_log_state(4, &log_state)
100                .expect("log-state queue");
101            println!("created queue with log state");
102        }
103        Err(error) => println!("log state unavailable on this OS: {error}"),
104    }
105
106    if device.supports_dynamic_libraries() {
107        let dynamic_path = common::artifact_path("example-dylib.metallib");
108        let dynamic_library = device
109            .new_dynamic_library_with_source(
110                common::DYNAMIC_LIB_SRC,
111                dynamic_path.to_string_lossy().as_ref(),
112            )
113            .expect("dynamic library from source");
114        dynamic_library
115            .serialize_to_file(&dynamic_path)
116            .expect("serialize dynamic library");
117        let reloaded = device
118            .load_dynamic_library(&dynamic_path)
119            .expect("reload dynamic library");
120        println!("dynamic library install name: {}", reloaded.install_name());
121
122        let render_library = device
123            .new_library_with_source(common::RENDER_SRC)
124            .expect("compile render library");
125        let vertex = render_library
126            .new_function("fullscreen_vertex")
127            .expect("vertex function");
128        let fragment = render_library
129            .new_function("solid_fragment")
130            .expect("fragment function");
131        let increment = library
132            .new_function("increment")
133            .expect("increment function");
134
135        let archive_path = common::artifact_path("example-archive.metalarc");
136        let archive = device.new_binary_archive(None).expect("binary archive");
137        archive
138            .add_compute_function(&increment)
139            .expect("archive compute pipeline");
140        archive
141            .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
142            .expect("archive render pipeline");
143        archive
144            .serialize_to_file(&archive_path)
145            .expect("serialize binary archive");
146        let _ = device
147            .new_binary_archive(Some(&archive_path))
148            .expect("reload binary archive");
149        println!("binary archive written to {}", archive_path.display());
150    } else {
151        println!("dynamic libraries unsupported; skipping archive serialization");
152    }
153}
Source

pub fn new_residency_set( &self, label: Option<&str>, initial_capacity: usize, ) -> Result<ResidencySet, String>

Create a residency set.

§Errors

Returns Metal’s localized residency-set creation error on failure.

Examples found in repository?
examples/07_advanced_objects.rs (line 196)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn new_argument_encoder_with_descriptors( &self, descriptors: &[ArgumentDescriptor], ) -> Result<ArgumentEncoder, ArgumentEncoderError>

Create an argument encoder from explicit descriptors.

§Errors

Returns descriptor validation failures or native creation failure.

Source

pub fn new_spatial_scaler( &self, descriptor: &SpatialScalerDescriptor, ) -> Option<SpatialScaler>

Create a MTLFXSpatialScaler for this device.

Source

pub fn new_temporal_scaler( &self, descriptor: &TemporalScalerDescriptor, ) -> Option<TemporalScaler>

Create a MTLFXTemporalScaler for this device.

Source

pub fn new_compute_pipeline_state_with_descriptor( &self, descriptor: &ComputePipelineDescriptor<'_>, ) -> Result<ComputePipelineState, String>

Compile a compute pipeline from a public MTLComputePipelineDescriptor wrapper.

§Errors

Returns Metal’s localized pipeline compiler error on failure.

Source

pub fn new_render_pipeline_state_with_descriptor( &self, descriptor: &RenderPipelineDescriptor<'_>, ) -> Result<RenderPipelineState, String>

Compile a render pipeline from a public MTLRenderPipelineDescriptor wrapper.

§Errors

Returns Metal’s localized pipeline compiler error on failure.

Source

pub fn new_tile_render_pipeline_state( &self, descriptor: &TileRenderPipelineDescriptor<'_>, ) -> Result<RenderPipelineState, String>

Compile a tile render pipeline from a public MTLTileRenderPipelineDescriptor wrapper.

§Errors

Returns Metal’s localized pipeline compiler error on failure.

Source

pub fn new_render_pipeline_state( &self, vertex: &MetalFunction, fragment: &MetalFunction, color_pixel_format: usize, sample_count: usize, ) -> Result<RenderPipelineState, String>

Compile a render pipeline state from vertex and fragment functions.

§Errors

Returns Metal’s localized pipeline compiler error on failure.

Examples found in repository?
examples/05_render_and_explicit_encoders.rs (line 93)
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}
Source

pub fn argument_buffers_support(&self) -> usize

Query the device for the supported argument-buffer tier.

Source

pub fn new_depth_stencil_state( &self, descriptor: &DepthStencilDescriptor, ) -> Option<DepthStencilState>

Compile a MTLDepthStencilState from the given descriptor.

Source

pub fn new_sampler_state( &self, descriptor: &SamplerDescriptor, ) -> Option<SamplerState>

Compile a MTLSamplerState from the given descriptor.

Source

pub fn as_ptr(&self) -> *mut c_void

Raw id<MTLDevice> pointer.

Examples found in repository?
examples/01_get_device.rs (line 5)
3fn main() {
4    let device = MetalDevice::system_default().expect("no Metal device found");
5    println!("got Metal device at {:p}", device.as_ptr());
6    assert!(!device.as_ptr().is_null());
7}
Source

pub fn has_unified_memory(&self) -> bool

True if the GPU uses unified memory (Apple Silicon).

Examples found in repository?
examples/02_caps_buffer_texture.rs (line 5)
3fn main() {
4    let d = MetalDevice::system_default().expect("no Metal");
5    println!("unified memory: {}", d.has_unified_memory());
6    println!(
7        "recommended max working set: {} MB",
8        d.recommended_max_working_set_size() / (1024 * 1024)
9    );
10    println!("supports Metal3: {}", d.supports_family(gpu_family::METAL3));
11    println!("supports Apple7: {}", d.supports_family(gpu_family::APPLE7));
12
13    let buf = d
14        .new_buffer(4096, resource_options::STORAGE_MODE_SHARED)
15        .expect("buffer create failed");
16    println!(
17        "buffer {} bytes, cpu_accessible={}",
18        buf.length(),
19        buf.is_cpu_accessible()
20    );
21    unsafe {
22        buf.write_bytes(0, b"hello metal")
23            .expect("write shared buffer");
24    }
25    println!("wrote {} bytes", b"hello metal".len());
26
27    let tx = d
28        .new_texture(TextureDescriptor::new_2d(
29            256,
30            256,
31            pixel_format::BGRA8UNORM,
32        ))
33        .expect("texture create failed");
34    println!(
35        "texture {}x{} fmt={}",
36        tx.width(),
37        tx.height(),
38        tx.pixel_format()
39    );
40}
More examples
Hide additional examples
examples/04_compute_shader.rs (line 23)
21fn main() {
22    let device = MetalDevice::system_default().expect("MTLCreateSystemDefaultDevice");
23    println!("Device unified={}", device.has_unified_memory());
24
25    let lib = device
26        .new_library_with_source(KERNEL_SRC)
27        .expect("compile MSL source");
28    println!("✅ Compiled library {:p}", lib.as_ptr());
29
30    let func = lib.new_function("mul2").expect("locate function 'mul2'");
31    println!("✅ Found function mul2 {:p}", func.as_ptr());
32
33    let pso = device
34        .new_compute_pipeline_state(&func)
35        .expect("build compute pipeline state");
36    println!("✅ Compute pipeline state {:p}", pso.as_ptr());
37
38    let byte_len = N * core::mem::size_of::<f32>();
39    let buffer = device
40        .new_buffer(byte_len, resource_options::STORAGE_MODE_SHARED)
41        .expect("allocate buffer");
42
43    {
44        let mut mapping = unsafe { buffer.map_write().expect("map compute input") };
45        for (i, bytes) in mapping.chunks_exact_mut(4).take(N).enumerate() {
46            bytes.copy_from_slice(&(i as f32).to_ne_bytes());
47        }
48        let input: Vec<f32> = mapping
49            .chunks_exact(4)
50            .take(N)
51            .map(|bytes| f32::from_ne_bytes(bytes.try_into().expect("four-byte float")))
52            .collect();
53        drop(mapping);
54        println!("Input : {input:?}");
55    }
56
57    let queue = device.new_command_queue().expect("MTLCommandQueue");
58    let cb = queue.new_command_buffer().expect("MTLCommandBuffer");
59    cb.dispatch_compute_1d(&pso, &[&buffer], N, 1)
60        .expect("dispatch compute");
61    cb.commit().expect("commit compute");
62    cb.wait_until_completed().expect("complete compute");
63
64    let mapping = unsafe { buffer.map_read().expect("map compute output") };
65    let output: Vec<f32> = mapping
66        .chunks_exact(4)
67        .take(N)
68        .map(|bytes| f32::from_ne_bytes(bytes.try_into().expect("four-byte float")))
69        .collect();
70    drop(mapping);
71    println!("Output: {output:?}");
72
73    for (i, &v) in output.iter().enumerate() {
74        let expected = (i as f32) * 2.0;
75        assert_eq!(v, expected, "element {i} expected {expected} got {v}");
76    }
77    println!("✅ All {N} elements correctly doubled by the GPU kernel");
78}
Source

pub fn recommended_max_working_set_size(&self) -> u64

Recommended maximum working-set size in bytes.

Examples found in repository?
examples/02_caps_buffer_texture.rs (line 8)
3fn main() {
4    let d = MetalDevice::system_default().expect("no Metal");
5    println!("unified memory: {}", d.has_unified_memory());
6    println!(
7        "recommended max working set: {} MB",
8        d.recommended_max_working_set_size() / (1024 * 1024)
9    );
10    println!("supports Metal3: {}", d.supports_family(gpu_family::METAL3));
11    println!("supports Apple7: {}", d.supports_family(gpu_family::APPLE7));
12
13    let buf = d
14        .new_buffer(4096, resource_options::STORAGE_MODE_SHARED)
15        .expect("buffer create failed");
16    println!(
17        "buffer {} bytes, cpu_accessible={}",
18        buf.length(),
19        buf.is_cpu_accessible()
20    );
21    unsafe {
22        buf.write_bytes(0, b"hello metal")
23            .expect("write shared buffer");
24    }
25    println!("wrote {} bytes", b"hello metal".len());
26
27    let tx = d
28        .new_texture(TextureDescriptor::new_2d(
29            256,
30            256,
31            pixel_format::BGRA8UNORM,
32        ))
33        .expect("texture create failed");
34    println!(
35        "texture {}x{} fmt={}",
36        tx.width(),
37        tx.height(),
38        tx.pixel_format()
39    );
40}
Source

pub fn supports_family(&self, family: i64) -> bool

True if this device supports the requested feature family — see gpu_family.

Examples found in repository?
examples/02_caps_buffer_texture.rs (line 10)
3fn main() {
4    let d = MetalDevice::system_default().expect("no Metal");
5    println!("unified memory: {}", d.has_unified_memory());
6    println!(
7        "recommended max working set: {} MB",
8        d.recommended_max_working_set_size() / (1024 * 1024)
9    );
10    println!("supports Metal3: {}", d.supports_family(gpu_family::METAL3));
11    println!("supports Apple7: {}", d.supports_family(gpu_family::APPLE7));
12
13    let buf = d
14        .new_buffer(4096, resource_options::STORAGE_MODE_SHARED)
15        .expect("buffer create failed");
16    println!(
17        "buffer {} bytes, cpu_accessible={}",
18        buf.length(),
19        buf.is_cpu_accessible()
20    );
21    unsafe {
22        buf.write_bytes(0, b"hello metal")
23            .expect("write shared buffer");
24    }
25    println!("wrote {} bytes", b"hello metal".len());
26
27    let tx = d
28        .new_texture(TextureDescriptor::new_2d(
29            256,
30            256,
31            pixel_format::BGRA8UNORM,
32        ))
33        .expect("texture create failed");
34    println!(
35        "texture {}x{} fmt={}",
36        tx.width(),
37        tx.height(),
38        tx.pixel_format()
39    );
40}
Source

pub fn new_buffer(&self, length: usize, options: usize) -> Option<MetalBuffer>

Allocate a GPU-visible buffer of length bytes. options is an MTLResourceOptions bitmask (see resource_options).

Examples found in repository?
examples/03_command_buffer_blit.rs (line 7)
3fn main() {
4    let dev = MetalDevice::system_default().expect("no Metal");
5    let queue = dev.new_command_queue().expect("queue");
6    let src = dev
7        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
8        .expect("src");
9    let dst = dev
10        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
11        .expect("dst");
12    unsafe {
13        src.write_bytes(0, b"hello GPU blit from apple-metal-rs!!!!!")
14            .expect("write source buffer");
15    }
16
17    let cb = queue.new_command_buffer().expect("cb");
18    cb.blit_copy_buffer(&src, 0, &dst, 0, 64)
19        .expect("encode blit copy");
20    cb.commit().expect("commit blit");
21    cb.wait_until_completed().expect("complete blit");
22
23    let bytes = {
24        let mapping = unsafe { dst.map_read().expect("map destination") };
25        let bytes = mapping[..40].to_vec();
26        drop(mapping);
27        bytes
28    };
29    let s = String::from_utf8_lossy(&bytes);
30    println!("GPU blit result: {s:?}");
31    assert!(s.starts_with("hello GPU blit"));
32}
More examples
Hide additional examples
examples/02_caps_buffer_texture.rs (line 14)
3fn main() {
4    let d = MetalDevice::system_default().expect("no Metal");
5    println!("unified memory: {}", d.has_unified_memory());
6    println!(
7        "recommended max working set: {} MB",
8        d.recommended_max_working_set_size() / (1024 * 1024)
9    );
10    println!("supports Metal3: {}", d.supports_family(gpu_family::METAL3));
11    println!("supports Apple7: {}", d.supports_family(gpu_family::APPLE7));
12
13    let buf = d
14        .new_buffer(4096, resource_options::STORAGE_MODE_SHARED)
15        .expect("buffer create failed");
16    println!(
17        "buffer {} bytes, cpu_accessible={}",
18        buf.length(),
19        buf.is_cpu_accessible()
20    );
21    unsafe {
22        buf.write_bytes(0, b"hello metal")
23            .expect("write shared buffer");
24    }
25    println!("wrote {} bytes", b"hello metal".len());
26
27    let tx = d
28        .new_texture(TextureDescriptor::new_2d(
29            256,
30            256,
31            pixel_format::BGRA8UNORM,
32        ))
33        .expect("texture create failed");
34    println!(
35        "texture {}x{} fmt={}",
36        tx.width(),
37        tx.height(),
38        tx.pixel_format()
39    );
40}
examples/04_compute_shader.rs (line 40)
21fn main() {
22    let device = MetalDevice::system_default().expect("MTLCreateSystemDefaultDevice");
23    println!("Device unified={}", device.has_unified_memory());
24
25    let lib = device
26        .new_library_with_source(KERNEL_SRC)
27        .expect("compile MSL source");
28    println!("✅ Compiled library {:p}", lib.as_ptr());
29
30    let func = lib.new_function("mul2").expect("locate function 'mul2'");
31    println!("✅ Found function mul2 {:p}", func.as_ptr());
32
33    let pso = device
34        .new_compute_pipeline_state(&func)
35        .expect("build compute pipeline state");
36    println!("✅ Compute pipeline state {:p}", pso.as_ptr());
37
38    let byte_len = N * core::mem::size_of::<f32>();
39    let buffer = device
40        .new_buffer(byte_len, resource_options::STORAGE_MODE_SHARED)
41        .expect("allocate buffer");
42
43    {
44        let mut mapping = unsafe { buffer.map_write().expect("map compute input") };
45        for (i, bytes) in mapping.chunks_exact_mut(4).take(N).enumerate() {
46            bytes.copy_from_slice(&(i as f32).to_ne_bytes());
47        }
48        let input: Vec<f32> = mapping
49            .chunks_exact(4)
50            .take(N)
51            .map(|bytes| f32::from_ne_bytes(bytes.try_into().expect("four-byte float")))
52            .collect();
53        drop(mapping);
54        println!("Input : {input:?}");
55    }
56
57    let queue = device.new_command_queue().expect("MTLCommandQueue");
58    let cb = queue.new_command_buffer().expect("MTLCommandBuffer");
59    cb.dispatch_compute_1d(&pso, &[&buffer], N, 1)
60        .expect("dispatch compute");
61    cb.commit().expect("commit compute");
62    cb.wait_until_completed().expect("complete compute");
63
64    let mapping = unsafe { buffer.map_read().expect("map compute output") };
65    let output: Vec<f32> = mapping
66        .chunks_exact(4)
67        .take(N)
68        .map(|bytes| f32::from_ne_bytes(bytes.try_into().expect("four-byte float")))
69        .collect();
70    drop(mapping);
71    println!("Output: {output:?}");
72
73    for (i, &v) in output.iter().enumerate() {
74        let expected = (i as f32) * 2.0;
75        assert_eq!(v, expected, "element {i} expected {expected} got {v}");
76    }
77    println!("✅ All {N} elements correctly doubled by the GPU kernel");
78}
examples/05_render_and_explicit_encoders.rs (line 28)
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}
examples/06_resources_and_archives.rs (lines 30-33)
10fn main() {
11    let device = MetalDevice::system_default().expect("Metal device available");
12    println!("device: {}", device.name());
13
14    let queue = device
15        .new_command_queue_with_max_command_buffer_count(4)
16        .expect("bounded command queue");
17    let scratch = unsafe {
18        queue
19            .new_command_buffer_with_unretained_references()
20            .expect("bounded scratch command buffer")
21    };
22    println!("bounded queue scratch status={}", scratch.status());
23
24    let library = device
25        .new_library_with_source(common::COMPUTE_SRC)
26        .expect("compile compute library");
27    let args = library.new_function("use_args").expect("use_args function");
28    let mut argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
29    let argument_buffer = device
30        .new_buffer(
31            argument_encoder.encoded_length(),
32            resource_options::STORAGE_MODE_SHARED,
33        )
34        .expect("argument buffer");
35    let payload = device
36        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
37        .expect("payload buffer");
38    let texture = device
39        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
40        .expect("argument texture");
41    unsafe {
42        let mut binding = argument_encoder
43            .bind_argument_buffer(&argument_buffer, 0)
44            .expect("bind argument buffer");
45        binding
46            .set_buffer_unchecked(&payload, 0, 0)
47            .expect("bind payload");
48        binding
49            .set_texture_unchecked(&texture, 1)
50            .expect("bind texture");
51    }
52    println!(
53        "argument encoder length={} alignment={}",
54        argument_encoder.encoded_length(),
55        argument_encoder.alignment(),
56    );
57
58    let backing = device
59        .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
60        .expect("backing buffer");
61    let buffer_texture = backing
62        .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
63        .expect("buffer-backed texture");
64    println!(
65        "buffer-backed texture {}x{} fmt={}",
66        buffer_texture.width(),
67        buffer_texture.height(),
68        buffer_texture.pixel_format(),
69    );
70
71    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
72        let heap_buffer = heap
73            .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
74            .expect("heap buffer");
75        let heap_texture = heap
76            .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
77            .expect("heap texture");
78        println!(
79            "heap size={} used={} current={} max_available={}",
80            heap.size(),
81            heap.used_size(),
82            heap.current_allocated_size(),
83            heap.max_available_size(256),
84        );
85        println!(
86            "heap buffer len={} heap texture {}x{} purgeable={}",
87            heap_buffer.length(),
88            heap_texture.width(),
89            heap_texture.height(),
90            heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
91        );
92    } else {
93        println!("heaps are unavailable on this device");
94    }
95
96    match device.new_log_state(log_level::INFO, 1_024) {
97        Ok(log_state) => {
98            let _ = device
99                .new_command_queue_with_log_state(4, &log_state)
100                .expect("log-state queue");
101            println!("created queue with log state");
102        }
103        Err(error) => println!("log state unavailable on this OS: {error}"),
104    }
105
106    if device.supports_dynamic_libraries() {
107        let dynamic_path = common::artifact_path("example-dylib.metallib");
108        let dynamic_library = device
109            .new_dynamic_library_with_source(
110                common::DYNAMIC_LIB_SRC,
111                dynamic_path.to_string_lossy().as_ref(),
112            )
113            .expect("dynamic library from source");
114        dynamic_library
115            .serialize_to_file(&dynamic_path)
116            .expect("serialize dynamic library");
117        let reloaded = device
118            .load_dynamic_library(&dynamic_path)
119            .expect("reload dynamic library");
120        println!("dynamic library install name: {}", reloaded.install_name());
121
122        let render_library = device
123            .new_library_with_source(common::RENDER_SRC)
124            .expect("compile render library");
125        let vertex = render_library
126            .new_function("fullscreen_vertex")
127            .expect("vertex function");
128        let fragment = render_library
129            .new_function("solid_fragment")
130            .expect("fragment function");
131        let increment = library
132            .new_function("increment")
133            .expect("increment function");
134
135        let archive_path = common::artifact_path("example-archive.metalarc");
136        let archive = device.new_binary_archive(None).expect("binary archive");
137        archive
138            .add_compute_function(&increment)
139            .expect("archive compute pipeline");
140        archive
141            .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
142            .expect("archive render pipeline");
143        archive
144            .serialize_to_file(&archive_path)
145            .expect("serialize binary archive");
146        let _ = device
147            .new_binary_archive(Some(&archive_path))
148            .expect("reload binary archive");
149        println!("binary archive written to {}", archive_path.display());
150    } else {
151        println!("dynamic libraries unsupported; skipping archive serialization");
152    }
153}
examples/07_advanced_objects.rs (line 57)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn new_texture(&self, descriptor: TextureDescriptor) -> Option<MetalTexture>

Allocate a fresh MTLTexture matching descriptor.

Examples found in repository?
examples/02_caps_buffer_texture.rs (lines 28-32)
3fn main() {
4    let d = MetalDevice::system_default().expect("no Metal");
5    println!("unified memory: {}", d.has_unified_memory());
6    println!(
7        "recommended max working set: {} MB",
8        d.recommended_max_working_set_size() / (1024 * 1024)
9    );
10    println!("supports Metal3: {}", d.supports_family(gpu_family::METAL3));
11    println!("supports Apple7: {}", d.supports_family(gpu_family::APPLE7));
12
13    let buf = d
14        .new_buffer(4096, resource_options::STORAGE_MODE_SHARED)
15        .expect("buffer create failed");
16    println!(
17        "buffer {} bytes, cpu_accessible={}",
18        buf.length(),
19        buf.is_cpu_accessible()
20    );
21    unsafe {
22        buf.write_bytes(0, b"hello metal")
23            .expect("write shared buffer");
24    }
25    println!("wrote {} bytes", b"hello metal".len());
26
27    let tx = d
28        .new_texture(TextureDescriptor::new_2d(
29            256,
30            256,
31            pixel_format::BGRA8UNORM,
32        ))
33        .expect("texture create failed");
34    println!(
35        "texture {}x{} fmt={}",
36        tx.width(),
37        tx.height(),
38        tx.pixel_format()
39    );
40}
More examples
Hide additional examples
examples/05_render_and_explicit_encoders.rs (line 98)
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}
examples/06_resources_and_archives.rs (line 39)
10fn main() {
11    let device = MetalDevice::system_default().expect("Metal device available");
12    println!("device: {}", device.name());
13
14    let queue = device
15        .new_command_queue_with_max_command_buffer_count(4)
16        .expect("bounded command queue");
17    let scratch = unsafe {
18        queue
19            .new_command_buffer_with_unretained_references()
20            .expect("bounded scratch command buffer")
21    };
22    println!("bounded queue scratch status={}", scratch.status());
23
24    let library = device
25        .new_library_with_source(common::COMPUTE_SRC)
26        .expect("compile compute library");
27    let args = library.new_function("use_args").expect("use_args function");
28    let mut argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
29    let argument_buffer = device
30        .new_buffer(
31            argument_encoder.encoded_length(),
32            resource_options::STORAGE_MODE_SHARED,
33        )
34        .expect("argument buffer");
35    let payload = device
36        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
37        .expect("payload buffer");
38    let texture = device
39        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
40        .expect("argument texture");
41    unsafe {
42        let mut binding = argument_encoder
43            .bind_argument_buffer(&argument_buffer, 0)
44            .expect("bind argument buffer");
45        binding
46            .set_buffer_unchecked(&payload, 0, 0)
47            .expect("bind payload");
48        binding
49            .set_texture_unchecked(&texture, 1)
50            .expect("bind texture");
51    }
52    println!(
53        "argument encoder length={} alignment={}",
54        argument_encoder.encoded_length(),
55        argument_encoder.alignment(),
56    );
57
58    let backing = device
59        .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
60        .expect("backing buffer");
61    let buffer_texture = backing
62        .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
63        .expect("buffer-backed texture");
64    println!(
65        "buffer-backed texture {}x{} fmt={}",
66        buffer_texture.width(),
67        buffer_texture.height(),
68        buffer_texture.pixel_format(),
69    );
70
71    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
72        let heap_buffer = heap
73            .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
74            .expect("heap buffer");
75        let heap_texture = heap
76            .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
77            .expect("heap texture");
78        println!(
79            "heap size={} used={} current={} max_available={}",
80            heap.size(),
81            heap.used_size(),
82            heap.current_allocated_size(),
83            heap.max_available_size(256),
84        );
85        println!(
86            "heap buffer len={} heap texture {}x{} purgeable={}",
87            heap_buffer.length(),
88            heap_texture.width(),
89            heap_texture.height(),
90            heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
91        );
92    } else {
93        println!("heaps are unavailable on this device");
94    }
95
96    match device.new_log_state(log_level::INFO, 1_024) {
97        Ok(log_state) => {
98            let _ = device
99                .new_command_queue_with_log_state(4, &log_state)
100                .expect("log-state queue");
101            println!("created queue with log state");
102        }
103        Err(error) => println!("log state unavailable on this OS: {error}"),
104    }
105
106    if device.supports_dynamic_libraries() {
107        let dynamic_path = common::artifact_path("example-dylib.metallib");
108        let dynamic_library = device
109            .new_dynamic_library_with_source(
110                common::DYNAMIC_LIB_SRC,
111                dynamic_path.to_string_lossy().as_ref(),
112            )
113            .expect("dynamic library from source");
114        dynamic_library
115            .serialize_to_file(&dynamic_path)
116            .expect("serialize dynamic library");
117        let reloaded = device
118            .load_dynamic_library(&dynamic_path)
119            .expect("reload dynamic library");
120        println!("dynamic library install name: {}", reloaded.install_name());
121
122        let render_library = device
123            .new_library_with_source(common::RENDER_SRC)
124            .expect("compile render library");
125        let vertex = render_library
126            .new_function("fullscreen_vertex")
127            .expect("vertex function");
128        let fragment = render_library
129            .new_function("solid_fragment")
130            .expect("fragment function");
131        let increment = library
132            .new_function("increment")
133            .expect("increment function");
134
135        let archive_path = common::artifact_path("example-archive.metalarc");
136        let archive = device.new_binary_archive(None).expect("binary archive");
137        archive
138            .add_compute_function(&increment)
139            .expect("archive compute pipeline");
140        archive
141            .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
142            .expect("archive render pipeline");
143        archive
144            .serialize_to_file(&archive_path)
145            .expect("serialize binary archive");
146        let _ = device
147            .new_binary_archive(Some(&archive_path))
148            .expect("reload binary archive");
149        println!("binary archive written to {}", archive_path.display());
150    } else {
151        println!("dynamic libraries unsupported; skipping archive serialization");
152    }
153}
examples/07_advanced_objects.rs (lines 132-136)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn new_command_queue(&self) -> Option<CommandQueue>

Create a new MTLCommandQueue to schedule GPU work.

Examples found in repository?
examples/03_command_buffer_blit.rs (line 5)
3fn main() {
4    let dev = MetalDevice::system_default().expect("no Metal");
5    let queue = dev.new_command_queue().expect("queue");
6    let src = dev
7        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
8        .expect("src");
9    let dst = dev
10        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
11        .expect("dst");
12    unsafe {
13        src.write_bytes(0, b"hello GPU blit from apple-metal-rs!!!!!")
14            .expect("write source buffer");
15    }
16
17    let cb = queue.new_command_buffer().expect("cb");
18    cb.blit_copy_buffer(&src, 0, &dst, 0, 64)
19        .expect("encode blit copy");
20    cb.commit().expect("commit blit");
21    cb.wait_until_completed().expect("complete blit");
22
23    let bytes = {
24        let mapping = unsafe { dst.map_read().expect("map destination") };
25        let bytes = mapping[..40].to_vec();
26        drop(mapping);
27        bytes
28    };
29    let s = String::from_utf8_lossy(&bytes);
30    println!("GPU blit result: {s:?}");
31    assert!(s.starts_with("hello GPU blit"));
32}
More examples
Hide additional examples
examples/04_compute_shader.rs (line 57)
21fn main() {
22    let device = MetalDevice::system_default().expect("MTLCreateSystemDefaultDevice");
23    println!("Device unified={}", device.has_unified_memory());
24
25    let lib = device
26        .new_library_with_source(KERNEL_SRC)
27        .expect("compile MSL source");
28    println!("✅ Compiled library {:p}", lib.as_ptr());
29
30    let func = lib.new_function("mul2").expect("locate function 'mul2'");
31    println!("✅ Found function mul2 {:p}", func.as_ptr());
32
33    let pso = device
34        .new_compute_pipeline_state(&func)
35        .expect("build compute pipeline state");
36    println!("✅ Compute pipeline state {:p}", pso.as_ptr());
37
38    let byte_len = N * core::mem::size_of::<f32>();
39    let buffer = device
40        .new_buffer(byte_len, resource_options::STORAGE_MODE_SHARED)
41        .expect("allocate buffer");
42
43    {
44        let mut mapping = unsafe { buffer.map_write().expect("map compute input") };
45        for (i, bytes) in mapping.chunks_exact_mut(4).take(N).enumerate() {
46            bytes.copy_from_slice(&(i as f32).to_ne_bytes());
47        }
48        let input: Vec<f32> = mapping
49            .chunks_exact(4)
50            .take(N)
51            .map(|bytes| f32::from_ne_bytes(bytes.try_into().expect("four-byte float")))
52            .collect();
53        drop(mapping);
54        println!("Input : {input:?}");
55    }
56
57    let queue = device.new_command_queue().expect("MTLCommandQueue");
58    let cb = queue.new_command_buffer().expect("MTLCommandBuffer");
59    cb.dispatch_compute_1d(&pso, &[&buffer], N, 1)
60        .expect("dispatch compute");
61    cb.commit().expect("commit compute");
62    cb.wait_until_completed().expect("complete compute");
63
64    let mapping = unsafe { buffer.map_read().expect("map compute output") };
65    let output: Vec<f32> = mapping
66        .chunks_exact(4)
67        .take(N)
68        .map(|bytes| f32::from_ne_bytes(bytes.try_into().expect("four-byte float")))
69        .collect();
70    drop(mapping);
71    println!("Output: {output:?}");
72
73    for (i, &v) in output.iter().enumerate() {
74        let expected = (i as f32) * 2.0;
75        assert_eq!(v, expected, "element {i} expected {expected} got {v}");
76    }
77    println!("✅ All {N} elements correctly doubled by the GPU kernel");
78}
examples/05_render_and_explicit_encoders.rs (line 19)
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}
examples/07_advanced_objects.rs (line 13)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn new_library_with_source( &self, source: &str, ) -> Result<MetalLibrary, String>

Compile a Metal Shading Language source string into a runtime MTLLibrary. On error, returns the localized Metal compiler diagnostic.

§Errors

Returns the Metal compiler’s localized error string on failure.

Examples found in repository?
examples/04_compute_shader.rs (line 26)
21fn main() {
22    let device = MetalDevice::system_default().expect("MTLCreateSystemDefaultDevice");
23    println!("Device unified={}", device.has_unified_memory());
24
25    let lib = device
26        .new_library_with_source(KERNEL_SRC)
27        .expect("compile MSL source");
28    println!("✅ Compiled library {:p}", lib.as_ptr());
29
30    let func = lib.new_function("mul2").expect("locate function 'mul2'");
31    println!("✅ Found function mul2 {:p}", func.as_ptr());
32
33    let pso = device
34        .new_compute_pipeline_state(&func)
35        .expect("build compute pipeline state");
36    println!("✅ Compute pipeline state {:p}", pso.as_ptr());
37
38    let byte_len = N * core::mem::size_of::<f32>();
39    let buffer = device
40        .new_buffer(byte_len, resource_options::STORAGE_MODE_SHARED)
41        .expect("allocate buffer");
42
43    {
44        let mut mapping = unsafe { buffer.map_write().expect("map compute input") };
45        for (i, bytes) in mapping.chunks_exact_mut(4).take(N).enumerate() {
46            bytes.copy_from_slice(&(i as f32).to_ne_bytes());
47        }
48        let input: Vec<f32> = mapping
49            .chunks_exact(4)
50            .take(N)
51            .map(|bytes| f32::from_ne_bytes(bytes.try_into().expect("four-byte float")))
52            .collect();
53        drop(mapping);
54        println!("Input : {input:?}");
55    }
56
57    let queue = device.new_command_queue().expect("MTLCommandQueue");
58    let cb = queue.new_command_buffer().expect("MTLCommandBuffer");
59    cb.dispatch_compute_1d(&pso, &[&buffer], N, 1)
60        .expect("dispatch compute");
61    cb.commit().expect("commit compute");
62    cb.wait_until_completed().expect("complete compute");
63
64    let mapping = unsafe { buffer.map_read().expect("map compute output") };
65    let output: Vec<f32> = mapping
66        .chunks_exact(4)
67        .take(N)
68        .map(|bytes| f32::from_ne_bytes(bytes.try_into().expect("four-byte float")))
69        .collect();
70    drop(mapping);
71    println!("Output: {output:?}");
72
73    for (i, &v) in output.iter().enumerate() {
74        let expected = (i as f32) * 2.0;
75        assert_eq!(v, expected, "element {i} expected {expected} got {v}");
76    }
77    println!("✅ All {N} elements correctly doubled by the GPU kernel");
78}
More examples
Hide additional examples
examples/05_render_and_explicit_encoders.rs (line 52)
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}
examples/06_resources_and_archives.rs (line 25)
10fn main() {
11    let device = MetalDevice::system_default().expect("Metal device available");
12    println!("device: {}", device.name());
13
14    let queue = device
15        .new_command_queue_with_max_command_buffer_count(4)
16        .expect("bounded command queue");
17    let scratch = unsafe {
18        queue
19            .new_command_buffer_with_unretained_references()
20            .expect("bounded scratch command buffer")
21    };
22    println!("bounded queue scratch status={}", scratch.status());
23
24    let library = device
25        .new_library_with_source(common::COMPUTE_SRC)
26        .expect("compile compute library");
27    let args = library.new_function("use_args").expect("use_args function");
28    let mut argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
29    let argument_buffer = device
30        .new_buffer(
31            argument_encoder.encoded_length(),
32            resource_options::STORAGE_MODE_SHARED,
33        )
34        .expect("argument buffer");
35    let payload = device
36        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
37        .expect("payload buffer");
38    let texture = device
39        .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
40        .expect("argument texture");
41    unsafe {
42        let mut binding = argument_encoder
43            .bind_argument_buffer(&argument_buffer, 0)
44            .expect("bind argument buffer");
45        binding
46            .set_buffer_unchecked(&payload, 0, 0)
47            .expect("bind payload");
48        binding
49            .set_texture_unchecked(&texture, 1)
50            .expect("bind texture");
51    }
52    println!(
53        "argument encoder length={} alignment={}",
54        argument_encoder.encoded_length(),
55        argument_encoder.alignment(),
56    );
57
58    let backing = device
59        .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
60        .expect("backing buffer");
61    let buffer_texture = backing
62        .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
63        .expect("buffer-backed texture");
64    println!(
65        "buffer-backed texture {}x{} fmt={}",
66        buffer_texture.width(),
67        buffer_texture.height(),
68        buffer_texture.pixel_format(),
69    );
70
71    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
72        let heap_buffer = heap
73            .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
74            .expect("heap buffer");
75        let heap_texture = heap
76            .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
77            .expect("heap texture");
78        println!(
79            "heap size={} used={} current={} max_available={}",
80            heap.size(),
81            heap.used_size(),
82            heap.current_allocated_size(),
83            heap.max_available_size(256),
84        );
85        println!(
86            "heap buffer len={} heap texture {}x{} purgeable={}",
87            heap_buffer.length(),
88            heap_texture.width(),
89            heap_texture.height(),
90            heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
91        );
92    } else {
93        println!("heaps are unavailable on this device");
94    }
95
96    match device.new_log_state(log_level::INFO, 1_024) {
97        Ok(log_state) => {
98            let _ = device
99                .new_command_queue_with_log_state(4, &log_state)
100                .expect("log-state queue");
101            println!("created queue with log state");
102        }
103        Err(error) => println!("log state unavailable on this OS: {error}"),
104    }
105
106    if device.supports_dynamic_libraries() {
107        let dynamic_path = common::artifact_path("example-dylib.metallib");
108        let dynamic_library = device
109            .new_dynamic_library_with_source(
110                common::DYNAMIC_LIB_SRC,
111                dynamic_path.to_string_lossy().as_ref(),
112            )
113            .expect("dynamic library from source");
114        dynamic_library
115            .serialize_to_file(&dynamic_path)
116            .expect("serialize dynamic library");
117        let reloaded = device
118            .load_dynamic_library(&dynamic_path)
119            .expect("reload dynamic library");
120        println!("dynamic library install name: {}", reloaded.install_name());
121
122        let render_library = device
123            .new_library_with_source(common::RENDER_SRC)
124            .expect("compile render library");
125        let vertex = render_library
126            .new_function("fullscreen_vertex")
127            .expect("vertex function");
128        let fragment = render_library
129            .new_function("solid_fragment")
130            .expect("fragment function");
131        let increment = library
132            .new_function("increment")
133            .expect("increment function");
134
135        let archive_path = common::artifact_path("example-archive.metalarc");
136        let archive = device.new_binary_archive(None).expect("binary archive");
137        archive
138            .add_compute_function(&increment)
139            .expect("archive compute pipeline");
140        archive
141            .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
142            .expect("archive render pipeline");
143        archive
144            .serialize_to_file(&archive_path)
145            .expect("serialize binary archive");
146        let _ = device
147            .new_binary_archive(Some(&archive_path))
148            .expect("reload binary archive");
149        println!("binary archive written to {}", archive_path.display());
150    } else {
151        println!("dynamic libraries unsupported; skipping archive serialization");
152    }
153}
examples/07_advanced_objects.rs (line 104)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}
Source

pub fn new_compute_pipeline_state( &self, function: &MetalFunction, ) -> Result<ComputePipelineState, String>

Compile a kernel into a MTLComputePipelineState ready for dispatch on a command buffer.

§Errors

Returns the Metal pipeline compiler’s localized error string on failure.

Examples found in repository?
examples/04_compute_shader.rs (line 34)
21fn main() {
22    let device = MetalDevice::system_default().expect("MTLCreateSystemDefaultDevice");
23    println!("Device unified={}", device.has_unified_memory());
24
25    let lib = device
26        .new_library_with_source(KERNEL_SRC)
27        .expect("compile MSL source");
28    println!("✅ Compiled library {:p}", lib.as_ptr());
29
30    let func = lib.new_function("mul2").expect("locate function 'mul2'");
31    println!("✅ Found function mul2 {:p}", func.as_ptr());
32
33    let pso = device
34        .new_compute_pipeline_state(&func)
35        .expect("build compute pipeline state");
36    println!("✅ Compute pipeline state {:p}", pso.as_ptr());
37
38    let byte_len = N * core::mem::size_of::<f32>();
39    let buffer = device
40        .new_buffer(byte_len, resource_options::STORAGE_MODE_SHARED)
41        .expect("allocate buffer");
42
43    {
44        let mut mapping = unsafe { buffer.map_write().expect("map compute input") };
45        for (i, bytes) in mapping.chunks_exact_mut(4).take(N).enumerate() {
46            bytes.copy_from_slice(&(i as f32).to_ne_bytes());
47        }
48        let input: Vec<f32> = mapping
49            .chunks_exact(4)
50            .take(N)
51            .map(|bytes| f32::from_ne_bytes(bytes.try_into().expect("four-byte float")))
52            .collect();
53        drop(mapping);
54        println!("Input : {input:?}");
55    }
56
57    let queue = device.new_command_queue().expect("MTLCommandQueue");
58    let cb = queue.new_command_buffer().expect("MTLCommandBuffer");
59    cb.dispatch_compute_1d(&pso, &[&buffer], N, 1)
60        .expect("dispatch compute");
61    cb.commit().expect("commit compute");
62    cb.wait_until_completed().expect("complete compute");
63
64    let mapping = unsafe { buffer.map_read().expect("map compute output") };
65    let output: Vec<f32> = mapping
66        .chunks_exact(4)
67        .take(N)
68        .map(|bytes| f32::from_ne_bytes(bytes.try_into().expect("four-byte float")))
69        .collect();
70    drop(mapping);
71    println!("Output: {output:?}");
72
73    for (i, &v) in output.iter().enumerate() {
74        let expected = (i as f32) * 2.0;
75        assert_eq!(v, expected, "element {i} expected {expected} got {v}");
76    }
77    println!("✅ All {N} elements correctly doubled by the GPU kernel");
78}
More examples
Hide additional examples
examples/05_render_and_explicit_encoders.rs (line 58)
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}
examples/07_advanced_objects.rs (line 110)
11fn main() {
12    let device = MetalDevice::system_default().expect("Metal device available");
13    let queue = device.new_command_queue().expect("command queue");
14    let counter_sets = device.counter_set_names();
15    println!("counter sets: {counter_sets:?}");
16
17    if let Some(event) = device.new_shared_event() {
18        event.set_signaled_value(1);
19        println!("event signaled value={}", event.signaled_value());
20        let signal = queue
21            .new_command_buffer()
22            .expect("event signal command buffer");
23        signal
24            .encode_signal_event(&event, 2)
25            .expect("encode event signal");
26        signal.commit().expect("commit event signal");
27        signal
28            .wait_until_completed()
29            .expect("complete event signal");
30        println!(
31            "event reached value 2: {}",
32            event.wait_until_signaled_value(2, 1_000),
33        );
34
35        let wait = queue
36            .new_command_buffer()
37            .expect("event wait command buffer");
38        wait.encode_wait_for_event(&event, 2)
39            .expect("encode event wait");
40        wait.commit().expect("commit event wait");
41        wait.wait_until_completed().expect("complete event wait");
42    }
43
44    let fence_a = device.new_fence();
45    let fence_b = device.new_fence();
46    let sample_buffer = counter_sets.first().and_then(|name| {
47        if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
48            device
49                .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
50                .ok()
51        } else {
52            None
53        }
54    });
55
56    let src = device
57        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
58        .expect("source buffer");
59    let dst = device
60        .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
61        .expect("destination buffer");
62    let blit = queue.new_command_buffer().expect("blit command buffer");
63    let mut encoder = blit.new_blit_command_encoder().expect("blit encoder");
64    encoder
65        .fill_buffer(&src, 0..64, b'Q')
66        .expect("fill source buffer");
67    if let Some(fence) = fence_a.as_ref() {
68        encoder.update_fence(fence).expect("update fence");
69    }
70    encoder.end_encoding().expect("end first blit encoder");
71    blit.commit().expect("commit first blit");
72    blit.wait_until_completed().expect("complete first blit");
73
74    let blit = queue
75        .new_command_buffer()
76        .expect("second blit command buffer");
77    let mut encoder = blit
78        .new_blit_command_encoder()
79        .expect("second blit encoder");
80    if let Some(fence) = fence_a.as_ref() {
81        encoder.wait_for_fence(fence).expect("wait for fence");
82    }
83    if let Some(sample_buffer) = sample_buffer.as_ref() {
84        encoder
85            .sample_counters(sample_buffer, 0, false)
86            .expect("sample counters");
87    }
88    encoder
89        .copy_buffer(&src, 0, &dst, 0, 64)
90        .expect("copy buffers");
91    encoder.end_encoding().expect("end second blit encoder");
92    blit.commit().expect("commit second blit");
93    blit.wait_until_completed().expect("complete second blit");
94    if let Some(sample_buffer) = sample_buffer.as_ref() {
95        println!(
96            "resolved counter bytes={}",
97            sample_buffer
98                .resolve_range(0..1)
99                .map_or(0, |bytes| bytes.len())
100        );
101    }
102
103    let library = device
104        .new_library_with_source(common::COMPUTE_SRC)
105        .expect("compile compute library");
106    let increment = library
107        .new_function("increment")
108        .expect("increment function");
109    let pipeline = device
110        .new_compute_pipeline_state(&increment)
111        .expect("compute pipeline");
112    let visible_table = pipeline.new_visible_function_table(1);
113    let intersection_table = if device.supports_raytracing() {
114        pipeline.new_intersection_function_table(1)
115    } else {
116        None
117    };
118    if let Some(table) = intersection_table.as_ref() {
119        table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
120    }
121    let acceleration_structure = if device.supports_raytracing() {
122        device.new_acceleration_structure_with_size(256)
123    } else {
124        None
125    };
126
127    let buffer = device
128        .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
129        .expect("compute buffer");
130    common::write_u32_words(&buffer, &[1, 2, 3, 4]);
131    let texture = device
132        .new_texture(apple_metal::TextureDescriptor::new_2d(
133            4,
134            4,
135            apple_metal::pixel_format::BGRA8UNORM,
136        ))
137        .expect("compute texture");
138    let compute = queue.new_command_buffer().expect("compute command buffer");
139    let mut encoder = compute
140        .new_compute_command_encoder()
141        .expect("compute command encoder");
142    encoder
143        .set_compute_pipeline_state(&pipeline)
144        .expect("bind compute pipeline");
145    encoder
146        .set_buffer(&buffer, 0, 0)
147        .expect("bind compute buffer");
148    encoder
149        .set_texture(&texture, 1)
150        .expect("bind compute texture");
151    if let Some(fence) = fence_a.as_ref() {
152        encoder.wait_for_fence(fence).expect("wait for fence");
153    }
154    if let Some(table) = visible_table.as_ref() {
155        encoder
156            .set_visible_function_table(table, 2)
157            .expect("bind visible function table");
158    }
159    if let Some(table) = intersection_table.as_ref() {
160        encoder
161            .set_intersection_function_table(table, 3)
162            .expect("bind intersection function table");
163    }
164    if let Some(acceleration_structure) = acceleration_structure.as_ref() {
165        encoder
166            .set_acceleration_structure(acceleration_structure, 4)
167            .expect("bind acceleration structure");
168    }
169    encoder
170        .dispatch_threadgroups((1, 1, 1), (4, 1, 1))
171        .expect("dispatch compute");
172    if let Some(fence) = fence_b.as_ref() {
173        encoder.update_fence(fence).expect("update fence");
174    }
175    encoder.end_encoding().expect("end compute encoder");
176    compute.commit().expect("commit compute");
177    compute.wait_until_completed().expect("complete compute");
178    println!(
179        "compute buffer after dispatch: {:?}",
180        common::read_u32_words(&buffer, 4)
181    );
182
183    if let Some(indirect) = device.new_indirect_command_buffer(
184        indirect_command_type::CONCURRENT_DISPATCH,
185        1,
186        0,
187        0,
188        4,
189        resource_options::STORAGE_MODE_PRIVATE,
190    ) {
191        indirect.reset_range(0..1);
192        println!("indirect command buffer size={}", indirect.size());
193    }
194
195    if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
196        if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
197            let heap_buffer = heap
198                .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
199                .expect("heap buffer");
200            residency_set.add_buffer(&heap_buffer);
201            residency_set.add_heap(&heap);
202            residency_set.commit();
203            residency_set.request_residency();
204            queue.add_residency_set(&residency_set);
205            queue.remove_residency_set(&residency_set);
206            residency_set.end_residency();
207            residency_set.remove_all_allocations();
208            residency_set.commit();
209            println!(
210                "residency allocation count={}",
211                residency_set.allocation_count()
212            );
213        } else {
214            println!("residency sets unavailable on this OS");
215        }
216    }
217
218    if let Some(capture_manager) = CaptureManager::shared() {
219        println!(
220            "capture supported for developer tools={} active={}",
221            capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
222            capture_manager.is_capturing(),
223        );
224        if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
225            scope.begin();
226            scope.end();
227        }
228        if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
229            scope.begin();
230            scope.end();
231        }
232    }
233}

Trait Implementations§

Source§

impl Deref for ManuallyDropDevice

Source§

type Target = MetalDevice

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.