Процесор - потік даних пам'яті GPU [закрито]


16

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

  • Чи надсилаються його дані в пам'ять GPU лише один раз і сидять там назавжди?
  • Коли модель фактично візуалізується кожен кадр, чи повинні процесори GPU кожного разу отримувати його дані з пам'яті GPU? Що я маю на увазі - якщо б у мене було дві моделі, відображені кілька разів у кожній - було б важливо, якщо я першу зробив кілька разів, а потім другу кілька разів, чи першу я створив лише один раз, другу - один раз і продовжували переплутати це так? Я можу назвати це питання "внутрішнім потоком даних GPU" у цьому сенсі.
  • Очевидно, що відеокарти мають обмежену оперативну пам’ять - коли вона не може вмістити всі дані моделі, необхідні для візуалізації 1 кадру, я думаю, вона зберігає (деякі) це з оперативної пам'яті процесора кожного кадру, це правильно?

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

Редагувати: я забув зробити одне розрізнення: там надсилаються дані в GPU і є налаштування / прив'язка буферів як поточних . Чи викликає останній потік даних?

Edit2: Прочитавши публікацію Raxvan, я хотів би виділити кілька дій:

  • створення буфера з ініціалізацією (як він сказав, я можу зберігати дані або в операційному процесорі, або в одному з GPU)
  • оновлення буферних даних (що, на мою думку, є простим, коли дані зберігаються в операційному процесорі та вимагає отримання від GPU до оперативної пам'яті процесора (а потім назад), коли вони зберігаються в операційній пам'яті GPU)
  • прив'язування буфера до активного (чи це просто спосіб сказати API, що я хочу, щоб цей буфер був наданий під час наступного виклику розіграшу, і він нічого не робить сам по собі ?)
  • API дзвінка (тут я хотів би почути від вас, що насправді відбувається там)

Я не є експертом будь-якими способами, але якщо ви використовуєте сучасний (тобто не безпосередній) OpenGL з VAO та VBO, то дані надсилаються до GPU і зберігаються у VRAM, коли ви використовуєте одну з команд glBuffer, що належить до сімейства команд. Потім, кожного разу, коли ви малюєте, відповідні вершини виймаються з VRAM та надаються. Якщо це модель, яка рухається, ви, як правило, зберігаєте її статично і використовуєте матриці для переходу з простору моделі до простору світу / камери. Щодо останнього пункту, я не маю уявлення, що станеться, якщо у вас закінчиться оперативна пам’ять. Я здогадуюсь, що якщо у вас закінчується VRAM, дані просто не надсилаються, можливо, з кодом помилки.
Полярний

@Polar - не зовсім так. GL фактично не вказує, в якій пам'яті зберігається буферний об’єкт, і навіть вільно переміщати його під час виконання на основі схеми використання. GL4.4 дещо вирішує це, але зазначає, що врешті найкраще, що він може надати, - це "одна з тих дурних натякових речей"; дивіться opengl.org/registry/specs/ARB/buffer_storage.txt та особливо випуски 2 та 9.
Максим Мінімус

1
@JimmyShelter А, дякую - було б добре, якби у нас було менше "тих дурних натякових речей" і більш конкретної специфікації.
Полярний

@Polar - що дратує те, що ARB_buffer_storage міг уникнути ще одного натяку, але дизайнери пропустили таку можливість. Ну добре, можливо, 4,5 нарешті вийде правильно.
Максим Мінімус

2
Не редагуйте свої запитання, щоб "відповідати" на відповіді. Замість цього поставте нове запитання.

Відповіді:


12

Чи надсилаються його дані в пам'ять GPU лише один раз і сидять там назавжди?

Зазвичай так, але драйвер вільний робити те, що є «оптимальним», дані можуть зберігатися у VRAM або RAM або просто кешуватися тут - це передсердя, який пояснює, що насправді відбувається з потоком VBO .

Наприклад, якщо він позначений як динамічний буфер openGL (наприклад, VBO), він швидше зберігається в оперативній пам'яті. GPU використовує прямий доступ до пам'яті (DMA) для доступу до оперативної пам'яті безпосередньо без втручання процесора. Це контролюється контролером DMA в графічній карті та графічному драйвері і виконується в режимі ядра.

Коли модель фактично візуалізується кожен кадр, чи повинні процесори GPU кожного разу отримувати його дані з пам'яті GPU, навіть якщо модель рендерує кілька послідовних разів?

Так само, як і процесори, GPU дозволено повторно замовляти інструкції GPU та операції доступу до пам'яті (читати: поза виконанням замовлення ), тому, швидше за все, GPU буде обробляти сценарій, який ви згадали, отримуючи доступ до пам’яті, що знаходиться в його кеш-пам'яті (як правило, це доступ недавно ), але іноді це не вдається зробити.

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

