use std::ptr::null_mut;
use crate::define_unity_interface;
use crate::interface::UnityInterface;
use crate::bitflag;
use unity_native_plugin_sys::*;
define_unity_interface!(
UnityProfiler,
IUnityProfiler,
0x2CE79ED8316A4833_u64,
0x87076B2013E1571F_u64
);
#[repr(u16)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum BuiltinProfilerCategory {
Render = UnityBuiltinProfilerCategory__kUnityProfilerCategoryRender as u16,
Scripts = UnityBuiltinProfilerCategory__kUnityProfilerCategoryScripts as u16,
ManagedJobs = UnityBuiltinProfilerCategory__kUnityProfilerCategoryManagedJobs as u16,
BurstJobs = UnityBuiltinProfilerCategory__kUnityProfilerCategoryBurstJobs as u16,
GUI = UnityBuiltinProfilerCategory__kUnityProfilerCategoryGUI as u16,
Physics = UnityBuiltinProfilerCategory__kUnityProfilerCategoryPhysics as u16,
Animation = UnityBuiltinProfilerCategory__kUnityProfilerCategoryAnimation as u16,
AI = UnityBuiltinProfilerCategory__kUnityProfilerCategoryAI as u16,
Audio = UnityBuiltinProfilerCategory__kUnityProfilerCategoryAudio as u16,
AudioJob = UnityBuiltinProfilerCategory__kUnityProfilerCategoryAudioJob as u16,
AudioUpdateJob = UnityBuiltinProfilerCategory__kUnityProfilerCategoryAudioUpdateJob as u16,
Video = UnityBuiltinProfilerCategory__kUnityProfilerCategoryVideo as u16,
Particles = UnityBuiltinProfilerCategory__kUnityProfilerCategoryParticles as u16,
Gi = UnityBuiltinProfilerCategory__kUnityProfilerCategoryGi as u16,
Network = UnityBuiltinProfilerCategory__kUnityProfilerCategoryNetwork as u16,
Loading = UnityBuiltinProfilerCategory__kUnityProfilerCategoryLoading as u16,
Other = UnityBuiltinProfilerCategory__kUnityProfilerCategoryOther as u16,
GC = UnityBuiltinProfilerCategory__kUnityProfilerCategoryGC as u16,
VSync = UnityBuiltinProfilerCategory__kUnityProfilerCategoryVSync as u16,
Overhead = UnityBuiltinProfilerCategory__kUnityProfilerCategoryOverhead as u16,
PlayerLoop = UnityBuiltinProfilerCategory__kUnityProfilerCategoryPlayerLoop as u16,
Director = UnityBuiltinProfilerCategory__kUnityProfilerCategoryDirector as u16,
VR = UnityBuiltinProfilerCategory__kUnityProfilerCategoryVR as u16,
Allocation = UnityBuiltinProfilerCategory__kUnityProfilerCategoryAllocation as u16,
Internal = UnityBuiltinProfilerCategory__kUnityProfilerCategoryInternal as u16,
FileIO = UnityBuiltinProfilerCategory__kUnityProfilerCategoryFileIO as u16,
UISystemLayout = UnityBuiltinProfilerCategory__kUnityProfilerCategoryUISystemLayout as u16,
UISystemRender = UnityBuiltinProfilerCategory__kUnityProfilerCategoryUISystemRender as u16,
VFX = UnityBuiltinProfilerCategory__kUnityProfilerCategoryVFX as u16,
BuildInterface = UnityBuiltinProfilerCategory__kUnityProfilerCategoryBuildInterface as u16,
Input = UnityBuiltinProfilerCategory__kUnityProfilerCategoryInput as u16,
VirtualTexturing = UnityBuiltinProfilerCategory__kUnityProfilerCategoryVirtualTexturing as u16,
GPU = UnityBuiltinProfilerCategory__kUnityProfilerCategoryGPU as u16,
Physics2D = UnityBuiltinProfilerCategory__kUnityProfilerCategoryPhysics2D as u16,
NetworkOperations = UnityBuiltinProfilerCategory__kUnityProfilerCategoryNetworkOperations as u16,
UIDetails = UnityBuiltinProfilerCategory__kUnityProfilerCategoryUIDetails as u16,
Debug = UnityBuiltinProfilerCategory__kUnityProfilerCategoryDebug as u16,
Jobs = UnityBuiltinProfilerCategory__kUnityProfilerCategoryJobs as u16,
Text = UnityBuiltinProfilerCategory__kUnityProfilerCategoryText as u16,
}
pub type ProfilerCategoryId = UnityProfilerCategoryId;
#[repr(u16)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ProfilerMarkerFlag {
Default = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagDefault as u16,
ScriptUser = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagScriptUser as u16,
ScriptInvoke = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagScriptInvoke as u16,
ScriptEnterLeave = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagScriptEnterLeave as u16,
AvailabilityEditor = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagAvailabilityEditor as u16,
AvailabilityNonDev = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagAvailabilityNonDev as u16,
Warning = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagWarning as u16,
Counter = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagCounter as u16,
VerbosityDebug = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagVerbosityDebug as u16,
VerbosityInternal = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagVerbosityInternal as u16,
VerbosityAdvanced = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagVerbosityAdvanced as u16,
}
bitflag!(ProfilerMarkerFlags, ProfilerMarkerFlag, UnityProfilerMarkerFlags);
#[repr(u16)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ProfilerMarkerEventType {
Begin = UnityProfilerMarkerEventType__kUnityProfilerMarkerEventTypeBegin as u16,
End = UnityProfilerMarkerEventType__kUnityProfilerMarkerEventTypeEnd as u16,
Single = UnityProfilerMarkerEventType__kUnityProfilerMarkerEventTypeSingle as u16,
}
impl ProfilerMarkerEventType {
pub fn from(value: u16) -> Option<Self> {
use ProfilerMarkerEventType::*;
if value <= Single as u16 {
Some(unsafe { std::mem::transmute(value) })
} else {
None
}
}
}
pub type ProfilerMarkerId = UnityProfilerMarkerId;
#[derive(Clone)]
pub struct ProfilerMarkerDesc {
pub(crate) native: *const UnityProfilerMarkerDesc,
}
unsafe impl Send for ProfilerMarkerDesc {}
impl std::fmt::Debug for ProfilerMarkerDesc {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
fmt,
"[desc id={}, flags={}, cat={}, name={:?}]",
self.id(),
self.flags().flag,
self.category_id(),
self.name()
)
}
}
impl ProfilerMarkerDesc {
pub fn id(&self) -> ProfilerMarkerId {
unsafe { (*self.native).id as ProfilerMarkerId }
}
pub fn flags(&self) -> ProfilerMarkerFlags {
unsafe { ProfilerMarkerFlags::from((*self.native).flags) }
}
pub fn category_id(&self) -> ProfilerCategoryId {
unsafe { (*self.native).categoryId as ProfilerCategoryId }
}
pub fn name(&self) -> &std::ffi::CStr {
unsafe { std::ffi::CStr::from_ptr((*self.native).name) }
}
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ProfilerMarkerDataType {
None = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeNone as u8,
InstanceId = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeInstanceId as u8,
Int32 = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeInt32 as u8,
UInt32 = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeUInt32 as u8,
Int64 = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeInt64 as u8,
UInt64 = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeUInt64 as u8,
Float = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeFloat as u8,
Double = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeDouble as u8,
String = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeString as u8,
String16 = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeString16 as u8,
Blob8 = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeBlob8 as u8,
GfxResourceId = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeGfxResourceId as u8,
}
impl ProfilerMarkerDataType {
#[allow(unused)]
pub(crate) fn from(value: u8) -> Option<Self> {
if value <= ProfilerMarkerDataType::Blob8 as u8 {
Some(unsafe { std::mem::transmute(value) })
} else {
None
}
}
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ProfilerMarkerDataUnit {
Undefined = UnityProfilerMarkerDataUnit__kUnityProfilerMarkerDataUnitUndefined as u8,
TimeNanoseconds =
UnityProfilerMarkerDataUnit__kUnityProfilerMarkerDataUnitTimeNanoseconds as u8,
Bytes = UnityProfilerMarkerDataUnit__kUnityProfilerMarkerDataUnitBytes as u8,
Count = UnityProfilerMarkerDataUnit__kUnityProfilerMarkerDataUnitCount as u8,
Percent = UnityProfilerMarkerDataUnit__kUnityProfilerMarkerDataUnitPercent as u8,
FrequencyHz = UnityProfilerMarkerDataUnit__kUnityProfilerMarkerDataUnitFrequencyHz as u8,
}
impl ProfilerMarkerDataUnit {
#[allow(unused)]
pub(crate) fn from(value: u8) -> Option<Self> {
if value <= ProfilerMarkerDataUnit::FrequencyHz as u8 {
Some(unsafe { std::mem::transmute(value) })
} else {
None
}
}
}
#[repr(C)]
pub struct ProfilerMarkerData<'a> {
native: UnityProfilerMarkerData,
data_ref: &'a [u8],
}
impl ProfilerMarkerData<'_> {
pub fn new<'a>(data_type: ProfilerMarkerDataType, data: &'a [u8]) -> ProfilerMarkerData<'a> {
unsafe {
ProfilerMarkerData {
native: UnityProfilerMarkerData {
type_: data_type as UnityProfilerMarkerDataType,
reserved0: 0,
reserved1: 0,
size: data.len() as u32,
ptr: &*(data.as_ptr() as *const ::std::os::raw::c_void),
},
data_ref: data,
}
}
}
pub fn data_type(&self) -> ProfilerMarkerDataType {
unsafe { std::mem::transmute(self.native.type_) }
}
pub fn data(&self) -> &'_ [u8] {
self.data_ref
}
}
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ProfilerFlowEventType {
Begin = UnityProfilerFlowEventType__kUnityProfilerFlowEventTypeBegin as u8,
Next = UnityProfilerFlowEventType__kUnityProfilerFlowEventTypeNext as u8,
End = UnityProfilerFlowEventType__kUnityProfilerFlowEventTypeEnd as u8,
}
impl ProfilerFlowEventType {
pub fn from(value: u8) -> Option<Self> {
if value <= ProfilerFlowEventType::End as u8 {
Some(unsafe { std::mem::transmute(value) })
} else {
None
}
}
}
#[repr(u16)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ProfilerCounterFlag {
None = UnityProfilerCounterFlags__kUnityProfilerCounterFlagNone as u16,
FlashOnEndOfFrame = UnityProfilerCounterFlags__kUnityProfilerCounterFlushOnEndOfFrame as u16,
ResetToZeroOnFlush = UnityProfilerCounterFlags__kUnityProfilerCounterFlagResetToZeroOnFlush as u16,
Atomic = UnityProfilerCounterFlags__kUnityProfilerCounterFlagAtomic as u16,
Getter = UnityProfilerCounterFlags__kUnityProfilerCounterFlagGetter as u16,
}
bitflag!(ProfilerCounterFlags, ProfilerCounterFlag, UnityProfilerCounterFlags);
pub type ProfilerThreadId = UnityProfilerThreadId;
macro_rules! impl_profiler {
() => {
pub fn emit_event(
&self,
marker_desc: &ProfilerMarkerDesc,
event_type: ProfilerMarkerEventType,
event_data: &[ProfilerMarkerData],
) {
unsafe {
self.interface().EmitEvent.expect("EmitEvent")(
marker_desc.native,
event_type as UnityProfilerMarkerEventType,
event_data.len() as u16,
event_data.as_ptr() as *const _,
);
}
}
pub fn is_enabled(&self) -> bool {
unsafe { self.interface().IsEnabled.expect("IsEnabled")() != 0 }
}
pub fn is_available(&self) -> bool {
unsafe { self.interface().IsAvailable.expect("IsAvailable")() != 0 }
}
pub fn create_marker<'a>(
&'a self,
name: &std::ffi::CStr,
category: ProfilerCategoryId,
flags: ProfilerMarkerFlags,
event_data_count: ::std::os::raw::c_int,
) -> Result<ProfilerMarkerDesc, ::std::os::raw::c_int> {
unsafe {
let mut ret = std::ptr::null::<UnityProfilerMarkerDesc>();
let result = self.interface().CreateMarker.expect("CreateMarker")(
&mut ret,
name.as_ptr(),
category as _,
flags.flag as _,
event_data_count,
);
if result > 0 {
Err(result)
} else {
Ok(ProfilerMarkerDesc { native: ret })
}
}
}
pub fn set_marker_metadata_name(
&self,
desc: &ProfilerMarkerDesc,
index: ::std::os::raw::c_int,
metadata_name: &std::ffi::CStr,
metadata_type: ProfilerMarkerDataType,
metadata_unit: ProfilerMarkerDataUnit,
) -> Result<(), ::std::os::raw::c_int> {
unsafe {
let result = self
.interface()
.SetMarkerMetadataName
.expect("SetMarkerMetadataName")(
desc.native,
index,
metadata_name.as_ptr(),
metadata_type as _,
metadata_unit as _,
);
if result > 0 {
Err(result)
} else {
Ok(())
}
}
}
pub fn register_thread(
&self,
group_name: &std::ffi::CStr,
name: &std::ffi::CStr,
) -> Result<ProfilerThreadId, ::std::os::raw::c_int> {
unsafe {
let mut thread_id = std::mem::zeroed::<UnityProfilerThreadId>();
let result = self.interface().RegisterThread.expect("RegisterThread")(
&mut thread_id,
group_name.as_ptr(),
name.as_ptr(),
);
if result > 0 {
Err(result)
} else {
Ok(thread_id)
}
}
}
pub fn unregister_thread(
&self,
thread_id: ProfilerThreadId,
) -> Result<(), ::std::os::raw::c_int> {
unsafe {
let result = self.interface().UnregisterThread.expect("UnregisterThread")(thread_id);
if result > 0 {
Err(result)
} else {
Ok(())
}
}
}
};
}
impl UnityProfiler {
impl_profiler!();
}
define_unity_interface!(
UnityProfilerV2,
IUnityProfilerV2,
0xB957E0189CB6A30B_u64,
0x83CE589AE85B9068_u64
);
pub type ProfilerCounterStatePtrCallback = UnityProfilerCounterStatePtrCallback;
pub struct ProfilerCounter<T> {
pub(crate) counter: *mut T,
}
impl<T> ProfilerCounter<T> {
pub fn value(&self) -> &T {
unsafe {
&*self.counter
}
}
pub fn value_mut(&mut self) -> &mut T {
unsafe {
&mut *self.counter
}
}
}
macro_rules! impl_profiler_v2 {
() => {
impl_profiler!();
pub fn create_category(&self, name: &std::ffi::CStr, unused: u32) -> Option<ProfilerCategoryId> {
unsafe {
let mut category: UnityProfilerCategoryId = std::mem::zeroed();
let r = self.interface().CreateCategory.expect("CreateCategory")(&mut category as *mut UnityProfilerCategoryId, name.as_ptr(), unused);
if r > 0 {
Some(category)
} else {
None
}
}
}
pub unsafe fn create_counter_value(&self,
category: ProfilerCategoryId,
name: &std::ffi::CStr,
flags: ProfilerMarkerFlags,
value_type: ProfilerMarkerDataType,
value_unit: ProfilerMarkerDataUnit,
value_size: usize,
counter_flags: ProfilerCounterFlags,
activate_func: ProfilerCounterStatePtrCallback,
deactivate_func: ProfilerCounterStatePtrCallback,
user_data: *mut ::std::os::raw::c_void) -> *mut ::std::os::raw::c_void {
unsafe {
self.interface().CreateCounterValue.expect("CreateCounterValue")(category, name.as_ptr(), flags.into(), value_type as u8, value_unit as u8, value_size, counter_flags.into(), activate_func, deactivate_func, user_data)
}
}
pub unsafe fn flush_counter_value(&self, counter: *mut ::std::os::raw::c_void) {
unsafe {
self.interface().FlushCounterValue.expect("FlushCounterValue")(counter)
}
}
pub unsafe fn create_counter<T>(&self,
category: ProfilerCategoryId,
name: &std::ffi::CStr,
flags: ProfilerMarkerFlags,
value_type: ProfilerMarkerDataType,
value_unit: ProfilerMarkerDataUnit,
counter_flags: ProfilerCounterFlags,
activate_func: ProfilerCounterStatePtrCallback,
deactivate_func: ProfilerCounterStatePtrCallback,
user_data: *mut ::std::os::raw::c_void) -> Option<ProfilerCounter<T>> {
unsafe {
let r = self.create_counter_value(category, name, flags, value_type, value_unit, std::mem::size_of::<T>(), counter_flags.into(), activate_func, deactivate_func, user_data);
if r != null_mut() {
Some(ProfilerCounter::<T> { counter: r as *mut T })
} else {
None
}
}
}
pub unsafe fn flush_counter<T>(&self, counter: &mut ProfilerCounter<T>) {
unsafe {
self.flush_counter_value(counter.counter as *mut ::std::os::raw::c_void);
}
}
}
}
impl UnityProfilerV2 {
impl_profiler_v2!();
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn flags_test() {
assert_eq!(
::std::mem::size_of::<ProfilerMarkerFlags>(),
::std::mem::size_of::<unity_native_plugin_sys::UnityProfilerMarkerFlags>()
);
let f = [
unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagScriptUser,
unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagScriptInvoke,
unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagScriptEnterLeave,
unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagAvailabilityEditor,
unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagAvailabilityNonDev,
unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagWarning,
unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagVerbosityDebug,
unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagVerbosityInternal,
unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagVerbosityAdvanced,
];
let f2 = [
ProfilerMarkerFlag::ScriptUser,
ProfilerMarkerFlag::ScriptInvoke,
ProfilerMarkerFlag::ScriptEnterLeave,
ProfilerMarkerFlag::AvailabilityEditor,
ProfilerMarkerFlag::AvailabilityNonDev,
ProfilerMarkerFlag::Warning,
ProfilerMarkerFlag::VerbosityDebug,
ProfilerMarkerFlag::VerbosityInternal,
ProfilerMarkerFlag::VerbosityAdvanced,
];
for i in 0..f.len() {
assert!(ProfilerMarkerFlags::from(f[i] as u16).has_flag(f2[i]));
assert_eq!(ProfilerMarkerFlags::new(f2[i]).unset_flag(f2[i]).flag, 0);
}
}
}