Войти
ПрограммированиеФорумГрафика

ECS во все поля (3 стр)

Страницы: 1 2 3 4 5 6 Следующая »
#30
16:50, 11 апр. 2020

Suslik
> что если я забуду вот тут: ... перечислить size_t?
Там компайл тайм проверки на 200+ строк кода, все что можно проверяется))

> у flecs разница в том, что они вызывают один раз лямбду на чанк
У меня в самом начале так было, потом сделал более низкоуровнево.

> reg.GetSingletonEntity().SetComponent<TimeDelta>(...);
В тру ECS энтити - это айдишник и никаких методов быть не может.

> если ещё что-то вспомнишь, пость.
Да я сам все ссылки из ecs-faq не прочитал))
Еще в прошлом году начал статью по ecs писать, но без многопоточности и разбора всяких хитрых ситуаций там ничего нового не написать, а на все это пока времени нет.

> чувак именно этот принцип положил в основу.
В EnTT используется подход MegaArray, по мне так он хуже архетипов. Где-то была статья, где разбираются все подходы к ecs.

#31
16:52, 11 апр. 2020

Suslik
> аа, как я сам до этого не догадался?!
Я такое использовал в фреймграфе. Из плюсов - POD объекты вместо шаред поинтеров.

#32
16:54, 11 апр. 2020

> Где-то была статья, где разбираются все подходы к ecs.
вот она http://t-machine.org/index.php/2014/03/08/data-structures-for-ent… guous-memory/

#33
(Правка: 17:15) 16:58, 11 апр. 2020

/A\
> В тру ECS энтити - это айдишник и никаких методов быть не может.
ну ради бога, имеется в виду так:

reg.GetComponent<TimeDelta>(reg.GetSingletonEntity())

/A\
> В EnTT используется подход MegaArray, по мне так он хуже архетипов
мне тоже нравится концепция архетипов и мне кажется over-engineering'ом писать реализацию, которая не использует знания архетипов. то есть реализация ecs будет точно не сложнее и точно не медленнее, если предоставить ей информацию об архетипах, которая всё равно в любом мыслимом дизайне должна в каком-то виде где-то присутствовать.

> Я такое использовал в фреймграфе. Из плюсов - POD объекты вместо шаред поинтеров.
блин, сколько ж мне теперь кода из-за этого переписывать.. потому что я использовал другой (более убогий) паттерн, который переиспользовал все id после удаления только с задержкой в 1 кадр, которая использовалась для того, чтобы проверить всем заинтересованным, что такой-то id находится в процессе освобождения. короче, с версиями гораздо лучше и логичнее.

ещё интересный момент — в EnTT вместо синглтонов использует т.н. контекст:

// creates a new context variable initialized with the given values
registry.set<my_type>(42, 'c');
 
// gets the context variable
const auto &var = registry.ctx<my_type>();
 
// if in doubts, probe the registry to avoid assertions in case of errors
if(auto *ptr = registry.try_ctx<my_type>(); ptr) {
    // uses the context variable associated with the registry, if any
}
 
// unsets the context variable
registry.unset<my_type>();
то есть контекст содержит не совсем компоненты, а просто структуры произвольных типов. интересная идея, мне на самом деле нравится, потому что зачем называть компонентами то. что по сути можно компонентами не считать?

важное отличие между контекстом и энтити-синглтоном заключается в том, что при итерировании по всем энтитям, имеющим такой-то компонент, мы бы проитерировались через синглтон, а через контекст — нет.

#34
17:43, 11 апр. 2020

Вот кусочек с обзором разных подходов.

+ Показать

#35
(Правка: 21:46) 21:42, 11 апр. 2020

/A\
> for (size_t i = 0; i < entities.size(); ++i)
> {
> ComponentA& a = componentsA[i];
> ComponentB& b = componentsB[i];
> ComponentC& c = componentsC[i];
>
> Update( EntityID(i), a, b, c );
> }
чивоо? ты где такое видел? entt вовсе не так реализован, там нет пустых компонентов. там используются sparse sets, которые гораздо умнее: https://programmingpraxis.com/2012/03/09/sparse-sets/

