Як ЦП та графічний процесор взаємодіють у відображенні комп’ютерної графіки?


58

Тут ви можете побачити скріншот невеликої програми C ++ під назвою Triangle.exe з обертовим трикутником на основі API OpenGL.

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

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

Мені було просто цікаво і хотілося дізнатися весь процес від подвійного клацання по Triangle.exe під Windows XP до моменту, коли я можу побачити трикутник, що обертається на моніторі. Що відбувається, як взаємодіють процесор (який першим обробляє .exe) та GPU (який нарешті виводить трикутник на екран)?

Я думаю, що участь у відображенні цього обертового трикутника передусім є наступним обладнанням / програмним забезпеченням серед інших:

Обладнання

  • Жорсткий диск
  • Пам'ять системи (ОЗП)
  • ЦП
  • Відеопам'ять
  • GPU
  • РК-дисплей

Програмне забезпечення

  • Операційна система
  • DirectX / OpenGL API
  • Водій Nvidia

Хтось може пояснити процес, можливо, з якоюсь схемою потоку для ілюстрації?

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

Я впевнений, що багато людей, які навіть називали себе ІТ-професіоналами, не змогли описати цей процес правильно.


Ваша дилема буде закінчена, якщо ви можете просто розглянути GPU розширенням процесора!
KawaiKx

Відповіді:


55

Я вирішив трохи написати про аспект програмування та про те, як компоненти спілкуються один з одним. Можливо, воно проллє трохи світла на певні ділянки.

Презентація

Для чого потрібно мати навіть те єдине зображення, яке ви розмістили у своєму запитанні, на екрані?

Існує багато способів намалювати трикутник на екрані. Для простоти припустимо, що не використовувалися вершинні буфери. ( Буфер вершин - це область пам’яті, де ви зберігаєте координати.) Припустимо, програма просто повідомила конвеєр обробки графіки про кожну вершину (вершина - це лише координата в просторі) підряд.

Але , перш ніж ми зможемо що-небудь намалювати, спершу треба виконати ліси. Ми побачимо, чому пізніше:

// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

// Reset The Current Modelview Matrix
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity();

// Drawing Using Triangles
glBegin(GL_TRIANGLES);

  // Red
  glColor3f(1.0f,0.0f,0.0f);
  // Top Of Triangle (Front)
  glVertex3f( 0.0f, 1.0f, 0.0f);

  // Green
  glColor3f(0.0f,1.0f,0.0f);
  // Left Of Triangle (Front)
  glVertex3f(-1.0f,-1.0f, 1.0f);

  // Blue
  glColor3f(0.0f,0.0f,1.0f);
  // Right Of Triangle (Front)
  glVertex3f( 1.0f,-1.0f, 1.0f);

// Done Drawing
glEnd();

Так що це зробив?

Коли ви пишете програму, яка хоче використовувати відеокарту, зазвичай вибираєте драйвер якогось інтерфейсу. Деякі добре відомі інтерфейси для драйвера:

  • OpenGL
  • Direct3D
  • CUDA

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

Цей інтерфейс обов'язково надасть вам певні інструменти . Ці інструменти мають форму API, на який можна дзвонити зі своєї програми.

Цей API - це те, що ми бачимо як використаний у наведеному вище прикладі. Давайте докладніше розглянемо.

Ліси будівельні

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

Але ми не будемо дивитися ні на що з цього. Ми просто поглянемо на те, що вам доведеться робити кожен кадр . Подібно до:

Очищення екрана

Графічний конвеєр не збирається очищати екран для кожного кадру. Вам доведеться це сказати. Чому? Ось чому:

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

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

Трансформація

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

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

Далі застосовуємо нашу матрицю проекцій. Це переміщує всі координати, щоб вони стикалися з нашою камерою правильно.

Тепер ми ще раз перетворюємося за допомогою нашої матриці Viewport. Ми робимо це для масштабування нашої моделі під розмір нашого монітора. Тепер у нас є набір вершин, які готові винести!

Ми повернемося до трансформації трохи пізніше.

Малювання

