tgoop.com/unity_cg/76093
Last Update:
Регистровый файл - это просто кусок памяти, особенность которого, что он распаян прямо на ядре и доступ к данным в нём буквально мгновенный.
У нас в этом файле лежат данные тредов, всех этих 32х32 пикселей. С оффсетом 32.
Если застряли на первых 32 ячейках, просто прыгни на вторые 32 ячейки и обработай инструкции для них.
(да, в реальности всё сложнее, помимо данных у нас ещё хранится стэк вызова - т.е. номер инструкции, да и ячеек может быть занято куда больше чем одна на тред - об этом чуть позже). Переключение варпов - по сути - мгновенное, ничего не стоит. И пока у нас текстурный модуль застрял на чтении текстур, мы пропрыгаем по всем варпам и посчитаем математику для всех.
В итоге, вот эти "один считаем, 31 в уме" варпы позволяют нам маскировать задержки, добиваясь того, чтобы все физические юниты были задействованы на полную мощь и шейдер выполнялся так быстро, как это только возможно.
Скажем, мы вернулись к первому варпу и обнаружили, что читки закончились а текстурный юнит трудится уже на втором варпе. Тогда делаем алу для первого варпа и.... оп. А текстурный юнит для второго варпа ещё не отработал.
Такую ситуацию мы называем "stall on texture fetches" - и теперь ALU стоят и ждут пока текстурный юнит отработает. Если написать шейдер иначе, то можно от этого избавиться, но это тема для целой отдельной статьи.
Но это тоже не худшее, что может случиться.
Помните, я упоминал, что у нас 8192 байта в регистрах на ядро?
Допустим, у нас каждый тред занимает float2 (uv) + half4(цвет), тогда у нас float4 = 16 байт на тред. Значит у нас максимум может быть 8192 / 16 = 512 тредов нанято. А это всего 16 (512/32) варпов! Из максимальных - 32.
Тогда мы говорим что у нас occupancy = 16 / 32 = 50%. При нормальных условиях она должна быть от 50% до 100%. Если занятость меньше 50, то это грозит "проливкой регистров" - stack spilling, чаща регистров переполнена и она проливается в L1 кэш. А читать из L1 кэша намноооооого дольше, чем из регистров!
А если шейдер написан иначе и у нас считаются сначала uv1, uv2, uv3 и uv4 для разных читок? Мы же не можем использовать один регистр для них всех, нам они нужны "раздельно", чтобы использовать для чтения текстуры. Тогда придется держать одновременно float2 + float2 + float2+ float2 + half4 = 40 байт! А это ещё больше занимает регистров и значит ещё меньше варпов можно нанять и стэк может пролиться.
TLDR;
Регистров надо использовать меньше, а код шейдера писать так, чтобы разные юниты (ALU, SFU, TU, и пр) не заставляли остальных ждать себя.
BY WellMOR in Unity CG Tech
Share with your friend now:
tgoop.com/unity_cg/76093