Skip to content

Commit

Permalink
Tweaked: Don't store entities in chunks twice (ComponentRecord had a …
Browse files Browse the repository at this point in the history
…duplicate)

Tweaked: Cleanups
  • Loading branch information
richardbiely committed Sep 25, 2024
1 parent 31ac69e commit 11ac62d
Show file tree
Hide file tree
Showing 11 changed files with 392 additions and 377 deletions.
18 changes: 9 additions & 9 deletions include/gaia/ecs/archetype.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ namespace gaia {

return true;
}
}
} // namespace detail

class ArchetypeBase {
protected:
Expand Down Expand Up @@ -96,7 +96,7 @@ namespace gaia {
};

private:
using AsPairsIndexBuffer = cnt::sarr<uint8_t, Chunk::MAX_COMPONENTS>;
using AsPairsIndexBuffer = cnt::sarr<uint8_t, ChunkHeader::MAX_COMPONENTS>;

ArchetypeIdLookupKey::LookupHash m_archetypeIdHash;
//! Hash of components within this archetype - used for lookups
Expand All @@ -120,13 +120,13 @@ namespace gaia {
//! Offsets to various parts of data inside chunk
ChunkDataOffsets m_dataOffsets;
//! Array of entities used to identify the archetype
Entity m_ids[Chunk::MAX_COMPONENTS];
Entity m_ids[ChunkHeader::MAX_COMPONENTS];
//! Array of indices to Is relationship pairs in m_ids
uint8_t m_pairs_as_index_buffer[Chunk::MAX_COMPONENTS];
uint8_t m_pairs_as_index_buffer[ChunkHeader::MAX_COMPONENTS];
//! Array of component ids
Component m_comps[Chunk::MAX_COMPONENTS];
Component m_comps[ChunkHeader::MAX_COMPONENTS];
//! Array of components offset indices
ChunkDataOffset m_compOffs[Chunk::MAX_COMPONENTS];
ChunkDataOffset m_compOffs[ChunkHeader::MAX_COMPONENTS];

//! Archetype list index
uint32_t m_listIdx;
Expand All @@ -140,9 +140,9 @@ namespace gaia {
//! Remaining lifespan of the archetype
uint32_t m_lifespanCountdown: ARCHETYPE_LIFESPAN_BITS;
//! Number of relationship pairs on the archetype
uint32_t m_pairCnt: Chunk::MAX_COMPONENTS_BITS;
uint32_t m_pairCnt: ChunkHeader::MAX_COMPONENTS_BITS;
//! Number of Is relationship pairs on the archetype
uint32_t m_pairCnt_is: Chunk::MAX_COMPONENTS_BITS;
uint32_t m_pairCnt_is: ChunkHeader::MAX_COMPONENTS_BITS;
//! Unused bits
// uint32_t m_unused : 6;

Expand Down Expand Up @@ -188,7 +188,7 @@ namespace gaia {
m_dataOffsets.firstByte_CompEntities = (ChunkDataOffset)offset;

// Storage-wise, treat the component array as it it were MAX_COMPONENTS long.
offset += sizeof(Entity) * Chunk::MAX_COMPONENTS;
offset += sizeof(Entity) * ChunkHeader::MAX_COMPONENTS;
}
}

Expand Down
40 changes: 20 additions & 20 deletions include/gaia/ecs/chunk.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,9 @@ namespace gaia {
namespace ecs {
class Chunk final {
public:
static constexpr uint32_t MAX_COMPONENTS_BITS = 5U;
//! Maximum number of components on archetype
static constexpr uint32_t MAX_COMPONENTS = 1U << MAX_COMPONENTS_BITS;

using EntityArray = cnt::sarray_ext<Entity, MAX_COMPONENTS>;
using ComponentArray = cnt::sarray_ext<Component, MAX_COMPONENTS>;
using ComponentOffsetArray = cnt::sarray_ext<ChunkDataOffset, MAX_COMPONENTS>;
using EntityArray = cnt::sarray_ext<Entity, ChunkHeader::MAX_COMPONENTS>;
using ComponentArray = cnt::sarray_ext<Component, ChunkHeader::MAX_COMPONENTS>;
using ComponentOffsetArray = cnt::sarray_ext<ChunkDataOffset, ChunkHeader::MAX_COMPONENTS>;

// TODO: Make this private
//! Chunk header
Expand Down Expand Up @@ -93,15 +89,14 @@ namespace gaia {
uint32_t j = 0;
for (; j < cntEntities; ++j)
dst[j] = ids[j];
for (; j < MAX_COMPONENTS; ++j)
for (; j < ChunkHeader::MAX_COMPONENTS; ++j)
dst[j] = EntityBad;
}

// Cache component records
if (cntEntities > 0) {
auto* dst = m_records.pRecords = (ComponentRecord*)&data(headerOffsets.firstByte_Records);
GAIA_FOR_(cntEntities, j) {
dst[j].entity = ids[j];
dst[j].comp = comps[j];
dst[j].pData = &data(compOffs[j]);
dst[j].pItem = m_header.cc->find(comps[j].id());
Expand All @@ -113,18 +108,20 @@ namespace gaia {
// Now that records are set, we use the cached component descriptors to set ctor/dtor masks.
{
auto recs = comp_rec_view();
for (const auto& rec: recs) {
GAIA_EACH(recs) {
const auto& rec = recs[i];
if (rec.comp.size() == 0)
continue;

if (rec.entity.kind() == EntityKind::EK_Gen) {
const auto e = m_records.pCompEntities[i];
if (e.kind() == EntityKind::EK_Gen) {
m_header.hasAnyCustomGenCtor |= (rec.pItem->func_ctor != nullptr);
m_header.hasAnyCustomGenDtor |= (rec.pItem->func_dtor != nullptr);
} else {
m_header.hasAnyCustomUniCtor |= (rec.pItem->func_ctor != nullptr);
m_header.hasAnyCustomUniDtor |= (rec.pItem->func_dtor != nullptr);

// We construct unique components rowB away if possible
// We construct unique components right away if possible
call_ctor(0, *rec.pItem);
}
}
Expand Down Expand Up @@ -618,7 +615,8 @@ namespace gaia {

auto oldRecs = pOldChunk->comp_rec_view();

// Copy generic component data from reference entity to our new entity
// Copy generic component data from reference entity to our new entity.
// Unique components do not change place in the chunk so there is no need to move them.
GAIA_FOR(pOldChunk->m_header.genEntities) {
const auto& rec = oldRecs[i];
if (rec.comp.size() == 0U)
Expand All @@ -639,7 +637,8 @@ namespace gaia {
auto* pOldChunk = ec.pChunk;
auto oldRecs = pOldChunk->comp_rec_view();

// Copy generic component data from reference entity to our new entity
// Copy generic component data from reference entity to our new entity.
// Unique components do not change place in the chunk so there is no need to move them.
GAIA_FOR(pOldChunk->m_header.genEntities) {
const auto& rec = oldRecs[i];
if (rec.comp.size() == 0U)
Expand Down Expand Up @@ -667,6 +666,7 @@ namespace gaia {
// Find intersection of the two component lists.
// Arrays are sorted so we can do linear intersection lookup.
// Call constructor on each match.
// Unique components do not change place in the chunk so there is no need to move them.
{
uint32_t i = 0;
uint32_t j = 0;
Expand All @@ -676,7 +676,6 @@ namespace gaia {

if (oldId == newId) {
const auto& rec = newRecs[j];
GAIA_ASSERT(rec.entity == newId);
if (rec.comp.size() != 0U) {
auto* pSrc = (void*)pOldChunk->comp_ptr_mut(i);
auto* pDst = (void*)pNewChunk->comp_ptr_mut(j);
Expand All @@ -690,7 +689,6 @@ namespace gaia {
} else {
// No match with the old chunk. Construct the component
const auto& rec = newRecs[j];
GAIA_ASSERT(rec.entity == newId);
if (rec.pItem != nullptr && rec.pItem->func_ctor != nullptr) {
auto* pDst = (void*)pNewChunk->comp_ptr_mut(j, newRow);
rec.pItem->func_ctor(pDst, 1);
Expand Down Expand Up @@ -758,8 +756,8 @@ namespace gaia {

// Entity has been replaced with the last one in our chunk. Update its container record.
ecB.row = rowA;
} else {
// This is the last entity in chunk so simply destroy its data
} else if (m_header.hasAnyCustomGenDtor) {
// This is the last entity in the chunk so simply destroy its data
auto recView = comp_rec_view();
GAIA_FOR(m_header.genEntities) {
const auto& rec = recView[i];
Expand Down Expand Up @@ -960,6 +958,7 @@ namespace gaia {
void call_all_dtors() {
GAIA_PROF_SCOPE(Chunk::call_all_dtors);

auto ids = ents_id_view();
auto recs = comp_rec_view();
GAIA_EACH(recs) {
const auto& rec = recs[i];
Expand All @@ -969,7 +968,8 @@ namespace gaia {
continue;

auto* pSrc = (void*)comp_ptr_mut(i, 0);
const auto cnt = (rec.entity.kind() == EntityKind::EK_Gen) ? m_header.count : 1;
const auto e = ids[i];
const auto cnt = (e.kind() == EntityKind::EK_Gen) ? m_header.count : 1;
pDesc->func_dtor(pSrc, cnt);
}
};
Expand Down Expand Up @@ -1131,7 +1131,7 @@ namespace gaia {
//! \param entity Component
//! \return Component index if the component was found. -1 otherwise.
GAIA_NODISCARD uint32_t comp_idx(Entity entity) const {
return ecs::comp_idx<MAX_COMPONENTS>(m_records.pCompEntities, entity);
return ecs::comp_idx<ChunkHeader::MAX_COMPONENTS>(m_records.pCompEntities, entity);
}

//----------------------------------------------------------------------
Expand Down
6 changes: 4 additions & 2 deletions include/gaia/ecs/chunk_header.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ namespace gaia {
};

struct ComponentRecord {
//! Entity id
Entity entity;
//! Component id
Component comp;
//! Pointer to where the first instance of the component is stored
Expand All @@ -49,6 +47,10 @@ namespace gaia {
};

struct ChunkHeader final {
static constexpr uint32_t MAX_COMPONENTS_BITS = 5U;
//! Maximum number of components on archetype
static constexpr uint32_t MAX_COMPONENTS = 1U << MAX_COMPONENTS_BITS;

//! Maximum number of entities per chunk.
//! Defined as sizeof(big_chunk) / sizeof(entity)
static constexpr uint16_t MAX_CHUNK_ENTITIES = (mem_block_size(1) - 64) / sizeof(Entity);
Expand Down
4 changes: 2 additions & 2 deletions include/gaia/ecs/chunk_iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ namespace gaia {
template <Constraints IterConstraint>
class ChunkIterImpl {
protected:
using CompIndicesBitView = core::bit_view<Chunk::MAX_COMPONENTS_BITS>;
using CompIndicesBitView = core::bit_view<ChunkHeader::MAX_COMPONENTS_BITS>;

//! Chunk currently associated with the iterator
Chunk* m_pChunk = nullptr;
//! Chunk::MAX_COMPONENTS values for component indices mapping for the parent archetype
//! ChunkHeader::MAX_COMPONENTS values for component indices mapping for the parent archetype
const uint8_t* m_pCompIdxMapping = nullptr;
//! GroupId. 0 if not set.
GroupId m_groupId = 0;
Expand Down
Loading

0 comments on commit 11ac62d

Please sign in to comment.