Ви не хочете, щоб це сталося. Але незалежно від того, якщо це станеться, GPU почне переміщувати пам’ять між оперативною пам’яттю та VRAM (командний процесор в GPU відповідає за це), що зробить візуалізацію набагато повільніше, що призведе до того, що GPU зупиниться, тому що потрібно буде чекати даних копіювати з / в V / ОЗУ.

Там надсилаються дані в GPU і там налаштовують / прив'язують буфери як поточні. Чи викликає останній потік даних?

Графічні процесори містять буфер команд , і всі команди API підпорядковані цьому буфері, зауважте, що це може статися одночасно з даними, скопійованими в GPU. Команда кільцевої буфер черги зв'язку між CPU і GPU , будь-яка команда , яка повинна бути виконана потреби , які будуть представлені в чергу , щоб він міг бути execulated ГПУ. Як і будь-яка операція, що прив'язує нові буфери, потрібно подати в gpu, щоб він мав доступ до деякого місця пам'яті.

Це одна з причин того, що glBegin / glEnd був застарілим, для подання нових команд потрібна синхронізація черги (використовуючи огорожі / бар'єри пам'яті).

введіть тут опис зображення

Щодо інших ваших моментів:

Створення буфера з ініціалізацією

Ви можете виділити буфер без ініціалізації та зберегти його для подальшого використання. Або ви можете виділити його буфером і одночасно скопіювати дані (мова про рівень API).

оновлення даних буфера

Ви можете використовувати glMapBuffer для оновлення пам'яті на стороні GPU. чи буде копіюватися пам'ять з / в оперативну пам’ять, насправді не є стандартним стандартом і сильно відрізнятиметься в залежності від постачальника, типу GPU та драйвера.

API дзвінка (тут я хотів би почути від вас, що там насправді відбувається).

Мій другий пункт головного питання охоплює це.

прив'язування буфера до активного (чи це просто спосіб сказати API, що я хочу, щоб цей буфер> був виведений під час наступного виклику розіграшу, і він сам нічого не робить?)

Подумайте про прив'язку як використання thisвказівника на будь-якій об'єктно-орієнтованій мові, хоча це не суворо однаково, будь-які послідовні виклики API будуть стосуватися цього буфера зв’язування.


3

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

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

другий момент : У візуалізації є багато хитрощів, але головний спосіб зробити це з багатокутниками. На кадрі gpu візуалізує об'єкти, виготовлені з багатокутників, один за одним і після закінчення цього графічний процесор відправить зображення на дисплей. Такого поняття, як об'єкти, немає, є просто багатокутники, і спосіб їх складання створить образ. завдання GPU полягає в проектуванні цих полігонів від 3d до 2d і застосуванні ефекту (за бажанням). Полігони йдуть лише через CPU-> GPU-> SCREEN або GPU-> SCREEN безпосередньо (якщо полігони вже є в операційній пам’яті GPU)

третій момент : Якщо ви створюєте анімацію, наприклад, краще зберігати дані близько до процесора, оскільки там він робить важкий підйом, не було б оптимальним зберігати дані в GPU, переміщувати їх до процесора та повертати кожен кадр. Існує маса інших прикладів, таких як цей, для підрахунку, але загалом усі дані залишатимуться близько до тих, хто проводить обчислення. Зазвичай ви хочете перемістити якомога більше даних до оперативної пам’яті GPU, щоб отримати ефективність.

Фактичне надсилання даних у gpu здійснюється API, який ви використовуєте (directx / opengl чи інший), а концепція прив'язки та подібних матеріалів - це лише абстракції, щоб API зрозумів, що ви хочете зробити.

