mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Perf] (MG_Pipe): lifetime-id slot lookups get a direct-mapped front and buffer binding slots are indexed (rd12 monolith +1.5%).
This commit is contained in:
@@ -206,10 +206,20 @@ namespace MobileGL::MG_Pipe {
|
||||
#endif
|
||||
if (lifetimeId == 0) return kMGPipeNullHandle;
|
||||
const KindState& state = StateOf(kind);
|
||||
// The direct-mapped front (SlotAllocator.h): a hit is only believed when the slot it
|
||||
// names is live AND still owned by this very lifetime id.
|
||||
auto& recent = state.Recent[lifetimeId % KindState::kRecentEntries];
|
||||
if (recent.LifetimeId == lifetimeId) {
|
||||
const SlotState* entry = EntryOf(state, kind, recent.Slot);
|
||||
if (entry != nullptr && entry->Live && entry->LifetimeId == lifetimeId)
|
||||
return MGPipeHandle{recent.Slot, entry->Gen};
|
||||
}
|
||||
const auto it = state.ByLifetimeId.find(lifetimeId);
|
||||
if (it == state.ByLifetimeId.end()) return kMGPipeNullHandle;
|
||||
const SlotState* entry = EntryOf(state, kind, it->second);
|
||||
if (entry == nullptr || !entry->Live) return kMGPipeNullHandle;
|
||||
recent.LifetimeId = lifetimeId;
|
||||
recent.Slot = it->second;
|
||||
return MGPipeHandle{it->second, entry->Gen};
|
||||
}
|
||||
|
||||
@@ -304,6 +314,7 @@ namespace MobileGL::MG_Pipe {
|
||||
state.BandSlots.clear();
|
||||
state.BandFreeList.clear();
|
||||
state.ByLifetimeId.clear();
|
||||
state.Recent.fill({});
|
||||
state.LiveCount = 0;
|
||||
state.BandLiveCount = 0;
|
||||
}
|
||||
|
||||
@@ -144,6 +144,17 @@ namespace MobileGL::MG_Pipe {
|
||||
Vector<SlotState> BandSlots;
|
||||
Vector<Uint32> BandFreeList;
|
||||
UnorderedMap<Uint64, Uint32> ByLifetimeId;
|
||||
// P14: a direct-mapped front for ByLifetimeId. Every draw resolves its VAO, its
|
||||
// vertex buffers and its textures by lifetime id, and the hash map was ~2-3% of a
|
||||
// Minecraft frame. Keyed on the lifetime id (monotonic, never reused) and confirmed
|
||||
// against the slot's own LifetimeId and Live bit on every hit, so a stale entry can
|
||||
// only miss. Mutable: FindByLifetimeId is const and fills it.
|
||||
struct RecentEntry {
|
||||
Uint64 LifetimeId = 0;
|
||||
Uint32 Slot = 0;
|
||||
};
|
||||
static constexpr SizeT kRecentEntries = 1024;
|
||||
mutable Array<RecentEntry, kRecentEntries> Recent{};
|
||||
Uint32 LiveCount = 0;
|
||||
// The band's share of LiveCount above, so the two spaces can be reported apart
|
||||
// without walking either table. Always 0 for every kind but ShaderCso.
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
BufferState::BufferState() {
|
||||
m_bindingSlotIndex.fill(-1);
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
m_bindingSlots[i] = BindingSlot<BufferObject>(GlobalBufferTargets[i]);
|
||||
const auto target = static_cast<SizeT>(GlobalBufferTargets[i]);
|
||||
if (target < m_bindingSlotIndex.size()) m_bindingSlotIndex[target] = static_cast<Int16>(i);
|
||||
}
|
||||
for (SizeT i = 0; i < m_touchedBindPointCount.size(); ++i) {
|
||||
m_touchedBindPointCount[i] = 0;
|
||||
@@ -19,6 +22,10 @@ namespace MobileGL::MG_State::GLState {
|
||||
}
|
||||
|
||||
BindingSlot<BufferObject>& BufferState::GetBindingSlot(BufferTarget target) {
|
||||
// O(1) through the index the constructor built (every draw asks for several targets).
|
||||
const auto index = static_cast<SizeT>(target);
|
||||
if (index < m_bindingSlotIndex.size() && m_bindingSlotIndex[index] >= 0)
|
||||
return m_bindingSlots[static_cast<SizeT>(m_bindingSlotIndex[index])];
|
||||
for (auto& bindingSlot : m_bindingSlots) {
|
||||
if (bindingSlot.GetTarget() == target) {
|
||||
return bindingSlot;
|
||||
|
||||
@@ -106,6 +106,8 @@ namespace MobileGL::MG_State::GLState {
|
||||
Uint64 m_anyBufferChangeGeneration = 0;
|
||||
Array<Uint64, BufferBindPointTargets.size()> m_bindPointGeneration{};
|
||||
Array<BindingSlot<BufferObject>, GlobalBufferTargets.size()> m_bindingSlots;
|
||||
// BufferTarget -> index into m_bindingSlots, -1 for a target with no global slot.
|
||||
Array<Int16, static_cast<SizeT>(BufferTarget::BufferTargetCount)> m_bindingSlotIndex{};
|
||||
// TODO: query the count somewhere globally?
|
||||
// For glBindBufferBase / glBindBufferRange
|
||||
Array<Array<BindingSlotRange1D<BufferObject>, BufferBindingPointCount>, BufferBindPointTargets.size()>
|
||||
|
||||
Reference in New Issue
Block a user