jak-project/common/global_profiler/GlobalProfiler.h

63 lines
1.6 KiB
C
Raw Normal View History

#pragma once
#include <atomic>
#include <optional>
#include <string>
#include <vector>
#include "common/common_types.h"
struct ProfNode {
u64 ts;
u64 tid;
[merc2] support vertex updates, use this for blerc in jak 1 and jak 2 (#2179) This PR adds a feature to merc2 to update vertices. This will be needed to efficient do effects like blerc/ripple/texture scroll. It's enabled for blerc in jak 1 and jak 2, but with a few disclaimers: - currently we still use the mips2c blerc implementation, which is slow and has some "jittering" because of integer precision. When porting to PC, there was an additional synchronization problem because blerc overwrites the merc data as its being read by the renderers. I _think_ this wasn't an issue on PS2 because the blerc dma is higher priority than the VIF1 DMA, but I'm not certain. Either way, I had to add a mutex for this on PC to avoid very slight flickering/gaps. This isn't ideal for performance, but still beats generic by a significant amount in every place I tested. If you see merc taking 2ms to draw, it is likely because it is stuck waiting on blerc to finish. This will go away once blerc itself is ported to C++. - in jak 1, we end up using generic in some cases where we could use merc. In particular maia in village3 hut. This will be fixed later once we can use merc in more places. I don't want to mess with the merc/generic selection logic when we're hopefully going to get rid of it soon. - There is no support for ripple or texture scroll. These use generic on jak 1, and remain broken on jak 2. - Like with `emerc`, jak 1 has a toggle to go back to the old behavior `*blerc-hack*`. - In most cases, toggling this causes no visual differences. One exception is Gol's teeth. I believe this is caused by texture coordinate rounding issues, where generic has an additional float -> int -> float compared to PC merc. It is very hard to notice so I'm not going to worry about it.
2023-01-31 18:23:39 -05:00
char name[128];
enum Kind : u8 { BEGIN, END, INSTANT, UNUSED } kind = UNUSED;
};
class GlobalProfiler {
public:
GlobalProfiler();
size_t get_max_events() { return m_max_events; }
void update_event_buffer_size(size_t new_size);
void set_waiting_for_event(const std::string& event_name);
void instant_event(const char* name);
void begin_event(const char* name);
void event(const char* name, ProfNode::Kind kind);
void end_event();
void clear();
void set_enable(bool en);
void dump_to_json();
void root_event();
bool is_enabled() { return m_enabled; }
size_t get_next_idx();
bool m_enable_compression = false;
private:
std::atomic_bool m_enabled = false;
size_t m_max_events = 65536;
u64 m_t0 = 0;
std::atomic_size_t m_next_idx = 0;
std::vector<ProfNode> m_nodes;
// this is very niche, but sometimes you want to capture up to a given event (ie. long startup)
// instead of having to make the user quit and record as fast as possible, we can instead just
// stop capturing events once we have received what we are looking for
std::optional<std::string> m_waiting_for_event = {};
bool m_ignore_events = false;
};
struct ScopedEvent {
ScopedEvent(GlobalProfiler* _prof) : prof(_prof){};
ScopedEvent(const ScopedEvent&) = delete;
ScopedEvent& operator=(const ScopedEvent&) = delete;
GlobalProfiler* prof = nullptr;
~ScopedEvent() {
if (prof) {
prof->end_event();
}
}
};
GlobalProfiler& prof();
ScopedEvent scoped_prof(const char* name);