
Як процесор і графічний процесор взаємодіють для візуалізації комп'ютерної графіки?
Центральний процесор (CPU) і графічний процесор (GPU) вашого комп'ютера взаємодіють щоразу, коли ви використовуєте комп'ютер, щоб надати вам чіткий і чуйний візуальний інтерфейс. Читайте далі, щоб краще зрозуміти, як вони працюють разом.
Фото від sskennel.
Сьогоднішня сесія Питань і Відповідей приходить до нас завдяки SuperUser - підрозділу Stack Exchange, що об'єднує спільноти веб-сайтів питань і відповідей.
Питання
Читач SuperUser Сатья поставив запитання:
Тут ви можете побачити скріншот невеликої програми на C++ під назвою Triangle.exe з обертовим трикутником на основі OpenGL API.
За загальним визнанням дуже простий приклад, але я думаю, що це стосується інших операцій з графічними картами.
Мені було просто цікаво, і я хотів дізнатися весь процес від подвійного клацання на Triangle.exe під Windows XP, поки не зможу побачити трикутник на моніторі. Що відбувається, як взаємодіють процесор (який спочатку обробляєт.exe) і графічний процесор (який, нарешті, виводить трикутник на екран)?
Я вважаю, що для відображення цього обертового трикутника в першу чергу використовується наступне апаратне/програмне забезпечення:
апаратні засоби
- жорсткий диск
- Системна пам'ять (RAM)
- Процесор
- Відеопамять
- GPU
- ЖК дисплей
Програмне забезпечення
- Операційна система
- DirectX / OpenGL API
- Nvidia Driver
Може хтось пояснити процес, може бути, з якийсь блок-схем для ілюстрації?
Це не повинно бути складне пояснення, яке охоплює кожен окремий крок (припустимо, що воно виходить за рамки), а пояснення, за яким може слідувати фахівець з ІТ.
Я впевнений, що багато людей, які навіть називають себе ІТ-фахівцями, не могли правильно описати цей процес.
Відповідь
Хоча кілька членів спільноти відповіли на запитання, Олівер Зальцбург пройшов зайву милю і відповів на неї не тільки детальною відповіддю, а й чудовою супровідною графікою.
Зображення JasonC, доступне як шпалери тут.
Він пише:
Я вирішив написати трохи про програмний аспект і про те, як компоненти взаємодіють один з одним. Можливо, це допоможе пролити світло на деякі області.
Презентація
Що потрібно, щоб намалювати на екрані те єдине зображення, яке ви розмістили в своєму питанні?
Є багато способів намалювати трикутник на екрані. Для простоти припустимо, що буфери вершин не використовувалися. (Буфер вершин - це область пам'яті, в якій зберігаються координати.) Припустимо, що програма просто повідомила конвеєру графічної обробки про кожну окрему вершину (вершина - це просто координата в просторі) в рядку.
Але перш ніж ми зможемо щось намалювати, ми повинні спочатку запустити деякі будівельні ліси. Ми побачимо чому пізніше:
// 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 виробляє обертання an^ градусів навколо вектора xyz. Поточна матриця (див. GlMatrixMode) множиться на матрицю обертання з продуктом, що замінює поточну матрицю, як якщо б glMultMatrix викликався з наступною матрицею як аргумент:
x 2 1 — c + cx y z 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 буде настільки швидкою, що я навіть не знаю, як це висловити. Відправка тисяч вершин з ЦП в ДП, кожен окремий кадр, швидше за все, не проблема.
Очищення екрана може зайняти мілісекунду або навіть гірше (майте на увазі, що у вас зазвичай є тільки близько 16 мілісекунд часу для промальовки кожного кадру), залежно від розміру вашого вікна перегляду. Щоб очистити його, OpenGL повинен намалювати кожен піксель у колір, який ви хочете очистити, це може бути мільйони пікселів.
Крім цього, ми можемо тільки запитати OpenGL про можливості нашого графічного адаптера (максимальна роздільна здатність, максимальне згладжування, максимальна глибина кольору тощо).
Але ми також можемо заповнити текстуру пікселями, кожен з яких має певний колір. Таким чином, кожен піксель містить значення, а текстура являє собою гігантський «файл», заповнений даними. Ми можемо завантажити це в графічну карту (створивши текстурний буфер), потім завантажити шейдер, сказати цьому шейдеру використовувати нашу текстуру в якості вхідних даних і виконати деякі надзвичайно важкі обчислення для нашого «файлу».
Потім ми можемо «візуалізувати» результат нашого обчислення (у вигляді нових кольорів) в нову текстуру.
Ось як ви можете змусити працювати графічний процесор іншими способами. Я припускаю, що CUDA працює аналогічно цьому аспекту, але у мене ніколи не було можливості працювати з ним.
Ми дійсно лише трохи торкнулися всієї теми. Програмування 3D-графіки - пекельне чудовисько.
Є що додати до пояснення? Звук вимкнено у коментарях. Хочете дізнатися більше відповідей від інших досвідчених користувачів Stack Exchange? Ознайомтеся з повною гілкою обговорення тут.