use crate::define_unity_interface;
use crate::interface::UnityInterface;
use crate::profiler::*;
use std::ffi::c_void;
use std::fmt::*;
use unity_native_plugin_sys::*;
define_unity_interface!(
UnityProfilerCallbacks,
unity_native_plugin_sys::IUnityProfilerCallbacks,
0x572FDB38CE3C4B1F_u64,
0xA6071A9A7C4F52D8_u64
);
#[derive(Debug)]
pub struct ProfilerCategoryDesc {
pub(crate) native: *const UnityProfilerCategoryDesc,
}
impl ProfilerCategoryDesc {
pub fn id(&self) -> ProfilerCategoryId {
unsafe { (*self.native).id as ProfilerCategoryId }
}
pub fn rgba_color(&self) -> u32 {
unsafe { (*self.native).rgbaColor }
}
pub fn name(&self) -> &std::ffi::CStr {
unsafe { std::ffi::CStr::from_ptr((*self.native).name) }
}
}
pub struct ProfilerThreadDesc {
pub(crate) native: *const UnityProfilerThreadDesc,
}
impl ProfilerThreadDesc {
pub fn thread_id(&self) -> ProfilerThreadId {
unsafe { (*self.native).threadId as ProfilerThreadId }
}
pub fn group_name(&self) -> &std::ffi::CStr {
unsafe { std::ffi::CStr::from_ptr((*self.native).groupName) }
}
pub fn name(&self) -> &std::ffi::CStr {
unsafe { std::ffi::CStr::from_ptr((*self.native).name) }
}
}
pub struct ProfilerMarkerEvent<'a> {
pub desc: ProfilerMarkerDesc,
pub event_type: ProfilerMarkerEventType,
pub event_data: &'a [ProfilerMarkerData],
}
impl<'a> std::fmt::Debug for ProfilerMarkerEvent<'a> {
fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
write!(
fmt,
"[event desc={:?}, ty={:?}, data_len={:?}]",
self.desc,
self.event_type,
self.event_data.len(),
)
}
}
#[repr(transparent)]
pub struct ProfilerMarkerData(UnityProfilerMarkerData);
impl ProfilerMarkerData {
pub fn value(&self) -> ProfilerMarkerDataValue {
match unsafe { std::mem::transmute::<_, ProfilerMarkerDataType>(self.0.type_) } {
ProfilerMarkerDataType::None => ProfilerMarkerDataValue::None,
ProfilerMarkerDataType::InstanceId => {
ProfilerMarkerDataValue::InstanceId(unsafe { *(self.0.ptr as *const i32) })
}
ProfilerMarkerDataType::Int32 => {
ProfilerMarkerDataValue::Int32(unsafe { *(self.0.ptr as *const i32) })
}
ProfilerMarkerDataType::UInt32 => {
ProfilerMarkerDataValue::UInt32(unsafe { *(self.0.ptr as *const u32) })
}
ProfilerMarkerDataType::Int64 => {
ProfilerMarkerDataValue::Int64(unsafe { *(self.0.ptr as *const i64) })
}
ProfilerMarkerDataType::UInt64 => {
ProfilerMarkerDataValue::UInt64(unsafe { *(self.0.ptr as *const u64) })
}
ProfilerMarkerDataType::Float => {
ProfilerMarkerDataValue::Float(unsafe { *(self.0.ptr as *const f32) })
}
ProfilerMarkerDataType::Double => {
ProfilerMarkerDataValue::Double(unsafe { *(self.0.ptr as *const f64) })
}
ProfilerMarkerDataType::String => ProfilerMarkerDataValue::String(unsafe {
std::ffi::CStr::from_ptr(self.0.ptr as *const std::ffi::c_char)
.to_str()
.unwrap()
.to_string()
}),
ProfilerMarkerDataType::String16 => ProfilerMarkerDataValue::String(
std::char::decode_utf16(unsafe {
std::slice::from_raw_parts(
self.0.ptr as *const u16,
(self.0.size / 2 - 1) as usize,
)
.iter()
.copied()
})
.map(|c| c.unwrap_or(std::char::REPLACEMENT_CHARACTER))
.collect(),
),
other => ProfilerMarkerDataValue::Unknown {
ty: other,
data: unsafe {
std::slice::from_raw_parts(self.0.ptr as *const u8, self.0.size as usize)
},
},
}
}
}
#[derive(Debug)]
pub enum ProfilerMarkerDataValue<'a> {
None,
InstanceId(i32),
Int32(i32),
UInt32(u32),
Int64(i64),
UInt64(u64),
Float(f32),
Double(f64),
String(String),
Unknown {
ty: ProfilerMarkerDataType,
data: &'a [u8],
},
}
extern "system" fn create_category_bridge(
_desc: *const UnityProfilerCategoryDesc,
_userdata: *mut c_void,
) {
let ptr = _userdata as *mut Box<dyn FnMut(&ProfilerCategoryDesc)>;
let mut cb = unsafe { Box::from_raw(ptr) };
let desc = ProfilerCategoryDesc { native: _desc };
cb(&desc);
std::mem::forget(cb);
}
extern "system" fn create_marker_bridge(
_desc: *const UnityProfilerMarkerDesc,
_userdata: *mut c_void,
) {
let ptr = _userdata as *mut Box<dyn FnMut(&ProfilerMarkerDesc)>;
let mut cb = unsafe { Box::from_raw(ptr) };
let desc = ProfilerMarkerDesc { native: _desc };
cb(&desc);
std::mem::forget(cb);
}
extern "system" fn marker_event_bridge(
_desc: *const UnityProfilerMarkerDesc,
_event_type: UnityProfilerMarkerEventType,
_event_data_count: u16,
_event_data: *const UnityProfilerMarkerData,
_userdata: *mut c_void,
) {
let desc = ProfilerMarkerDesc { native: _desc };
let event_type = match ProfilerMarkerEventType::from(_event_type) {
Some(v) => v,
None => return,
};
let event_data = if !_event_data.is_null() && _event_data_count > 0 {
unsafe {
std::slice::from_raw_parts(
_event_data as *const ProfilerMarkerData,
_event_data_count as usize,
)
}
} else {
&[]
};
let desc = ProfilerMarkerEvent {
desc,
event_type,
event_data,
};
let ptr = _userdata as *mut Box<dyn FnMut(&ProfilerMarkerEvent)>;
let mut cb = unsafe { Box::from_raw(ptr) };
cb(&desc);
std::mem::forget(cb);
}
extern "system" fn frame_bridge(_userdata: *mut c_void) {
let ptr = _userdata as *mut Box<dyn FnMut()>;
let mut cb = unsafe { Box::from_raw(ptr) };
cb();
std::mem::forget(cb);
}
extern "system" fn create_thread_bridge(
desc: *const UnityProfilerThreadDesc,
_userdata: *mut c_void,
) {
let desc = ProfilerThreadDesc { native: desc };
let ptr = _userdata as *mut Box<dyn FnMut(&ProfilerThreadDesc)>;
let mut cb = unsafe { Box::from_raw(ptr) };
cb(&desc);
std::mem::forget(cb);
}
pub struct CreateCategoryRegister(*mut c_void);
pub struct CreateMarkerRegister(*mut c_void);
pub struct MarkerEventRegister {
ptr: *mut c_void,
desc: *const UnityProfilerMarkerDesc,
}
pub struct FrameRegister(*mut c_void);
pub struct CreateThreadRegister(*mut c_void);
macro_rules! iface_fn {
($self:tt, $name:tt) => {
$self.interface().$name.expect(stringify!($name))
};
}
macro_rules! common_impl {
($name: tt) => {
impl $name {
pub fn register_create_category(
&self,
f: Box<dyn FnMut(&ProfilerCategoryDesc) + Send + Sync>,
) -> CreateCategoryRegister {
let ptr = Box::into_raw(Box::new(f)) as *mut c_void;
unsafe {
iface_fn!(self, RegisterCreateCategoryCallback)(
Some(create_category_bridge),
ptr,
);
}
CreateCategoryRegister(ptr)
}
pub fn unregister_create_category(&self, register: CreateCategoryRegister) {
unsafe {
iface_fn!(self, UnregisterCreateCategoryCallback)(
Some(create_category_bridge),
register.0,
);
}
}
pub fn register_create_marker(
&self,
f: Box<dyn FnMut(&ProfilerMarkerDesc) + Send + Sync>,
) -> CreateMarkerRegister {
let ptr = Box::into_raw(Box::new(f)) as *mut c_void;
unsafe {
iface_fn!(self, RegisterCreateMarkerCallback)(Some(create_marker_bridge), ptr);
}
CreateMarkerRegister(ptr)
}
pub fn unregister_create_marker(&self, register: CreateMarkerRegister) {
unsafe {
iface_fn!(self, UnregisterCreateMarkerCallback)(
Some(create_marker_bridge),
register.0,
);
}
}
pub fn register_marker_event(
&self,
desc: &ProfilerMarkerDesc,
f: Box<dyn FnMut(&ProfilerMarkerEvent) + Send + Sync>,
) -> MarkerEventRegister {
let ptr = Box::into_raw(Box::new(f)) as *mut c_void;
unsafe {
iface_fn!(self, RegisterMarkerEventCallback)(
desc.native,
Some(marker_event_bridge),
ptr,
);
}
MarkerEventRegister {
ptr,
desc: desc.native,
}
}
pub fn unregister_marker_event(&self, register: MarkerEventRegister) {
unsafe {
iface_fn!(self, UnregisterMarkerEventCallback)(
register.desc,
Some(marker_event_bridge),
register.ptr,
);
}
}
pub fn register_frame(&self, f: Box<dyn FnMut() + Send + Sync>) -> FrameRegister {
let ptr = Box::into_raw(Box::new(f)) as *mut c_void;
unsafe {
iface_fn!(self, RegisterFrameCallback)(Some(frame_bridge), ptr);
}
FrameRegister(ptr)
}
pub fn unregister_frame(&self, register: FrameRegister) {
unsafe {
iface_fn!(self, UnregisterFrameCallback)(Some(frame_bridge), register.0);
}
}
pub fn register_create_thread(
&self,
f: Box<dyn FnMut(&ProfilerThreadDesc) + Send + Sync>,
) -> CreateThreadRegister {
let ptr = Box::into_raw(Box::new(f)) as *mut c_void;
unsafe {
iface_fn!(self, RegisterCreateThreadCallback)(Some(create_thread_bridge), ptr);
}
CreateThreadRegister(ptr)
}
pub fn unregister_create_thread(&self, register: CreateThreadRegister) {
unsafe {
iface_fn!(self, UnregisterCreateThreadCallback)(
Some(create_thread_bridge),
register.0,
);
}
}
}
};
}
common_impl!(UnityProfilerCallbacks);
define_unity_interface!(
UnityProfilerCallbacksV2,
unity_native_plugin_sys::IUnityProfilerCallbacksV2,
0x5DEB59E88F2D4571_u64,
0x81E8583069A5E33C_u64
);
#[derive(Clone, Copy, Debug)]
pub struct ProfilerFlowEvent {
pub ty: ProfilerFlowEventType,
pub flow_id: u32,
}
extern "system" fn flow_event_bridge(
ty: UnityProfilerFlowEventType,
flow_id: u32,
_userdata: *mut c_void,
) {
let ty = match ProfilerFlowEventType::from(ty) {
Some(ty) => ty,
None => return,
};
let desc = ProfilerFlowEvent { ty, flow_id };
let ptr = _userdata as *mut Box<dyn FnMut(&ProfilerFlowEvent)>;
let mut cb = unsafe { Box::from_raw(ptr) };
cb(&desc);
std::mem::forget(cb);
}
pub struct FlowEventRegister(*mut c_void);
common_impl!(UnityProfilerCallbacksV2);
impl UnityProfilerCallbacksV2 {
pub fn register_flow_event(
&self,
f: Box<dyn FnMut(&ProfilerFlowEvent) + Send + Sync>,
) -> FlowEventRegister {
let ptr = Box::into_raw(Box::new(f)) as *mut c_void;
unsafe {
iface_fn!(self, RegisterFlowEventCallback)(Some(flow_event_bridge), ptr);
}
FlowEventRegister(ptr)
}
pub fn unregister_flow_event(&self, register: FlowEventRegister) {
unsafe {
iface_fn!(self, UnregisterFlowEventCallback)(Some(flow_event_bridge), register.0);
}
}
}