| #ifndef _RIVE_PROFILE_HPP_ | |
| #define _RIVE_PROFILE_HPP_ | |
| #include <cstdint> | |
| #include <functional> | |
| #include <string> | |
| #include <unordered_map> | |
| #include <vector> | |
| namespace rive | |
| { | |
| /// Bitmask for which profile data to log. Combine flags to enable multiple. | |
| enum ProfileLogFlags : uint32_t | |
| { | |
| ProfileLogNone = 0, | |
| ProfileLogTransitionRecords = 1u << 0, | |
| ProfileLogListenerPerformChanges = 1u << 1, | |
| }; | |
| /// Segment of the artboard path (root to state machine artboard). | |
| /// type: 0 = NestedArtboard, 1 = ArtboardComponentList. index is used only when | |
| /// type is ArtboardComponentList (logical index in list); otherwise -1. | |
| struct ArtboardPathSegment | |
| { | |
| uint8_t type = 0; | |
| uint32_t nameId = 0; | |
| int32_t index = -1; | |
| }; | |
| /// Record for a single state machine transition (used when profiling). | |
| /// String fields are stored as indices into the profiler string table; | |
| /// see getStringTable() and resolveStringId(). path is root-to-leaf host chain. | |
| struct TransitionRecord | |
| { | |
| uint32_t artboardId = 0; | |
| uint32_t smId = 0; | |
| uint32_t layerId = 0; | |
| uint32_t fromStateId = 0; | |
| uint32_t toStateId = 0; | |
| uint64_t tick = 0; | |
| std::vector<ArtboardPathSegment> path; | |
| }; | |
| /// Record for a single listener performChanges call (used when profiling). | |
| /// artboardId, smId, listenerNameId index into the profiler string table. | |
| /// listenerType and hitEvent are raw ListenerType enum values; consumer maps to | |
| /// string. | |
| struct ListenerPerformChangeRecord | |
| { | |
| uint32_t artboardId = 0; | |
| uint32_t smId = 0; | |
| uint32_t listenerNameId = 0; | |
| uint32_t listenerType = 0; | |
| uint32_t hitEvent = 0; | |
| uint32_t pointerId = 0; | |
| uint64_t tick = 0; | |
| }; | |
| /// Singleton that wraps all MicroProfile calls and collects transition records | |
| /// as they occur during advance/apply (when RIVE_MICROPROFILE is defined). | |
| class RiveProfile | |
| { | |
| public: | |
| using FlushCallback = | |
| std::function<void(const std::vector<TransitionRecord>&)>; | |
| using ListenerPerformChangeFlushCallback = | |
| std::function<void(const std::vector<ListenerPerformChangeRecord>&)>; | |
| static RiveProfile& instance(); | |
| RiveProfile(const RiveProfile&) = delete; | |
| RiveProfile& operator=(const RiveProfile&) = delete; | |
| // MicroProfile lifecycle (no-ops when RIVE_MICROPROFILE is not defined) | |
| void init(); | |
| void frame(); | |
| void endFrame(); | |
| /// Profiling session (used by native binding for start/stop/dump). | |
| void start(); | |
| void stop(); | |
| bool isActive() const; | |
| /// Append header (once) and new frame events to \a buffer. Call after | |
| /// flushTransitionRecords() so the binding can merge transition data. | |
| void flushFrameDataTo(std::vector<uint8_t>& buffer); | |
| /// Record a state machine transition. Data is collected as it runs; no | |
| /// second pass over instances is required. No-op when RIVE_MICROPROFILE is | |
| /// undefined, the profiling session is inactive, no transition flush | |
| /// callback is set, or ProfileLogTransitionRecords is not set. | |
| /// If artboardForPath is non-null, the full artboard path is built and | |
| /// stored on the record (only when recording). | |
| void recordTransition(std::string artboardName, | |
| std::string smName, | |
| std::string layerName, | |
| std::string fromStateName, | |
| std::string toStateName, | |
| class Artboard* artboardForPath = nullptr); | |
| /// Set the callback invoked when flushTransitionRecords() is called with | |
| /// all collected records for the current frame. The binding uses this to | |
| /// serialize records into the event buffer. | |
| void setFlushCallback(FlushCallback callback); | |
| /// Invoke the flush callback with accumulated transition records and clear | |
| /// the buffer. Call after advanceAndApply. No-op when callback is not set. | |
| void flushTransitionRecords(); | |
| /// Record a listener performChanges call. No-op when RIVE_MICROPROFILE is | |
| /// undefined, the profiling session is inactive, no listener flush callback | |
| /// is set, or ProfileLogListenerPerformChanges is not set. listenerType and | |
| /// hitEvent are stored as raw uint (ListenerType enum); consumer maps to | |
| /// string. | |
| void recordListenerPerformChange(std::string artboardName, | |
| std::string smName, | |
| std::string listenerName, | |
| uint32_t listenerType, | |
| uint32_t hitEvent, | |
| uint32_t pointerId); | |
| /// Set the callback invoked when flushListenerPerformChangeRecords() is | |
| /// called with all collected listener records for the current frame. | |
| void setListenerPerformChangeFlushCallback( | |
| ListenerPerformChangeFlushCallback callback); | |
| /// Invoke the listener flush callback with accumulated records and clear | |
| /// the buffer. Call after flushTransitionRecords() when profiling. | |
| void flushListenerPerformChangeRecords(); | |
| /// Set which profile data to log (bitmask of ProfileLogFlags). Combine | |
| /// flags to enable multiple log types. | |
| void setLogFlags(uint32_t flags) { m_logFlags = flags; } | |
| uint32_t logFlags() const { return m_logFlags; } | |
| /// Resolve a string to a stable id in the profiler string table. Used by | |
| /// transition records and any future record type that needs to log strings. | |
| /// Returns existing id if the string was seen before, otherwise assigns new | |
| /// id. | |
| uint32_t resolveStringId(const std::string& str); | |
| /// Return the current profiler string table (id index -> string). The | |
| /// binding uses this to emit 0x04 string table records; other record types | |
| /// use ids that index into this table. | |
| const std::vector<std::string>& getStringTable() const; | |
| private: | |
| RiveProfile() = default; | |
| FlushCallback m_flushCallback; | |
| ListenerPerformChangeFlushCallback m_listenerPerformChangeFlushCallback; | |
| std::vector<TransitionRecord> m_transitionRecords; | |
| std::vector<ListenerPerformChangeRecord> m_listenerPerformChangeRecords; | |
| std::unordered_map<std::string, uint32_t> m_stringTable; | |
| std::vector<std::string> m_stringList; | |
| bool m_profilingActive = false; | |
| uint32_t m_logFlags = 3; | |
| bool m_headerWritten = false; | |
| uint64_t m_lastFlushedFrameIndex = 0; | |
| }; | |
| } // namespace rive | |
| #endif |