297 lines
7.4 KiB
C++
297 lines
7.4 KiB
C++
/*
|
|
* 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 <string>
|
|
#include <cstring>
|
|
|
|
#ifdef ADVANCED_ZONE_MANAGEMENT
|
|
#include <unordered_map>
|
|
#include <stack>
|
|
#include <mutex>
|
|
#include <thread>
|
|
#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<SimpleZone> zones;
|
|
};
|
|
|
|
std::unordered_map<std::thread::id, ThreadZones> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<tracy::ScopedZone*> zones;
|
|
};
|
|
|
|
std::unordered_map<std::thread::id, ThreadZones> threadZones;
|
|
std::mutex mutex;
|
|
|
|
public:
|
|
void BeginZone(const char* name, const char* function, const char* file, uint32_t line)
|
|
{
|
|
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<uint32_t>(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
|
|
*/
|
|
|