> vector<range> ranges = registry.view<ComponentA, ComponentB>();
entt не выделяет память при взятии view. view умеет только итерироваться, он никуда не сохраняет ranges. а group<ComponentA, ComponentB> определяет layout таким образом, что компоненты тех энтитей, которые обладают ComponentA и ComponentB, хранятся в своих массивах по одинаковым индексам, поэтому итерирование по ним одновременно осуществляется через perfect SoA (одним куском без оверхеда). тут очень хорошее объяснение того, как группы в entt работают: https://skypjack.github.io/2019-11-19-ecs-baf-part-6/

#36
(Правка: 22:29) 22:14, 11 апр. 2020

>MegaArray.
Говно решение.
Весь смысл ECS - в расовой чистоте кеша. Остальные плюшки - чисто дополнительные.

Даже я, гоняя простейшие одноклеточные тесты на Паскале (в т.ч. со связанными списками) то и дело упирался в пропускную способность памяти.

Если задействовать N сильномогучих ядер ЦПУ - проблема обостряется в N раз.

>кэш промахи происходят только при переходе на новый блок
Я в своём поделиИ замутил под это специальный менеджер памяти для обычного ООП. Каждый класс - отдельны набор пулов.
Жаль, проверить удастся только осенью: работы - выше крыши.

>большое разнообразие архетипов может привести к частым кэш промахам
А не надо сразу несколько разных окучивать.

З.Ы. Спасибо, мужики. Ваше обсуждение дало мне новые идеи для моих преждевременных оптимизаций: читать приведёенные ссылки - лень, да и мозг я бы на них сломал.

З.З.Ы. Я и сам уже собирался делать ограниченный вариант ECS - сам изобрёл, ещё не зная, что это так называется, как до того изобрёл рендер в динамический размер таргета и многопоточность. Идеи в воздухе летают, правильные идеи приходят ко всем.

З.З.З.Ы. Чем плоха ООП? Релевантные поля размазаны по инстансам классов и, например, путешествуя по связанному списку, ЦПУ каждый раз тащит в кеш 64-байтный кусок инстанса ради одного 8-байтного указателя. А даже когда релевантные данные - поболе размером (те же 64 байта или больше) - как ты их в инстансе выровняешь на те же 64 байта?

Откуда, в ECS стоит
1) выносить некоторые типы данных, для которых жизненно важны упакованность и выравнивание.
2) выносить некоторые типы сущностей, обход которых - отдельный процесс, плоскопараллельный всему остальному. Причём, сами сущности можно оставить обычным ООП.
Главная фишка - обходя компоненты по массиву, где они скучены - не дёргаешь указатель на них, к которому прилип 64-байтный кусок инстанса владельца.

#37
22:21, 11 апр. 2020

Suslik
> чивоо? ты где такое видел?
это было 4 мес назад, уже не помню, но исходники ковырял

#38
22:43, 11 апр. 2020

Cheb
> Релевантные поля размазаны по инстансам классов и, например, путешествуя по
> связанному списку,

А в чем тогда смысл ECS на уровне скриптования? Доклады были с примерами на сишарпе, где вообще ничего ни сделаешь с размещением в памяти, промахами в кеше. Т.е. эта тема низкоуровневого движко строения или всетаки архитектурная?

#39
(Правка: 22:50) 22:44, 11 апр. 2020

/A\
> это было 4 мес назад, уже не помню, но исходники ковырял
в нём есть sparse массив интов и dense массив интов для каждого типа компонентов. в sparse массиве s[id] хранится, где находится компонент энтити с номером id. в этом массиве есть дырки, но он используется только для того, чтобы узнать, где находится компонент энтити с номером id (это медленная операция, так как вызывает лишнее обращение к массиву и при итерировании ей пользоваться не надо). в dense массиве хранятся (плотно) айди всех ныне живых энтитей, у которых есть этот компонент. также есть ещё один массив (тоже плотный) с, собственно, компонентами, которые хранятся в том же порядке, что и dense массив. дырок в нём нет. в итоге добавление новой энтити/компоненты делается за O(1), удаление — тоже, итерирование — за O(n), n — количество живых энтитей, обладающих этим компонентом. единственный оверхед — это оверхед по памяти на sparse массив интов. по памяти это эквивалентно тому, чтобы в каждой энтити хранить указатель на каждую компоненту, который может быть нулевым. то есть если энтитей всего P, а различных компонентов всего Q, общие затраты памяти на sparse массивы будут sizeof(int) * P * Q, это и есть главный недостаток подхода, который использует entt — потенциально большое количество памяти, если разных компонентов много, а используются они редко. однако, преимущество — предельно локальный доступ к компонентам при итерации по ним, что называется perfect SoA. также используется концепция групп, чтобы perfect SoA итерироваться можно было сразу по группам компонент, практически бесплатно, но с ограничениемя, какие именно могут быть группы.

