Чи вважається зміна текстури (малювання на ній) "зміною стану"?


11

Конвенція в графіці полягає в тому, що проводити меншу кількість змін стану краще, ніж виконувати більші зміни стану (комутація шейдерів, зв'язування буферів, зв'язування текстур тощо). Для текстур швидше візуалізувати багато полігонів, використовуючи один атлас (для візуалізації спрайтів / тексту), ніж індивідуально прив’язувати нову текстуру для кожного багатокутника.

Чи це справедливо, якщо я постійно малюю текстуру через glTexSubImage2D? У мене надходить потік даних (через мережу), який піддається обробці і потім малюється до текстури один рядок. Дані представлені візуально в нескінченному сувій.

Чи краще мені малювати одну текстуру, зображену на одному великому прямокутнику (прокручування намальованих даних на вигляд)? Ідея тут полягає в тому, що я мав би будь-яку (або дві) текстури зв'язати в будь-який момент часу, поки я просто продовжую малювати її.

Або я повинен малювати багато маленьких прямокутників (розкриття прямокутника лише під час фарбування)? Я припускаю, що я зв'язав би одну текстуру на прямокутник.

Відповіді:


11

Оновлення області пам’яті в графічному пристрої (текстура, буфер тощо) не зовсім те саме, що зміна стану візуалізації.

Те, що робить зміну стану рендерингу дорогою, - це кількість роботи, яку повинен виконати водій, щоб перевірити новий стан (и) та змінити трубопровід. Це, швидше за все, також спричинить деяку синхронізацію між процесором та графічним пристроєм. Однак обсяг даних, переданих між пристроями, повинен бути малим для зміни стану (можливо, лише кілька команд).

З іншого боку, для оновлення текстури / буфера основна вартість лежить у самій передачі даних. Теоретично, якщо ви не читаєте дані текстури назад до центрального процесора після оновлення, не повинно бути затримок синхронізації та конвеєра. Однак слід розглянути ще один аспект: накладні витрати API. Навіть якщо обсяг даних, який ви надсилаєте на графічний пристрій, невеликий, якщо ви робите це досить часто, з часом вартість спілкування з драйвером / пристроєм стане більшою, ніж вартість передачі даних. Це ще одна причина, чому дозування настільки важлива при оптимізації рендерінгу.

Тож у вашому випадку найкращим підходом, як мені здається, було б зберегти копію текстури, що ви оновлюєте, коли ви надходите нові дані. Встановіть брудний прапор і консолідуйте якомога більше оновлень в одному glTexSubImageдля всієї текстури (або великої послідовної частини її). Ви також можете грати з об'єктами Pixel Buffer і намагатися робити асинхронну передачу даних, щоб максимально скоротити стояки конвеєра. Якщо ви можете реалізувати якусь подвійну буферизацію, тоді ви можете записати до однієї копії текстури, поки інша передається. Цей підручникдосліджує цей сценарій. Це мій інтуїтивний підхід, я б спробував зменшити кількість викликів API і "пакетно" оновити текстуру. Однак, це дуже спекулятивно, і вам доведеться профайлювати та порівнювати це з іншими підходами, як-от робити кілька невеликих оновлень, щоб точно знати, який є найефективнішим у вашому випадку використання.

В якості додаткового зауваження, ця презентація від NVidia також є актуальною і дає багато хороших розумінь: Наближення нульових драйверів накладних витрат у OpenGL .


5
Я не знаю напевно, але я б точно запідозрив, що glTexSubImage на текстурі, що була надана в останньому кадрі або двох, буде затримувати конвеєр, оскільки драйвери ПК часто намагаються запамповувати кадр або два, і це мало ймовірно щоб зробити копії цілих текстур через крихітне оновлення. Тому я б очікував, що для максимальної продуктивності потрібно буде подвійне або потрійне буферування текстур (або піксельних буферних об'єктів).
Джон Калсбек
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.