1use std::ffi::c_void;
4use std::ptr::NonNull;
5
6use mtl_foundation::{Integer, Referencing, UInteger};
7use mtl_sys::{msg_send_0, msg_send_1, msg_send_2, msg_send_3, sel};
8
9use crate::enums::{CullMode, DepthClipMode, IndexType, PrimitiveType, TriangleFillMode, Winding};
10use crate::types::Size;
11use crate::{Buffer, DepthStencilState, RenderPipelineState};
12
13#[repr(transparent)]
20pub struct IndirectRenderCommand(NonNull<c_void>);
21
22impl IndirectRenderCommand {
23 #[inline]
29 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
30 NonNull::new(ptr).map(Self)
31 }
32
33 #[inline]
35 pub fn as_raw(&self) -> *mut c_void {
36 self.0.as_ptr()
37 }
38
39 #[inline]
43 pub fn reset(&self) {
44 unsafe {
45 msg_send_0::<()>(self.as_ptr(), sel!(reset));
46 }
47 }
48
49 #[inline]
53 pub fn set_barrier(&self) {
54 unsafe {
55 msg_send_0::<()>(self.as_ptr(), sel!(setBarrier));
56 }
57 }
58
59 #[inline]
63 pub fn clear_barrier(&self) {
64 unsafe {
65 msg_send_0::<()>(self.as_ptr(), sel!(clearBarrier));
66 }
67 }
68
69 pub fn set_render_pipeline_state(&self, state: &RenderPipelineState) {
73 unsafe {
74 msg_send_1::<(), *const c_void>(
75 self.as_ptr(),
76 sel!(setRenderPipelineState:),
77 state.as_ptr(),
78 );
79 }
80 }
81
82 pub fn set_vertex_buffer(&self, buffer: &Buffer, offset: UInteger, index: UInteger) {
86 unsafe {
87 msg_send_3::<(), *const c_void, UInteger, UInteger>(
88 self.as_ptr(),
89 sel!(setVertexBuffer: offset: atIndex:),
90 buffer.as_ptr(),
91 offset,
92 index,
93 );
94 }
95 }
96
97 pub fn set_vertex_buffer_with_stride(
101 &self,
102 buffer: &Buffer,
103 offset: UInteger,
104 stride: UInteger,
105 index: UInteger,
106 ) {
107 unsafe {
108 mtl_sys::msg_send_4::<(), *const c_void, UInteger, UInteger, UInteger>(
109 self.as_ptr(),
110 sel!(setVertexBuffer: offset: attributeStride: atIndex:),
111 buffer.as_ptr(),
112 offset,
113 stride,
114 index,
115 );
116 }
117 }
118
119 pub fn set_fragment_buffer(&self, buffer: &Buffer, offset: UInteger, index: UInteger) {
123 unsafe {
124 msg_send_3::<(), *const c_void, UInteger, UInteger>(
125 self.as_ptr(),
126 sel!(setFragmentBuffer: offset: atIndex:),
127 buffer.as_ptr(),
128 offset,
129 index,
130 );
131 }
132 }
133
134 pub fn set_mesh_buffer(&self, buffer: &Buffer, offset: UInteger, index: UInteger) {
138 unsafe {
139 msg_send_3::<(), *const c_void, UInteger, UInteger>(
140 self.as_ptr(),
141 sel!(setMeshBuffer: offset: atIndex:),
142 buffer.as_ptr(),
143 offset,
144 index,
145 );
146 }
147 }
148
149 pub fn set_object_buffer(&self, buffer: &Buffer, offset: UInteger, index: UInteger) {
153 unsafe {
154 msg_send_3::<(), *const c_void, UInteger, UInteger>(
155 self.as_ptr(),
156 sel!(setObjectBuffer: offset: atIndex:),
157 buffer.as_ptr(),
158 offset,
159 index,
160 );
161 }
162 }
163
164 pub fn set_object_threadgroup_memory_length(&self, length: UInteger, index: UInteger) {
168 unsafe {
169 msg_send_2::<(), UInteger, UInteger>(
170 self.as_ptr(),
171 sel!(setObjectThreadgroupMemoryLength: atIndex:),
172 length,
173 index,
174 );
175 }
176 }
177
178 #[inline]
182 pub fn set_cull_mode(&self, mode: CullMode) {
183 unsafe {
184 msg_send_1::<(), CullMode>(self.as_ptr(), sel!(setCullMode:), mode);
185 }
186 }
187
188 pub fn set_depth_bias(&self, depth_bias: f32, slope_scale: f32, clamp: f32) {
192 unsafe {
193 msg_send_3::<(), f32, f32, f32>(
194 self.as_ptr(),
195 sel!(setDepthBias: slopeScale: clamp:),
196 depth_bias,
197 slope_scale,
198 clamp,
199 );
200 }
201 }
202
203 #[inline]
207 pub fn set_depth_clip_mode(&self, mode: DepthClipMode) {
208 unsafe {
209 msg_send_1::<(), DepthClipMode>(self.as_ptr(), sel!(setDepthClipMode:), mode);
210 }
211 }
212
213 pub fn set_depth_stencil_state(&self, state: &DepthStencilState) {
217 unsafe {
218 msg_send_1::<(), *const c_void>(
219 self.as_ptr(),
220 sel!(setDepthStencilState:),
221 state.as_ptr(),
222 );
223 }
224 }
225
226 #[inline]
230 pub fn set_front_facing_winding(&self, winding: Winding) {
231 unsafe {
232 msg_send_1::<(), Winding>(self.as_ptr(), sel!(setFrontFacingWinding:), winding);
233 }
234 }
235
236 #[inline]
240 pub fn set_triangle_fill_mode(&self, mode: TriangleFillMode) {
241 unsafe {
242 msg_send_1::<(), TriangleFillMode>(self.as_ptr(), sel!(setTriangleFillMode:), mode);
243 }
244 }
245
246 pub fn draw_primitives(
250 &self,
251 primitive_type: PrimitiveType,
252 vertex_start: UInteger,
253 vertex_count: UInteger,
254 instance_count: UInteger,
255 base_instance: UInteger,
256 ) {
257 unsafe {
258 mtl_sys::msg_send_5::<(), PrimitiveType, UInteger, UInteger, UInteger, UInteger>(
259 self.as_ptr(),
260 sel!(drawPrimitives: vertexStart: vertexCount: instanceCount: baseInstance:),
261 primitive_type,
262 vertex_start,
263 vertex_count,
264 instance_count,
265 base_instance,
266 );
267 }
268 }
269
270 #[allow(clippy::too_many_arguments)]
274 pub fn draw_indexed_primitives(
275 &self,
276 primitive_type: PrimitiveType,
277 index_count: UInteger,
278 index_type: IndexType,
279 index_buffer: &Buffer,
280 index_buffer_offset: UInteger,
281 instance_count: UInteger,
282 base_vertex: Integer,
283 base_instance: UInteger,
284 ) {
285 unsafe {
286 mtl_sys::msg_send_8::<
287 (),
288 PrimitiveType,
289 UInteger,
290 IndexType,
291 *const c_void,
292 UInteger,
293 UInteger,
294 Integer,
295 UInteger,
296 >(
297 self.as_ptr(),
298 sel!(drawIndexedPrimitives: indexCount: indexType: indexBuffer: indexBufferOffset: instanceCount: baseVertex: baseInstance:),
299 primitive_type,
300 index_count,
301 index_type,
302 index_buffer.as_ptr(),
303 index_buffer_offset,
304 instance_count,
305 base_vertex,
306 base_instance,
307 );
308 }
309 }
310
311 pub fn draw_mesh_threadgroups(
315 &self,
316 threadgroups_per_grid: Size,
317 threads_per_object_threadgroup: Size,
318 threads_per_mesh_threadgroup: Size,
319 ) {
320 unsafe {
321 msg_send_3::<(), Size, Size, Size>(
322 self.as_ptr(),
323 sel!(drawMeshThreadgroups: threadsPerObjectThreadgroup: threadsPerMeshThreadgroup:),
324 threadgroups_per_grid,
325 threads_per_object_threadgroup,
326 threads_per_mesh_threadgroup,
327 );
328 }
329 }
330
331 pub fn draw_mesh_threads(
335 &self,
336 threads_per_grid: Size,
337 threads_per_object_threadgroup: Size,
338 threads_per_mesh_threadgroup: Size,
339 ) {
340 unsafe {
341 msg_send_3::<(), Size, Size, Size>(
342 self.as_ptr(),
343 sel!(drawMeshThreads: threadsPerObjectThreadgroup: threadsPerMeshThreadgroup:),
344 threads_per_grid,
345 threads_per_object_threadgroup,
346 threads_per_mesh_threadgroup,
347 );
348 }
349 }
350}
351
352impl Referencing for IndirectRenderCommand {
353 #[inline]
354 fn as_ptr(&self) -> *const c_void {
355 self.0.as_ptr()
356 }
357}
358
359impl std::fmt::Debug for IndirectRenderCommand {
362 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
363 f.debug_struct("IndirectRenderCommand").finish()
364 }
365}