Щоб намалювати трикутник, ми можемо просто сказати OpenGL почати новий список трикутників , зателефонувавши glBeginз GL_TRIANGLESконстантою.
Є й інші форми, які можна намалювати. Як трикутник або трикутник . Це в першу чергу оптимізація, оскільки вони вимагають меншої комунікації між процесором та графічним процесором, щоб намалювати однакову кількість трикутників.

Після цього ми можемо надати перелік множин з 3 вершин, які повинні складати кожен трикутник. Кожен трикутник використовує 3 координати (як у 3D-просторі). Крім того, я також надаю колір для кожної вершини, зателефонувавши glColor3f перед викликом glVertex3f.

Відтінок між 3 вершинами (3 кутами трикутника) обчислюється OpenGL автоматично . Це дозволить інтерполювати колір по всій грані багатокутника.

Взаємодія

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

Це стає набагато складніше, коли ви захочете розпочати взаємодію зі своєю 3D-сценою.

Спочатку ви повинні чітко знати, на який піксель користувач натиснув вікно. Потім, враховуючи свою точку зору , ви можете обчислити напрямок променя, починаючи з точки клацання миші на вашу сцену. Потім ви можете підрахувати, чи перетинається якийсь об’єкт у вашій сцені з цим променем . Тепер ви знаєте, чи користувач клацав об’єкт.

Отже, як змусити його обертатись?

Трансформація

Мені відомі два типи перетворень, які зазвичай застосовуються:

  • Перетворення на основі матриці
  • Перетворення на основі кісток

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

Приклад

Раніше ми завантажували свою матрицю ідентичності перед тим, як намалювати наш трикутник. Матриця ідентичності - це така, яка просто не забезпечує взагалі ніякої трансформації . Тож, що б я не малював, впливає лише моя перспектива. Отже, трикутник взагалі не буде обертатися.

Якщо я хочу повернути його зараз, я можу або зробити математику самостійно (на процесорі) і просто подзвонити glVertex3fз іншими координатами (які обертаються). Або я міг би дозволити GPU виконати всю роботу, зателефонувавши glRotatefперед малюванням:

// Rotate The Triangle On The Y axis
glRotatef(amount,0.0f,1.0f,0.0f);               

amountце, звичайно, лише фіксоване значення. Якщо ви хочете анімувати , вам доведеться відстежувати amountта збільшувати його кожен кадр.

Отже, зачекайте, що сталося з усіма розмовами про матрицю раніше?

У цьому простому прикладі нам не потрібно дбати про матриці. Ми просто дзвонимо, glRotatefі вона піклується про все, що для нас.

glRotateвиробляє обертання angleградусів навколо вектора xyz. Поточна матриця (див. GlMatrixMode ) множиться на матрицю обертання з продуктом, що замінює поточну матрицю, як ніби glMultMatrix викликається такою матрицею як її аргумент:

x 2 ⁡ 1 - c + cx ⁢ y ⁡ 1 - c - z ⁢ sx ⁢ z ⁡ 1 - c + y ⁢ s 0 y ⁢ x ⁡ 1 - c + z ⁢ sy 2 ⁡ 1 - c + cy ⁢ z ⁡ 1 - c - x ⁢ s 0 x ⁢ z ⁡ 1 - c - y ⁢ sy ⁢ z ⁡ 1 - c + x ⁢ sz 2 ⁡ 1 - c + c 0 0 0 0 1

Ну, дякую за це!

Висновок

Що стає очевидним - це багато розмов з OpenGL. Але це нам нічого не говорить . Де спілкування?

Єдине, що нам говорить OpenGL у цьому прикладі, це коли це зроблено . Кожна операція займе певну кількість часу. Деякі операції займають неймовірно багато часу, інші - неймовірно швидко.

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

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

Крім цього, ми можемо лише запитати OpenGL про можливості нашого графічного адаптера (максимальна роздільна здатність, максимум згладжування, максимальна глибина кольору ...).

Але ми також можемо заповнити текстуру пікселями, кожен з яких має певний колір. Кожен піксель, таким чином, має значення, а текстура - це гігантський "файл", наповнений даними. Ми можемо завантажити це у відеокарту (створивши буфер текстури), а потім завантажити шейдер , сказати цьому шейдеру використовувати нашу текстуру в якості вхідного даних та виконати кілька надзвичайно важких обчислень на нашому "файлі".

