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