kas
> ну нет. просто есть "дефолтное" состояние. когда надо не оно - переводишь в то
> которое надо и сразу после - назад. работает отлично, на перф чтобы влияло не
> похоже, причем и для дх12 тоже самое все
ну да, особенно если у тебя дефолтное состояние — рендертаргет, но есть 10 пассов подряд, которые из него читают в шейдере. тогда у тебя будет 10 подряд барьеров, которые будут маслать лейаут взад-вперёд.
фреймграф — это в первую очередь не про то, как выжать максимум производительности здесь и сейчас (потому что здесь и сейчас лейауты на нвидии, например, просто игнорируются), а как проектировать рендер на будущее, когда эти вещи будут играть бОльшую роль. или для более экзотического железа вроде мобил, где оно неиллюзорно играет роль уже сейчас.
Suslik
> ну да, особенно если у тебя дефолтное состояние — рендертаргет, но есть 10
> пассов подряд, которые из него читают в шейдере. тогда у тебя будет 10 подряд
> барьеров, которые будут маслать лейаут взад-вперёд.
ну как бы если ты не понимаешь что делаешь - тебя никакие графы не спасут, нет? но да, если делать условный пинг понг будет много барьеров. и в фреймграфе тоже - магии то нет. на мобилах совсем не лейауты играют роль. но если ты не понимаешь что рендить можно только в спец память из которой нельзя текстурировать - то снова тебя никаких фреймграфы не спасут
kas
> но да, если делать условный пинг понг будет много барьеров. и в фреймграфе тоже - магии то нет
нет. я говорю о случае, когда дефолтное для ресурса состояние — например, рендертаргет, но 10 подряд пассов из него что-то читают в шейдере. поэтому каждый пасс сначала переводит лейаут в оптимальный для чтения, а потом — обратно в оптимальный для рендеринга(дефолтный). фреймграф же увидит, что 10 пассов подряд из таргета только читают и переводить между ними в состояние для рендеринга не будет.
> ну как бы если ты не понимаешь что делаешь - тебя никакие графы не спасут, нет?
можно подумать, ты будешь что-то понимать, когда у тебя количество рендерпассов перейдёт хотя бы за несколько десятков. напомню, во фростбайте их — несколько сотен и при этом многие из них — опциональные, которые включаются только при определённых условиях.
да и как бы можно подумать, я тебя убедить пытаюсь, почему все дороги ведут к фреймграфам. мне от этого ни тепло ни холодно, разобраться в этом — в твоих интересах, поэтому сам гугли доклады по фреймграфам и втыкай, почему люди о них заморачиваются.
Suslik
> я говорю о случае, когда дефолтное для ресурса состояние — например,
> рендертаргет
а я говорю о случае - когда нет такого дефолтного состояния. можно придумывать проблемы и героически их решать, а можно нет.
Suslik
> можно подумать, ты будешь что-то понимать, когда у тебя количество рендерпассов
> перейдёт хотя бы за несколько десятков. напомню, во фростбайте их — несколько
> сотен и при этом многие из них — опциональные, которые включаются только при
> определённых условиях.
> да и как бы можно подумать, я тебя убедить пытаюсь, почему все дороги ведут к
> фреймграфам. мне от этого ни тепло ни холодно, разобраться в этом — в твоих
> интересах, поэтому сам гугли доклады по фреймграфам и втыкай, почему люди о них
> заморачиваются.
доклады я читал - у меня стойкое ощущение что там основная мотивация память сэкономить а вовсе не то что вы пишите. поетому и спрашиваю!
kas
> у меня стойкое ощущение что там основная мотивация память сэкономить
Для этого использовался первый фреймграф, но тогда памяти было намного меньше.
С фреймграфом ты можешь оптимизировать некоторые участки, например выкинуть лишнее рисование или копирование, если результат нигде не используется. Можешь заменить несколько тасков одним оптимизированым с каким-нибудь вендорским расширением.
kas
> просто есть "дефолтное" состояние
kas
> а я говорю о случае - когда нет такого дефолтного состояния
так ты определишься, может? есть у тебя дефолтное состояние или нет? я говорю, что если есть — это наивное решение по типу легаси API, которое при определённых условиях использования может выродиться в кучу перекладываний лейаута. а если нет, то ты не будешь знать, в какое состояние переводить ресурс при инициализации пасса, так как ты не знаешь, как он будет использоваться после него.
энивей, фреймграф — это не усложнение и не упрощение рендера. переход с декларативного объявления рендерпассов к фреймграфу — это скорее следующий логический этап абстракции графического пайплайна на уровне двига. таким же образом когда-то шейдерный пайплайн сменял фиксированный и тогда многие продолжали использовать фиксированный пайплайн по старинке, потому что он казался проще и удобнее. но на самом деле он накладывал гораздо больше ограничений, чем давал удобства, а потом и просто становился палками в колёсах и легаси говном. а шейдерный пайплайн давал больше возможностей и предоставлял более рациональный интерфейс общения с gpu. вот так же и фреймграф будет развиваться — он просто более адекватно абстрагирует интерфейс общения с современными gpu.
Suslik
> так ты определишься, может? есть у тебя дефолтное состояние или нет?
я то определен. там слово _такого_ не просто так. дефолтное состояние текстуры - это текстура. проблемы будут если несколько раз подряд бегин енд пасс делать в одну и туже, тут фреймграф может помочь безусловно
> энивей, фреймграф — это не усложнение и не упрощение рендера. переход с
> декларативного объявления рендерпассов к фреймграфу — это скорее следующий
> логический этап абстракции графического пайплайна на уровне двига. таким же
> образом когда-то шейдерный пайплайн сменял фиксированный и тогда многие
> продолжали использовать фиксированный пайплайн по старинке, потому что он
> казался проще и удобнее. но на самом деле он накладывал гораздо больше
> ограничений, чем давал удобства, а потом и просто становился палками в колёсах
> и легаси говном. а шейдерный пайплайн давал больше возможностей и предоставлял
> более рациональный интерфейс общения с gpu. вот так же и фреймграф будет
> развиваться — он просто более адекватно абстрагирует интерфейс общения с
> современными gpu.
все так, да. надо просто дозреть видимо!
Я понял что мне очень нехватает возможности устанавливать зависимости между командными буферамы во время их заполнения.
Например где-то отдельно работает стриминг или процедурная генерация, это может быть в отдельной очереди на ГПУ. И мне надо использовать результат загрузки/генерации, поэтому я говорю фреймграфу, что текущие команды надо выполнять после вон того командного буфера и дальше все синхронизации происходят автоматически - внутри одной очереди будет барьер, между разными очередями - семафор.
Выглядит это так:
class ICommandBuffer { // это новое virtual void AddDependency (CommandBufferPtr) = 0; // тут все попрежнему virtual Task AddTask ( ...) = 0; }; class IFrameGraph { virtual CommandBufferPtr Begin ( ...) = 0; // добавляем командный буфер в очередь, так как vkQueueSubmit дорогая операция, // то команды будут отправляться батчами virtual void Execute ( CommandBufferPtr) = 0; // принудительно отправляем команды и ожидаем fence virtual bool Wait ( ArrayView<CommandBufferPtr>) = 0; // отправляем все командны на ГПУ virtual void Flush ( ) = 0; // отправляем все команды и ожидаем их завершения virtual void WaitIdle ( ) = 0; }; void main ( ) { // какая-то генерация auto cmd1 = fg->Begin( EQueue::AsyncCompute ); cmd1->AddTask( Dispatch{}... ); fg->Execute( cmd1 ); ... ... // рисование auto cmd2 = fg->Begin( EQueue::Graphics ); ... // проверяем, что команды генерации уже записаны if ( ... ) { cmd2->AddDependency( cmd1 ); // рисуем то что сгенерировали cmd2->AddTask( ... ); } fg->Execute( cmd2 ); }
Стабилизировал версию 0.9, как раз тот новый интерфейс из предыдущего поста.
Также давно уже выложен сэмпл с рейтрейсом на RTX, но там пока еще примитивно все.
Suslik
>// массив ресурсов на чтение. если к началу исполнения таска ресурс находится не в
> том layout'е, то он автоматически переводится в eShaderRead барьером.
Я попробовал такой же подход - в начале рендер пасса указывать все ресурсы, которые могут быть не в том лейауте, который ожидается. И на шрифтах получился облом - текстуры с атласами запрятаны где-то далеко, а новый глиф может создаться на любом кадре. Вариантов остается два: делать отдельный командный буфер, куда будут записаны команды копирования и в конце лейаут перейдет в дефолтное состояние как раз для чтения. Либо оставить как было, пройтись по всем дескриптор сетам и выставить барьеры, с имутабельностью получается достаточно быстро.
/A\
> И на шрифтах получился облом - текстуры с атласами запрятаны где-то далеко, а
> новый глиф может создаться на любом кадре.
не понял, в чём проблема. вообще текстуры со шрифтами обычно по кодовым страницам распределены и ты просто загружаешь всю страницу, тут в принципе переводы лейаутов не нужны.
> Я попробовал такой же подход - в начале рендер пасса указывать все ресурсы, которые могут быть не в том лейауте, который ожидается
я, кстати, ещё дальше этого подхода пошёл. если раньше я хранил для каждого ресурса его текущее состояние, то теперь даже этого не делаю, а нахожу состояние ресурса перед началом исполнения таска как состояние этого ресурса на момент выполнения последнего таска, использовавшего этот ресурс. например, если последний раз этот ресурс фигурировал в каком-то таске, как ресурс на чтение из шейдера, то он будет в состоянии eShaderReadOptimal. получается полностью stateless модель.
ещё я отказался от переводов лейаутов через зависимости сабпассов, так как кто-то замерял производительность и она оказалась аналогичной просто установке барьера. то есть барьеры переводят рендертаргет в eColorAttachmentOptimal и они же переводят потом в какой-нибудь eShaderReadOptimal или что-то другое. как выяснилось, переводы лейаутов через сабпассы нужны в первую очередь если этих самых сабпассов больше одного и между ними нужно переводить состояния ресурсов. однако, если сабпасс один и зависимости у него только от VK_SUBPASS_EXTERNAL, то нет никакого смысла усложнять логику и проще использовать обычные барьеры.
ещё я реализовал автоматический сабмит рендерпассов в graphics queue, компьют пассов в compute queue и трасфер пассов в transfer queue, автоматически передаю владение над ресурсами, расставляю семафоры, всё такое, пользуясь той же самой философией — последний пасс, использовавший ресурс, однозначно определяет, в каком он будет лейауте и какой queue им будет владеть.
Suslik
> как состояние этого ресурса на момент выполнения последнего таска
Там же один таск может использовать один диапазон, второй - другой диапазон и тебе придется их все учитывать. У меня такое было в одной из первых реализаций.
> вообще текстуры со шрифтами обычно по кодовым страницам распределены и ты
> просто загружаешь всю страницу, тут в принципе переводы лейаутов не нужны.
У меня только используемые глифы загружаются. По крайней мере такой вариант использовался в навигаторе, где отображался весь мир с кучей юникод символов и с разными размерами шрифтов. Заранее хоть что-то загружать достаточно дорого.
Suslik
> автоматически передаю владение над ресурсами
А как разруливаешь ситуации когда ресурс захвачен compute queue, а используется в graphics queue, тут получается или заранее передавать или записывать командный буфер чтоб освободить ресурс в compute queue.
Или как быть с чтением ресурса из разных очередей? Тут только concurrent режим подходит.
> ещё я отказался от переводов лейаутов через зависимости сабпассов, так как
> кто-то замерял производительность и она оказалась аналогичной просто установке барьера.
Ну я давно еще говорил, что во всех движках также делают.
/A\
> Там же один таск может использовать один диапазон, второй - другой диапазон и
> тебе придется их все учитывать.
именно так, потому что владение определяется не для ресурса, а для сабресурса. то есть сабпасс говорит, что использует такой-то image view, которому соответствует subresource range, поэтому именно этот subresource range будет в соответствующем лейауте. далее я конструирую барьеры для каждого сабресурса отдельно, но по возможности объединяю их все в один барьер с более широким диапазоном сабресурсов.
/A\
> У меня только используемые глифы загружаются. По крайней мере такой вариант
> использовался в навигаторе, где отображался весь мир с кучей юникод символов и
> с разными размерами шрифтов. Заранее хоть что-то загружать достаточно дорого.
>
>
если честно, я с трудом представляю себе ситуацию, когда тебе одновременно нужно выводить на экране символы из более чем ~5 юникодных страниц. пожалуй, рендеринг карты мира — одно из редких исключений, но даже если очень хочется собирать атлас шрифтов из отдельных глифов, я всё равно не понимаю, в чём проблема.
> А как разруливаешь ситуации когда ресурс захвачен compute queue, а используется в graphics queue, тут получается или заранее передавать или записывать командный буфер чтоб освободить ресурс в compute queue.
> Или как быть с чтением ресурса из разных очередей? Тут только concurrent режим подходит.
при расстановке барьеров я автоматически меняю лейаут и передаю владение, если необходимо. однако, ремарка: у меня сейчас compute и graphics queue используют один и тот же queue family index, поэтому я пока не тестировал, если они действительно разные. может быть какой-то баг, о котором я пока не догадываюсь.
Suslik
> я всё равно не понимаю, в чём проблема.
Проблема в том, что не удобно руками указывать все эти атласы.
Тема в архиве.