Skip to main content

mtl_gpu/encoder/render_encoder/
draw.rs

1//! Drawing commands for render encoder.
2//!
3//! This module contains methods for drawing primitives, indexed primitives,
4//! patches, and mesh shaders.
5
6use std::ffi::c_void;
7
8use mtl_foundation::{Integer, Referencing, UInteger};
9use mtl_sys::{msg_send_1, sel};
10
11use crate::Buffer;
12use crate::enums::{IndexType, PrimitiveType};
13use crate::types::Size;
14
15use super::RenderCommandEncoder;
16
17impl RenderCommandEncoder {
18    // =========================================================================
19    // Drawing
20    // =========================================================================
21
22    /// Draw primitives.
23    ///
24    /// C++ equivalent: `void drawPrimitives(MTL::PrimitiveType, NS::UInteger, NS::UInteger)`
25    #[inline]
26    pub fn draw_primitives(
27        &self,
28        primitive_type: PrimitiveType,
29        vertex_start: UInteger,
30        vertex_count: UInteger,
31    ) {
32        unsafe {
33            mtl_sys::msg_send_3::<(), PrimitiveType, UInteger, UInteger>(
34                self.as_ptr(),
35                sel!(drawPrimitives: vertexStart: vertexCount:),
36                primitive_type,
37                vertex_start,
38                vertex_count,
39            );
40        }
41    }
42
43    /// Draw primitives with instance count.
44    ///
45    /// C++ equivalent: `void drawPrimitives(MTL::PrimitiveType, NS::UInteger, NS::UInteger, NS::UInteger)`
46    #[inline]
47    pub fn draw_primitives_instanced(
48        &self,
49        primitive_type: PrimitiveType,
50        vertex_start: UInteger,
51        vertex_count: UInteger,
52        instance_count: UInteger,
53    ) {
54        unsafe {
55            mtl_sys::msg_send_4::<(), PrimitiveType, UInteger, UInteger, UInteger>(
56                self.as_ptr(),
57                sel!(drawPrimitives: vertexStart: vertexCount: instanceCount:),
58                primitive_type,
59                vertex_start,
60                vertex_count,
61                instance_count,
62            );
63        }
64    }
65
66    /// Draw primitives with instance count and base instance.
67    ///
68    /// C++ equivalent: `void drawPrimitives(MTL::PrimitiveType, NS::UInteger, NS::UInteger, NS::UInteger, NS::UInteger)`
69    #[inline]
70    pub fn draw_primitives_instanced_base_instance(
71        &self,
72        primitive_type: PrimitiveType,
73        vertex_start: UInteger,
74        vertex_count: UInteger,
75        instance_count: UInteger,
76        base_instance: UInteger,
77    ) {
78        unsafe {
79            mtl_sys::msg_send_5::<(), PrimitiveType, UInteger, UInteger, UInteger, UInteger>(
80                self.as_ptr(),
81                sel!(drawPrimitives: vertexStart: vertexCount: instanceCount: baseInstance:),
82                primitive_type,
83                vertex_start,
84                vertex_count,
85                instance_count,
86                base_instance,
87            );
88        }
89    }
90
91    /// Draw primitives using an indirect buffer.
92    ///
93    /// C++ equivalent: `void drawPrimitives(MTL::PrimitiveType, const Buffer*, NS::UInteger)`
94    #[inline]
95    pub fn draw_primitives_indirect(
96        &self,
97        primitive_type: PrimitiveType,
98        indirect_buffer: &Buffer,
99        indirect_buffer_offset: UInteger,
100    ) {
101        unsafe {
102            mtl_sys::msg_send_3::<(), PrimitiveType, *const c_void, UInteger>(
103                self.as_ptr(),
104                sel!(drawPrimitives: indirectBuffer: indirectBufferOffset:),
105                primitive_type,
106                indirect_buffer.as_ptr(),
107                indirect_buffer_offset,
108            );
109        }
110    }
111
112    // =========================================================================
113    // Indexed Drawing
114    // =========================================================================
115
116    /// Draw indexed primitives.
117    ///
118    /// C++ equivalent: `void drawIndexedPrimitives(MTL::PrimitiveType, NS::UInteger, MTL::IndexType, const Buffer*, NS::UInteger)`
119    #[inline]
120    pub fn draw_indexed_primitives(
121        &self,
122        primitive_type: PrimitiveType,
123        index_count: UInteger,
124        index_type: IndexType,
125        index_buffer: &Buffer,
126        index_buffer_offset: UInteger,
127    ) {
128        unsafe {
129            mtl_sys::msg_send_5::<(), PrimitiveType, UInteger, IndexType, *const c_void, UInteger>(
130                self.as_ptr(),
131                sel!(drawIndexedPrimitives: indexCount: indexType: indexBuffer: indexBufferOffset:),
132                primitive_type,
133                index_count,
134                index_type,
135                index_buffer.as_ptr(),
136                index_buffer_offset,
137            );
138        }
139    }
140
141    /// Draw indexed primitives with instance count.
142    ///
143    /// C++ equivalent: `void drawIndexedPrimitives(MTL::PrimitiveType, NS::UInteger, MTL::IndexType, const Buffer*, NS::UInteger, NS::UInteger)`
144    #[inline]
145    pub fn draw_indexed_primitives_instanced(
146        &self,
147        primitive_type: PrimitiveType,
148        index_count: UInteger,
149        index_type: IndexType,
150        index_buffer: &Buffer,
151        index_buffer_offset: UInteger,
152        instance_count: UInteger,
153    ) {
154        unsafe {
155            mtl_sys::msg_send_6::<
156                (),
157                PrimitiveType,
158                UInteger,
159                IndexType,
160                *const c_void,
161                UInteger,
162                UInteger,
163            >(
164                self.as_ptr(),
165                sel!(drawIndexedPrimitives: indexCount: indexType: indexBuffer: indexBufferOffset: instanceCount:),
166                primitive_type,
167                index_count,
168                index_type,
169                index_buffer.as_ptr(),
170                index_buffer_offset,
171                instance_count,
172            );
173        }
174    }
175
176    /// Draw indexed primitives with base vertex and base instance.
177    ///
178    /// C++ equivalent: `void drawIndexedPrimitives(...instanceCount: baseVertex: baseInstance:)`
179    #[allow(clippy::too_many_arguments)]
180    #[inline]
181    pub fn draw_indexed_primitives_instanced_base_vertex_base_instance(
182        &self,
183        primitive_type: PrimitiveType,
184        index_count: UInteger,
185        index_type: IndexType,
186        index_buffer: &Buffer,
187        index_buffer_offset: UInteger,
188        instance_count: UInteger,
189        base_vertex: Integer,
190        base_instance: UInteger,
191    ) {
192        unsafe {
193            mtl_sys::msg_send_8::<
194                (),
195                PrimitiveType,
196                UInteger,
197                IndexType,
198                *const c_void,
199                UInteger,
200                UInteger,
201                Integer,
202                UInteger,
203            >(
204                self.as_ptr(),
205                sel!(drawIndexedPrimitives: indexCount: indexType: indexBuffer: indexBufferOffset: instanceCount: baseVertex: baseInstance:),
206                primitive_type,
207                index_count,
208                index_type,
209                index_buffer.as_ptr(),
210                index_buffer_offset,
211                instance_count,
212                base_vertex,
213                base_instance,
214            );
215        }
216    }
217
218    /// Draw indexed primitives using an indirect buffer.
219    ///
220    /// C++ equivalent: `void drawIndexedPrimitives(MTL::PrimitiveType, MTL::IndexType, const Buffer*, NS::UInteger, const Buffer*, NS::UInteger)`
221    #[inline]
222    pub fn draw_indexed_primitives_indirect(
223        &self,
224        primitive_type: PrimitiveType,
225        index_type: IndexType,
226        index_buffer: &Buffer,
227        index_buffer_offset: UInteger,
228        indirect_buffer: &Buffer,
229        indirect_buffer_offset: UInteger,
230    ) {
231        unsafe {
232            mtl_sys::msg_send_6::<
233                (),
234                PrimitiveType,
235                IndexType,
236                *const c_void,
237                UInteger,
238                *const c_void,
239                UInteger,
240            >(
241                self.as_ptr(),
242                sel!(drawIndexedPrimitives: indexType: indexBuffer: indexBufferOffset: indirectBuffer: indirectBufferOffset:),
243                primitive_type,
244                index_type,
245                index_buffer.as_ptr(),
246                index_buffer_offset,
247                indirect_buffer.as_ptr(),
248                indirect_buffer_offset,
249            );
250        }
251    }
252
253    // =========================================================================
254    // Tessellation
255    // =========================================================================
256
257    /// Set the tessellation factor buffer.
258    ///
259    /// C++ equivalent: `void setTessellationFactorBuffer(const Buffer*, NS::UInteger, NS::UInteger)`
260    #[inline]
261    pub fn set_tessellation_factor_buffer(
262        &self,
263        buffer: &Buffer,
264        offset: UInteger,
265        instance_stride: UInteger,
266    ) {
267        unsafe {
268            mtl_sys::msg_send_3::<(), *const c_void, UInteger, UInteger>(
269                self.as_ptr(),
270                sel!(setTessellationFactorBuffer: offset: instanceStride:),
271                buffer.as_ptr(),
272                offset,
273                instance_stride,
274            );
275        }
276    }
277
278    /// Set the tessellation factor scale.
279    ///
280    /// C++ equivalent: `void setTessellationFactorScale(float)`
281    #[inline]
282    pub fn set_tessellation_factor_scale(&self, scale: f32) {
283        unsafe {
284            msg_send_1::<(), f32>(self.as_ptr(), sel!(setTessellationFactorScale:), scale);
285        }
286    }
287
288    /// Draw patches.
289    ///
290    /// C++ equivalent: `void drawPatches(...)`
291    #[allow(clippy::too_many_arguments)]
292    pub fn draw_patches(
293        &self,
294        number_of_patch_control_points: UInteger,
295        patch_start: UInteger,
296        patch_count: UInteger,
297        patch_index_buffer: Option<&Buffer>,
298        patch_index_buffer_offset: UInteger,
299        instance_count: UInteger,
300        base_instance: UInteger,
301    ) {
302        let patch_index_buffer_ptr = patch_index_buffer
303            .map(|b| b.as_ptr())
304            .unwrap_or(std::ptr::null());
305        unsafe {
306            mtl_sys::msg_send_7::<
307                (),
308                UInteger,
309                UInteger,
310                UInteger,
311                *const c_void,
312                UInteger,
313                UInteger,
314                UInteger,
315            >(
316                self.as_ptr(),
317                sel!(drawPatches: patchStart: patchCount: patchIndexBuffer: patchIndexBufferOffset: instanceCount: baseInstance:),
318                number_of_patch_control_points,
319                patch_start,
320                patch_count,
321                patch_index_buffer_ptr,
322                patch_index_buffer_offset,
323                instance_count,
324                base_instance,
325            );
326        }
327    }
328
329    /// Draw indexed patches.
330    ///
331    /// C++ equivalent: `void drawIndexedPatches(...)`
332    #[allow(clippy::too_many_arguments)]
333    pub fn draw_indexed_patches(
334        &self,
335        number_of_patch_control_points: UInteger,
336        patch_start: UInteger,
337        patch_count: UInteger,
338        patch_index_buffer: Option<&Buffer>,
339        patch_index_buffer_offset: UInteger,
340        control_point_index_buffer: &Buffer,
341        control_point_index_buffer_offset: UInteger,
342        instance_count: UInteger,
343        base_instance: UInteger,
344    ) {
345        let patch_index_buffer_ptr = patch_index_buffer
346            .map(|b| b.as_ptr())
347            .unwrap_or(std::ptr::null());
348        unsafe {
349            mtl_sys::msg_send_9::<
350                (),
351                UInteger,
352                UInteger,
353                UInteger,
354                *const c_void,
355                UInteger,
356                *const c_void,
357                UInteger,
358                UInteger,
359                UInteger,
360            >(
361                self.as_ptr(),
362                sel!(drawIndexedPatches: patchStart: patchCount: patchIndexBuffer: patchIndexBufferOffset: controlPointIndexBuffer: controlPointIndexBufferOffset: instanceCount: baseInstance:),
363                number_of_patch_control_points,
364                patch_start,
365                patch_count,
366                patch_index_buffer_ptr,
367                patch_index_buffer_offset,
368                control_point_index_buffer.as_ptr(),
369                control_point_index_buffer_offset,
370                instance_count,
371                base_instance,
372            );
373        }
374    }
375
376    /// Draw indexed patches with indirect buffer.
377    ///
378    /// C++ equivalent: `void drawIndexedPatches(...indirectBuffer...)`
379    #[allow(clippy::too_many_arguments)]
380    pub fn draw_indexed_patches_indirect(
381        &self,
382        number_of_patch_control_points: UInteger,
383        patch_index_buffer: Option<&Buffer>,
384        patch_index_buffer_offset: UInteger,
385        control_point_index_buffer: &Buffer,
386        control_point_index_buffer_offset: UInteger,
387        indirect_buffer: &Buffer,
388        indirect_buffer_offset: UInteger,
389    ) {
390        let patch_index_buffer_ptr = patch_index_buffer
391            .map(|b| b.as_ptr())
392            .unwrap_or(std::ptr::null());
393        unsafe {
394            mtl_sys::msg_send_7::<
395                (),
396                UInteger,
397                *const c_void,
398                UInteger,
399                *const c_void,
400                UInteger,
401                *const c_void,
402                UInteger,
403            >(
404                self.as_ptr(),
405                sel!(drawIndexedPatches: patchIndexBuffer: patchIndexBufferOffset: controlPointIndexBuffer: controlPointIndexBufferOffset: indirectBuffer: indirectBufferOffset:),
406                number_of_patch_control_points,
407                patch_index_buffer_ptr,
408                patch_index_buffer_offset,
409                control_point_index_buffer.as_ptr(),
410                control_point_index_buffer_offset,
411                indirect_buffer.as_ptr(),
412                indirect_buffer_offset,
413            );
414        }
415    }
416
417    /// Draw patches with indirect buffer.
418    ///
419    /// C++ equivalent: `void drawPatches(...indirectBuffer...)`
420    pub fn draw_patches_indirect(
421        &self,
422        number_of_patch_control_points: UInteger,
423        patch_index_buffer: Option<&Buffer>,
424        patch_index_buffer_offset: UInteger,
425        indirect_buffer: &Buffer,
426        indirect_buffer_offset: UInteger,
427    ) {
428        let patch_index_buffer_ptr = patch_index_buffer
429            .map(|b| b.as_ptr())
430            .unwrap_or(std::ptr::null());
431        unsafe {
432            mtl_sys::msg_send_5::<(), UInteger, *const c_void, UInteger, *const c_void, UInteger>(
433                self.as_ptr(),
434                sel!(drawPatches: patchIndexBuffer: patchIndexBufferOffset: indirectBuffer: indirectBufferOffset:),
435                number_of_patch_control_points,
436                patch_index_buffer_ptr,
437                patch_index_buffer_offset,
438                indirect_buffer.as_ptr(),
439                indirect_buffer_offset,
440            );
441        }
442    }
443
444    // =========================================================================
445    // Mesh Shaders
446    // =========================================================================
447
448    /// Draw mesh threadgroups.
449    ///
450    /// C++ equivalent: `void drawMeshThreadgroups(MTL::Size, MTL::Size, MTL::Size)`
451    #[inline]
452    pub fn draw_mesh_threadgroups(
453        &self,
454        threadgroups_per_grid: Size,
455        threads_per_object_threadgroup: Size,
456        threads_per_mesh_threadgroup: Size,
457    ) {
458        unsafe {
459            mtl_sys::msg_send_3::<(), Size, Size, Size>(
460                self.as_ptr(),
461                sel!(drawMeshThreadgroups: threadsPerObjectThreadgroup: threadsPerMeshThreadgroup:),
462                threadgroups_per_grid,
463                threads_per_object_threadgroup,
464                threads_per_mesh_threadgroup,
465            );
466        }
467    }
468
469    /// Draw mesh threads.
470    ///
471    /// C++ equivalent: `void drawMeshThreads(MTL::Size, MTL::Size, MTL::Size)`
472    #[inline]
473    pub fn draw_mesh_threads(
474        &self,
475        threads_per_grid: Size,
476        threads_per_object_threadgroup: Size,
477        threads_per_mesh_threadgroup: Size,
478    ) {
479        unsafe {
480            mtl_sys::msg_send_3::<(), Size, Size, Size>(
481                self.as_ptr(),
482                sel!(drawMeshThreads: threadsPerObjectThreadgroup: threadsPerMeshThreadgroup:),
483                threads_per_grid,
484                threads_per_object_threadgroup,
485                threads_per_mesh_threadgroup,
486            );
487        }
488    }
489
490    /// Draw mesh threadgroups with indirect buffer.
491    ///
492    /// C++ equivalent: `void drawMeshThreadgroups(const Buffer*, NS::UInteger, MTL::Size, MTL::Size)`
493    #[inline]
494    pub fn draw_mesh_threadgroups_indirect(
495        &self,
496        indirect_buffer: &Buffer,
497        indirect_buffer_offset: UInteger,
498        threads_per_object_threadgroup: Size,
499        threads_per_mesh_threadgroup: Size,
500    ) {
501        unsafe {
502            mtl_sys::msg_send_4::<(), *const c_void, UInteger, Size, Size>(
503                self.as_ptr(),
504                sel!(drawMeshThreadgroupsWithIndirectBuffer: indirectBufferOffset: threadsPerObjectThreadgroup: threadsPerMeshThreadgroup:),
505                indirect_buffer.as_ptr(),
506                indirect_buffer_offset,
507                threads_per_object_threadgroup,
508                threads_per_mesh_threadgroup,
509            );
510        }
511    }
512
513    // =========================================================================
514    // Tile Dispatch
515    // =========================================================================
516
517    /// Dispatch threads per tile.
518    ///
519    /// C++ equivalent: `void dispatchThreadsPerTile(MTL::Size)`
520    #[inline]
521    pub fn dispatch_threads_per_tile(&self, threads_per_tile: Size) {
522        unsafe {
523            msg_send_1::<(), Size>(
524                self.as_ptr(),
525                sel!(dispatchThreadsPerTile:),
526                threads_per_tile,
527            );
528        }
529    }
530}