Для некоторых задач существует необходимость передавать большие объемы данных, к примеру - карту высот, параметры частиц, кадры анимации и прочие данные, не привязанные к вершинам. Возник резонный вопрос - как лучше передавать эти данные в шейдер.
В древние времена вариантов у нас было немного, фактически было всего два подхода - "Vertex Texture Fetch" (VTF) от NVidia и "Render to Vertex Buffer" (R2VB) от ATI. Каждый из подходов имел свои достоинства, недостатки и ограничения. С тех пор прошло 10 лет, на замену устаревшим техникам пришли UBO, TBO и наконец - SSBO. Для больших объемов данных UBO не пригоден, потому я решил сравнить как обстоят дела у TBO и SSBO.
Предыдущие тесты показали что скорость выборки как из TBO так и из SSBO достаточно высокая, чтоб как-то сравнить эти результаты я решил вывести кусок ландшафта по карте высот, размерность 1280х1280 вершин:
Как сгенерировать буфер TBO/SSBO я оставляю за кадром, так как на эту тему существует множество статей, желающие могут найти пример этого кода здесь.
Остановлюсь немного на вершинном шейдере, вот весь его код:
Код универсальный, выбор функции осуществляется через шейдерные подпрограммы о которых я рассказывал в предыдущих статьях. Так как функция задается только один раз для всех вершин и этот вызов присутствует для всех трех техник, то это никак не влияет на fps.
Данные для TBO у нас передаются как samplerBuffer tbo_tex (строка 10), SSBO объявляется в строках 12-14. В обоих случаях шейдер ничего не знает о размерности буферов, так что их нам придется указать вручную. Я их указал явно в расчете смещения (строка 36).
Для чтения данных я объявил три подпрограммы - ssboValue, tboValue и zeroValue, между которыми мы и будем переключаться. Модификация высоты происходит в строке 38 за счет вызова соответствующей функции.
Прогнав тесты (исходные коды вы можете найти здесь) я обнаружил что отличия минимальны:
SSBO - 418 fps
TBO - 420 fps
Zero - 420 fps
Есть не существенная просадка фпс (целых 2 кадра) при использовании SSBO, но ею можно пренебречь. За счет использования TMU и prefetch выборка с использованием TBO получилась практически бесплатной. На этом можно было бы и завершить статью (или вообще не выкладывать), со словами "используйте что хотите", но в процессе разработки демо я слегка изменил код, нарушив порядок следования данных, каково же было мое удивление когда я увидел просадку по фпс у SSBO в 2.5 раза относительно TBO! Придется и с этим разобраться :)
Чтоб понять на сколько влияет случайная выборка я прикрутил к демо случайный выбор смещения, получилось примерно так:
Это изменение никак не повлияло на смену текстурных координат для zero-варианта, но одинаково снизило фпс до ~62 кадров, для TBO - 62.05 fps и SSBO 61.66 fps, что в 7 раз меньше предыдущих результатов, так что с произвольным доступом плохо в обоих случаях...
Но я на этом не остановился, решил провести еще пару тестов:
Здесь я оставил нетронутой координату Y, в обоих случаях это никак не повлияло на fps, чего и следовало ожидать, учитывая организацию данных в памяти и prefetch.
Второй эксперимент был более простым, я попытался добавить некоторый шаг к текстурным координатам, в начале х3, потом х10:
Тут я получил очень интересный результат, как видите со скриншота - для TBO фпс практически не изменился (-1,5 кадра), а вот для SSBO результат оказался плачевным - 57 фпс:
Так что не смотря на всю мою любовь к SSBO приходится признать что для произвольного последовательного доступа TBO все же предпочтительнее, возможно из-за того что эта нагрузка ложится на TMU, возможно из-за размера prefetch-буфера, он явно имеет предел, что показал тест с совсем случайным доступом, но при последовательном обращении оно отрабатывает на отлично.
Вот такие вот получились результаты...
Исходные коды проекта и фреймворка можно найти здесь:
https://github.com/karpenyuk/GL_Demos/tree/master/VTFvsSSBO
Непосредственно код примера здесь:
https://github.com/karpenyuk/GL_Demos/blob/master/VTFvsSSBO/demo0.inl
В древние времена вариантов у нас было немного, фактически было всего два подхода - "Vertex Texture Fetch" (VTF) от NVidia и "Render to Vertex Buffer" (R2VB) от ATI. Каждый из подходов имел свои достоинства, недостатки и ограничения. С тех пор прошло 10 лет, на замену устаревшим техникам пришли UBO, TBO и наконец - SSBO. Для больших объемов данных UBO не пригоден, потому я решил сравнить как обстоят дела у TBO и SSBO.
Как сгенерировать буфер TBO/SSBO я оставляю за кадром, так как на эту тему существует множество статей, желающие могут найти пример этого кода здесь.
Остановлюсь немного на вершинном шейдере, вот весь его код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | const char vShader[] = SHADER_SOURCE( layout(location = 0) in vec3 in_Position; layout(location = 1) in vec3 in_Normal; layout(location = 2) in vec3 in_TexCoord; uniform mat4 Proj; uniform mat4 View; uniform samplerBuffer tbo_tex; layout(std430, binding = 3) readonly buffer hm { float heights[]; }; subroutine float SSBO_TBO(in int offset); subroutine (SSBO_TBO) float ssboValue(in int offset) { return heights[offset]; } subroutine (SSBO_TBO) float tboValue(in int offset) { return texelFetch(tbo_tex, offset).r; } subroutine (SSBO_TBO) float zeroValue(in int offset) { return 0.0; } subroutine uniform SSBO_TBO ssbo_tboSelector; out vec2 tc; void main(){ tc = in_TexCoord.st; vec4 p = vec4(in_Position.xyz,1.0); int offs = int(tc.x*1280.0+(tc.y*1280.0*1280.0)); p.y = ssbo_tboSelector(offs)*3.0-1.5; gl_Position = Proj*View*p; } ); |
Код универсальный, выбор функции осуществляется через шейдерные подпрограммы о которых я рассказывал в предыдущих статьях. Так как функция задается только один раз для всех вершин и этот вызов присутствует для всех трех техник, то это никак не влияет на fps.
Данные для TBO у нас передаются как samplerBuffer tbo_tex (строка 10), SSBO объявляется в строках 12-14. В обоих случаях шейдер ничего не знает о размерности буферов, так что их нам придется указать вручную. Я их указал явно в расчете смещения (строка 36).
Для чтения данных я объявил три подпрограммы - ssboValue, tboValue и zeroValue, между которыми мы и будем переключаться. Модификация высоты происходит в строке 38 за счет вызова соответствующей функции.
Прогнав тесты (исходные коды вы можете найти здесь) я обнаружил что отличия минимальны:
SSBO - 418 fps
TBO - 420 fps
Zero - 420 fps
Есть не существенная просадка фпс (целых 2 кадра) при использовании SSBO, но ею можно пренебречь. За счет использования TMU и prefetch выборка с использованием TBO получилась практически бесплатной. На этом можно было бы и завершить статью (или вообще не выкладывать), со словами "используйте что хотите", но в процессе разработки демо я слегка изменил код, нарушив порядок следования данных, каково же было мое удивление когда я увидел просадку по фпс у SSBO в 2.5 раза относительно TBO! Придется и с этим разобраться :)
Чтоб понять на сколько влияет случайная выборка я прикрутил к демо случайный выбор смещения, получилось примерно так:
Это изменение никак не повлияло на смену текстурных координат для zero-варианта, но одинаково снизило фпс до ~62 кадров, для TBO - 62.05 fps и SSBO 61.66 fps, что в 7 раз меньше предыдущих результатов, так что с произвольным доступом плохо в обоих случаях...
Но я на этом не остановился, решил провести еще пару тестов:
Здесь я оставил нетронутой координату Y, в обоих случаях это никак не повлияло на fps, чего и следовало ожидать, учитывая организацию данных в памяти и prefetch.
Второй эксперимент был более простым, я попытался добавить некоторый шаг к текстурным координатам, в начале х3, потом х10:
Тут я получил очень интересный результат, как видите со скриншота - для TBO фпс практически не изменился (-1,5 кадра), а вот для SSBO результат оказался плачевным - 57 фпс:
Так что не смотря на всю мою любовь к SSBO приходится признать что для произвольного последовательного доступа TBO все же предпочтительнее, возможно из-за того что эта нагрузка ложится на TMU, возможно из-за размера prefetch-буфера, он явно имеет предел, что показал тест с совсем случайным доступом, но при последовательном обращении оно отрабатывает на отлично.
Вот такие вот получились результаты...
Исходные коды проекта и фреймворка можно найти здесь:
https://github.com/karpenyuk/GL_Demos/tree/master/VTFvsSSBO
Непосредственно код примера здесь:
https://github.com/karpenyuk/GL_Demos/blob/master/VTFvsSSBO/demo0.inl
Комментариев нет:
Отправить комментарий