use objc2::{Message, extern_protocol, msg_send, rc::Retained, runtime::ProtocolObject};
use objc2_foundation::{NSError, NSObjectProtocol, NSString};
use crate::{
MTLAccelerationStructureCommandEncoder, MTLAccelerationStructurePassDescriptor, MTLBlitCommandEncoder,
MTLBlitPassDescriptor, MTLCommandBufferHandler, MTLCommandBufferStatus, MTLCommandQueue, MTLComputeCommandEncoder,
MTLComputePassDescriptor, MTLDevice, MTLDispatchType, MTLDrawable, MTLEvent, MTLLogContainer,
MTLRenderCommandEncoder, MTLRenderPassDescriptor, MTLResourceStateCommandEncoder, MTLResourceStatePassDescriptor,
};
extern_protocol!(
pub unsafe trait MTLCommandBuffer: NSObjectProtocol {
#[unsafe(method(device))]
#[unsafe(method_family = none)]
fn device(&self) -> Retained<ProtocolObject<dyn MTLDevice>>;
#[unsafe(method(commandQueue))]
#[unsafe(method_family = none)]
fn command_queue(&self) -> Retained<ProtocolObject<dyn MTLCommandQueue>>;
#[unsafe(method(retainedReferences))]
#[unsafe(method_family = none)]
fn retained_references(&self) -> bool;
#[unsafe(method(enqueue))]
#[unsafe(method_family = none)]
fn enqueue(&self);
#[unsafe(method(commit))]
#[unsafe(method_family = none)]
fn commit(&self);
#[unsafe(method(waitUntilScheduled))]
#[unsafe(method_family = none)]
fn wait_until_scheduled(&self);
#[unsafe(method(waitUntilCompleted))]
#[unsafe(method_family = none)]
fn wait_until_completed(&self);
#[unsafe(method(error))]
#[unsafe(method_family = none)]
fn error(&self) -> Option<Retained<NSError>>;
#[unsafe(method(status))]
#[unsafe(method_family = none)]
fn status(&self) -> MTLCommandBufferStatus;
#[unsafe(method(logs))]
#[unsafe(method_family = none)]
fn logs(&self) -> Retained<ProtocolObject<dyn MTLLogContainer>>;
#[unsafe(method(presentDrawable:))]
#[unsafe(method_family = none)]
fn present_drawable(
&self,
drawable: &ProtocolObject<dyn MTLDrawable>,
);
#[unsafe(method(encodeWaitForEvent:value:))]
#[unsafe(method_family = none)]
fn encode_wait_for_event_value(
&self,
event: &ProtocolObject<dyn MTLEvent>,
value: u64,
);
#[unsafe(method(encodeSignalEvent:value:))]
#[unsafe(method_family = none)]
fn encode_signal_event_value(
&self,
event: &ProtocolObject<dyn MTLEvent>,
value: u64,
);
#[unsafe(method(renderCommandEncoderWithDescriptor:))]
#[unsafe(method_family = none)]
fn render_command_encoder_with_descriptor(
&self,
render_pass_descriptor: &MTLRenderPassDescriptor,
) -> Option<Retained<ProtocolObject<dyn MTLRenderCommandEncoder>>>;
#[unsafe(method(computeCommandEncoder))]
#[unsafe(method_family = none)]
fn compute_command_encoder(&self) -> Option<Retained<ProtocolObject<dyn MTLComputeCommandEncoder>>>;
#[unsafe(method(computeCommandEncoderWithDispatchType:))]
#[unsafe(method_family = none)]
fn compute_command_encoder_with_dispatch_type(
&self,
dispatch_type: MTLDispatchType,
) -> Option<Retained<ProtocolObject<dyn MTLComputeCommandEncoder>>>;
#[unsafe(method(blitCommandEncoder))]
#[unsafe(method_family = none)]
fn blit_command_encoder(&self) -> Option<Retained<ProtocolObject<dyn MTLBlitCommandEncoder>>>;
#[unsafe(method(computeCommandEncoderWithDescriptor:))]
#[unsafe(method_family = none)]
fn compute_command_encoder_with_descriptor(
&self,
compute_pass_descriptor: &MTLComputePassDescriptor,
) -> Option<Retained<ProtocolObject<dyn MTLComputeCommandEncoder>>>;
#[unsafe(method(blitCommandEncoderWithDescriptor:))]
#[unsafe(method_family = none)]
fn blit_command_encoder_with_descriptor(
&self,
blit_pass_descriptor: &MTLBlitPassDescriptor,
) -> Option<Retained<ProtocolObject<dyn MTLBlitCommandEncoder>>>;
#[unsafe(method(resourceStateCommandEncoder))]
#[unsafe(method_family = none)]
fn resource_state_command_encoder(
&self
) -> Option<Retained<ProtocolObject<dyn MTLResourceStateCommandEncoder>>>;
#[unsafe(method(resourceStateCommandEncoderWithDescriptor:))]
#[unsafe(method_family = none)]
fn resource_state_command_encoder_with_descriptor(
&self,
resource_state_pass_descriptor: &MTLResourceStatePassDescriptor,
) -> Option<Retained<ProtocolObject<dyn MTLResourceStateCommandEncoder>>>;
#[unsafe(method(accelerationStructureCommandEncoder))]
#[unsafe(method_family = none)]
fn acceleration_structure_command_encoder(
&self
) -> Option<Retained<ProtocolObject<dyn MTLAccelerationStructureCommandEncoder>>>;
#[unsafe(method(accelerationStructureCommandEncoderWithDescriptor:))]
#[unsafe(method_family = none)]
fn acceleration_structure_command_encoder_with_descriptor(
&self,
descriptor: &MTLAccelerationStructurePassDescriptor,
) -> Option<Retained<ProtocolObject<dyn MTLAccelerationStructureCommandEncoder>>>;
}
);
#[allow(unused)]
pub trait MTLCommandBufferExt: MTLCommandBuffer + Message {
fn label(&self) -> Option<String>;
fn set_label(
&self,
label: Option<&str>,
);
fn add_scheduled_handler(
&self,
handler: &MTLCommandBufferHandler,
);
fn add_completed_handler(
&self,
handler: &MTLCommandBufferHandler,
);
fn push_debug_group(
&self,
string: &str,
);
fn pop_debug_group(&self);
fn kernel_start_time(&self) -> Option<f64>;
fn kernel_end_time(&self) -> Option<f64>;
fn gpu_start_time(&self) -> f64;
fn gpu_end_time(&self) -> f64;
}
impl MTLCommandBufferExt for ProtocolObject<dyn MTLCommandBuffer> {
fn label(&self) -> Option<String> {
let label: Option<Retained<NSString>> = unsafe { msg_send![self, label] };
label.map(|s| s.to_string())
}
fn set_label(
&self,
label: Option<&str>,
) {
unsafe {
let _: () = msg_send![self, setLabel: label.map(NSString::from_str).as_deref()];
}
}
fn add_scheduled_handler(
&self,
handler: &MTLCommandBufferHandler,
) {
unsafe {
let _: () = msg_send![self, addScheduledHandler: &**handler];
}
}
fn add_completed_handler(
&self,
handler: &MTLCommandBufferHandler,
) {
unsafe {
let _: () = msg_send![self, addCompletedHandler: &**handler];
}
}
fn push_debug_group(
&self,
string: &str,
) {
unsafe {
let _: () = msg_send![self, pushDebugGroup: &*NSString::from_str(string)];
}
}
fn pop_debug_group(&self) {
unsafe {
let _: () = msg_send![self, popDebugGroup];
}
}
fn kernel_start_time(&self) -> Option<f64> {
let start_time: f64 = unsafe { msg_send![self, kernelStartTime] };
if start_time > 0.0 {
Some(start_time)
} else {
None
}
}
fn kernel_end_time(&self) -> Option<f64> {
let end_time: f64 = unsafe { msg_send![self, kernelEndTime] };
if end_time > 0.0 {
Some(end_time)
} else {
None
}
}
fn gpu_start_time(&self) -> f64 {
unsafe { msg_send![self, GPUStartTime] }
}
fn gpu_end_time(&self) -> f64 {
unsafe { msg_send![self, GPUEndTime] }
}
}