/* * Tracy Unity Plugin - Simplified Implementation * * This is a simplified Tracy Unity Plugin implementation * demonstrating how to integrate Tracy into Unity Native Plugin * * Build instructions: * Windows: Use CMake (see CMakeLists.txt) * macOS: Use CMake (see CMakeLists.txt) * Linux: Use CMake (see CMakeLists.txt) */ #pragma warning(disable:4100) #include "tracy/Tracy.hpp" #include #include #ifdef ADVANCED_ZONE_MANAGEMENT #include #include #include #include #endif // Platform specific export definition #if defined(_WIN32) || defined(_WIN64) #define UNITY_PLUGIN_EXPORT __declspec(dllexport) #elif defined(__APPLE__) || defined(__linux__) #define UNITY_PLUGIN_EXPORT __attribute__((visibility("default"))) #else #define UNITY_PLUGIN_EXPORT #endif // Simple Zone Manager for basic Zone tracking #ifndef ADVANCED_ZONE_MANAGEMENT namespace { struct SimpleZone { const char* name; int64_t startTime; }; struct ThreadZones { std::stack zones; }; std::unordered_map g_threadZones; std::mutex g_zonesMutex; } #endif // C export functions (Unity requires C linkage) extern "C" { /** * Initialize Tracy * Unity C# call: [DllImport] private static extern void TracyInit(); */ UNITY_PLUGIN_EXPORT void TracyInit() { // Tracy initializes automatically, additional initialization logic can be added here } /** * Shutdown Tracy * Unity C# call: [DllImport] private static extern void TracyShutdown(); */ UNITY_PLUGIN_EXPORT void TracyShutdown() { #ifndef ADVANCED_ZONE_MANAGEMENT std::lock_guard lock(g_zonesMutex); g_threadZones.clear(); #endif } /** * Mark frame boundary * Unity C# call: [DllImport] private static extern void TracyFrameMark(); */ UNITY_PLUGIN_EXPORT void TracyFrameMark() { FrameMark; } /** * Plot value * Unity C# call: [DllImport] private static extern void TracyPlotValue(string name, double value); */ UNITY_PLUGIN_EXPORT void TracyPlotValue(const char* name, double value) { if (name != nullptr) { TracyPlot(name, value); } } /** * Send message * Unity C# call: [DllImport] private static extern void TracySendMessage(string message); */ UNITY_PLUGIN_EXPORT void TracySendMessage(const char* message) { if (message != nullptr) { TracyMessage(message, std::strlen(message)); } } /** * Set thread name * Unity C# call: [DllImport] private static extern void TracySetThreadName(string name); */ UNITY_PLUGIN_EXPORT void TracySetThreadName(const char* name) { if (name != nullptr) { tracy::SetThreadName(name); } } /** * Begin a named Zone * Unity C# call: [DllImport] private static extern void TracyZoneBegin(string name); * * Note: This is a simplified implementation. For production use, consider using * ADVANCED_ZONE_MANAGEMENT or a different Zone management approach. */ UNITY_PLUGIN_EXPORT void TracyZoneBegin(const char* name) { #ifndef ADVANCED_ZONE_MANAGEMENT if (name != nullptr) { std::lock_guard lock(g_zonesMutex); auto threadId = std::this_thread::get_id(); SimpleZone zone; zone.name = name; zone.startTime = tracy::GetTime(); g_threadZones[threadId].zones.push(zone); // Send zone begin event to Tracy TracyMessageL(name); } #endif } /** * End current Zone * Unity C# call: [DllImport] private static extern void TracyZoneEnd(); */ UNITY_PLUGIN_EXPORT void TracyZoneEnd() { #ifndef ADVANCED_ZONE_MANAGEMENT std::lock_guard lock(g_zonesMutex); auto threadId = std::this_thread::get_id(); auto it = g_threadZones.find(threadId); if (it != g_threadZones.end() && !it->second.zones.empty()) { it->second.zones.pop(); } #endif } /** * Unity plugin lifecycle function - called on load */ UNITY_PLUGIN_EXPORT void UnityPluginLoad() { // Optional: perform initialization when plugin loads } /** * Unity plugin lifecycle function - called on unload */ UNITY_PLUGIN_EXPORT void UnityPluginUnload() { // Optional: perform cleanup when plugin unloads TracyShutdown(); } } // extern "C" /* * Advanced Implementation Example - Zone Management * * Below is a more complete Zone management implementation example * Can be extended as needed */ #ifdef ADVANCED_ZONE_MANAGEMENT // Zone Manager (Thread-safe) class ZoneManager { private: struct ThreadZones { std::stack zones; }; std::unordered_map threadZones; std::mutex mutex; public: void BeginZone(const char* name, const char* function, const char* file, uint32_t line) { std::lock_guard lock(mutex); auto threadId = std::this_thread::get_id(); auto& zones = threadZones[threadId].zones; // Create source location info static const tracy::SourceLocationData loc{name, function, file, line, 0}; // Create Zone (note: must be heap allocated) auto* zone = new tracy::ScopedZone(&loc, true); zones.push(zone); } void EndZone() { std::lock_guard lock(mutex); auto threadId = std::this_thread::get_id(); auto it = threadZones.find(threadId); if (it != threadZones.end() && !it->second.zones.empty()) { auto* zone = it->second.zones.top(); it->second.zones.pop(); delete zone; } } void ClearThread() { std::lock_guard lock(mutex); auto threadId = std::this_thread::get_id(); auto it = threadZones.find(threadId); if (it != threadZones.end()) { // Clean up all unfinished Zones while (!it->second.zones.empty()) { delete it->second.zones.top(); it->second.zones.pop(); } threadZones.erase(it); } } }; // Global Zone Manager instance static ZoneManager g_zoneManager; extern "C" { UNITY_PLUGIN_EXPORT void TracyZoneBeginAdvanced(const char* name, const char* function, const char* file, int line) { g_zoneManager.BeginZone(name, function, file, static_cast(line)); } UNITY_PLUGIN_EXPORT void TracyZoneEndAdvanced() { g_zoneManager.EndZone(); } UNITY_PLUGIN_EXPORT void TracyClearThreadZones() { g_zoneManager.ClearThread(); } } // extern "C" #endif // ADVANCED_ZONE_MANAGEMENT /* * Build and Deployment Instructions: * * Use CMake for all platforms (see CMakeLists.txt) * * Quick build: * 1. mkdir build && cd build * 2. cmake .. -DTRACY_ROOT="/path/to/tracy" * 3. cmake --build . --config Release * * Deploy to Unity: * - Copy compiled library to Unity project Assets/Plugins/ directory * - Place in appropriate subdirectory based on platform * - Configure Plugin Import Settings to match target platform */