Змінити для редагування:

  • buffer creation with initialisation: це як різниця між int a = new int[10]і a[0] = 0,a[1] = 1.... etc коли ви створюєте буфер, ви створюєте місце для даних і коли ви вводите дані, ви поміщаєте туди потрібні речі.

  • buffer data updateякщо це на операційному процесорі, то у вас є vertex * verticesте, що ви можете грати з ним, якщо його немає, вам доведеться перемістити його з GPU vertex * vertices = map(buffer_id);(карта - міфологічна функція, яка повинна переміщувати дані з GPU в процесорний баран, вона також має опозицію buffer_id = create_buffer(vertices);

  • binding the buffer as activeце просто концепція, яку вони називають bindingвізуалізацією, це складний процес і це як виклик функції з 10000 параметрами. Зв'язування - це лише термін, який вони використовували для того, щоб сказати, який буфер куди йде. Немає справжньої магії за цим терміном, він не перетворює, не переміщує і не перерозподіляє буфери, просто повідомляє драйверу, що при наступному виклику розіграшу використовувати цей буфер.

  • API draw callЗрештою, буфери для прив'язки та налаштування - це місце, де гума зустрічається з дорогою. Виклик жеребкування візьме всі дані (або ідентифікатори, які вказують на дані), які ви вказали, надішле їх до GPU (якщо потрібно) і скаже GPU, щоб почати стискати цифри. Це не зовсім вірно, що на всіх платформах є багато відмінностей, але для простоти речей малюнок підкаже графічному процесору .... малювати.


2

Найправильніша відповідь - це залежить від того, як ви її запрограмуєте, але це непогано потурбуватися. У той час як GPU стали неймовірно швидкими, пропускна здатність до та від GPU RAM не є, і буде вашим найприємнішим вузьким місцем.

Чи надсилаються його дані в пам'ять GPU лише один раз і сидять там назавжди?

Сподіваюсь, так. Для швидкості візуалізації ви хочете якомога більше даних сидіти на графічному процесорі, замість того, щоб повторно надсилати їх кожен кадр. VBO служать саме цій цілі. Існують як статичні, так і динамічні VBO, перші найкращі для статичних моделей, а другі найкращі для моделей, вершини яких змінять кожен кадр (скажімо, система частинок). Навіть якщо мова йде про динамічні VBO, то ви не хочете повторно відправляти всі вершини кожного кадру; тільки ті, що змінюються.

У випадку вашої будівлі дані вершини просто сидітимуть там, і єдине, що змінюється - це ваші матриці (модель / світ, проекція та вид).

Що стосується системи частинок, я зробив динамічний VBO досить великий, щоб зберігати максимальну кількість частинок, які коли-небудь існуватимуть для цієї системи. Кожен кадр я надсилаю дані для частинок, що випромінювали цей кадр, разом із паровою формою, і це все. Коли я малюю, я можу вказати початкову та кінцеву точку в цьому VBO, тому мені не потрібно видаляти дані про частинки. Я можу сказати, що не малюйте.

Коли модель фактично візуалізується кожен кадр, чи повинні процесори GPU кожного разу отримувати його дані з пам'яті GPU? Що я маю на увазі - якщо б у мене було дві моделі, відображені кілька разів у кожній - було б важливо, якщо я першу зробив кілька разів, а потім другу кілька разів, чи першу я створив лише один раз, другу - один раз і продовжували переплутати це так?

Дія надсилання декількох розіграшів замість одного лише набагато більша межа. Перевірте інстальовану візуалізацію; це може допомогти вам багато чого і зробити відповідь на це питання марною. У мене були деякі проблеми з драйверами, які я ще не розробив, але якщо ви можете працювати, тоді проблема вирішена.

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

Ви не хочете, щоб не вистачало пам’яті GPU. Якщо ви це зробите, то змініть речі, щоб цього не зробити. За самим гіпотетичним сценарієм, який у вас закінчується, він, мабуть, зазнає краху, але я ніколи не бачив, щоб це сталося, я, чесно кажучи, не знаю.

Я забув зробити одне розрізнення: там надсилаються дані в GPU і є налаштування / прив'язка буферів як поточних. Чи викликає останній потік даних?

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

створення буфера з ініціалізацією

Відповідь Раксвана звучить добре, але це не зовсім точно. У OpenGL створення буфера не залишає місця. Якщо ви хочете зарезервувати місце, не передаючи жодних даних, ви можете зателефонувати на glBufferData і просто пропустити null. (Див. Розділ приміток тут .)

оновлення даних буфера

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

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

Так, але це може зробити трохи більше, ніж це. Наприклад, якщо ви прив'язуєте VAO (об'єкт вершинного масиву), то прив'язуєте VBO, що VBO стає прив’язаним до VAO. Пізніше, якщо ви знову зв’яжете це VAO і зателефонуєте glDrawArrays, він буде знати, що VBO малювати.

Зауважте, що хоча у багатьох навчальних посібниках буде створено VAO для кожного VBO, мені сказали, що це не їх призначення. Нібито ви повинні створити один VAO і використовувати його для кожного VBO, який має однакові атрибути. Я ще цього не пробував, тому не можу точно сказати, чи краще, чи гірше.

API виклику

Що тут відбувається досить просто (з нашої точки зору). Скажімо, ви зв’язуєте VAO, а потім викликаєте glDrawArrays. Ви вказуєте початкову точку і кількість, і вона запускає вашу вершинну шейдер для кожної вершини в цьому діапазоні, яка, в свою чергу, передає свої результати вниз по лінії. Цей весь процес є ще одним власним нарисом.


"Тоді проблема вирішена" Так, інстанція допоможе дуже багато, але без неї мені все одно доведеться робити дзвінок для кожного об'єкта. В обох випадках однаковий амут. Тож мені цікаво, чи має значення порядок.
NPS

@NPS - Це має значення деякі . Якщо вони замовлені, тож вам не доведеться продовжувати перемикати прив’язки, так, ймовірно, це буде швидше мінусової суми. Але якщо вам доведеться вийти зі свого шляху, щоб сортувати їх, це, мабуть, буде набагато дорожче. Занадто багато змінних, залежних від вашої реалізації, щоб сказати набагато більше, ніж це.
Льодяний дефанс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.