RANDOM_RUST_DEV Telegram 45
Ничего давно не постил. Потихоньку делаю work-graph для работы с GPU в движке и эдиторе.

Сначала я хотел просто отображать графи рендерпассов, без возможности менять его в UI, так как он задается кодом.

Сейчас рядом с рендерграфом почти вырос более обобщенный WorkGraph, который можно собрать из джобов, которые плагины будут экспортировать. Джобы будут инстанциироваться и соединятся как угодно, в пределах типизации пинов.
В первом черновике входы и выходы типизировались растовыми типами и соотвественно в данных лежал TypeId, но так как плагины могут в рантайме перезагружаться, то TypeId может меняться.
Сейчас за неимением сильно лучшей альтернативы в нодах лежит kind: String. А в дженерик методах, где есть тип T: Target проверяется T::kind() == pin.kind. Если у вас есть идеи что будет лучше, милости прошу, оставьте в комментариях.

Но граф существует как граф только в редакторе.
В джижке он тут же превращается в тыкву очередь.
В самом деле, зачем нам хранить граф как граф, если нас интересует только его обход в dependencies-first или dependencies-last порядке. Можно просто сделать очередь и ходить по ней в двух направлениях.

В конструкторе WorkGraph на вход подаются джобы и их связи.
Портам, которые соединены с другим(и) назначаются target IDшки, так что бы у соединенных был одинаковый ID, а так же у update пар внутри каждой джобы.
Еще всем входам прописываются их джобы-зависимости. Почему портам а не джобам? Сейчас мы к этому придем.

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

Но все же не совсем статичный.
В граф можно добавить к выходам внешние таргеты, так результат работы графа и экстрактится из него.
Например можно захватить следующую картинку из Swapchain и установить в качестве таргета у вообще любого выхода подходящего типа. Это даже вполне ок делать каждый кадр, если их количество не зашкаливает.

Дальше то что идет каждый кадр.
1. Планирование. Берем все внешние таргеты и добавляем в сет selected все джобы ноды от этих выходов.
2. Потом идем с конца, пропуская джобы не из selected и собираем дескрипшны со всех входов, так мы узнаем например какого разрешение должен быть таргет картинка или размер таргета буфера.
В этот момент так же добавляются в selected джобы-зависимости каждого входного порта. Да, вот они где используются.
В конце получаем сет всех джоб, которые нужно запустить, что бы заполнить все внешние таргеты. А еще у каждого таргета, который нужно будет создать, собирается Target::Info для инициализации.
3. Наконец идем в прямом порядке и запускаем выполнение всех selected джоб. В этот момент создаются все нужные таргеты (берутся из кэша, если предыдущий Target::Info совпадает).
Кроме таргетов джоба аллоцирует нужное количество CommandEncoder -ов которые сразу кладутся в очередь, а джобе достается только ссылка. Так джоба не забудет сделать Queue::submit, потому что она и не должна.
К тому же перед тем как отдать первый CommandBuffer джобе, туда ловко вставляется синхронизация (в коде еще нет, но такой план).
Так же джоба вольна пользоваться Device для создания внутренних ресурсов и чего только ей не захочется.
4. В последний CommandEncoder вписывается синхронизация между джобами и внешним кодом для внешних ресурсов. Туда же добавится CommandEncoder::present. После чего все они сабмитятся в порядке аллокации.

Вот так примерно оно должно будет работать.

Кто досюда дочитал - молодец и умница, возьми угощение на полочке и поставь лайк.
👍4



tgoop.com/random_rust_dev/45
Create:
Last Update:

Ничего давно не постил. Потихоньку делаю work-graph для работы с GPU в движке и эдиторе.

Сначала я хотел просто отображать графи рендерпассов, без возможности менять его в UI, так как он задается кодом.

Сейчас рядом с рендерграфом почти вырос более обобщенный WorkGraph, который можно собрать из джобов, которые плагины будут экспортировать. Джобы будут инстанциироваться и соединятся как угодно, в пределах типизации пинов.
В первом черновике входы и выходы типизировались растовыми типами и соотвественно в данных лежал TypeId, но так как плагины могут в рантайме перезагружаться, то TypeId может меняться.
Сейчас за неимением сильно лучшей альтернативы в нодах лежит kind: String. А в дженерик методах, где есть тип T: Target проверяется T::kind() == pin.kind. Если у вас есть идеи что будет лучше, милости прошу, оставьте в комментариях.

Но граф существует как граф только в редакторе.
В джижке он тут же превращается в тыкву очередь.
В самом деле, зачем нам хранить граф как граф, если нас интересует только его обход в dependencies-first или dependencies-last порядке. Можно просто сделать очередь и ходить по ней в двух направлениях.

В конструкторе WorkGraph на вход подаются джобы и их связи.
Портам, которые соединены с другим(и) назначаются target IDшки, так что бы у соединенных был одинаковый ID, а так же у update пар внутри каждой джобы.
Еще всем входам прописываются их джобы-зависимости. Почему портам а не джобам? Сейчас мы к этому придем.

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

Но все же не совсем статичный.
В граф можно добавить к выходам внешние таргеты, так результат работы графа и экстрактится из него.
Например можно захватить следующую картинку из Swapchain и установить в качестве таргета у вообще любого выхода подходящего типа. Это даже вполне ок делать каждый кадр, если их количество не зашкаливает.

Дальше то что идет каждый кадр.
1. Планирование. Берем все внешние таргеты и добавляем в сет selected все джобы ноды от этих выходов.
2. Потом идем с конца, пропуская джобы не из selected и собираем дескрипшны со всех входов, так мы узнаем например какого разрешение должен быть таргет картинка или размер таргета буфера.
В этот момент так же добавляются в selected джобы-зависимости каждого входного порта. Да, вот они где используются.
В конце получаем сет всех джоб, которые нужно запустить, что бы заполнить все внешние таргеты. А еще у каждого таргета, который нужно будет создать, собирается Target::Info для инициализации.
3. Наконец идем в прямом порядке и запускаем выполнение всех selected джоб. В этот момент создаются все нужные таргеты (берутся из кэша, если предыдущий Target::Info совпадает).
Кроме таргетов джоба аллоцирует нужное количество CommandEncoder -ов которые сразу кладутся в очередь, а джобе достается только ссылка. Так джоба не забудет сделать Queue::submit, потому что она и не должна.
К тому же перед тем как отдать первый CommandBuffer джобе, туда ловко вставляется синхронизация (в коде еще нет, но такой план).
Так же джоба вольна пользоваться Device для создания внутренних ресурсов и чего только ей не захочется.
4. В последний CommandEncoder вписывается синхронизация между джобами и внешним кодом для внешних ресурсов. Туда же добавится CommandEncoder::present. После чего все они сабмитятся в порядке аллокации.

Вот так примерно оно должно будет работать.

Кто досюда дочитал - молодец и умница, возьми угощение на полочке и поставь лайк.

BY Random Rust Dev


Share with your friend now:
tgoop.com/random_rust_dev/45

View MORE
Open in Telegram


Telegram News

Date: |

Ng was convicted in April for conspiracy to incite a riot, public nuisance, arson, criminal damage, manufacturing of explosives, administering poison and wounding with intent to do grievous bodily harm between October 2019 and June 2020. The Channel name and bio must be no more than 255 characters long The SUCK Channel on Telegram, with a message saying some content has been removed by the police. Photo: Telegram screenshot. With the “Bear Market Screaming Therapy Group,” we’ve now transcended language. How to create a business channel on Telegram? (Tutorial)
from us


Telegram Random Rust Dev
FROM American