Потім ми можемо «перетворити» результат нашого обчислення (у вигляді нових кольорів) в нову текстуру.

Ось так ви можете змусити GPU працювати для вас іншими способами. Я припускаю, що CUDA працює аналогічно цьому аспекту, але я ніколи не мав можливості працювати з цим.

Ми дійсно лише трохи торкнулися всієї теми. 3D-графічне програмування - це пекло звіра.

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


38

Важко зрозуміти, що саме це ти не розумієш.

У графічному процесорі є серія регістрів, які відображає BIOS. Вони дозволяють процесору отримати доступ до пам’яті GPU і доручати GPU виконувати операції. ЦП підключає значення до цих регістрів, щоб відобразити частину пам’яті GPU, щоб CPU мав доступ до неї. Потім він завантажує інструкції в цю пам'ять. Потім він записує значення в регістр, який спонукає GPU виконувати інструкції, завантажені процесором у свою пам'ять.

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

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


1
Дякуємо за ваше пояснення. В основному те, що я не розумів, - це те, як набір інструкцій CPU спілкується з набором інструкцій GPU, але очевидно, що ця частина виконує цю драйвер. Це я мав на увазі під шарами абстракції.
JohnnyFromBF

2
Немає жодного набору інструкцій для процесора. Драйвер та час виконання компілюють ваші CUDA, OpenGL, Direct3D тощо у рідні програми / ядра GPU, які також завантажуються у пам'ять пристрою. Потім буфер команд відноситься до таких, як будь-який інший ресурс.
Axel Gneiting

2
Я не впевнений, на які програми ви посилаєтесь (які працюють на gpu і входять до драйверів). Gpu - це в основному апаратне забезпечення з фіксованою функцією, і єдині програми, які він буде запускати, - це шейдери, які надає додаток, а не драйвер. Драйвер лише компілює ці програми, а потім завантажує їх у пам'ять gpu.
Бен Річардс

1
@ sidran32: Наприклад, в архітектурі Kepler nVidia ядра, потоки та події створюються програмним забезпеченням, яке працює на графічному процесорі, а не (як правило) в процесорі. Програмне забезпечення на стороні GPU також управляє RDMA. Все це програмне забезпечення завантажується в пам'ять графічного процесора драйвером і працює як "mini-OS" на графічному процесорі, який обробляє GPU-сторону CPU / GPU співпрацюючої пари.
Девід Шварц

@DavidSchwartz Я забув про завдання обчислення GPU. Однак вони все одно поводяться схожі на шейдери, в реалізації все одно. Я б не назвав це "міні-ОС", оскільки він не має тієї ж функціональності, як правило, пов'язаної з ОС. Це все ще дуже спеціалізоване програмне забезпечення, оскільки GPU не розроблений як процесор (з поважних причин).
Бен Річардс

13

Мені було просто цікаво і хотілося дізнатися весь процес від подвійного клацання по Triangle.exe під Windows XP до моменту, коли я можу побачити трикутник, що обертається на моніторі. Що відбувається, як взаємодіють процесор (який першим обробляє .exe) та GPU (який нарешті виводить трикутник на екран)?

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

Який інтерфейс між процесором та графічним процесором?

Використовуючи драйвер , процесор може спілкуватися через такі функції материнської плати, як PCI, на графічну карту та надсилати до неї команди для виконання деяких інструкцій GPU, доступу / оновлення пам’яті GPU , завантаження коду, який потрібно виконати на GPU та багато іншого ...

Але ви не можете реально спілкуватися з обладнанням або драйвером з коду; тож це має відбуватися через такі API, як OpenGL, Direct3D, CUDA, HLSL, Cg. У той час як перші виконують інструкції GPU та / або оновлюють пам'ять GPU, останні фактично виконують код на GPU, оскільки вони є мовами фізики / шейдерів.

Чому запускати код на графічному процесорі, а не на процесорі?

