1#![doc = include_str!("../README.md")]
2
3#[expect(
4 clippy::missing_safety_doc,
5 clippy::ptr_offset_with_cast,
6 clippy::useless_transmute,
7 non_camel_case_types,
8 non_snake_case,
9 non_upper_case_globals
10)]
11pub mod bindings {
12 include!("bindings.rs");
14
15 pub use objc2_metal::MTLResourceID;
16}
17pub use bindings as ffi;
18
19use std::ptr::NonNull;
20
21use objc2::runtime::ProtocolObject;
22use objc2_metal::{
23 MTLBuffer, MTLIndexType, MTLPrimitiveType, MTLRenderCommandEncoder, MTLSamplerState, MTLTexture,
24};
25
26#[doc(alias = "IRBufferView")]
28pub struct BufferView<'a> {
29 pub buffer: &'a ProtocolObject<dyn MTLBuffer>,
30 pub buffer_offset: u64,
31 pub buffer_size: u64,
32 pub texture_buffer_view: Option<&'a ProtocolObject<dyn MTLTexture>>,
33 pub texture_view_offset_in_elements: u32,
34 pub typed_buffer: bool,
35}
36
37impl ffi::IRDescriptorTableEntry {
38 #[doc(alias = "IRDescriptorTableSetBuffer")]
49 pub fn buffer(gpu_address: u64, metadata: u64) -> Self {
50 Self {
51 gpuVA: gpu_address,
52 textureViewID: 0,
53 metadata,
54 }
55 }
56
57 #[doc(alias = "IRDescriptorTableSetBufferView")]
62 pub fn buffer_view(buffer_view: &BufferView<'_>) -> Self {
63 Self {
64 gpuVA: buffer_view.buffer.gpuAddress() + buffer_view.buffer_offset,
65 textureViewID: match buffer_view.texture_buffer_view {
66 Some(texture) => unsafe { texture.gpuResourceID() }.to_raw(),
67 None => 0,
68 },
69 metadata: Self::buffer_metadata(buffer_view),
70 }
71 }
72
73 #[doc(alias = "IRDescriptorTableSetTexture")]
78 pub fn texture(argument: &ProtocolObject<dyn MTLTexture>, min_lod_clamp: f32) -> Self {
79 const METADATA: u32 = 0; Self {
81 gpuVA: 0,
82 textureViewID: unsafe { argument.gpuResourceID() }.to_raw(),
83 metadata: min_lod_clamp.to_bits() as u64 | ((METADATA as u64) << 32),
84 }
85 }
86
87 #[doc(alias = "IRDescriptorTableSetSampler")]
92 pub fn sampler(argument: &ProtocolObject<dyn MTLSamplerState>, lod_bias: f32) -> Self {
93 Self {
94 gpuVA: unsafe { argument.gpuResourceID() }.to_raw(),
95 textureViewID: 0,
96 metadata: lod_bias.to_bits() as u64,
97 }
98 }
99
100 #[doc(alias = "IRDescriptorTableSetAccelerationStructure")]
105 pub fn acceleration_structure(gpu_address: u64) -> Self {
106 Self {
107 gpuVA: gpu_address,
108 textureViewID: 0,
109 metadata: 0,
110 }
111 }
112
113 #[doc(alias = "IRDescriptorTableGetBufferMetadata")]
118 pub fn buffer_metadata(view: &BufferView<'_>) -> u64 {
119 let mut metadata = (view.buffer_size & ffi::kIRBufSizeMask) << ffi::kIRBufSizeOffset;
120 metadata |= (view.texture_view_offset_in_elements as u64 & ffi::kIRTexViewMask)
121 << ffi::kIRTexViewOffset;
122 metadata |= (view.typed_buffer as u64) << ffi::kIRTypedBufferOffset;
123 metadata
124 }
125}
126
127#[doc(alias = "IRRuntimeDrawPrimitives")]
128pub fn draw_primitives(
129 encoder: &ProtocolObject<dyn MTLRenderCommandEncoder>,
130 primitive_type: MTLPrimitiveType,
131 vertex_start: usize,
132 vertex_count: usize,
133 instance_count: usize,
134 base_instance: usize,
135) {
136 let mut dp = ffi::IRRuntimeDrawParams {
137 u_1: ffi::IRRuntimeDrawParams_u {
138 draw: ffi::IRRuntimeDrawArgument {
139 vertexCountPerInstance: vertex_count as u32,
140 instanceCount: instance_count as u32,
141 startVertexLocation: vertex_start as u32,
142 startInstanceLocation: base_instance as u32,
143 },
144 },
145 };
146 unsafe {
147 encoder.setVertexBytes_length_atIndex(
148 NonNull::new(&raw mut dp).unwrap().cast(),
149 size_of_val(&dp),
150 ffi::kIRArgumentBufferDrawArgumentsBindPoint as usize,
151 );
152 let mut non_indexed_draw = ffi::kIRNonIndexedDraw;
153 encoder.setVertexBytes_length_atIndex(
154 NonNull::new(&raw mut non_indexed_draw).unwrap().cast(),
155 size_of_val(&non_indexed_draw),
156 ffi::kIRArgumentBufferUniformsBindPoint as usize,
157 );
158 encoder.drawPrimitives_vertexStart_vertexCount_instanceCount_baseInstance(
159 primitive_type,
160 vertex_start,
161 vertex_count,
162 instance_count,
163 base_instance,
164 );
165 }
166}
167
168#[doc(alias = "IRMetalIndexToIRIndex")]
169pub fn metal_index_to_ir_index(index_type: MTLIndexType) -> u16 {
170 index_type.0 as u16 + 1
171}
172
173#[doc(alias = "IRRuntimeDrawIndexedPrimitives")]
174#[expect(clippy::too_many_arguments)]
175pub fn draw_indexed_primitives(
176 encoder: &ProtocolObject<dyn MTLRenderCommandEncoder>,
177 primitive_type: MTLPrimitiveType,
178 index_count: usize,
179 index_type: MTLIndexType,
180 index_buffer: &ProtocolObject<dyn MTLBuffer>,
181 index_buffer_offset: usize,
182 instance_count: usize,
183 base_vertex: isize,
184 base_instance: usize,
185) {
186 let mut dp = ffi::IRRuntimeDrawParams {
187 u_1: ffi::IRRuntimeDrawParams_u {
188 drawIndexed: ffi::IRRuntimeDrawIndexedArgument {
189 indexCountPerInstance: index_count as u32,
190 instanceCount: instance_count as u32,
191 startIndexLocation: index_buffer_offset as u32,
192 baseVertexLocation: base_vertex as i32,
193 startInstanceLocation: base_instance as u32,
194 },
195 },
196 };
197 let mut ir_index_type = metal_index_to_ir_index(index_type);
198 unsafe {
199 encoder.setVertexBytes_length_atIndex(
200 NonNull::new(&raw mut dp).unwrap().cast(),
201 size_of_val(&dp),
202 ffi::kIRArgumentBufferDrawArgumentsBindPoint as usize,
203 );
204 encoder.setVertexBytes_length_atIndex(
205 NonNull::new(&raw mut ir_index_type).unwrap().cast(),
206 size_of_val(&ir_index_type),
207 ffi::kIRArgumentBufferUniformsBindPoint as usize,
208 );
209 encoder.drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_baseVertex_baseInstance(
210 primitive_type,
211 index_count,
212 index_type,
213 index_buffer,
214 index_buffer_offset,
215 instance_count,
216 base_vertex,
217 base_instance,
218 );
219 }
220}
221
222#[doc(alias = "IRRuntimeDrawIndexedPrimitives")]
223pub fn draw_indexed_primitives_indirect(
224 encoder: &ProtocolObject<dyn MTLRenderCommandEncoder>,
225 primitive_type: MTLPrimitiveType,
226 index_type: MTLIndexType,
227 index_buffer: &ProtocolObject<dyn MTLBuffer>,
228 index_buffer_offset: usize,
229 indirect_buffer: &ProtocolObject<dyn MTLBuffer>,
230 indirect_buffer_offset: usize,
231) {
232 let mut ir_index_type = metal_index_to_ir_index(index_type);
233
234 unsafe {
235 encoder.setVertexBuffer_offset_atIndex(
236 Some(indirect_buffer),
237 0,
238 ffi::kIRArgumentBufferDrawArgumentsBindPoint as usize,
239 );
240 encoder.setVertexBytes_length_atIndex(
241 NonNull::new(&raw mut ir_index_type).unwrap().cast(),
242 size_of_val(&ir_index_type),
243 ffi::kIRArgumentBufferUniformsBindPoint as usize,
244 );
245 encoder.drawIndexedPrimitives_indexType_indexBuffer_indexBufferOffset_indirectBuffer_indirectBufferOffset(
246 primitive_type,
247 index_type,
248 index_buffer,
249 index_buffer_offset,
250 indirect_buffer,
251 indirect_buffer_offset
252 );
253 }
254}