pub struct ManuallyDropDevice { /* private fields */ }Expand description
Borrowed MetalDevice that does not release on drop.
Methods from Deref<Target = MetalDevice>§
Sourcepub fn name(&self) -> String
pub fn name(&self) -> String
Human-readable device name.
Examples found in repository?
11fn main() {
12 let device = MetalDevice::system_default().expect("Metal device available");
13 println!(
14 "device: {} (registry id {})",
15 device.name(),
16 device.registry_id()
17 );
18
19 let queue = device.new_command_queue().expect("command queue");
20 let status_buffer = queue
21 .new_command_buffer_with_unretained_references()
22 .expect("scratch command buffer");
23 println!("scratch command buffer status={}", status_buffer.status());
24
25 let src = device
26 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
27 .expect("source buffer");
28 let dst = device
29 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
30 .expect("destination buffer");
31 let blit_cb = queue.new_command_buffer().expect("blit command buffer");
32 let blit = blit_cb
33 .new_blit_command_encoder()
34 .expect("blit command encoder");
35 assert!(blit.fill_buffer(&src, 0..64, b'Z'));
36 assert!(blit.copy_buffer(&src, 0, &dst, 0, 64));
37 blit.end_encoding();
38 blit_cb.commit();
39 blit_cb.wait_until_completed();
40 let copied = unsafe {
41 core::slice::from_raw_parts(dst.contents().expect("dst contents").cast::<u8>(), 8)
42 };
43 println!("blit copied bytes: {copied:?}");
44
45 let library = device
46 .new_library_with_source(common::COMPUTE_SRC)
47 .expect("compile compute library");
48 let increment = library
49 .new_function("increment")
50 .expect("increment function");
51 let pipeline = device
52 .new_compute_pipeline_state(&increment)
53 .expect("compute pipeline");
54
55 let buffer = device
56 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
57 .expect("compute buffer");
58 common::write_u32_words(&buffer, &[10, 20, 30, 40]);
59 let compute_cb = queue.new_command_buffer().expect("compute command buffer");
60 let compute = compute_cb
61 .new_compute_command_encoder()
62 .expect("compute command encoder");
63 compute.set_compute_pipeline_state(&pipeline);
64 compute.set_buffer(&buffer, 0, 0);
65 compute.dispatch_threads((4, 1, 1), (1, 1, 1));
66 compute.end_encoding();
67 compute_cb.commit();
68 compute_cb.wait_until_completed();
69 println!("compute output: {:?}", common::read_u32_words(&buffer, 4));
70
71 let render_library = device
72 .new_library_with_source(common::RENDER_SRC)
73 .expect("compile render library");
74 let vertex = render_library
75 .new_function("fullscreen_vertex")
76 .expect("vertex function");
77 let fragment = render_library
78 .new_function("solid_fragment")
79 .expect("fragment function");
80 let render_pipeline = device
81 .new_render_pipeline_state(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
82 .expect("render pipeline");
83 println!("render pipeline label: {:?}", render_pipeline.label());
84
85 let render_target = device
86 .new_texture(common::shared_render_target(4, 4))
87 .expect("render target");
88 let vertex_buffer = device
89 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
90 .expect("vertex buffer");
91 let render_cb = queue.new_command_buffer().expect("render command buffer");
92 let render = render_cb
93 .new_render_command_encoder(
94 &render_target,
95 load_action::CLEAR,
96 store_action::STORE,
97 [0.0, 0.0, 0.0, 1.0],
98 )
99 .expect("render command encoder");
100 render.set_render_pipeline_state(&render_pipeline);
101 render.set_vertex_buffer(&vertex_buffer, 0, 0);
102 render.draw_primitives(primitive_type::TRIANGLE, 0, 3);
103 render.end_encoding();
104 render_cb.commit();
105 render_cb.wait_until_completed();
106
107 let mut rendered = vec![0_u8; 4 * 4 * 4];
108 assert!(render_target.read_bytes_2d(&mut rendered, 16, (0, 0), (4, 4), 0));
109 println!("first rendered pixel: {:?}", &rendered[..4]);
110
111 let shared_texture = device
112 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
113 .expect("shared texture");
114 let upload = vec![0x22_u8; 4 * 4 * 4];
115 assert!(shared_texture.replace_region_2d(&upload, 16, (0, 0), (4, 4), 0));
116 let mut download = vec![0_u8; upload.len()];
117 assert!(shared_texture.read_bytes_2d(&mut download, 16, (0, 0), (4, 4), 0));
118 let view = shared_texture
119 .new_view(pixel_format::BGRA8UNORM)
120 .expect("texture view");
121 println!(
122 "texture {}x{} usage={} storage_mode={} view_width={}",
123 shared_texture.width(),
124 shared_texture.height(),
125 shared_texture.usage(),
126 shared_texture.storage_mode(),
127 view.width(),
128 );
129}More examples
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 = queue
18 .new_command_buffer_with_unretained_references()
19 .expect("bounded scratch command buffer");
20 println!("bounded queue scratch status={}", scratch.status());
21
22 let library = device
23 .new_library_with_source(common::COMPUTE_SRC)
24 .expect("compile compute library");
25 let args = library.new_function("use_args").expect("use_args function");
26 let argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
27 let argument_buffer = device
28 .new_buffer(
29 argument_encoder.encoded_length(),
30 resource_options::STORAGE_MODE_SHARED,
31 )
32 .expect("argument buffer");
33 let payload = device
34 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
35 .expect("payload buffer");
36 let texture = device
37 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
38 .expect("argument texture");
39 argument_encoder.set_argument_buffer(&argument_buffer, 0);
40 argument_encoder.set_buffer(&payload, 0, 0);
41 argument_encoder.set_texture(&texture, 1);
42 println!(
43 "argument encoder length={} alignment={}",
44 argument_encoder.encoded_length(),
45 argument_encoder.alignment(),
46 );
47
48 let backing = device
49 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
50 .expect("backing buffer");
51 let buffer_texture = backing
52 .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
53 .expect("buffer-backed texture");
54 println!(
55 "buffer-backed texture {}x{} fmt={}",
56 buffer_texture.width(),
57 buffer_texture.height(),
58 buffer_texture.pixel_format(),
59 );
60
61 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
62 let heap_buffer = heap
63 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
64 .expect("heap buffer");
65 let heap_texture = heap
66 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
67 .expect("heap texture");
68 println!(
69 "heap size={} used={} current={} max_available={}",
70 heap.size(),
71 heap.used_size(),
72 heap.current_allocated_size(),
73 heap.max_available_size(256),
74 );
75 println!(
76 "heap buffer len={} heap texture {}x{} purgeable={}",
77 heap_buffer.length(),
78 heap_texture.width(),
79 heap_texture.height(),
80 heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
81 );
82 } else {
83 println!("heaps are unavailable on this device");
84 }
85
86 match device.new_log_state(log_level::INFO, 1_024) {
87 Ok(log_state) => {
88 let _ = device
89 .new_command_queue_with_log_state(4, &log_state)
90 .expect("log-state queue");
91 println!("created queue with log state");
92 }
93 Err(error) => println!("log state unavailable on this OS: {error}"),
94 }
95
96 if device.supports_dynamic_libraries() {
97 let dynamic_path = common::artifact_path("example-dylib.metallib");
98 let dynamic_library = device
99 .new_dynamic_library_with_source(
100 common::DYNAMIC_LIB_SRC,
101 dynamic_path.to_string_lossy().as_ref(),
102 )
103 .expect("dynamic library from source");
104 dynamic_library
105 .serialize_to_file(&dynamic_path)
106 .expect("serialize dynamic library");
107 let reloaded = device
108 .load_dynamic_library(&dynamic_path)
109 .expect("reload dynamic library");
110 println!("dynamic library install name: {}", reloaded.install_name());
111
112 let render_library = device
113 .new_library_with_source(common::RENDER_SRC)
114 .expect("compile render library");
115 let vertex = render_library
116 .new_function("fullscreen_vertex")
117 .expect("vertex function");
118 let fragment = render_library
119 .new_function("solid_fragment")
120 .expect("fragment function");
121 let increment = library
122 .new_function("increment")
123 .expect("increment function");
124
125 let archive_path = common::artifact_path("example-archive.metalarc");
126 let archive = device.new_binary_archive(None).expect("binary archive");
127 archive
128 .add_compute_function(&increment)
129 .expect("archive compute pipeline");
130 archive
131 .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
132 .expect("archive render pipeline");
133 archive
134 .serialize_to_file(&archive_path)
135 .expect("serialize binary archive");
136 let _ = device
137 .new_binary_archive(Some(&archive_path))
138 .expect("reload binary archive");
139 println!("binary archive written to {}", archive_path.display());
140 } else {
141 println!("dynamic libraries unsupported; skipping archive serialization");
142 }
143}Sourcepub fn registry_id(&self) -> u64
pub fn registry_id(&self) -> u64
Global IORegistry identifier for the device.
Examples found in repository?
11fn main() {
12 let device = MetalDevice::system_default().expect("Metal device available");
13 println!(
14 "device: {} (registry id {})",
15 device.name(),
16 device.registry_id()
17 );
18
19 let queue = device.new_command_queue().expect("command queue");
20 let status_buffer = queue
21 .new_command_buffer_with_unretained_references()
22 .expect("scratch command buffer");
23 println!("scratch command buffer status={}", status_buffer.status());
24
25 let src = device
26 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
27 .expect("source buffer");
28 let dst = device
29 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
30 .expect("destination buffer");
31 let blit_cb = queue.new_command_buffer().expect("blit command buffer");
32 let blit = blit_cb
33 .new_blit_command_encoder()
34 .expect("blit command encoder");
35 assert!(blit.fill_buffer(&src, 0..64, b'Z'));
36 assert!(blit.copy_buffer(&src, 0, &dst, 0, 64));
37 blit.end_encoding();
38 blit_cb.commit();
39 blit_cb.wait_until_completed();
40 let copied = unsafe {
41 core::slice::from_raw_parts(dst.contents().expect("dst contents").cast::<u8>(), 8)
42 };
43 println!("blit copied bytes: {copied:?}");
44
45 let library = device
46 .new_library_with_source(common::COMPUTE_SRC)
47 .expect("compile compute library");
48 let increment = library
49 .new_function("increment")
50 .expect("increment function");
51 let pipeline = device
52 .new_compute_pipeline_state(&increment)
53 .expect("compute pipeline");
54
55 let buffer = device
56 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
57 .expect("compute buffer");
58 common::write_u32_words(&buffer, &[10, 20, 30, 40]);
59 let compute_cb = queue.new_command_buffer().expect("compute command buffer");
60 let compute = compute_cb
61 .new_compute_command_encoder()
62 .expect("compute command encoder");
63 compute.set_compute_pipeline_state(&pipeline);
64 compute.set_buffer(&buffer, 0, 0);
65 compute.dispatch_threads((4, 1, 1), (1, 1, 1));
66 compute.end_encoding();
67 compute_cb.commit();
68 compute_cb.wait_until_completed();
69 println!("compute output: {:?}", common::read_u32_words(&buffer, 4));
70
71 let render_library = device
72 .new_library_with_source(common::RENDER_SRC)
73 .expect("compile render library");
74 let vertex = render_library
75 .new_function("fullscreen_vertex")
76 .expect("vertex function");
77 let fragment = render_library
78 .new_function("solid_fragment")
79 .expect("fragment function");
80 let render_pipeline = device
81 .new_render_pipeline_state(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
82 .expect("render pipeline");
83 println!("render pipeline label: {:?}", render_pipeline.label());
84
85 let render_target = device
86 .new_texture(common::shared_render_target(4, 4))
87 .expect("render target");
88 let vertex_buffer = device
89 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
90 .expect("vertex buffer");
91 let render_cb = queue.new_command_buffer().expect("render command buffer");
92 let render = render_cb
93 .new_render_command_encoder(
94 &render_target,
95 load_action::CLEAR,
96 store_action::STORE,
97 [0.0, 0.0, 0.0, 1.0],
98 )
99 .expect("render command encoder");
100 render.set_render_pipeline_state(&render_pipeline);
101 render.set_vertex_buffer(&vertex_buffer, 0, 0);
102 render.draw_primitives(primitive_type::TRIANGLE, 0, 3);
103 render.end_encoding();
104 render_cb.commit();
105 render_cb.wait_until_completed();
106
107 let mut rendered = vec![0_u8; 4 * 4 * 4];
108 assert!(render_target.read_bytes_2d(&mut rendered, 16, (0, 0), (4, 4), 0));
109 println!("first rendered pixel: {:?}", &rendered[..4]);
110
111 let shared_texture = device
112 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
113 .expect("shared texture");
114 let upload = vec![0x22_u8; 4 * 4 * 4];
115 assert!(shared_texture.replace_region_2d(&upload, 16, (0, 0), (4, 4), 0));
116 let mut download = vec![0_u8; upload.len()];
117 assert!(shared_texture.read_bytes_2d(&mut download, 16, (0, 0), (4, 4), 0));
118 let view = shared_texture
119 .new_view(pixel_format::BGRA8UNORM)
120 .expect("texture view");
121 println!(
122 "texture {}x{} usage={} storage_mode={} view_width={}",
123 shared_texture.width(),
124 shared_texture.height(),
125 shared_texture.usage(),
126 shared_texture.storage_mode(),
127 view.width(),
128 );
129}Sourcepub fn supports_dynamic_libraries(&self) -> bool
pub fn supports_dynamic_libraries(&self) -> bool
Whether this device supports Metal dynamic libraries.
Examples found in repository?
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 = queue
18 .new_command_buffer_with_unretained_references()
19 .expect("bounded scratch command buffer");
20 println!("bounded queue scratch status={}", scratch.status());
21
22 let library = device
23 .new_library_with_source(common::COMPUTE_SRC)
24 .expect("compile compute library");
25 let args = library.new_function("use_args").expect("use_args function");
26 let argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
27 let argument_buffer = device
28 .new_buffer(
29 argument_encoder.encoded_length(),
30 resource_options::STORAGE_MODE_SHARED,
31 )
32 .expect("argument buffer");
33 let payload = device
34 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
35 .expect("payload buffer");
36 let texture = device
37 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
38 .expect("argument texture");
39 argument_encoder.set_argument_buffer(&argument_buffer, 0);
40 argument_encoder.set_buffer(&payload, 0, 0);
41 argument_encoder.set_texture(&texture, 1);
42 println!(
43 "argument encoder length={} alignment={}",
44 argument_encoder.encoded_length(),
45 argument_encoder.alignment(),
46 );
47
48 let backing = device
49 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
50 .expect("backing buffer");
51 let buffer_texture = backing
52 .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
53 .expect("buffer-backed texture");
54 println!(
55 "buffer-backed texture {}x{} fmt={}",
56 buffer_texture.width(),
57 buffer_texture.height(),
58 buffer_texture.pixel_format(),
59 );
60
61 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
62 let heap_buffer = heap
63 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
64 .expect("heap buffer");
65 let heap_texture = heap
66 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
67 .expect("heap texture");
68 println!(
69 "heap size={} used={} current={} max_available={}",
70 heap.size(),
71 heap.used_size(),
72 heap.current_allocated_size(),
73 heap.max_available_size(256),
74 );
75 println!(
76 "heap buffer len={} heap texture {}x{} purgeable={}",
77 heap_buffer.length(),
78 heap_texture.width(),
79 heap_texture.height(),
80 heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
81 );
82 } else {
83 println!("heaps are unavailable on this device");
84 }
85
86 match device.new_log_state(log_level::INFO, 1_024) {
87 Ok(log_state) => {
88 let _ = device
89 .new_command_queue_with_log_state(4, &log_state)
90 .expect("log-state queue");
91 println!("created queue with log state");
92 }
93 Err(error) => println!("log state unavailable on this OS: {error}"),
94 }
95
96 if device.supports_dynamic_libraries() {
97 let dynamic_path = common::artifact_path("example-dylib.metallib");
98 let dynamic_library = device
99 .new_dynamic_library_with_source(
100 common::DYNAMIC_LIB_SRC,
101 dynamic_path.to_string_lossy().as_ref(),
102 )
103 .expect("dynamic library from source");
104 dynamic_library
105 .serialize_to_file(&dynamic_path)
106 .expect("serialize dynamic library");
107 let reloaded = device
108 .load_dynamic_library(&dynamic_path)
109 .expect("reload dynamic library");
110 println!("dynamic library install name: {}", reloaded.install_name());
111
112 let render_library = device
113 .new_library_with_source(common::RENDER_SRC)
114 .expect("compile render library");
115 let vertex = render_library
116 .new_function("fullscreen_vertex")
117 .expect("vertex function");
118 let fragment = render_library
119 .new_function("solid_fragment")
120 .expect("fragment function");
121 let increment = library
122 .new_function("increment")
123 .expect("increment function");
124
125 let archive_path = common::artifact_path("example-archive.metalarc");
126 let archive = device.new_binary_archive(None).expect("binary archive");
127 archive
128 .add_compute_function(&increment)
129 .expect("archive compute pipeline");
130 archive
131 .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
132 .expect("archive render pipeline");
133 archive
134 .serialize_to_file(&archive_path)
135 .expect("serialize binary archive");
136 let _ = device
137 .new_binary_archive(Some(&archive_path))
138 .expect("reload binary archive");
139 println!("binary archive written to {}", archive_path.display());
140 } else {
141 println!("dynamic libraries unsupported; skipping archive serialization");
142 }
143}Sourcepub fn supports_render_dynamic_libraries(&self) -> bool
pub fn supports_render_dynamic_libraries(&self) -> bool
Whether this device supports render-stage dynamic libraries.
Sourcepub fn supports_raytracing(&self) -> bool
pub fn supports_raytracing(&self) -> bool
Whether this device supports compute ray tracing.
Examples found in repository?
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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn supports_counter_sampling(&self, sampling_point: usize) -> bool
pub fn supports_counter_sampling(&self, sampling_point: usize) -> bool
Query support for a hardware counter sampling point.
Examples found in repository?
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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn counter_set_names(&self) -> Vec<String>
pub fn counter_set_names(&self) -> Vec<String>
Return the names of all counter sets exposed by this device.
Examples found in repository?
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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn new_command_queue_with_max_command_buffer_count(
&self,
max_command_buffer_count: usize,
) -> Option<CommandQueue>
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?
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 = queue
18 .new_command_buffer_with_unretained_references()
19 .expect("bounded scratch command buffer");
20 println!("bounded queue scratch status={}", scratch.status());
21
22 let library = device
23 .new_library_with_source(common::COMPUTE_SRC)
24 .expect("compile compute library");
25 let args = library.new_function("use_args").expect("use_args function");
26 let argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
27 let argument_buffer = device
28 .new_buffer(
29 argument_encoder.encoded_length(),
30 resource_options::STORAGE_MODE_SHARED,
31 )
32 .expect("argument buffer");
33 let payload = device
34 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
35 .expect("payload buffer");
36 let texture = device
37 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
38 .expect("argument texture");
39 argument_encoder.set_argument_buffer(&argument_buffer, 0);
40 argument_encoder.set_buffer(&payload, 0, 0);
41 argument_encoder.set_texture(&texture, 1);
42 println!(
43 "argument encoder length={} alignment={}",
44 argument_encoder.encoded_length(),
45 argument_encoder.alignment(),
46 );
47
48 let backing = device
49 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
50 .expect("backing buffer");
51 let buffer_texture = backing
52 .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
53 .expect("buffer-backed texture");
54 println!(
55 "buffer-backed texture {}x{} fmt={}",
56 buffer_texture.width(),
57 buffer_texture.height(),
58 buffer_texture.pixel_format(),
59 );
60
61 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
62 let heap_buffer = heap
63 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
64 .expect("heap buffer");
65 let heap_texture = heap
66 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
67 .expect("heap texture");
68 println!(
69 "heap size={} used={} current={} max_available={}",
70 heap.size(),
71 heap.used_size(),
72 heap.current_allocated_size(),
73 heap.max_available_size(256),
74 );
75 println!(
76 "heap buffer len={} heap texture {}x{} purgeable={}",
77 heap_buffer.length(),
78 heap_texture.width(),
79 heap_texture.height(),
80 heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
81 );
82 } else {
83 println!("heaps are unavailable on this device");
84 }
85
86 match device.new_log_state(log_level::INFO, 1_024) {
87 Ok(log_state) => {
88 let _ = device
89 .new_command_queue_with_log_state(4, &log_state)
90 .expect("log-state queue");
91 println!("created queue with log state");
92 }
93 Err(error) => println!("log state unavailable on this OS: {error}"),
94 }
95
96 if device.supports_dynamic_libraries() {
97 let dynamic_path = common::artifact_path("example-dylib.metallib");
98 let dynamic_library = device
99 .new_dynamic_library_with_source(
100 common::DYNAMIC_LIB_SRC,
101 dynamic_path.to_string_lossy().as_ref(),
102 )
103 .expect("dynamic library from source");
104 dynamic_library
105 .serialize_to_file(&dynamic_path)
106 .expect("serialize dynamic library");
107 let reloaded = device
108 .load_dynamic_library(&dynamic_path)
109 .expect("reload dynamic library");
110 println!("dynamic library install name: {}", reloaded.install_name());
111
112 let render_library = device
113 .new_library_with_source(common::RENDER_SRC)
114 .expect("compile render library");
115 let vertex = render_library
116 .new_function("fullscreen_vertex")
117 .expect("vertex function");
118 let fragment = render_library
119 .new_function("solid_fragment")
120 .expect("fragment function");
121 let increment = library
122 .new_function("increment")
123 .expect("increment function");
124
125 let archive_path = common::artifact_path("example-archive.metalarc");
126 let archive = device.new_binary_archive(None).expect("binary archive");
127 archive
128 .add_compute_function(&increment)
129 .expect("archive compute pipeline");
130 archive
131 .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
132 .expect("archive render pipeline");
133 archive
134 .serialize_to_file(&archive_path)
135 .expect("serialize binary archive");
136 let _ = device
137 .new_binary_archive(Some(&archive_path))
138 .expect("reload binary archive");
139 println!("binary archive written to {}", archive_path.display());
140 } else {
141 println!("dynamic libraries unsupported; skipping archive serialization");
142 }
143}Sourcepub fn new_command_queue_with_log_state(
&self,
max_command_buffer_count: usize,
log_state: &LogState,
) -> Option<CommandQueue>
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?
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 = queue
18 .new_command_buffer_with_unretained_references()
19 .expect("bounded scratch command buffer");
20 println!("bounded queue scratch status={}", scratch.status());
21
22 let library = device
23 .new_library_with_source(common::COMPUTE_SRC)
24 .expect("compile compute library");
25 let args = library.new_function("use_args").expect("use_args function");
26 let argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
27 let argument_buffer = device
28 .new_buffer(
29 argument_encoder.encoded_length(),
30 resource_options::STORAGE_MODE_SHARED,
31 )
32 .expect("argument buffer");
33 let payload = device
34 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
35 .expect("payload buffer");
36 let texture = device
37 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
38 .expect("argument texture");
39 argument_encoder.set_argument_buffer(&argument_buffer, 0);
40 argument_encoder.set_buffer(&payload, 0, 0);
41 argument_encoder.set_texture(&texture, 1);
42 println!(
43 "argument encoder length={} alignment={}",
44 argument_encoder.encoded_length(),
45 argument_encoder.alignment(),
46 );
47
48 let backing = device
49 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
50 .expect("backing buffer");
51 let buffer_texture = backing
52 .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
53 .expect("buffer-backed texture");
54 println!(
55 "buffer-backed texture {}x{} fmt={}",
56 buffer_texture.width(),
57 buffer_texture.height(),
58 buffer_texture.pixel_format(),
59 );
60
61 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
62 let heap_buffer = heap
63 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
64 .expect("heap buffer");
65 let heap_texture = heap
66 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
67 .expect("heap texture");
68 println!(
69 "heap size={} used={} current={} max_available={}",
70 heap.size(),
71 heap.used_size(),
72 heap.current_allocated_size(),
73 heap.max_available_size(256),
74 );
75 println!(
76 "heap buffer len={} heap texture {}x{} purgeable={}",
77 heap_buffer.length(),
78 heap_texture.width(),
79 heap_texture.height(),
80 heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
81 );
82 } else {
83 println!("heaps are unavailable on this device");
84 }
85
86 match device.new_log_state(log_level::INFO, 1_024) {
87 Ok(log_state) => {
88 let _ = device
89 .new_command_queue_with_log_state(4, &log_state)
90 .expect("log-state queue");
91 println!("created queue with log state");
92 }
93 Err(error) => println!("log state unavailable on this OS: {error}"),
94 }
95
96 if device.supports_dynamic_libraries() {
97 let dynamic_path = common::artifact_path("example-dylib.metallib");
98 let dynamic_library = device
99 .new_dynamic_library_with_source(
100 common::DYNAMIC_LIB_SRC,
101 dynamic_path.to_string_lossy().as_ref(),
102 )
103 .expect("dynamic library from source");
104 dynamic_library
105 .serialize_to_file(&dynamic_path)
106 .expect("serialize dynamic library");
107 let reloaded = device
108 .load_dynamic_library(&dynamic_path)
109 .expect("reload dynamic library");
110 println!("dynamic library install name: {}", reloaded.install_name());
111
112 let render_library = device
113 .new_library_with_source(common::RENDER_SRC)
114 .expect("compile render library");
115 let vertex = render_library
116 .new_function("fullscreen_vertex")
117 .expect("vertex function");
118 let fragment = render_library
119 .new_function("solid_fragment")
120 .expect("fragment function");
121 let increment = library
122 .new_function("increment")
123 .expect("increment function");
124
125 let archive_path = common::artifact_path("example-archive.metalarc");
126 let archive = device.new_binary_archive(None).expect("binary archive");
127 archive
128 .add_compute_function(&increment)
129 .expect("archive compute pipeline");
130 archive
131 .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
132 .expect("archive render pipeline");
133 archive
134 .serialize_to_file(&archive_path)
135 .expect("serialize binary archive");
136 let _ = device
137 .new_binary_archive(Some(&archive_path))
138 .expect("reload binary archive");
139 println!("binary archive written to {}", archive_path.display());
140 } else {
141 println!("dynamic libraries unsupported; skipping archive serialization");
142 }
143}Sourcepub fn new_heap(&self, size: usize, storage_mode: usize) -> Option<Heap>
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?
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 = queue
18 .new_command_buffer_with_unretained_references()
19 .expect("bounded scratch command buffer");
20 println!("bounded queue scratch status={}", scratch.status());
21
22 let library = device
23 .new_library_with_source(common::COMPUTE_SRC)
24 .expect("compile compute library");
25 let args = library.new_function("use_args").expect("use_args function");
26 let argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
27 let argument_buffer = device
28 .new_buffer(
29 argument_encoder.encoded_length(),
30 resource_options::STORAGE_MODE_SHARED,
31 )
32 .expect("argument buffer");
33 let payload = device
34 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
35 .expect("payload buffer");
36 let texture = device
37 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
38 .expect("argument texture");
39 argument_encoder.set_argument_buffer(&argument_buffer, 0);
40 argument_encoder.set_buffer(&payload, 0, 0);
41 argument_encoder.set_texture(&texture, 1);
42 println!(
43 "argument encoder length={} alignment={}",
44 argument_encoder.encoded_length(),
45 argument_encoder.alignment(),
46 );
47
48 let backing = device
49 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
50 .expect("backing buffer");
51 let buffer_texture = backing
52 .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
53 .expect("buffer-backed texture");
54 println!(
55 "buffer-backed texture {}x{} fmt={}",
56 buffer_texture.width(),
57 buffer_texture.height(),
58 buffer_texture.pixel_format(),
59 );
60
61 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
62 let heap_buffer = heap
63 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
64 .expect("heap buffer");
65 let heap_texture = heap
66 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
67 .expect("heap texture");
68 println!(
69 "heap size={} used={} current={} max_available={}",
70 heap.size(),
71 heap.used_size(),
72 heap.current_allocated_size(),
73 heap.max_available_size(256),
74 );
75 println!(
76 "heap buffer len={} heap texture {}x{} purgeable={}",
77 heap_buffer.length(),
78 heap_texture.width(),
79 heap_texture.height(),
80 heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
81 );
82 } else {
83 println!("heaps are unavailable on this device");
84 }
85
86 match device.new_log_state(log_level::INFO, 1_024) {
87 Ok(log_state) => {
88 let _ = device
89 .new_command_queue_with_log_state(4, &log_state)
90 .expect("log-state queue");
91 println!("created queue with log state");
92 }
93 Err(error) => println!("log state unavailable on this OS: {error}"),
94 }
95
96 if device.supports_dynamic_libraries() {
97 let dynamic_path = common::artifact_path("example-dylib.metallib");
98 let dynamic_library = device
99 .new_dynamic_library_with_source(
100 common::DYNAMIC_LIB_SRC,
101 dynamic_path.to_string_lossy().as_ref(),
102 )
103 .expect("dynamic library from source");
104 dynamic_library
105 .serialize_to_file(&dynamic_path)
106 .expect("serialize dynamic library");
107 let reloaded = device
108 .load_dynamic_library(&dynamic_path)
109 .expect("reload dynamic library");
110 println!("dynamic library install name: {}", reloaded.install_name());
111
112 let render_library = device
113 .new_library_with_source(common::RENDER_SRC)
114 .expect("compile render library");
115 let vertex = render_library
116 .new_function("fullscreen_vertex")
117 .expect("vertex function");
118 let fragment = render_library
119 .new_function("solid_fragment")
120 .expect("fragment function");
121 let increment = library
122 .new_function("increment")
123 .expect("increment function");
124
125 let archive_path = common::artifact_path("example-archive.metalarc");
126 let archive = device.new_binary_archive(None).expect("binary archive");
127 archive
128 .add_compute_function(&increment)
129 .expect("archive compute pipeline");
130 archive
131 .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
132 .expect("archive render pipeline");
133 archive
134 .serialize_to_file(&archive_path)
135 .expect("serialize binary archive");
136 let _ = device
137 .new_binary_archive(Some(&archive_path))
138 .expect("reload binary archive");
139 println!("binary archive written to {}", archive_path.display());
140 } else {
141 println!("dynamic libraries unsupported; skipping archive serialization");
142 }
143}More examples
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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn new_fence(&self) -> Option<Fence>
pub fn new_fence(&self) -> Option<Fence>
Create a new fence.
Examples found in repository?
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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Create a new shared event.
Examples found in repository?
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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn new_dynamic_library_with_source(
&self,
source: &str,
install_name: &str,
) -> Result<DynamicLibrary, String>
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?
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 = queue
18 .new_command_buffer_with_unretained_references()
19 .expect("bounded scratch command buffer");
20 println!("bounded queue scratch status={}", scratch.status());
21
22 let library = device
23 .new_library_with_source(common::COMPUTE_SRC)
24 .expect("compile compute library");
25 let args = library.new_function("use_args").expect("use_args function");
26 let argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
27 let argument_buffer = device
28 .new_buffer(
29 argument_encoder.encoded_length(),
30 resource_options::STORAGE_MODE_SHARED,
31 )
32 .expect("argument buffer");
33 let payload = device
34 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
35 .expect("payload buffer");
36 let texture = device
37 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
38 .expect("argument texture");
39 argument_encoder.set_argument_buffer(&argument_buffer, 0);
40 argument_encoder.set_buffer(&payload, 0, 0);
41 argument_encoder.set_texture(&texture, 1);
42 println!(
43 "argument encoder length={} alignment={}",
44 argument_encoder.encoded_length(),
45 argument_encoder.alignment(),
46 );
47
48 let backing = device
49 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
50 .expect("backing buffer");
51 let buffer_texture = backing
52 .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
53 .expect("buffer-backed texture");
54 println!(
55 "buffer-backed texture {}x{} fmt={}",
56 buffer_texture.width(),
57 buffer_texture.height(),
58 buffer_texture.pixel_format(),
59 );
60
61 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
62 let heap_buffer = heap
63 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
64 .expect("heap buffer");
65 let heap_texture = heap
66 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
67 .expect("heap texture");
68 println!(
69 "heap size={} used={} current={} max_available={}",
70 heap.size(),
71 heap.used_size(),
72 heap.current_allocated_size(),
73 heap.max_available_size(256),
74 );
75 println!(
76 "heap buffer len={} heap texture {}x{} purgeable={}",
77 heap_buffer.length(),
78 heap_texture.width(),
79 heap_texture.height(),
80 heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
81 );
82 } else {
83 println!("heaps are unavailable on this device");
84 }
85
86 match device.new_log_state(log_level::INFO, 1_024) {
87 Ok(log_state) => {
88 let _ = device
89 .new_command_queue_with_log_state(4, &log_state)
90 .expect("log-state queue");
91 println!("created queue with log state");
92 }
93 Err(error) => println!("log state unavailable on this OS: {error}"),
94 }
95
96 if device.supports_dynamic_libraries() {
97 let dynamic_path = common::artifact_path("example-dylib.metallib");
98 let dynamic_library = device
99 .new_dynamic_library_with_source(
100 common::DYNAMIC_LIB_SRC,
101 dynamic_path.to_string_lossy().as_ref(),
102 )
103 .expect("dynamic library from source");
104 dynamic_library
105 .serialize_to_file(&dynamic_path)
106 .expect("serialize dynamic library");
107 let reloaded = device
108 .load_dynamic_library(&dynamic_path)
109 .expect("reload dynamic library");
110 println!("dynamic library install name: {}", reloaded.install_name());
111
112 let render_library = device
113 .new_library_with_source(common::RENDER_SRC)
114 .expect("compile render library");
115 let vertex = render_library
116 .new_function("fullscreen_vertex")
117 .expect("vertex function");
118 let fragment = render_library
119 .new_function("solid_fragment")
120 .expect("fragment function");
121 let increment = library
122 .new_function("increment")
123 .expect("increment function");
124
125 let archive_path = common::artifact_path("example-archive.metalarc");
126 let archive = device.new_binary_archive(None).expect("binary archive");
127 archive
128 .add_compute_function(&increment)
129 .expect("archive compute pipeline");
130 archive
131 .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
132 .expect("archive render pipeline");
133 archive
134 .serialize_to_file(&archive_path)
135 .expect("serialize binary archive");
136 let _ = device
137 .new_binary_archive(Some(&archive_path))
138 .expect("reload binary archive");
139 println!("binary archive written to {}", archive_path.display());
140 } else {
141 println!("dynamic libraries unsupported; skipping archive serialization");
142 }
143}Sourcepub fn load_dynamic_library(
&self,
path: &Path,
) -> Result<DynamicLibrary, String>
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?
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 = queue
18 .new_command_buffer_with_unretained_references()
19 .expect("bounded scratch command buffer");
20 println!("bounded queue scratch status={}", scratch.status());
21
22 let library = device
23 .new_library_with_source(common::COMPUTE_SRC)
24 .expect("compile compute library");
25 let args = library.new_function("use_args").expect("use_args function");
26 let argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
27 let argument_buffer = device
28 .new_buffer(
29 argument_encoder.encoded_length(),
30 resource_options::STORAGE_MODE_SHARED,
31 )
32 .expect("argument buffer");
33 let payload = device
34 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
35 .expect("payload buffer");
36 let texture = device
37 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
38 .expect("argument texture");
39 argument_encoder.set_argument_buffer(&argument_buffer, 0);
40 argument_encoder.set_buffer(&payload, 0, 0);
41 argument_encoder.set_texture(&texture, 1);
42 println!(
43 "argument encoder length={} alignment={}",
44 argument_encoder.encoded_length(),
45 argument_encoder.alignment(),
46 );
47
48 let backing = device
49 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
50 .expect("backing buffer");
51 let buffer_texture = backing
52 .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
53 .expect("buffer-backed texture");
54 println!(
55 "buffer-backed texture {}x{} fmt={}",
56 buffer_texture.width(),
57 buffer_texture.height(),
58 buffer_texture.pixel_format(),
59 );
60
61 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
62 let heap_buffer = heap
63 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
64 .expect("heap buffer");
65 let heap_texture = heap
66 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
67 .expect("heap texture");
68 println!(
69 "heap size={} used={} current={} max_available={}",
70 heap.size(),
71 heap.used_size(),
72 heap.current_allocated_size(),
73 heap.max_available_size(256),
74 );
75 println!(
76 "heap buffer len={} heap texture {}x{} purgeable={}",
77 heap_buffer.length(),
78 heap_texture.width(),
79 heap_texture.height(),
80 heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
81 );
82 } else {
83 println!("heaps are unavailable on this device");
84 }
85
86 match device.new_log_state(log_level::INFO, 1_024) {
87 Ok(log_state) => {
88 let _ = device
89 .new_command_queue_with_log_state(4, &log_state)
90 .expect("log-state queue");
91 println!("created queue with log state");
92 }
93 Err(error) => println!("log state unavailable on this OS: {error}"),
94 }
95
96 if device.supports_dynamic_libraries() {
97 let dynamic_path = common::artifact_path("example-dylib.metallib");
98 let dynamic_library = device
99 .new_dynamic_library_with_source(
100 common::DYNAMIC_LIB_SRC,
101 dynamic_path.to_string_lossy().as_ref(),
102 )
103 .expect("dynamic library from source");
104 dynamic_library
105 .serialize_to_file(&dynamic_path)
106 .expect("serialize dynamic library");
107 let reloaded = device
108 .load_dynamic_library(&dynamic_path)
109 .expect("reload dynamic library");
110 println!("dynamic library install name: {}", reloaded.install_name());
111
112 let render_library = device
113 .new_library_with_source(common::RENDER_SRC)
114 .expect("compile render library");
115 let vertex = render_library
116 .new_function("fullscreen_vertex")
117 .expect("vertex function");
118 let fragment = render_library
119 .new_function("solid_fragment")
120 .expect("fragment function");
121 let increment = library
122 .new_function("increment")
123 .expect("increment function");
124
125 let archive_path = common::artifact_path("example-archive.metalarc");
126 let archive = device.new_binary_archive(None).expect("binary archive");
127 archive
128 .add_compute_function(&increment)
129 .expect("archive compute pipeline");
130 archive
131 .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
132 .expect("archive render pipeline");
133 archive
134 .serialize_to_file(&archive_path)
135 .expect("serialize binary archive");
136 let _ = device
137 .new_binary_archive(Some(&archive_path))
138 .expect("reload binary archive");
139 println!("binary archive written to {}", archive_path.display());
140 } else {
141 println!("dynamic libraries unsupported; skipping archive serialization");
142 }
143}Sourcepub fn new_binary_archive(
&self,
path: Option<&Path>,
) -> Result<BinaryArchive, String>
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?
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 = queue
18 .new_command_buffer_with_unretained_references()
19 .expect("bounded scratch command buffer");
20 println!("bounded queue scratch status={}", scratch.status());
21
22 let library = device
23 .new_library_with_source(common::COMPUTE_SRC)
24 .expect("compile compute library");
25 let args = library.new_function("use_args").expect("use_args function");
26 let argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
27 let argument_buffer = device
28 .new_buffer(
29 argument_encoder.encoded_length(),
30 resource_options::STORAGE_MODE_SHARED,
31 )
32 .expect("argument buffer");
33 let payload = device
34 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
35 .expect("payload buffer");
36 let texture = device
37 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
38 .expect("argument texture");
39 argument_encoder.set_argument_buffer(&argument_buffer, 0);
40 argument_encoder.set_buffer(&payload, 0, 0);
41 argument_encoder.set_texture(&texture, 1);
42 println!(
43 "argument encoder length={} alignment={}",
44 argument_encoder.encoded_length(),
45 argument_encoder.alignment(),
46 );
47
48 let backing = device
49 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
50 .expect("backing buffer");
51 let buffer_texture = backing
52 .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
53 .expect("buffer-backed texture");
54 println!(
55 "buffer-backed texture {}x{} fmt={}",
56 buffer_texture.width(),
57 buffer_texture.height(),
58 buffer_texture.pixel_format(),
59 );
60
61 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
62 let heap_buffer = heap
63 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
64 .expect("heap buffer");
65 let heap_texture = heap
66 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
67 .expect("heap texture");
68 println!(
69 "heap size={} used={} current={} max_available={}",
70 heap.size(),
71 heap.used_size(),
72 heap.current_allocated_size(),
73 heap.max_available_size(256),
74 );
75 println!(
76 "heap buffer len={} heap texture {}x{} purgeable={}",
77 heap_buffer.length(),
78 heap_texture.width(),
79 heap_texture.height(),
80 heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
81 );
82 } else {
83 println!("heaps are unavailable on this device");
84 }
85
86 match device.new_log_state(log_level::INFO, 1_024) {
87 Ok(log_state) => {
88 let _ = device
89 .new_command_queue_with_log_state(4, &log_state)
90 .expect("log-state queue");
91 println!("created queue with log state");
92 }
93 Err(error) => println!("log state unavailable on this OS: {error}"),
94 }
95
96 if device.supports_dynamic_libraries() {
97 let dynamic_path = common::artifact_path("example-dylib.metallib");
98 let dynamic_library = device
99 .new_dynamic_library_with_source(
100 common::DYNAMIC_LIB_SRC,
101 dynamic_path.to_string_lossy().as_ref(),
102 )
103 .expect("dynamic library from source");
104 dynamic_library
105 .serialize_to_file(&dynamic_path)
106 .expect("serialize dynamic library");
107 let reloaded = device
108 .load_dynamic_library(&dynamic_path)
109 .expect("reload dynamic library");
110 println!("dynamic library install name: {}", reloaded.install_name());
111
112 let render_library = device
113 .new_library_with_source(common::RENDER_SRC)
114 .expect("compile render library");
115 let vertex = render_library
116 .new_function("fullscreen_vertex")
117 .expect("vertex function");
118 let fragment = render_library
119 .new_function("solid_fragment")
120 .expect("fragment function");
121 let increment = library
122 .new_function("increment")
123 .expect("increment function");
124
125 let archive_path = common::artifact_path("example-archive.metalarc");
126 let archive = device.new_binary_archive(None).expect("binary archive");
127 archive
128 .add_compute_function(&increment)
129 .expect("archive compute pipeline");
130 archive
131 .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
132 .expect("archive render pipeline");
133 archive
134 .serialize_to_file(&archive_path)
135 .expect("serialize binary archive");
136 let _ = device
137 .new_binary_archive(Some(&archive_path))
138 .expect("reload binary archive");
139 println!("binary archive written to {}", archive_path.display());
140 } else {
141 println!("dynamic libraries unsupported; skipping archive serialization");
142 }
143}Sourcepub 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>
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?
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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn new_acceleration_structure_with_size(
&self,
size: usize,
) -> Option<AccelerationStructure>
pub fn new_acceleration_structure_with_size( &self, size: usize, ) -> Option<AccelerationStructure>
Allocate storage for a ray-tracing acceleration structure.
Examples found in repository?
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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn new_counter_sample_buffer(
&self,
counter_set_name: &str,
sample_count: usize,
storage_mode: usize,
label: Option<&str>,
) -> Result<CounterSampleBuffer, String>
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?
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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn new_log_state(
&self,
level: usize,
buffer_size: isize,
) -> Result<LogState, String>
pub fn new_log_state( &self, level: usize, buffer_size: isize, ) -> Result<LogState, String>
Examples found in repository?
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 = queue
18 .new_command_buffer_with_unretained_references()
19 .expect("bounded scratch command buffer");
20 println!("bounded queue scratch status={}", scratch.status());
21
22 let library = device
23 .new_library_with_source(common::COMPUTE_SRC)
24 .expect("compile compute library");
25 let args = library.new_function("use_args").expect("use_args function");
26 let argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
27 let argument_buffer = device
28 .new_buffer(
29 argument_encoder.encoded_length(),
30 resource_options::STORAGE_MODE_SHARED,
31 )
32 .expect("argument buffer");
33 let payload = device
34 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
35 .expect("payload buffer");
36 let texture = device
37 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
38 .expect("argument texture");
39 argument_encoder.set_argument_buffer(&argument_buffer, 0);
40 argument_encoder.set_buffer(&payload, 0, 0);
41 argument_encoder.set_texture(&texture, 1);
42 println!(
43 "argument encoder length={} alignment={}",
44 argument_encoder.encoded_length(),
45 argument_encoder.alignment(),
46 );
47
48 let backing = device
49 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
50 .expect("backing buffer");
51 let buffer_texture = backing
52 .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
53 .expect("buffer-backed texture");
54 println!(
55 "buffer-backed texture {}x{} fmt={}",
56 buffer_texture.width(),
57 buffer_texture.height(),
58 buffer_texture.pixel_format(),
59 );
60
61 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
62 let heap_buffer = heap
63 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
64 .expect("heap buffer");
65 let heap_texture = heap
66 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
67 .expect("heap texture");
68 println!(
69 "heap size={} used={} current={} max_available={}",
70 heap.size(),
71 heap.used_size(),
72 heap.current_allocated_size(),
73 heap.max_available_size(256),
74 );
75 println!(
76 "heap buffer len={} heap texture {}x{} purgeable={}",
77 heap_buffer.length(),
78 heap_texture.width(),
79 heap_texture.height(),
80 heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
81 );
82 } else {
83 println!("heaps are unavailable on this device");
84 }
85
86 match device.new_log_state(log_level::INFO, 1_024) {
87 Ok(log_state) => {
88 let _ = device
89 .new_command_queue_with_log_state(4, &log_state)
90 .expect("log-state queue");
91 println!("created queue with log state");
92 }
93 Err(error) => println!("log state unavailable on this OS: {error}"),
94 }
95
96 if device.supports_dynamic_libraries() {
97 let dynamic_path = common::artifact_path("example-dylib.metallib");
98 let dynamic_library = device
99 .new_dynamic_library_with_source(
100 common::DYNAMIC_LIB_SRC,
101 dynamic_path.to_string_lossy().as_ref(),
102 )
103 .expect("dynamic library from source");
104 dynamic_library
105 .serialize_to_file(&dynamic_path)
106 .expect("serialize dynamic library");
107 let reloaded = device
108 .load_dynamic_library(&dynamic_path)
109 .expect("reload dynamic library");
110 println!("dynamic library install name: {}", reloaded.install_name());
111
112 let render_library = device
113 .new_library_with_source(common::RENDER_SRC)
114 .expect("compile render library");
115 let vertex = render_library
116 .new_function("fullscreen_vertex")
117 .expect("vertex function");
118 let fragment = render_library
119 .new_function("solid_fragment")
120 .expect("fragment function");
121 let increment = library
122 .new_function("increment")
123 .expect("increment function");
124
125 let archive_path = common::artifact_path("example-archive.metalarc");
126 let archive = device.new_binary_archive(None).expect("binary archive");
127 archive
128 .add_compute_function(&increment)
129 .expect("archive compute pipeline");
130 archive
131 .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
132 .expect("archive render pipeline");
133 archive
134 .serialize_to_file(&archive_path)
135 .expect("serialize binary archive");
136 let _ = device
137 .new_binary_archive(Some(&archive_path))
138 .expect("reload binary archive");
139 println!("binary archive written to {}", archive_path.display());
140 } else {
141 println!("dynamic libraries unsupported; skipping archive serialization");
142 }
143}Sourcepub fn new_residency_set(
&self,
label: Option<&str>,
initial_capacity: usize,
) -> Result<ResidencySet, String>
pub fn new_residency_set( &self, label: Option<&str>, initial_capacity: usize, ) -> Result<ResidencySet, String>
Examples found in repository?
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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn new_argument_encoder_with_descriptors(
&self,
descriptors: &[ArgumentDescriptor],
) -> Option<ArgumentEncoder>
pub fn new_argument_encoder_with_descriptors( &self, descriptors: &[ArgumentDescriptor], ) -> Option<ArgumentEncoder>
Create an argument encoder from a slice of MTLArgumentDescriptor values.
Sourcepub fn new_spatial_scaler(
&self,
descriptor: &SpatialScalerDescriptor,
) -> Option<SpatialScaler>
pub fn new_spatial_scaler( &self, descriptor: &SpatialScalerDescriptor, ) -> Option<SpatialScaler>
Create a MTLFXSpatialScaler for this device.
Sourcepub fn new_temporal_scaler(
&self,
descriptor: &TemporalScalerDescriptor,
) -> Option<TemporalScaler>
pub fn new_temporal_scaler( &self, descriptor: &TemporalScalerDescriptor, ) -> Option<TemporalScaler>
Create a MTLFXTemporalScaler for this device.
Sourcepub fn new_compute_pipeline_state_with_descriptor(
&self,
descriptor: &ComputePipelineDescriptor<'_>,
) -> Result<ComputePipelineState, String>
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.
Sourcepub fn new_render_pipeline_state_with_descriptor(
&self,
descriptor: &RenderPipelineDescriptor<'_>,
) -> Result<RenderPipelineState, String>
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.
Sourcepub fn new_tile_render_pipeline_state(
&self,
descriptor: &TileRenderPipelineDescriptor<'_>,
) -> Result<RenderPipelineState, String>
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.
Sourcepub fn new_render_pipeline_state(
&self,
vertex: &MetalFunction,
fragment: &MetalFunction,
color_pixel_format: usize,
sample_count: usize,
) -> Result<RenderPipelineState, String>
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?
11fn main() {
12 let device = MetalDevice::system_default().expect("Metal device available");
13 println!(
14 "device: {} (registry id {})",
15 device.name(),
16 device.registry_id()
17 );
18
19 let queue = device.new_command_queue().expect("command queue");
20 let status_buffer = queue
21 .new_command_buffer_with_unretained_references()
22 .expect("scratch command buffer");
23 println!("scratch command buffer status={}", status_buffer.status());
24
25 let src = device
26 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
27 .expect("source buffer");
28 let dst = device
29 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
30 .expect("destination buffer");
31 let blit_cb = queue.new_command_buffer().expect("blit command buffer");
32 let blit = blit_cb
33 .new_blit_command_encoder()
34 .expect("blit command encoder");
35 assert!(blit.fill_buffer(&src, 0..64, b'Z'));
36 assert!(blit.copy_buffer(&src, 0, &dst, 0, 64));
37 blit.end_encoding();
38 blit_cb.commit();
39 blit_cb.wait_until_completed();
40 let copied = unsafe {
41 core::slice::from_raw_parts(dst.contents().expect("dst contents").cast::<u8>(), 8)
42 };
43 println!("blit copied bytes: {copied:?}");
44
45 let library = device
46 .new_library_with_source(common::COMPUTE_SRC)
47 .expect("compile compute library");
48 let increment = library
49 .new_function("increment")
50 .expect("increment function");
51 let pipeline = device
52 .new_compute_pipeline_state(&increment)
53 .expect("compute pipeline");
54
55 let buffer = device
56 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
57 .expect("compute buffer");
58 common::write_u32_words(&buffer, &[10, 20, 30, 40]);
59 let compute_cb = queue.new_command_buffer().expect("compute command buffer");
60 let compute = compute_cb
61 .new_compute_command_encoder()
62 .expect("compute command encoder");
63 compute.set_compute_pipeline_state(&pipeline);
64 compute.set_buffer(&buffer, 0, 0);
65 compute.dispatch_threads((4, 1, 1), (1, 1, 1));
66 compute.end_encoding();
67 compute_cb.commit();
68 compute_cb.wait_until_completed();
69 println!("compute output: {:?}", common::read_u32_words(&buffer, 4));
70
71 let render_library = device
72 .new_library_with_source(common::RENDER_SRC)
73 .expect("compile render library");
74 let vertex = render_library
75 .new_function("fullscreen_vertex")
76 .expect("vertex function");
77 let fragment = render_library
78 .new_function("solid_fragment")
79 .expect("fragment function");
80 let render_pipeline = device
81 .new_render_pipeline_state(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
82 .expect("render pipeline");
83 println!("render pipeline label: {:?}", render_pipeline.label());
84
85 let render_target = device
86 .new_texture(common::shared_render_target(4, 4))
87 .expect("render target");
88 let vertex_buffer = device
89 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
90 .expect("vertex buffer");
91 let render_cb = queue.new_command_buffer().expect("render command buffer");
92 let render = render_cb
93 .new_render_command_encoder(
94 &render_target,
95 load_action::CLEAR,
96 store_action::STORE,
97 [0.0, 0.0, 0.0, 1.0],
98 )
99 .expect("render command encoder");
100 render.set_render_pipeline_state(&render_pipeline);
101 render.set_vertex_buffer(&vertex_buffer, 0, 0);
102 render.draw_primitives(primitive_type::TRIANGLE, 0, 3);
103 render.end_encoding();
104 render_cb.commit();
105 render_cb.wait_until_completed();
106
107 let mut rendered = vec![0_u8; 4 * 4 * 4];
108 assert!(render_target.read_bytes_2d(&mut rendered, 16, (0, 0), (4, 4), 0));
109 println!("first rendered pixel: {:?}", &rendered[..4]);
110
111 let shared_texture = device
112 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
113 .expect("shared texture");
114 let upload = vec![0x22_u8; 4 * 4 * 4];
115 assert!(shared_texture.replace_region_2d(&upload, 16, (0, 0), (4, 4), 0));
116 let mut download = vec![0_u8; upload.len()];
117 assert!(shared_texture.read_bytes_2d(&mut download, 16, (0, 0), (4, 4), 0));
118 let view = shared_texture
119 .new_view(pixel_format::BGRA8UNORM)
120 .expect("texture view");
121 println!(
122 "texture {}x{} usage={} storage_mode={} view_width={}",
123 shared_texture.width(),
124 shared_texture.height(),
125 shared_texture.usage(),
126 shared_texture.storage_mode(),
127 view.width(),
128 );
129}Sourcepub fn argument_buffers_support(&self) -> usize
pub fn argument_buffers_support(&self) -> usize
Query the device for the supported argument-buffer tier.
Sourcepub fn new_depth_stencil_state(
&self,
descriptor: &DepthStencilDescriptor,
) -> Option<DepthStencilState>
pub fn new_depth_stencil_state( &self, descriptor: &DepthStencilDescriptor, ) -> Option<DepthStencilState>
Compile a MTLDepthStencilState from the given descriptor.
Sourcepub fn new_sampler_state(
&self,
descriptor: &SamplerDescriptor,
) -> Option<SamplerState>
pub fn new_sampler_state( &self, descriptor: &SamplerDescriptor, ) -> Option<SamplerState>
Compile a MTLSamplerState from the given descriptor.
Sourcepub fn has_unified_memory(&self) -> bool
pub fn has_unified_memory(&self) -> bool
True if the GPU uses unified memory (Apple Silicon).
Examples found in repository?
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, contents={:?}",
18 buf.length(),
19 buf.contents().is_some()
20 );
21 let n = buf.write_bytes(b"hello metal");
22 println!("wrote {n} bytes");
23
24 let tx = d
25 .new_texture(TextureDescriptor::new_2d(
26 256,
27 256,
28 pixel_format::BGRA8UNORM,
29 ))
30 .expect("texture create failed");
31 println!(
32 "texture {}x{} fmt={}",
33 tx.width(),
34 tx.height(),
35 tx.pixel_format()
36 );
37}More examples
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 let slice: &mut [f32] = unsafe {
44 core::slice::from_raw_parts_mut(
45 buffer.contents().expect("buffer.contents").cast::<f32>(),
46 N,
47 )
48 };
49 for (i, x) in slice.iter_mut().enumerate() {
50 *x = i as f32;
51 }
52 println!("Input : {slice:?}");
53
54 let queue = device.new_command_queue().expect("MTLCommandQueue");
55 let cb = queue.new_command_buffer().expect("MTLCommandBuffer");
56 let ok = cb.dispatch_compute_1d(&pso, &[&buffer], N, 1);
57 assert!(ok, "dispatch_compute_1d failed");
58 cb.commit();
59 cb.wait_until_completed();
60
61 let slice: &[f32] = unsafe {
62 core::slice::from_raw_parts(buffer.contents().expect("buffer.contents").cast::<f32>(), N)
63 };
64 println!("Output: {slice:?}");
65
66 for (i, &v) in slice.iter().enumerate() {
67 let expected = (i as f32) * 2.0;
68 assert_eq!(v, expected, "element {i} expected {expected} got {v}");
69 }
70 println!("✅ All {N} elements correctly doubled by the GPU kernel");
71}Sourcepub fn recommended_max_working_set_size(&self) -> u64
pub fn recommended_max_working_set_size(&self) -> u64
Recommended maximum working-set size in bytes.
Examples found in repository?
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, contents={:?}",
18 buf.length(),
19 buf.contents().is_some()
20 );
21 let n = buf.write_bytes(b"hello metal");
22 println!("wrote {n} bytes");
23
24 let tx = d
25 .new_texture(TextureDescriptor::new_2d(
26 256,
27 256,
28 pixel_format::BGRA8UNORM,
29 ))
30 .expect("texture create failed");
31 println!(
32 "texture {}x{} fmt={}",
33 tx.width(),
34 tx.height(),
35 tx.pixel_format()
36 );
37}Sourcepub fn supports_family(&self, family: i64) -> bool
pub fn supports_family(&self, family: i64) -> bool
True if this device supports the requested feature family —
see gpu_family.
Examples found in repository?
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, contents={:?}",
18 buf.length(),
19 buf.contents().is_some()
20 );
21 let n = buf.write_bytes(b"hello metal");
22 println!("wrote {n} bytes");
23
24 let tx = d
25 .new_texture(TextureDescriptor::new_2d(
26 256,
27 256,
28 pixel_format::BGRA8UNORM,
29 ))
30 .expect("texture create failed");
31 println!(
32 "texture {}x{} fmt={}",
33 tx.width(),
34 tx.height(),
35 tx.pixel_format()
36 );
37}Sourcepub fn new_buffer(&self, length: usize, options: usize) -> Option<MetalBuffer>
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?
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 let _ = src.write_bytes(b"hello GPU blit from apple-metal-rs!!!!!");
13
14 let cb = queue.new_command_buffer().expect("cb");
15 assert!(cb.blit_copy_buffer(&src, 0, &dst, 0, 64));
16 cb.commit();
17 cb.wait_until_completed();
18
19 let p = dst.contents().unwrap().cast::<u8>();
20 let bytes = unsafe { core::slice::from_raw_parts(p, 40) };
21 let s = String::from_utf8_lossy(bytes);
22 println!("GPU blit result: {s:?}");
23 assert!(s.starts_with("hello GPU blit"));
24}More examples
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, contents={:?}",
18 buf.length(),
19 buf.contents().is_some()
20 );
21 let n = buf.write_bytes(b"hello metal");
22 println!("wrote {n} bytes");
23
24 let tx = d
25 .new_texture(TextureDescriptor::new_2d(
26 256,
27 256,
28 pixel_format::BGRA8UNORM,
29 ))
30 .expect("texture create failed");
31 println!(
32 "texture {}x{} fmt={}",
33 tx.width(),
34 tx.height(),
35 tx.pixel_format()
36 );
37}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 let slice: &mut [f32] = unsafe {
44 core::slice::from_raw_parts_mut(
45 buffer.contents().expect("buffer.contents").cast::<f32>(),
46 N,
47 )
48 };
49 for (i, x) in slice.iter_mut().enumerate() {
50 *x = i as f32;
51 }
52 println!("Input : {slice:?}");
53
54 let queue = device.new_command_queue().expect("MTLCommandQueue");
55 let cb = queue.new_command_buffer().expect("MTLCommandBuffer");
56 let ok = cb.dispatch_compute_1d(&pso, &[&buffer], N, 1);
57 assert!(ok, "dispatch_compute_1d failed");
58 cb.commit();
59 cb.wait_until_completed();
60
61 let slice: &[f32] = unsafe {
62 core::slice::from_raw_parts(buffer.contents().expect("buffer.contents").cast::<f32>(), N)
63 };
64 println!("Output: {slice:?}");
65
66 for (i, &v) in slice.iter().enumerate() {
67 let expected = (i as f32) * 2.0;
68 assert_eq!(v, expected, "element {i} expected {expected} got {v}");
69 }
70 println!("✅ All {N} elements correctly doubled by the GPU kernel");
71}11fn main() {
12 let device = MetalDevice::system_default().expect("Metal device available");
13 println!(
14 "device: {} (registry id {})",
15 device.name(),
16 device.registry_id()
17 );
18
19 let queue = device.new_command_queue().expect("command queue");
20 let status_buffer = queue
21 .new_command_buffer_with_unretained_references()
22 .expect("scratch command buffer");
23 println!("scratch command buffer status={}", status_buffer.status());
24
25 let src = device
26 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
27 .expect("source buffer");
28 let dst = device
29 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
30 .expect("destination buffer");
31 let blit_cb = queue.new_command_buffer().expect("blit command buffer");
32 let blit = blit_cb
33 .new_blit_command_encoder()
34 .expect("blit command encoder");
35 assert!(blit.fill_buffer(&src, 0..64, b'Z'));
36 assert!(blit.copy_buffer(&src, 0, &dst, 0, 64));
37 blit.end_encoding();
38 blit_cb.commit();
39 blit_cb.wait_until_completed();
40 let copied = unsafe {
41 core::slice::from_raw_parts(dst.contents().expect("dst contents").cast::<u8>(), 8)
42 };
43 println!("blit copied bytes: {copied:?}");
44
45 let library = device
46 .new_library_with_source(common::COMPUTE_SRC)
47 .expect("compile compute library");
48 let increment = library
49 .new_function("increment")
50 .expect("increment function");
51 let pipeline = device
52 .new_compute_pipeline_state(&increment)
53 .expect("compute pipeline");
54
55 let buffer = device
56 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
57 .expect("compute buffer");
58 common::write_u32_words(&buffer, &[10, 20, 30, 40]);
59 let compute_cb = queue.new_command_buffer().expect("compute command buffer");
60 let compute = compute_cb
61 .new_compute_command_encoder()
62 .expect("compute command encoder");
63 compute.set_compute_pipeline_state(&pipeline);
64 compute.set_buffer(&buffer, 0, 0);
65 compute.dispatch_threads((4, 1, 1), (1, 1, 1));
66 compute.end_encoding();
67 compute_cb.commit();
68 compute_cb.wait_until_completed();
69 println!("compute output: {:?}", common::read_u32_words(&buffer, 4));
70
71 let render_library = device
72 .new_library_with_source(common::RENDER_SRC)
73 .expect("compile render library");
74 let vertex = render_library
75 .new_function("fullscreen_vertex")
76 .expect("vertex function");
77 let fragment = render_library
78 .new_function("solid_fragment")
79 .expect("fragment function");
80 let render_pipeline = device
81 .new_render_pipeline_state(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
82 .expect("render pipeline");
83 println!("render pipeline label: {:?}", render_pipeline.label());
84
85 let render_target = device
86 .new_texture(common::shared_render_target(4, 4))
87 .expect("render target");
88 let vertex_buffer = device
89 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
90 .expect("vertex buffer");
91 let render_cb = queue.new_command_buffer().expect("render command buffer");
92 let render = render_cb
93 .new_render_command_encoder(
94 &render_target,
95 load_action::CLEAR,
96 store_action::STORE,
97 [0.0, 0.0, 0.0, 1.0],
98 )
99 .expect("render command encoder");
100 render.set_render_pipeline_state(&render_pipeline);
101 render.set_vertex_buffer(&vertex_buffer, 0, 0);
102 render.draw_primitives(primitive_type::TRIANGLE, 0, 3);
103 render.end_encoding();
104 render_cb.commit();
105 render_cb.wait_until_completed();
106
107 let mut rendered = vec![0_u8; 4 * 4 * 4];
108 assert!(render_target.read_bytes_2d(&mut rendered, 16, (0, 0), (4, 4), 0));
109 println!("first rendered pixel: {:?}", &rendered[..4]);
110
111 let shared_texture = device
112 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
113 .expect("shared texture");
114 let upload = vec![0x22_u8; 4 * 4 * 4];
115 assert!(shared_texture.replace_region_2d(&upload, 16, (0, 0), (4, 4), 0));
116 let mut download = vec![0_u8; upload.len()];
117 assert!(shared_texture.read_bytes_2d(&mut download, 16, (0, 0), (4, 4), 0));
118 let view = shared_texture
119 .new_view(pixel_format::BGRA8UNORM)
120 .expect("texture view");
121 println!(
122 "texture {}x{} usage={} storage_mode={} view_width={}",
123 shared_texture.width(),
124 shared_texture.height(),
125 shared_texture.usage(),
126 shared_texture.storage_mode(),
127 view.width(),
128 );
129}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 = queue
18 .new_command_buffer_with_unretained_references()
19 .expect("bounded scratch command buffer");
20 println!("bounded queue scratch status={}", scratch.status());
21
22 let library = device
23 .new_library_with_source(common::COMPUTE_SRC)
24 .expect("compile compute library");
25 let args = library.new_function("use_args").expect("use_args function");
26 let argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
27 let argument_buffer = device
28 .new_buffer(
29 argument_encoder.encoded_length(),
30 resource_options::STORAGE_MODE_SHARED,
31 )
32 .expect("argument buffer");
33 let payload = device
34 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
35 .expect("payload buffer");
36 let texture = device
37 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
38 .expect("argument texture");
39 argument_encoder.set_argument_buffer(&argument_buffer, 0);
40 argument_encoder.set_buffer(&payload, 0, 0);
41 argument_encoder.set_texture(&texture, 1);
42 println!(
43 "argument encoder length={} alignment={}",
44 argument_encoder.encoded_length(),
45 argument_encoder.alignment(),
46 );
47
48 let backing = device
49 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
50 .expect("backing buffer");
51 let buffer_texture = backing
52 .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
53 .expect("buffer-backed texture");
54 println!(
55 "buffer-backed texture {}x{} fmt={}",
56 buffer_texture.width(),
57 buffer_texture.height(),
58 buffer_texture.pixel_format(),
59 );
60
61 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
62 let heap_buffer = heap
63 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
64 .expect("heap buffer");
65 let heap_texture = heap
66 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
67 .expect("heap texture");
68 println!(
69 "heap size={} used={} current={} max_available={}",
70 heap.size(),
71 heap.used_size(),
72 heap.current_allocated_size(),
73 heap.max_available_size(256),
74 );
75 println!(
76 "heap buffer len={} heap texture {}x{} purgeable={}",
77 heap_buffer.length(),
78 heap_texture.width(),
79 heap_texture.height(),
80 heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
81 );
82 } else {
83 println!("heaps are unavailable on this device");
84 }
85
86 match device.new_log_state(log_level::INFO, 1_024) {
87 Ok(log_state) => {
88 let _ = device
89 .new_command_queue_with_log_state(4, &log_state)
90 .expect("log-state queue");
91 println!("created queue with log state");
92 }
93 Err(error) => println!("log state unavailable on this OS: {error}"),
94 }
95
96 if device.supports_dynamic_libraries() {
97 let dynamic_path = common::artifact_path("example-dylib.metallib");
98 let dynamic_library = device
99 .new_dynamic_library_with_source(
100 common::DYNAMIC_LIB_SRC,
101 dynamic_path.to_string_lossy().as_ref(),
102 )
103 .expect("dynamic library from source");
104 dynamic_library
105 .serialize_to_file(&dynamic_path)
106 .expect("serialize dynamic library");
107 let reloaded = device
108 .load_dynamic_library(&dynamic_path)
109 .expect("reload dynamic library");
110 println!("dynamic library install name: {}", reloaded.install_name());
111
112 let render_library = device
113 .new_library_with_source(common::RENDER_SRC)
114 .expect("compile render library");
115 let vertex = render_library
116 .new_function("fullscreen_vertex")
117 .expect("vertex function");
118 let fragment = render_library
119 .new_function("solid_fragment")
120 .expect("fragment function");
121 let increment = library
122 .new_function("increment")
123 .expect("increment function");
124
125 let archive_path = common::artifact_path("example-archive.metalarc");
126 let archive = device.new_binary_archive(None).expect("binary archive");
127 archive
128 .add_compute_function(&increment)
129 .expect("archive compute pipeline");
130 archive
131 .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
132 .expect("archive render pipeline");
133 archive
134 .serialize_to_file(&archive_path)
135 .expect("serialize binary archive");
136 let _ = device
137 .new_binary_archive(Some(&archive_path))
138 .expect("reload binary archive");
139 println!("binary archive written to {}", archive_path.display());
140 } else {
141 println!("dynamic libraries unsupported; skipping archive serialization");
142 }
143}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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn new_texture(&self, descriptor: TextureDescriptor) -> Option<MetalTexture>
pub fn new_texture(&self, descriptor: TextureDescriptor) -> Option<MetalTexture>
Allocate a fresh MTLTexture matching descriptor.
Examples found in repository?
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, contents={:?}",
18 buf.length(),
19 buf.contents().is_some()
20 );
21 let n = buf.write_bytes(b"hello metal");
22 println!("wrote {n} bytes");
23
24 let tx = d
25 .new_texture(TextureDescriptor::new_2d(
26 256,
27 256,
28 pixel_format::BGRA8UNORM,
29 ))
30 .expect("texture create failed");
31 println!(
32 "texture {}x{} fmt={}",
33 tx.width(),
34 tx.height(),
35 tx.pixel_format()
36 );
37}More examples
11fn main() {
12 let device = MetalDevice::system_default().expect("Metal device available");
13 println!(
14 "device: {} (registry id {})",
15 device.name(),
16 device.registry_id()
17 );
18
19 let queue = device.new_command_queue().expect("command queue");
20 let status_buffer = queue
21 .new_command_buffer_with_unretained_references()
22 .expect("scratch command buffer");
23 println!("scratch command buffer status={}", status_buffer.status());
24
25 let src = device
26 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
27 .expect("source buffer");
28 let dst = device
29 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
30 .expect("destination buffer");
31 let blit_cb = queue.new_command_buffer().expect("blit command buffer");
32 let blit = blit_cb
33 .new_blit_command_encoder()
34 .expect("blit command encoder");
35 assert!(blit.fill_buffer(&src, 0..64, b'Z'));
36 assert!(blit.copy_buffer(&src, 0, &dst, 0, 64));
37 blit.end_encoding();
38 blit_cb.commit();
39 blit_cb.wait_until_completed();
40 let copied = unsafe {
41 core::slice::from_raw_parts(dst.contents().expect("dst contents").cast::<u8>(), 8)
42 };
43 println!("blit copied bytes: {copied:?}");
44
45 let library = device
46 .new_library_with_source(common::COMPUTE_SRC)
47 .expect("compile compute library");
48 let increment = library
49 .new_function("increment")
50 .expect("increment function");
51 let pipeline = device
52 .new_compute_pipeline_state(&increment)
53 .expect("compute pipeline");
54
55 let buffer = device
56 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
57 .expect("compute buffer");
58 common::write_u32_words(&buffer, &[10, 20, 30, 40]);
59 let compute_cb = queue.new_command_buffer().expect("compute command buffer");
60 let compute = compute_cb
61 .new_compute_command_encoder()
62 .expect("compute command encoder");
63 compute.set_compute_pipeline_state(&pipeline);
64 compute.set_buffer(&buffer, 0, 0);
65 compute.dispatch_threads((4, 1, 1), (1, 1, 1));
66 compute.end_encoding();
67 compute_cb.commit();
68 compute_cb.wait_until_completed();
69 println!("compute output: {:?}", common::read_u32_words(&buffer, 4));
70
71 let render_library = device
72 .new_library_with_source(common::RENDER_SRC)
73 .expect("compile render library");
74 let vertex = render_library
75 .new_function("fullscreen_vertex")
76 .expect("vertex function");
77 let fragment = render_library
78 .new_function("solid_fragment")
79 .expect("fragment function");
80 let render_pipeline = device
81 .new_render_pipeline_state(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
82 .expect("render pipeline");
83 println!("render pipeline label: {:?}", render_pipeline.label());
84
85 let render_target = device
86 .new_texture(common::shared_render_target(4, 4))
87 .expect("render target");
88 let vertex_buffer = device
89 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
90 .expect("vertex buffer");
91 let render_cb = queue.new_command_buffer().expect("render command buffer");
92 let render = render_cb
93 .new_render_command_encoder(
94 &render_target,
95 load_action::CLEAR,
96 store_action::STORE,
97 [0.0, 0.0, 0.0, 1.0],
98 )
99 .expect("render command encoder");
100 render.set_render_pipeline_state(&render_pipeline);
101 render.set_vertex_buffer(&vertex_buffer, 0, 0);
102 render.draw_primitives(primitive_type::TRIANGLE, 0, 3);
103 render.end_encoding();
104 render_cb.commit();
105 render_cb.wait_until_completed();
106
107 let mut rendered = vec![0_u8; 4 * 4 * 4];
108 assert!(render_target.read_bytes_2d(&mut rendered, 16, (0, 0), (4, 4), 0));
109 println!("first rendered pixel: {:?}", &rendered[..4]);
110
111 let shared_texture = device
112 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
113 .expect("shared texture");
114 let upload = vec![0x22_u8; 4 * 4 * 4];
115 assert!(shared_texture.replace_region_2d(&upload, 16, (0, 0), (4, 4), 0));
116 let mut download = vec![0_u8; upload.len()];
117 assert!(shared_texture.read_bytes_2d(&mut download, 16, (0, 0), (4, 4), 0));
118 let view = shared_texture
119 .new_view(pixel_format::BGRA8UNORM)
120 .expect("texture view");
121 println!(
122 "texture {}x{} usage={} storage_mode={} view_width={}",
123 shared_texture.width(),
124 shared_texture.height(),
125 shared_texture.usage(),
126 shared_texture.storage_mode(),
127 view.width(),
128 );
129}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 = queue
18 .new_command_buffer_with_unretained_references()
19 .expect("bounded scratch command buffer");
20 println!("bounded queue scratch status={}", scratch.status());
21
22 let library = device
23 .new_library_with_source(common::COMPUTE_SRC)
24 .expect("compile compute library");
25 let args = library.new_function("use_args").expect("use_args function");
26 let argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
27 let argument_buffer = device
28 .new_buffer(
29 argument_encoder.encoded_length(),
30 resource_options::STORAGE_MODE_SHARED,
31 )
32 .expect("argument buffer");
33 let payload = device
34 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
35 .expect("payload buffer");
36 let texture = device
37 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
38 .expect("argument texture");
39 argument_encoder.set_argument_buffer(&argument_buffer, 0);
40 argument_encoder.set_buffer(&payload, 0, 0);
41 argument_encoder.set_texture(&texture, 1);
42 println!(
43 "argument encoder length={} alignment={}",
44 argument_encoder.encoded_length(),
45 argument_encoder.alignment(),
46 );
47
48 let backing = device
49 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
50 .expect("backing buffer");
51 let buffer_texture = backing
52 .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
53 .expect("buffer-backed texture");
54 println!(
55 "buffer-backed texture {}x{} fmt={}",
56 buffer_texture.width(),
57 buffer_texture.height(),
58 buffer_texture.pixel_format(),
59 );
60
61 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
62 let heap_buffer = heap
63 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
64 .expect("heap buffer");
65 let heap_texture = heap
66 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
67 .expect("heap texture");
68 println!(
69 "heap size={} used={} current={} max_available={}",
70 heap.size(),
71 heap.used_size(),
72 heap.current_allocated_size(),
73 heap.max_available_size(256),
74 );
75 println!(
76 "heap buffer len={} heap texture {}x{} purgeable={}",
77 heap_buffer.length(),
78 heap_texture.width(),
79 heap_texture.height(),
80 heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
81 );
82 } else {
83 println!("heaps are unavailable on this device");
84 }
85
86 match device.new_log_state(log_level::INFO, 1_024) {
87 Ok(log_state) => {
88 let _ = device
89 .new_command_queue_with_log_state(4, &log_state)
90 .expect("log-state queue");
91 println!("created queue with log state");
92 }
93 Err(error) => println!("log state unavailable on this OS: {error}"),
94 }
95
96 if device.supports_dynamic_libraries() {
97 let dynamic_path = common::artifact_path("example-dylib.metallib");
98 let dynamic_library = device
99 .new_dynamic_library_with_source(
100 common::DYNAMIC_LIB_SRC,
101 dynamic_path.to_string_lossy().as_ref(),
102 )
103 .expect("dynamic library from source");
104 dynamic_library
105 .serialize_to_file(&dynamic_path)
106 .expect("serialize dynamic library");
107 let reloaded = device
108 .load_dynamic_library(&dynamic_path)
109 .expect("reload dynamic library");
110 println!("dynamic library install name: {}", reloaded.install_name());
111
112 let render_library = device
113 .new_library_with_source(common::RENDER_SRC)
114 .expect("compile render library");
115 let vertex = render_library
116 .new_function("fullscreen_vertex")
117 .expect("vertex function");
118 let fragment = render_library
119 .new_function("solid_fragment")
120 .expect("fragment function");
121 let increment = library
122 .new_function("increment")
123 .expect("increment function");
124
125 let archive_path = common::artifact_path("example-archive.metalarc");
126 let archive = device.new_binary_archive(None).expect("binary archive");
127 archive
128 .add_compute_function(&increment)
129 .expect("archive compute pipeline");
130 archive
131 .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
132 .expect("archive render pipeline");
133 archive
134 .serialize_to_file(&archive_path)
135 .expect("serialize binary archive");
136 let _ = device
137 .new_binary_archive(Some(&archive_path))
138 .expect("reload binary archive");
139 println!("binary archive written to {}", archive_path.display());
140 } else {
141 println!("dynamic libraries unsupported; skipping archive serialization");
142 }
143}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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn new_command_queue(&self) -> Option<CommandQueue>
pub fn new_command_queue(&self) -> Option<CommandQueue>
Create a new MTLCommandQueue to schedule GPU work.
Examples found in repository?
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 let _ = src.write_bytes(b"hello GPU blit from apple-metal-rs!!!!!");
13
14 let cb = queue.new_command_buffer().expect("cb");
15 assert!(cb.blit_copy_buffer(&src, 0, &dst, 0, 64));
16 cb.commit();
17 cb.wait_until_completed();
18
19 let p = dst.contents().unwrap().cast::<u8>();
20 let bytes = unsafe { core::slice::from_raw_parts(p, 40) };
21 let s = String::from_utf8_lossy(bytes);
22 println!("GPU blit result: {s:?}");
23 assert!(s.starts_with("hello GPU blit"));
24}More examples
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 let slice: &mut [f32] = unsafe {
44 core::slice::from_raw_parts_mut(
45 buffer.contents().expect("buffer.contents").cast::<f32>(),
46 N,
47 )
48 };
49 for (i, x) in slice.iter_mut().enumerate() {
50 *x = i as f32;
51 }
52 println!("Input : {slice:?}");
53
54 let queue = device.new_command_queue().expect("MTLCommandQueue");
55 let cb = queue.new_command_buffer().expect("MTLCommandBuffer");
56 let ok = cb.dispatch_compute_1d(&pso, &[&buffer], N, 1);
57 assert!(ok, "dispatch_compute_1d failed");
58 cb.commit();
59 cb.wait_until_completed();
60
61 let slice: &[f32] = unsafe {
62 core::slice::from_raw_parts(buffer.contents().expect("buffer.contents").cast::<f32>(), N)
63 };
64 println!("Output: {slice:?}");
65
66 for (i, &v) in slice.iter().enumerate() {
67 let expected = (i as f32) * 2.0;
68 assert_eq!(v, expected, "element {i} expected {expected} got {v}");
69 }
70 println!("✅ All {N} elements correctly doubled by the GPU kernel");
71}11fn main() {
12 let device = MetalDevice::system_default().expect("Metal device available");
13 println!(
14 "device: {} (registry id {})",
15 device.name(),
16 device.registry_id()
17 );
18
19 let queue = device.new_command_queue().expect("command queue");
20 let status_buffer = queue
21 .new_command_buffer_with_unretained_references()
22 .expect("scratch command buffer");
23 println!("scratch command buffer status={}", status_buffer.status());
24
25 let src = device
26 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
27 .expect("source buffer");
28 let dst = device
29 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
30 .expect("destination buffer");
31 let blit_cb = queue.new_command_buffer().expect("blit command buffer");
32 let blit = blit_cb
33 .new_blit_command_encoder()
34 .expect("blit command encoder");
35 assert!(blit.fill_buffer(&src, 0..64, b'Z'));
36 assert!(blit.copy_buffer(&src, 0, &dst, 0, 64));
37 blit.end_encoding();
38 blit_cb.commit();
39 blit_cb.wait_until_completed();
40 let copied = unsafe {
41 core::slice::from_raw_parts(dst.contents().expect("dst contents").cast::<u8>(), 8)
42 };
43 println!("blit copied bytes: {copied:?}");
44
45 let library = device
46 .new_library_with_source(common::COMPUTE_SRC)
47 .expect("compile compute library");
48 let increment = library
49 .new_function("increment")
50 .expect("increment function");
51 let pipeline = device
52 .new_compute_pipeline_state(&increment)
53 .expect("compute pipeline");
54
55 let buffer = device
56 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
57 .expect("compute buffer");
58 common::write_u32_words(&buffer, &[10, 20, 30, 40]);
59 let compute_cb = queue.new_command_buffer().expect("compute command buffer");
60 let compute = compute_cb
61 .new_compute_command_encoder()
62 .expect("compute command encoder");
63 compute.set_compute_pipeline_state(&pipeline);
64 compute.set_buffer(&buffer, 0, 0);
65 compute.dispatch_threads((4, 1, 1), (1, 1, 1));
66 compute.end_encoding();
67 compute_cb.commit();
68 compute_cb.wait_until_completed();
69 println!("compute output: {:?}", common::read_u32_words(&buffer, 4));
70
71 let render_library = device
72 .new_library_with_source(common::RENDER_SRC)
73 .expect("compile render library");
74 let vertex = render_library
75 .new_function("fullscreen_vertex")
76 .expect("vertex function");
77 let fragment = render_library
78 .new_function("solid_fragment")
79 .expect("fragment function");
80 let render_pipeline = device
81 .new_render_pipeline_state(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
82 .expect("render pipeline");
83 println!("render pipeline label: {:?}", render_pipeline.label());
84
85 let render_target = device
86 .new_texture(common::shared_render_target(4, 4))
87 .expect("render target");
88 let vertex_buffer = device
89 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
90 .expect("vertex buffer");
91 let render_cb = queue.new_command_buffer().expect("render command buffer");
92 let render = render_cb
93 .new_render_command_encoder(
94 &render_target,
95 load_action::CLEAR,
96 store_action::STORE,
97 [0.0, 0.0, 0.0, 1.0],
98 )
99 .expect("render command encoder");
100 render.set_render_pipeline_state(&render_pipeline);
101 render.set_vertex_buffer(&vertex_buffer, 0, 0);
102 render.draw_primitives(primitive_type::TRIANGLE, 0, 3);
103 render.end_encoding();
104 render_cb.commit();
105 render_cb.wait_until_completed();
106
107 let mut rendered = vec![0_u8; 4 * 4 * 4];
108 assert!(render_target.read_bytes_2d(&mut rendered, 16, (0, 0), (4, 4), 0));
109 println!("first rendered pixel: {:?}", &rendered[..4]);
110
111 let shared_texture = device
112 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
113 .expect("shared texture");
114 let upload = vec![0x22_u8; 4 * 4 * 4];
115 assert!(shared_texture.replace_region_2d(&upload, 16, (0, 0), (4, 4), 0));
116 let mut download = vec![0_u8; upload.len()];
117 assert!(shared_texture.read_bytes_2d(&mut download, 16, (0, 0), (4, 4), 0));
118 let view = shared_texture
119 .new_view(pixel_format::BGRA8UNORM)
120 .expect("texture view");
121 println!(
122 "texture {}x{} usage={} storage_mode={} view_width={}",
123 shared_texture.width(),
124 shared_texture.height(),
125 shared_texture.usage(),
126 shared_texture.storage_mode(),
127 view.width(),
128 );
129}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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn new_library_with_source(
&self,
source: &str,
) -> Result<MetalLibrary, String>
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?
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 let slice: &mut [f32] = unsafe {
44 core::slice::from_raw_parts_mut(
45 buffer.contents().expect("buffer.contents").cast::<f32>(),
46 N,
47 )
48 };
49 for (i, x) in slice.iter_mut().enumerate() {
50 *x = i as f32;
51 }
52 println!("Input : {slice:?}");
53
54 let queue = device.new_command_queue().expect("MTLCommandQueue");
55 let cb = queue.new_command_buffer().expect("MTLCommandBuffer");
56 let ok = cb.dispatch_compute_1d(&pso, &[&buffer], N, 1);
57 assert!(ok, "dispatch_compute_1d failed");
58 cb.commit();
59 cb.wait_until_completed();
60
61 let slice: &[f32] = unsafe {
62 core::slice::from_raw_parts(buffer.contents().expect("buffer.contents").cast::<f32>(), N)
63 };
64 println!("Output: {slice:?}");
65
66 for (i, &v) in slice.iter().enumerate() {
67 let expected = (i as f32) * 2.0;
68 assert_eq!(v, expected, "element {i} expected {expected} got {v}");
69 }
70 println!("✅ All {N} elements correctly doubled by the GPU kernel");
71}More examples
11fn main() {
12 let device = MetalDevice::system_default().expect("Metal device available");
13 println!(
14 "device: {} (registry id {})",
15 device.name(),
16 device.registry_id()
17 );
18
19 let queue = device.new_command_queue().expect("command queue");
20 let status_buffer = queue
21 .new_command_buffer_with_unretained_references()
22 .expect("scratch command buffer");
23 println!("scratch command buffer status={}", status_buffer.status());
24
25 let src = device
26 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
27 .expect("source buffer");
28 let dst = device
29 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
30 .expect("destination buffer");
31 let blit_cb = queue.new_command_buffer().expect("blit command buffer");
32 let blit = blit_cb
33 .new_blit_command_encoder()
34 .expect("blit command encoder");
35 assert!(blit.fill_buffer(&src, 0..64, b'Z'));
36 assert!(blit.copy_buffer(&src, 0, &dst, 0, 64));
37 blit.end_encoding();
38 blit_cb.commit();
39 blit_cb.wait_until_completed();
40 let copied = unsafe {
41 core::slice::from_raw_parts(dst.contents().expect("dst contents").cast::<u8>(), 8)
42 };
43 println!("blit copied bytes: {copied:?}");
44
45 let library = device
46 .new_library_with_source(common::COMPUTE_SRC)
47 .expect("compile compute library");
48 let increment = library
49 .new_function("increment")
50 .expect("increment function");
51 let pipeline = device
52 .new_compute_pipeline_state(&increment)
53 .expect("compute pipeline");
54
55 let buffer = device
56 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
57 .expect("compute buffer");
58 common::write_u32_words(&buffer, &[10, 20, 30, 40]);
59 let compute_cb = queue.new_command_buffer().expect("compute command buffer");
60 let compute = compute_cb
61 .new_compute_command_encoder()
62 .expect("compute command encoder");
63 compute.set_compute_pipeline_state(&pipeline);
64 compute.set_buffer(&buffer, 0, 0);
65 compute.dispatch_threads((4, 1, 1), (1, 1, 1));
66 compute.end_encoding();
67 compute_cb.commit();
68 compute_cb.wait_until_completed();
69 println!("compute output: {:?}", common::read_u32_words(&buffer, 4));
70
71 let render_library = device
72 .new_library_with_source(common::RENDER_SRC)
73 .expect("compile render library");
74 let vertex = render_library
75 .new_function("fullscreen_vertex")
76 .expect("vertex function");
77 let fragment = render_library
78 .new_function("solid_fragment")
79 .expect("fragment function");
80 let render_pipeline = device
81 .new_render_pipeline_state(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
82 .expect("render pipeline");
83 println!("render pipeline label: {:?}", render_pipeline.label());
84
85 let render_target = device
86 .new_texture(common::shared_render_target(4, 4))
87 .expect("render target");
88 let vertex_buffer = device
89 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
90 .expect("vertex buffer");
91 let render_cb = queue.new_command_buffer().expect("render command buffer");
92 let render = render_cb
93 .new_render_command_encoder(
94 &render_target,
95 load_action::CLEAR,
96 store_action::STORE,
97 [0.0, 0.0, 0.0, 1.0],
98 )
99 .expect("render command encoder");
100 render.set_render_pipeline_state(&render_pipeline);
101 render.set_vertex_buffer(&vertex_buffer, 0, 0);
102 render.draw_primitives(primitive_type::TRIANGLE, 0, 3);
103 render.end_encoding();
104 render_cb.commit();
105 render_cb.wait_until_completed();
106
107 let mut rendered = vec![0_u8; 4 * 4 * 4];
108 assert!(render_target.read_bytes_2d(&mut rendered, 16, (0, 0), (4, 4), 0));
109 println!("first rendered pixel: {:?}", &rendered[..4]);
110
111 let shared_texture = device
112 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
113 .expect("shared texture");
114 let upload = vec![0x22_u8; 4 * 4 * 4];
115 assert!(shared_texture.replace_region_2d(&upload, 16, (0, 0), (4, 4), 0));
116 let mut download = vec![0_u8; upload.len()];
117 assert!(shared_texture.read_bytes_2d(&mut download, 16, (0, 0), (4, 4), 0));
118 let view = shared_texture
119 .new_view(pixel_format::BGRA8UNORM)
120 .expect("texture view");
121 println!(
122 "texture {}x{} usage={} storage_mode={} view_width={}",
123 shared_texture.width(),
124 shared_texture.height(),
125 shared_texture.usage(),
126 shared_texture.storage_mode(),
127 view.width(),
128 );
129}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 = queue
18 .new_command_buffer_with_unretained_references()
19 .expect("bounded scratch command buffer");
20 println!("bounded queue scratch status={}", scratch.status());
21
22 let library = device
23 .new_library_with_source(common::COMPUTE_SRC)
24 .expect("compile compute library");
25 let args = library.new_function("use_args").expect("use_args function");
26 let argument_encoder = args.new_argument_encoder(0).expect("argument encoder");
27 let argument_buffer = device
28 .new_buffer(
29 argument_encoder.encoded_length(),
30 resource_options::STORAGE_MODE_SHARED,
31 )
32 .expect("argument buffer");
33 let payload = device
34 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
35 .expect("payload buffer");
36 let texture = device
37 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
38 .expect("argument texture");
39 argument_encoder.set_argument_buffer(&argument_buffer, 0);
40 argument_encoder.set_buffer(&payload, 0, 0);
41 argument_encoder.set_texture(&texture, 1);
42 println!(
43 "argument encoder length={} alignment={}",
44 argument_encoder.encoded_length(),
45 argument_encoder.alignment(),
46 );
47
48 let backing = device
49 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
50 .expect("backing buffer");
51 let buffer_texture = backing
52 .new_texture_view_2d(pixel_format::BGRA8UNORM, 16, 4, 64, 0)
53 .expect("buffer-backed texture");
54 println!(
55 "buffer-backed texture {}x{} fmt={}",
56 buffer_texture.width(),
57 buffer_texture.height(),
58 buffer_texture.pixel_format(),
59 );
60
61 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
62 let heap_buffer = heap
63 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
64 .expect("heap buffer");
65 let heap_texture = heap
66 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
67 .expect("heap texture");
68 println!(
69 "heap size={} used={} current={} max_available={}",
70 heap.size(),
71 heap.used_size(),
72 heap.current_allocated_size(),
73 heap.max_available_size(256),
74 );
75 println!(
76 "heap buffer len={} heap texture {}x{} purgeable={}",
77 heap_buffer.length(),
78 heap_texture.width(),
79 heap_texture.height(),
80 heap.set_purgeable_state(apple_metal::purgeable_state::KEEP_CURRENT),
81 );
82 } else {
83 println!("heaps are unavailable on this device");
84 }
85
86 match device.new_log_state(log_level::INFO, 1_024) {
87 Ok(log_state) => {
88 let _ = device
89 .new_command_queue_with_log_state(4, &log_state)
90 .expect("log-state queue");
91 println!("created queue with log state");
92 }
93 Err(error) => println!("log state unavailable on this OS: {error}"),
94 }
95
96 if device.supports_dynamic_libraries() {
97 let dynamic_path = common::artifact_path("example-dylib.metallib");
98 let dynamic_library = device
99 .new_dynamic_library_with_source(
100 common::DYNAMIC_LIB_SRC,
101 dynamic_path.to_string_lossy().as_ref(),
102 )
103 .expect("dynamic library from source");
104 dynamic_library
105 .serialize_to_file(&dynamic_path)
106 .expect("serialize dynamic library");
107 let reloaded = device
108 .load_dynamic_library(&dynamic_path)
109 .expect("reload dynamic library");
110 println!("dynamic library install name: {}", reloaded.install_name());
111
112 let render_library = device
113 .new_library_with_source(common::RENDER_SRC)
114 .expect("compile render library");
115 let vertex = render_library
116 .new_function("fullscreen_vertex")
117 .expect("vertex function");
118 let fragment = render_library
119 .new_function("solid_fragment")
120 .expect("fragment function");
121 let increment = library
122 .new_function("increment")
123 .expect("increment function");
124
125 let archive_path = common::artifact_path("example-archive.metalarc");
126 let archive = device.new_binary_archive(None).expect("binary archive");
127 archive
128 .add_compute_function(&increment)
129 .expect("archive compute pipeline");
130 archive
131 .add_render_functions(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
132 .expect("archive render pipeline");
133 archive
134 .serialize_to_file(&archive_path)
135 .expect("serialize binary archive");
136 let _ = device
137 .new_binary_archive(Some(&archive_path))
138 .expect("reload binary archive");
139 println!("binary archive written to {}", archive_path.display());
140 } else {
141 println!("dynamic libraries unsupported; skipping archive serialization");
142 }
143}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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}Sourcepub fn new_compute_pipeline_state(
&self,
function: &MetalFunction,
) -> Result<ComputePipelineState, String>
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?
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 let slice: &mut [f32] = unsafe {
44 core::slice::from_raw_parts_mut(
45 buffer.contents().expect("buffer.contents").cast::<f32>(),
46 N,
47 )
48 };
49 for (i, x) in slice.iter_mut().enumerate() {
50 *x = i as f32;
51 }
52 println!("Input : {slice:?}");
53
54 let queue = device.new_command_queue().expect("MTLCommandQueue");
55 let cb = queue.new_command_buffer().expect("MTLCommandBuffer");
56 let ok = cb.dispatch_compute_1d(&pso, &[&buffer], N, 1);
57 assert!(ok, "dispatch_compute_1d failed");
58 cb.commit();
59 cb.wait_until_completed();
60
61 let slice: &[f32] = unsafe {
62 core::slice::from_raw_parts(buffer.contents().expect("buffer.contents").cast::<f32>(), N)
63 };
64 println!("Output: {slice:?}");
65
66 for (i, &v) in slice.iter().enumerate() {
67 let expected = (i as f32) * 2.0;
68 assert_eq!(v, expected, "element {i} expected {expected} got {v}");
69 }
70 println!("✅ All {N} elements correctly doubled by the GPU kernel");
71}More examples
11fn main() {
12 let device = MetalDevice::system_default().expect("Metal device available");
13 println!(
14 "device: {} (registry id {})",
15 device.name(),
16 device.registry_id()
17 );
18
19 let queue = device.new_command_queue().expect("command queue");
20 let status_buffer = queue
21 .new_command_buffer_with_unretained_references()
22 .expect("scratch command buffer");
23 println!("scratch command buffer status={}", status_buffer.status());
24
25 let src = device
26 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
27 .expect("source buffer");
28 let dst = device
29 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
30 .expect("destination buffer");
31 let blit_cb = queue.new_command_buffer().expect("blit command buffer");
32 let blit = blit_cb
33 .new_blit_command_encoder()
34 .expect("blit command encoder");
35 assert!(blit.fill_buffer(&src, 0..64, b'Z'));
36 assert!(blit.copy_buffer(&src, 0, &dst, 0, 64));
37 blit.end_encoding();
38 blit_cb.commit();
39 blit_cb.wait_until_completed();
40 let copied = unsafe {
41 core::slice::from_raw_parts(dst.contents().expect("dst contents").cast::<u8>(), 8)
42 };
43 println!("blit copied bytes: {copied:?}");
44
45 let library = device
46 .new_library_with_source(common::COMPUTE_SRC)
47 .expect("compile compute library");
48 let increment = library
49 .new_function("increment")
50 .expect("increment function");
51 let pipeline = device
52 .new_compute_pipeline_state(&increment)
53 .expect("compute pipeline");
54
55 let buffer = device
56 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
57 .expect("compute buffer");
58 common::write_u32_words(&buffer, &[10, 20, 30, 40]);
59 let compute_cb = queue.new_command_buffer().expect("compute command buffer");
60 let compute = compute_cb
61 .new_compute_command_encoder()
62 .expect("compute command encoder");
63 compute.set_compute_pipeline_state(&pipeline);
64 compute.set_buffer(&buffer, 0, 0);
65 compute.dispatch_threads((4, 1, 1), (1, 1, 1));
66 compute.end_encoding();
67 compute_cb.commit();
68 compute_cb.wait_until_completed();
69 println!("compute output: {:?}", common::read_u32_words(&buffer, 4));
70
71 let render_library = device
72 .new_library_with_source(common::RENDER_SRC)
73 .expect("compile render library");
74 let vertex = render_library
75 .new_function("fullscreen_vertex")
76 .expect("vertex function");
77 let fragment = render_library
78 .new_function("solid_fragment")
79 .expect("fragment function");
80 let render_pipeline = device
81 .new_render_pipeline_state(&vertex, &fragment, pixel_format::BGRA8UNORM, 1)
82 .expect("render pipeline");
83 println!("render pipeline label: {:?}", render_pipeline.label());
84
85 let render_target = device
86 .new_texture(common::shared_render_target(4, 4))
87 .expect("render target");
88 let vertex_buffer = device
89 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
90 .expect("vertex buffer");
91 let render_cb = queue.new_command_buffer().expect("render command buffer");
92 let render = render_cb
93 .new_render_command_encoder(
94 &render_target,
95 load_action::CLEAR,
96 store_action::STORE,
97 [0.0, 0.0, 0.0, 1.0],
98 )
99 .expect("render command encoder");
100 render.set_render_pipeline_state(&render_pipeline);
101 render.set_vertex_buffer(&vertex_buffer, 0, 0);
102 render.draw_primitives(primitive_type::TRIANGLE, 0, 3);
103 render.end_encoding();
104 render_cb.commit();
105 render_cb.wait_until_completed();
106
107 let mut rendered = vec![0_u8; 4 * 4 * 4];
108 assert!(render_target.read_bytes_2d(&mut rendered, 16, (0, 0), (4, 4), 0));
109 println!("first rendered pixel: {:?}", &rendered[..4]);
110
111 let shared_texture = device
112 .new_texture(TextureDescriptor::new_2d(4, 4, pixel_format::BGRA8UNORM))
113 .expect("shared texture");
114 let upload = vec![0x22_u8; 4 * 4 * 4];
115 assert!(shared_texture.replace_region_2d(&upload, 16, (0, 0), (4, 4), 0));
116 let mut download = vec![0_u8; upload.len()];
117 assert!(shared_texture.read_bytes_2d(&mut download, 16, (0, 0), (4, 4), 0));
118 let view = shared_texture
119 .new_view(pixel_format::BGRA8UNORM)
120 .expect("texture view");
121 println!(
122 "texture {}x{} usage={} storage_mode={} view_width={}",
123 shared_texture.width(),
124 shared_texture.height(),
125 shared_texture.usage(),
126 shared_texture.storage_mode(),
127 view.width(),
128 );
129}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.encode_signal_event(&event, 2);
24 signal.commit();
25 signal.wait_until_completed();
26 println!(
27 "event reached value 2: {}",
28 event.wait_until_signaled_value(2, 1_000),
29 );
30
31 let wait = queue
32 .new_command_buffer()
33 .expect("event wait command buffer");
34 wait.encode_wait_for_event(&event, 2);
35 wait.commit();
36 wait.wait_until_completed();
37 }
38
39 let fence_a = device.new_fence();
40 let fence_b = device.new_fence();
41 let sample_buffer = counter_sets.first().and_then(|name| {
42 if device.supports_counter_sampling(counter_sampling_point::AT_BLIT_BOUNDARY) {
43 device
44 .new_counter_sample_buffer(name, 2, storage_mode::SHARED, Some("example-samples"))
45 .ok()
46 } else {
47 None
48 }
49 });
50
51 let src = device
52 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
53 .expect("source buffer");
54 let dst = device
55 .new_buffer(64, resource_options::STORAGE_MODE_SHARED)
56 .expect("destination buffer");
57 let blit = queue.new_command_buffer().expect("blit command buffer");
58 let encoder = blit.new_blit_command_encoder().expect("blit encoder");
59 let _ = encoder.fill_buffer(&src, 0..64, b'Q');
60 if let Some(fence) = fence_a.as_ref() {
61 encoder.update_fence(fence);
62 }
63 encoder.end_encoding();
64 blit.commit();
65 blit.wait_until_completed();
66
67 let blit = queue
68 .new_command_buffer()
69 .expect("second blit command buffer");
70 let encoder = blit
71 .new_blit_command_encoder()
72 .expect("second blit encoder");
73 if let Some(fence) = fence_a.as_ref() {
74 encoder.wait_for_fence(fence);
75 }
76 if let Some(sample_buffer) = sample_buffer.as_ref() {
77 let _ = encoder.sample_counters(sample_buffer, 0, false);
78 }
79 let _ = encoder.copy_buffer(&src, 0, &dst, 0, 64);
80 encoder.end_encoding();
81 blit.commit();
82 blit.wait_until_completed();
83 if let Some(sample_buffer) = sample_buffer.as_ref() {
84 println!(
85 "resolved counter bytes={}",
86 sample_buffer
87 .resolve_range(0..1)
88 .map_or(0, |bytes| bytes.len())
89 );
90 }
91
92 let library = device
93 .new_library_with_source(common::COMPUTE_SRC)
94 .expect("compile compute library");
95 let increment = library
96 .new_function("increment")
97 .expect("increment function");
98 let pipeline = device
99 .new_compute_pipeline_state(&increment)
100 .expect("compute pipeline");
101 let visible_table = pipeline.new_visible_function_table(1);
102 let intersection_table = if device.supports_raytracing() {
103 pipeline.new_intersection_function_table(1)
104 } else {
105 None
106 };
107 if let Some(table) = intersection_table.as_ref() {
108 table.set_opaque_triangle_intersection_function(intersection_function_signature::NONE, 0);
109 }
110 let acceleration_structure = if device.supports_raytracing() {
111 device.new_acceleration_structure_with_size(256)
112 } else {
113 None
114 };
115
116 let buffer = device
117 .new_buffer(16, resource_options::STORAGE_MODE_SHARED)
118 .expect("compute buffer");
119 common::write_u32_words(&buffer, &[1, 2, 3, 4]);
120 let texture = device
121 .new_texture(apple_metal::TextureDescriptor::new_2d(
122 4,
123 4,
124 apple_metal::pixel_format::BGRA8UNORM,
125 ))
126 .expect("compute texture");
127 let compute = queue.new_command_buffer().expect("compute command buffer");
128 let encoder = compute
129 .new_compute_command_encoder()
130 .expect("compute command encoder");
131 encoder.set_compute_pipeline_state(&pipeline);
132 encoder.set_buffer(&buffer, 0, 0);
133 encoder.set_texture(&texture, 1);
134 if let Some(fence) = fence_a.as_ref() {
135 encoder.wait_for_fence(fence);
136 }
137 if let Some(table) = visible_table.as_ref() {
138 encoder.set_visible_function_table(table, 2);
139 }
140 if let Some(table) = intersection_table.as_ref() {
141 encoder.set_intersection_function_table(table, 3);
142 }
143 if let Some(acceleration_structure) = acceleration_structure.as_ref() {
144 encoder.set_acceleration_structure(acceleration_structure, 4);
145 }
146 encoder.dispatch_threadgroups((1, 1, 1), (4, 1, 1));
147 if let Some(fence) = fence_b.as_ref() {
148 encoder.update_fence(fence);
149 }
150 encoder.end_encoding();
151 compute.commit();
152 compute.wait_until_completed();
153 println!(
154 "compute buffer after dispatch: {:?}",
155 common::read_u32_words(&buffer, 4)
156 );
157
158 if let Some(indirect) = device.new_indirect_command_buffer(
159 indirect_command_type::CONCURRENT_DISPATCH,
160 1,
161 0,
162 0,
163 4,
164 resource_options::STORAGE_MODE_PRIVATE,
165 ) {
166 indirect.reset_range(0..1);
167 println!("indirect command buffer size={}", indirect.size());
168 }
169
170 if let Some(heap) = device.new_heap(1 << 20, storage_mode::SHARED) {
171 if let Ok(residency_set) = device.new_residency_set(Some("example-residency"), 4) {
172 let heap_buffer = heap
173 .new_buffer(256, resource_options::STORAGE_MODE_SHARED)
174 .expect("heap buffer");
175 residency_set.add_buffer(&heap_buffer);
176 residency_set.add_heap(&heap);
177 residency_set.commit();
178 residency_set.request_residency();
179 queue.add_residency_set(&residency_set);
180 queue.remove_residency_set(&residency_set);
181 residency_set.end_residency();
182 residency_set.remove_all_allocations();
183 residency_set.commit();
184 println!(
185 "residency allocation count={}",
186 residency_set.allocation_count()
187 );
188 } else {
189 println!("residency sets unavailable on this OS");
190 }
191 }
192
193 if let Some(capture_manager) = CaptureManager::shared() {
194 println!(
195 "capture supported for developer tools={} active={}",
196 capture_manager.supports_destination(capture_destination::DEVELOPER_TOOLS),
197 capture_manager.is_capturing(),
198 );
199 if let Some(scope) = capture_manager.new_capture_scope_with_device(&device) {
200 scope.begin();
201 scope.end();
202 }
203 if let Some(scope) = capture_manager.new_capture_scope_with_command_queue(&queue) {
204 scope.begin();
205 scope.end();
206 }
207 }
208}