Хоча процесор добре працює з нашими щоденними робочими станціями та серверними програмами, про всі ті блискучі графіки, які ви бачите в іграх цих днів, не надто багато думали. Ще в ті часи були програмні рендери, які зробили трюк з деяких 2D та 3D речей, але вони були дуже обмежуючими. Отже, ось де грає GPU.

Графічний процесор оптимізований для одного з найважливіших обчислень у графіці, матричного маніпулювання . Хоча процесору доводиться обчислювати кожне множення в маніпуляції матрицею по одному (пізніше такі речі, як 3DNow! І SSE наздогнали), GPU може робити всі ці множення відразу! Паралелізм.

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

Як ці інструкції GPU / пам'ять / код показують графіку?

Є один недолік, щоб змусити це все працювати, нам потрібно щось, що ми можемо написати, до чого потім зможемо прочитати та надіслати на екран. Ми можемо це зробити, створивши фреймбуфер . Яку б операцію ви не робили, ви з часом оновите пікселі у фреймбуфері; які крім розташування містять також інформацію про колір та глибину.

Наведемо приклад, де ви хотіли десь намалювати кровний спрайт (зображення); по-перше, сама текстура дерева завантажується в пам'ять GPU, що дозволяє легко перемалювати її за бажанням. Далі, щоб насправді намалювати спрайт кудись, ми можемо перекласти спрайт за допомогою вершин (поставивши його в потрібне положення), розширивши його (перетворивши його з 3D-об'єкта в пікселі) та оновивши фреймбуфер. Для кращого уявлення, ось схема запуску конвеєра OpenGL з Вікіпедії:

Це головна суть всієї графічної ідеї, більше дослідження - це домашнє завдання для читача.


7

Щоб все було просто, ми можемо описати це так. Деякі адреси пам'яті зарезервовано (за BIOS та / або операційною системою) не для оперативної пам'яті, а для відеокарти. Будь-які дані, записані на ці значення (покажчики), надходять на карту. Тож теоретично будь-яка програма може записувати безпосередньо на відеокарту, просто знаючи діапазон адрес, і саме так це було зроблено ще в старі часи. На практиці в сучасних ОС це управляє відеодрайвером та / або графічною бібліотекою зверху (DirectX, OpenGL тощо).


1
-1 він запитує, як виклик API DirectX з центрального процесора може спілкуватися з графічним процесором, а ваша відповідь - "ним керує драйвер та / або DirectX" ? Це також не пояснює, як можна запускати спеціальний код (ala CUDA).
BlueRaja - Danny Pflughoeft

3
будь ласка, навчись читати. Я сказав, записуючи на конкретні адреси пам'яті, які зарезервовані для GPU замість ОЗУ. І це пояснює, як можна все запустити. Діапазон пам'яті зареєстровано для картки. Все, що ви пишете в цьому діапазоні, спрямоване на обробку вершин GPU, CUDA, і все.
AZ.

5

Графічні процесори, як правило, керуються буферами DMA. Тобто, драйвер компілює команди, які він отримує від програми користувальницького простору, в потік інструкцій (перемикається стан, малює це таким чином, перемикає контексти тощо), які потім копіюються в пам'ять пристрою. Потім він доручає GPU виконувати цей буфер команд через регістр PCI або подібні методи.

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

На консолях ви навіть можете повеселитися робити все це самостійно, особливо на PS3.


0

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

Це на зразок оперативної пам'яті, де процесор зберігає речі, щоб він міг швидко завантажуватися та оброблятися. Обидва роблять ігри швидшими.

Або звукова карта чи чиста карта працюють за тим же принципом, тобто отримують дані та завантажують певну роботу процесора.


Це дублює іншу відповідь і не додає нового вмісту. Будь ласка, не публікуйте відповіді, якщо у вас насправді є щось нове.
DavidPostill

0

Я думаю, що op не впевнений, що саме процесор говорить графічній карті і чому графічні команди (наприклад, opengl або direct3d команди) не надсилаються безпосередньо в GPU.

Процесор просто говорить графічному процесору, що потрібно зробити. Всі інструкції спочатку проходять через центральний процесор, де вони отримують налаштування / ініціалізацію для GPU, щоб насправді зробити рендерінг.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.