да и ты почитай блог этого чувака, он вообще повёрнут на производительности и микрооптимизациях, он бы точно себе не позволил дырявые массивы компонентов хранить.


однако, я всё равно не в восторге от идеи хранить sizeof(int) * P * Q памяти. это не так уж фатально, но если явно указывать архетипы, можно обойтись без этого (вроде)

#40
23:07, 11 апр. 2020

да уж, я напрочь забыл, что вообще планировал прогать сегодня, но в итоге весь день читал то, как разные ecs работают. оказалось, что я знал ещё меньше, чем предполагал, но теперь хотя бы могу оценить, сколько именно я не знаю.

#41
(Правка: 0:24) 0:22, 12 апр. 2020

/* На правах чистого теоретика */

Suslik
> однако, это никак не отвечает на вопрос, как хранить представления, которые не являются локальными для энтитей — например, общее AABB tree всей сцены, всякие графы порталов между комнатами и прочие нелокальные сущности, не относящиеся к отдельным энтитям.
Так это же, вроде, очевидно: глобальные ускоряющие структуры — в синглтон-комопненте, всякие парные связи — в отдельных ентитях. На примере той же физики — квадтри в синглтоне, контакты в новых ентитях. А саму физику можно разбить на BroadCollisionSystem (обновляет квадтри), NarrowCollisionSystem (обновляет контакты) и, собственно, PhysicsSystem (считает динамику). Причем квадтри и контакты вполне могут быть полезны для систем игровой логики.

#42
(Правка: 1:12) 0:58, 12 апр. 2020

slepov

Это проблема позапрошлого уже поколения консолей,  где сони с межделмашем сделали эталонные кукурузные гигагерцы. И без DoD и ECS там всё было очень грустно прямо от слова совсем.

И с современным железом,  похоже,  проблема встаёт вновь,  поскольку все последние уязвимости вынуждают всё  больше и больше  кукурузить современные процессоры для защиты от side channel атак,  которые основаны на всех этих умных механизмах предсказания и предвыборки.

#43
7:30, 12 апр. 2020

забавно, что в статье от воргейминга они прямым образом написали абзац про то, как они считают некоторые основополагающие принципы ECS, не особо важными на практике. например, что у систем нет своих данных и что у компонентов не можеть быть методов — они говорят, что нет смысла хранить в синглтонах чисто внутренние данные системы и нет смысла избегать использования геттеров и сеттеров в компонентах.

#44
(Правка: 7:41) 7:41, 12 апр. 2020

короче, я останавливаюсь пока на EnTT. он очень прозрачно устроен, при правильном использовании даёт perfect SoA (то есть максимально cache-friendly доступ к компонентам), обладает очень интересной концепцией контекста вместо компонентов-синглтонов и минимальным, очень чистым и продуманным интерфейсом:

    registry.view<position, velocity>().each([](auto &pos, auto &vel)
    {
        pos.x += vel.dx * registry.ctx<Time>().dt; //ctx — доступ к контексту, аналог синглтона
        pos.y += vel.dy * registry.ctx<Time>().dt;
    });

следующий кандидат — flecs, но в нём мне не понравилось, что он реализован внутри на жуткомакросах plain C (имеется C++ байндинг) и включает в себя огромное количество функциональности, которая на самом деле не является базовой (контейнеры, иерархии, многопоточность, таймстеппинг). то есть я бы не назвал его интерфейс чистым или минималистичным, хотя он мне тоже понравился.

Страницы: 1 2 3 4 5 6 Следующая »
ПрограммированиеФорумГрафика