diff --git a/examples/circle/main.rs b/examples/circle/main.rs index 04c521fe..ed17a734 100644 --- a/examples/circle/main.rs +++ b/examples/circle/main.rs @@ -46,6 +46,18 @@ fn main() { let device = Device::system_default().expect("no device found"); println!("Your device is: {}", device.name(),); + // Scaffold required to sample the GPU and CPU timestamps + let mut cpu_start = 0; + let mut gpu_start = 0; + device.sample_timestamps(&mut cpu_start, &mut gpu_start); + let counter_sample_buffer = create_counter_sample_buffer(&device); + let destination_buffer = device.new_buffer( + (std::mem::size_of::() * 4 as usize) as u64, + MTLResourceOptions::StorageModeShared, + ); + let counter_sampling_point = MTLCounterSamplingPoint::AtStageBoundary; + assert!(device.supports_counter_sampling(counter_sampling_point)); + let binary_archive_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("examples/circle/binary_archive.metallib"); @@ -140,7 +152,14 @@ fn main() { // Obtain a renderPassDescriptor generated from the view's drawable textures. let render_pass_descriptor = RenderPassDescriptor::new(); - prepare_render_pass_descriptor(&render_pass_descriptor, drawable.texture()); + handle_render_pass_color_attachment( + &render_pass_descriptor, + drawable.texture(), + ); + handle_render_pass_sample_buffer_attachment( + &render_pass_descriptor, + &counter_sample_buffer, + ); // Create a render command encoder. let encoder = @@ -152,11 +171,23 @@ fn main() { encoder.draw_primitives(MTLPrimitiveType::TriangleStrip, 0, 1080); encoder.end_encoding(); + resolve_samples_into_buffer( + &command_buffer, + &counter_sample_buffer, + &destination_buffer, + ); + // Schedule a present once the framebuffer is complete using the current drawable. command_buffer.present_drawable(&drawable); // Finalize rendering here & push the command buffer to the GPU. command_buffer.commit(); + command_buffer.wait_until_completed(); + + let mut cpu_end = 0; + let mut gpu_end = 0; + device.sample_timestamps(&mut cpu_end, &mut gpu_end); + handle_timestamps(&destination_buffer, cpu_start, cpu_end, gpu_start, gpu_end); } _ => (), } @@ -210,7 +241,20 @@ fn create_vertex_points_for_circle() -> Vec { v } -fn prepare_render_pass_descriptor(descriptor: &RenderPassDescriptorRef, texture: &TextureRef) { +fn handle_render_pass_sample_buffer_attachment( + descriptor: &RenderPassDescriptorRef, + counter_sample_buffer: &CounterSampleBufferRef, +) { + let sample_buffer_attachment_descriptor = + descriptor.sample_buffer_attachments().object_at(0).unwrap(); + sample_buffer_attachment_descriptor.set_sample_buffer(&counter_sample_buffer); + sample_buffer_attachment_descriptor.set_start_of_vertex_sample_index(0 as NSUInteger); + sample_buffer_attachment_descriptor.set_end_of_vertex_sample_index(1 as NSUInteger); + sample_buffer_attachment_descriptor.set_start_of_fragment_sample_index(2 as NSUInteger); + sample_buffer_attachment_descriptor.set_end_of_fragment_sample_index(3 as NSUInteger); +} + +fn handle_render_pass_color_attachment(descriptor: &RenderPassDescriptorRef, texture: &TextureRef) { let color_attachment = descriptor.color_attachments().object_at(0).unwrap(); color_attachment.set_texture(Some(texture)); @@ -248,3 +292,86 @@ fn prepare_pipeline_state( .new_render_pipeline_state(&pipeline_state_descriptor) .unwrap() } + +fn resolve_samples_into_buffer( + command_buffer: &CommandBufferRef, + counter_sample_buffer: &CounterSampleBufferRef, + destination_buffer: &BufferRef, +) { + let blit_encoder = command_buffer.new_blit_command_encoder(); + blit_encoder.resolve_counters( + &counter_sample_buffer, + crate::NSRange::new(0_u64, 4), + &destination_buffer, + 0_u64, + ); + blit_encoder.end_encoding(); +} + +fn handle_timestamps( + resolved_sample_buffer: &BufferRef, + cpu_start: u64, + cpu_end: u64, + gpu_start: u64, + gpu_end: u64, +) { + let samples = unsafe { + std::slice::from_raw_parts(resolved_sample_buffer.contents() as *const u64, 4 as usize) + }; + let vertex_pass_start = samples[0]; + let vertex_pass_end = samples[1]; + let fragment_pass_start = samples[2]; + let fragment_pass_end = samples[3]; + + let cpu_time_span = cpu_end - cpu_start; + let gpu_time_span = gpu_end - gpu_start; + + let vertex_micros = microseconds_between_begin( + vertex_pass_start, + vertex_pass_end, + gpu_time_span, + cpu_time_span, + ); + let fragment_micros = microseconds_between_begin( + fragment_pass_start, + fragment_pass_end, + gpu_time_span, + cpu_time_span, + ); + + println!("Vertex pass duration: {:.2} µs", vertex_micros); + println!("Fragment pass duration: {:.2} µs\n", fragment_micros); +} + +fn create_counter_sample_buffer(device: &Device) -> CounterSampleBuffer { + let counter_sample_buffer_desc = metal::CounterSampleBufferDescriptor::new(); + counter_sample_buffer_desc.set_storage_mode(metal::MTLStorageMode::Shared); + counter_sample_buffer_desc.set_sample_count(4_u64); + counter_sample_buffer_desc.set_counter_set(&fetch_timestamp_counter_set(device)); + + device + .new_counter_sample_buffer_with_descriptor(&counter_sample_buffer_desc) + .unwrap() +} + +fn fetch_timestamp_counter_set(device: &Device) -> metal::CounterSet { + let counter_sets = device.counter_sets(); + let mut timestamp_counter = None; + for cs in counter_sets.iter() { + if cs.name() == "timestamp" { + timestamp_counter = Some(cs); + break; + } + } + timestamp_counter + .expect("No timestamp counter found") + .clone() +} + +/// +fn microseconds_between_begin(begin: u64, end: u64, gpu_time_span: u64, cpu_time_span: u64) -> f64 { + let time_span = (end as f64) - (begin as f64); + let nanoseconds = time_span / (gpu_time_span as f64) * (cpu_time_span as f64); + let microseconds = nanoseconds / 1000.0; + return microseconds; +} diff --git a/examples/compute/main.rs b/examples/compute/main.rs index 6497c790..066997d9 100644 --- a/examples/compute/main.rs +++ b/examples/compute/main.rs @@ -1,66 +1,41 @@ -// Copyright 2017 GFX developers -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - use metal::*; use objc::rc::autoreleasepool; -use std::mem; +use std::path::PathBuf; + +const NUM_SAMPLES: u64 = 2; +const NUM_ELEMENTS: u64 = 64 * 64; fn main() { autoreleasepool(|| { - let device = Device::system_default().expect("no device found"); - let command_queue = device.new_command_queue(); - - let data = [ - 1u32, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, - ]; - - let buffer = device.new_buffer_with_data( - unsafe { mem::transmute(data.as_ptr()) }, - (data.len() * mem::size_of::()) as u64, - MTLResourceOptions::CPUCacheModeDefaultCache, + let device = Device::system_default().expect("No device found"); + let mut cpu_start = 0; + let mut gpu_start = 0; + device.sample_timestamps(&mut cpu_start, &mut gpu_start); + + let counter_sample_buffer = create_counter_sample_buffer(&device); + let destination_buffer = device.new_buffer( + (std::mem::size_of::() * NUM_SAMPLES as usize) as u64, + MTLResourceOptions::StorageModeShared, ); - let sum = { - let data = [0u32]; - device.new_buffer_with_data( - unsafe { mem::transmute(data.as_ptr()) }, - (data.len() * mem::size_of::()) as u64, - MTLResourceOptions::CPUCacheModeDefaultCache, - ) - }; + let counter_sampling_point = MTLCounterSamplingPoint::AtStageBoundary; + assert!(device.supports_counter_sampling(counter_sampling_point)); + let command_queue = device.new_command_queue(); let command_buffer = command_queue.new_command_buffer(); - command_buffer.set_label("label"); - let block = block::ConcreteBlock::new(move |buffer: &metal::CommandBufferRef| { - println!("{}", buffer.label()); - }) - .copy(); - - command_buffer.add_completed_handler(&block); - - let encoder = command_buffer.new_compute_command_encoder(); - let library_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("examples/compute/shaders.metallib"); - - let library = device.new_library_with_file(library_path).unwrap(); - let kernel = library.get_function("sum", None).unwrap(); - - let pipeline_state_descriptor = ComputePipelineDescriptor::new(); - pipeline_state_descriptor.set_compute_function(Some(&kernel)); - - let pipeline_state = device - .new_compute_pipeline_state_with_function( - pipeline_state_descriptor.compute_function().unwrap(), - ) - .unwrap(); + let compute_pass_descriptor = ComputePassDescriptor::new(); + handle_compute_pass_sample_buffer_attachment( + &compute_pass_descriptor, + &counter_sample_buffer, + ); + let encoder = + command_buffer.compute_command_encoder_with_descriptor(&compute_pass_descriptor); + let pipeline_state = create_pipeline_state(&device); encoder.set_compute_pipeline_state(&pipeline_state); + + let (buffer, sum) = create_input_and_output_buffers(&device); encoder.set_buffer(0, Some(&buffer), 0); encoder.set_buffer(1, Some(&sum), 0); @@ -73,19 +48,141 @@ fn main() { }; let thread_group_size = MTLSize { - width: (data.len() as u64 + width) / width, + width: (NUM_ELEMENTS + width) / width, height: 1, depth: 1, }; encoder.dispatch_thread_groups(thread_group_count, thread_group_size); encoder.end_encoding(); + + resolve_samples_into_buffer(&command_buffer, &counter_sample_buffer, &destination_buffer); + command_buffer.commit(); command_buffer.wait_until_completed(); + let mut cpu_end = 0; + let mut gpu_end = 0; + device.sample_timestamps(&mut cpu_end, &mut gpu_end); let ptr = sum.contents() as *mut u32; + println!("Compute shader sum: {}", unsafe { *ptr }); + unsafe { - assert_eq!(465, *ptr); + assert_eq!(NUM_ELEMENTS as u32, *ptr); } + + handle_timestamps(&destination_buffer, cpu_start, cpu_end, gpu_start, gpu_end); }); } + +fn create_pipeline_state(device: &Device) -> ComputePipelineState { + let library_path = + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples/compute/shaders.metallib"); + let library = device.new_library_with_file(library_path).unwrap(); + let kernel = library.get_function("sum", None).unwrap(); + + let pipeline_state_descriptor = ComputePipelineDescriptor::new(); + pipeline_state_descriptor.set_compute_function(Some(&kernel)); + + device + .new_compute_pipeline_state_with_function( + pipeline_state_descriptor.compute_function().unwrap(), + ) + .unwrap() +} + +fn handle_compute_pass_sample_buffer_attachment( + compute_pass_descriptor: &ComputePassDescriptorRef, + counter_sample_buffer: &CounterSampleBufferRef, +) { + let sample_buffer_attachment_descriptor = compute_pass_descriptor + .sample_buffer_attachments() + .object_at(0) + .unwrap(); + + sample_buffer_attachment_descriptor.set_sample_buffer(&counter_sample_buffer); + sample_buffer_attachment_descriptor.set_start_of_encoder_sample_index(0); + sample_buffer_attachment_descriptor.set_end_of_encoder_sample_index(1); +} + +fn resolve_samples_into_buffer( + command_buffer: &CommandBufferRef, + counter_sample_buffer: &CounterSampleBufferRef, + destination_buffer: &BufferRef, +) { + let blit_encoder = command_buffer.new_blit_command_encoder(); + blit_encoder.resolve_counters( + &counter_sample_buffer, + crate::NSRange::new(0_u64, NUM_SAMPLES), + &destination_buffer, + 0_u64, + ); + blit_encoder.end_encoding(); +} + +fn handle_timestamps( + resolved_sample_buffer: &BufferRef, + cpu_start: u64, + cpu_end: u64, + gpu_start: u64, + gpu_end: u64, +) { + let samples = unsafe { + std::slice::from_raw_parts( + resolved_sample_buffer.contents() as *const u64, + NUM_SAMPLES as usize, + ) + }; + let pass_start = samples[0]; + let pass_end = samples[1]; + + let cpu_time_span = cpu_end - cpu_start; + let gpu_time_span = gpu_end - gpu_start; + + let micros = microseconds_between_begin(pass_start, pass_end, gpu_time_span, cpu_time_span); + println!("Compute pass duration: {} µs", micros); +} + +fn create_counter_sample_buffer(device: &Device) -> CounterSampleBuffer { + let counter_sample_buffer_desc = metal::CounterSampleBufferDescriptor::new(); + counter_sample_buffer_desc.set_storage_mode(metal::MTLStorageMode::Shared); + counter_sample_buffer_desc.set_sample_count(NUM_SAMPLES); + let counter_sets = device.counter_sets(); + + let timestamp_counter = counter_sets.iter().find(|cs| cs.name() == "timestamp"); + + counter_sample_buffer_desc + .set_counter_set(×tamp_counter.expect("No timestamp counter found")); + + device + .new_counter_sample_buffer_with_descriptor(&counter_sample_buffer_desc) + .unwrap() +} + +fn create_input_and_output_buffers(device: &Device) -> (metal::Buffer, metal::Buffer) { + let data = [1u32; 64 * 64]; + + let buffer = device.new_buffer_with_data( + unsafe { std::mem::transmute(data.as_ptr()) }, + (data.len() * std::mem::size_of::()) as u64, + MTLResourceOptions::CPUCacheModeDefaultCache, + ); + + let sum = { + let data = [0u32]; + device.new_buffer_with_data( + unsafe { std::mem::transmute(data.as_ptr()) }, + (data.len() * std::mem::size_of::()) as u64, + MTLResourceOptions::CPUCacheModeDefaultCache, + ) + }; + (buffer, sum) +} + +/// +fn microseconds_between_begin(begin: u64, end: u64, gpu_time_span: u64, cpu_time_span: u64) -> f64 { + let time_span = (end as f64) - (begin as f64); + let nanoseconds = time_span / (gpu_time_span as f64) * (cpu_time_span as f64); + let microseconds = nanoseconds / 1000.0; + return microseconds; +} diff --git a/src/commandbuffer.rs b/src/commandbuffer.rs index d51cde34..ec808f80 100644 --- a/src/commandbuffer.rs +++ b/src/commandbuffer.rs @@ -140,6 +140,13 @@ impl CommandBufferRef { unsafe { msg_send![self, computeCommandEncoderWithDispatchType: ty] } } + pub fn compute_command_encoder_with_descriptor( + &self, + descriptor: &ComputePassDescriptorRef, + ) -> &ComputeCommandEncoderRef { + unsafe { msg_send![self, computeCommandEncoderWithDescriptor: descriptor] } + } + pub fn encode_signal_event(&self, event: &EventRef, new_value: u64) { unsafe { msg_send![self, diff --git a/src/computepass.rs b/src/computepass.rs new file mode 100644 index 00000000..50774d68 --- /dev/null +++ b/src/computepass.rs @@ -0,0 +1,103 @@ +use super::*; + +/// See +pub enum MTLComputePassDescriptor {} + +foreign_obj_type! { + type CType = MTLComputePassDescriptor; + pub struct ComputePassDescriptor; +} + +impl ComputePassDescriptor { + /// Creates a default compute pass descriptor with no attachments. + pub fn new<'a>() -> &'a ComputePassDescriptorRef { + unsafe { msg_send![class!(MTLComputePassDescriptor), computePassDescriptor] } + } +} + +impl ComputePassDescriptorRef { + pub fn sample_buffer_attachments( + &self, + ) -> &ComputePassSampleBufferAttachmentDescriptorArrayRef { + unsafe { msg_send![self, sampleBufferAttachments] } + } +} + +/// See +pub enum MTLComputePassSampleBufferAttachmentDescriptorArray {} + +foreign_obj_type! { + type CType = MTLComputePassSampleBufferAttachmentDescriptorArray; + pub struct ComputePassSampleBufferAttachmentDescriptorArray; +} + +impl ComputePassSampleBufferAttachmentDescriptorArrayRef { + pub fn object_at( + &self, + index: NSUInteger, + ) -> Option<&ComputePassSampleBufferAttachmentDescriptorRef> { + unsafe { msg_send![self, objectAtIndexedSubscript: index] } + } + + pub fn set_object_at( + &self, + index: NSUInteger, + attachment: Option<&ComputePassSampleBufferAttachmentDescriptorRef>, + ) { + unsafe { + msg_send![self, setObject:attachment + atIndexedSubscript:index] + } + } +} + +/// See +pub enum MTLComputePassSampleBufferAttachmentDescriptor {} + +foreign_obj_type! { + type CType = MTLComputePassSampleBufferAttachmentDescriptor; + pub struct ComputePassSampleBufferAttachmentDescriptor; +} + +impl ComputePassSampleBufferAttachmentDescriptor { + pub fn new() -> Self { + let class = class!(MTLComputePassSampleBufferAttachmentDescriptor); + unsafe { msg_send![class, new] } + } +} + +impl ComputePassSampleBufferAttachmentDescriptorRef { + pub fn sample_buffer(&self) -> &CounterSampleBufferRef { + unsafe { msg_send![self, sampleBuffer] } + } + + pub fn set_sample_buffer(&self, sample_buffer: &CounterSampleBufferRef) { + unsafe { msg_send![self, setSampleBuffer: sample_buffer] } + } + + pub fn start_of_encoder_sample_index(&self) -> NSUInteger { + unsafe { msg_send![self, startOfEncoderSampleIndex] } + } + + pub fn set_start_of_encoder_sample_index(&self, start_of_encoder_sample_index: NSUInteger) { + unsafe { + msg_send![ + self, + setStartOfEncoderSampleIndex: start_of_encoder_sample_index + ] + } + } + + pub fn end_of_encoder_sample_index(&self) -> NSUInteger { + unsafe { msg_send![self, endOfEncoderSampleIndex] } + } + + pub fn set_end_of_encoder_sample_index(&self, end_of_encoder_sample_index: NSUInteger) { + unsafe { + msg_send![ + self, + setEndOfEncoderSampleIndex: end_of_encoder_sample_index + ] + } + } +} diff --git a/src/counters.rs b/src/counters.rs new file mode 100644 index 00000000..2963ebc8 --- /dev/null +++ b/src/counters.rs @@ -0,0 +1,96 @@ +use crate::MTLStorageMode; + +/// See +pub enum MTLCounterSampleBufferDescriptor {} + +foreign_obj_type! { + type CType = MTLCounterSampleBufferDescriptor; + pub struct CounterSampleBufferDescriptor; +} + +impl CounterSampleBufferDescriptor { + pub fn new() -> Self { + let class = class!(MTLCounterSampleBufferDescriptor); + unsafe { msg_send![class, new] } + } +} + +impl CounterSampleBufferDescriptorRef { + pub fn counter_set(&self) -> &CounterSetRef { + unsafe { msg_send![self, counterSet] } + } + + pub fn set_counter_set(&self, counter_set: &CounterSetRef) { + unsafe { msg_send![self, setCounterSet: counter_set] } + } + + pub fn label(&self) -> &str { + unsafe { msg_send![self, label] } + } + + pub fn set_label(&self, label: &str) { + unsafe { msg_send![self, setLabel: label] } + } + + pub fn sample_count(&self) -> u64 { + unsafe { msg_send![self, sampleCount] } + } + + pub fn set_sample_count(&self, sample_count: u64) { + unsafe { msg_send![self, setSampleCount: sample_count] } + } + + pub fn storage_mode(&self) -> MTLStorageMode { + unsafe { msg_send![self, storageMode] } + } + + pub fn set_storage_mode(&self, storage_mode: MTLStorageMode) { + unsafe { msg_send![self, setStorageMode: storage_mode] } + } +} + +/// See +pub enum MTLCounterSampleBuffer {} + +foreign_obj_type! { + type CType = MTLCounterSampleBuffer; + pub struct CounterSampleBuffer; +} + +/// See +pub enum MTLCounter {} + +foreign_obj_type! { + type CType = MTLCounter; + pub struct Counter; +} + +impl CounterRef {} + +/// See +pub enum MTLCounterSet {} + +foreign_obj_type! { + type CType = MTLCounterSet; + pub struct CounterSet; +} + +impl CounterSetRef { + pub fn name(&self) -> &str { + unsafe { + let name = msg_send![self, name]; + crate::nsstring_as_str(name) + } + } +} + +/// See +pub enum MTLCommonCounterSet {} + +/// See +pub enum MTLCommonCounter {} + +foreign_obj_type! { + type CType = MTLCommonCounter; + pub struct CommonCounter; +} diff --git a/src/device.rs b/src/device.rs index 2d520766..1b4a7296 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1987,6 +1987,20 @@ impl DeviceRef { } } + pub fn new_counter_sample_buffer_with_descriptor( + &self, + descriptor: &CounterSampleBufferDescriptorRef, + ) -> Result { + unsafe { + let counter_sample_buffer: *mut MTLCounterSampleBuffer = try_objc! { err => + msg_send![self, newCounterSampleBufferWithDescriptor: descriptor error:&mut err] + }; + + assert!(!counter_sample_buffer.is_null()); + Ok(CounterSampleBuffer::from_ptr(counter_sample_buffer)) + } + } + pub fn new_texture(&self, descriptor: &TextureDescriptorRef) -> Texture { unsafe { msg_send![self, newTextureWithDescriptor: descriptor] } } @@ -2149,4 +2163,23 @@ impl DeviceRef { ) -> accelerator_structure::AccelerationStructure { unsafe { msg_send![self, newAccelerationStructureWithSize: size] } } + + pub fn sample_timestamps(&self, cpu_timestamp: &mut u64, gpu_timestamp: &mut u64) { + unsafe { msg_send![self, sampleTimestamps: cpu_timestamp gpuTimestamp: gpu_timestamp] } + } + + pub fn counter_sets(&self) -> Vec { + unsafe { + let counter_sets: *mut Object = msg_send![self, counterSets]; + let count: NSUInteger = msg_send![counter_sets, count]; + let ret = (0..count) + .map(|i| { + let csp: *mut MTLCounterSet = msg_send![counter_sets, objectAtIndex: i]; + let () = msg_send![csp, retain]; + CounterSet::from_ptr(csp) + }) + .collect(); + ret + } + } } diff --git a/src/encoder.rs b/src/encoder.rs index c7db972c..0616d2c5 100644 --- a/src/encoder.rs +++ b/src/encoder.rs @@ -1072,6 +1072,23 @@ impl BlitCommandEncoderRef { pub fn wait_for_fence(&self, fence: &FenceRef) { unsafe { msg_send![self, waitForFence: fence] } } + + pub fn resolve_counters( + &self, + sample_buffer: &CounterSampleBufferRef, + range: crate::NSRange, + destination_buffer: &BufferRef, + destination_offset: NSUInteger, + ) { + unsafe { + msg_send![self, + resolveCounters: sample_buffer + inRange: range + destinationBuffer: destination_buffer + destinationOffset: destination_offset + ] + } + } } /// See @@ -1341,6 +1358,22 @@ impl ComputeCommandEncoderRef { ] } } + + /// See: + pub fn sample_counters_in_buffer( + &self, + sample_buffer: &CounterSampleBufferRef, + sample_index: NSUInteger, + with_barrier: bool, + ) { + unsafe { + msg_send![self, + sampleCountersInBuffer: sample_buffer + atSampleIndex: sample_index + withBarrier: with_barrier + ] + } + } } /// See diff --git a/src/lib.rs b/src/lib.rs index e3be852b..a2c7da6f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -544,7 +544,9 @@ mod capturedescriptor; mod capturemanager; mod commandbuffer; mod commandqueue; +mod computepass; mod constants; +mod counters; mod depthstencil; mod device; mod drawable; @@ -568,6 +570,8 @@ pub use { accelerator_structure::*, argument::*, buffer::*, + counters::*, + computepass::*, capturedescriptor::*, capturemanager::*, commandbuffer::*, diff --git a/src/renderpass.rs b/src/renderpass.rs index a18c61f3..f9aa50b5 100644 --- a/src/renderpass.rs +++ b/src/renderpass.rs @@ -250,6 +250,106 @@ impl RenderPassColorAttachmentDescriptorArrayRef { } } +/// See +pub enum MTLRenderPassSampleBufferAttachmentDescriptor {} + +foreign_obj_type! { + type CType = MTLRenderPassSampleBufferAttachmentDescriptor; + pub struct RenderPassSampleBufferAttachmentDescriptor; +} + +impl RenderPassSampleBufferAttachmentDescriptor { + pub fn new() -> Self { + let class = class!(MTLRenderPassSampleBufferAttachmentDescriptor); + unsafe { msg_send![class, new] } + } +} + +impl RenderPassSampleBufferAttachmentDescriptorRef { + pub fn sample_buffer(&self) -> &CounterSampleBufferRef { + unsafe { msg_send![self, sampleBuffer] } + } + + pub fn set_sample_buffer(&self, sample_buffer: &CounterSampleBufferRef) { + unsafe { msg_send![self, setSampleBuffer: sample_buffer] } + } + + pub fn start_of_vertex_sample_index(&self) -> NSUInteger { + unsafe { msg_send![self, startOfVertexSampleIndex] } + } + + pub fn set_start_of_vertex_sample_index(&self, start_of_vertex_sample_index: NSUInteger) { + unsafe { + msg_send![ + self, + setStartOfVertexSampleIndex: start_of_vertex_sample_index + ] + } + } + + pub fn end_of_vertex_sample_index(&self) -> NSUInteger { + unsafe { msg_send![self, endOfVertexSampleIndex] } + } + + pub fn set_end_of_vertex_sample_index(&self, end_of_vertex_sample_index: NSUInteger) { + unsafe { msg_send![self, setEndOfVertexSampleIndex: end_of_vertex_sample_index] } + } + + pub fn start_of_fragment_sample_index(&self) -> NSUInteger { + unsafe { msg_send![self, startOfFragmentSampleIndex] } + } + + pub fn set_start_of_fragment_sample_index(&self, start_of_fragment_sample_index: NSUInteger) { + unsafe { + msg_send![ + self, + setStartOfFragmentSampleIndex: start_of_fragment_sample_index + ] + } + } + + pub fn end_of_fragment_sample_index(&self) -> NSUInteger { + unsafe { msg_send![self, endOfFragmentSampleIndex] } + } + + pub fn set_end_of_fragment_sample_index(&self, end_of_fragment_sample_index: NSUInteger) { + unsafe { + msg_send![ + self, + setEndOfFragmentSampleIndex: end_of_fragment_sample_index + ] + } + } +} + +/// See +pub enum MTLRenderPassSampleBufferAttachmentDescriptorArray {} + +foreign_obj_type! { + type CType = MTLRenderPassSampleBufferAttachmentDescriptorArray; + pub struct RenderPassSampleBufferAttachmentDescriptorArray; +} + +impl RenderPassSampleBufferAttachmentDescriptorArrayRef { + pub fn object_at( + &self, + index: NSUInteger, + ) -> Option<&RenderPassSampleBufferAttachmentDescriptorRef> { + unsafe { msg_send![self, objectAtIndexedSubscript: index] } + } + + pub fn set_object_at( + &self, + index: NSUInteger, + attachment: Option<&RenderPassSampleBufferAttachmentDescriptorRef>, + ) { + unsafe { + msg_send![self, setObject:attachment + atIndexedSubscript:index] + } + } +} + /// ## Important! /// When configuring a [`MTLTextureDescriptor`] object for use with an attachment, set its usage /// value to renderTarget if you already know that you intend to use the resulting MTLTexture object in @@ -336,4 +436,8 @@ impl RenderPassDescriptorRef { pub fn set_default_raster_sample_count(&self, count: NSUInteger) { unsafe { msg_send![self, setDefaultRasterSampleCount: count] } } + + pub fn sample_buffer_attachments(&self) -> &RenderPassSampleBufferAttachmentDescriptorArrayRef { + unsafe { msg_send![self, sampleBufferAttachments] } + } }