Розширення

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

ARB_fragment_program

Повернемося в 2002 рік, GPU ще не мають вершинних та фрагментних шейдерів - все було зашито в мікросхеми. Це називалося Fixed-Function Pipeline (FFP) - «пайплайн» з фіксованими функціями. Таким чином, сама свіжа версія API, а це була OpenGL 1.3 не пропонувала нічого, що можна було назвати чи використовувати як шейдери, тому що вони ще не існували. Але в NVIDIA вирішили, що це було би дуже зручно описувати процес рендеру за допомогою коду, а не сотнями змінних та прапорців, що описують стан системи. Ось чому було створено ARB_fragment_program. Так, тоді не існувало GLSL, але вже можна було писати так:

!!ARBfp1.0 MOV result.color, fragment.color; END

Але що б заставити OpenGL використовувати такий код, нам потрібні спеціальні функції, яких ще не існувало в OpenGL. Але перед поясненнями, розглянемо ще один приклад.

ARB_debug_output

Гаразд, але ARB_fragment_program дуже стара штука, напевне нам вона більше не потрібна? Добре, але у нас є інші розширення, які бувають дуже зручні. Наприклад ARB_debug_output, яке додає функціональність, якої немає в OpenGL 3.3, але Ви маєте змогу використовувати його. Це розширення додає такі «токени» як GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB чи GL_DEBUG_SEVERITY_MEDIUM_ARB, та функції, наприклад DebugMessageCallbackARB. Чудова особливість цієї функції в тому, що якщо Ви напишете не зовсім коректний код, наприклад:

glEnable(GL_TEXTURE); // Помилка ! Скоріш за все Вам потрібен GL_TEXTURE_2D !

Ви отримаєте повідомлення про помилку та точні координати проблеми. Уроки вивчено:

  • Розширення все ще корисні, навіть в свіжому, 3.3 OpenGL
  • Використовуйте ARB_debug_output ! Дивіться посилання нижче.

Отримання розширень - складний спосіб

“Ручний спосіб” перевірки, чи доступне розширення полягає в використанні наступного шматка коду (взято з OpenGL.org wiki):

int NumberOfExtensions;
glGetIntegerv(GL_NUM_EXTENSIONS, &NumberOfExtensions);
for(i=0; i<NumberOfExtensions; i++) {
  const GLubyte *ccc=glGetStringi(GL_EXTENSIONS, i);
  if ( strcmp(ccc, (const GLubyte *)"GL_ARB_debug_output") == 0 ){
    // Це розширення доступно на нашій відеокарті та драйвері
    // Спробуємо отримати функцію "glDebugMessageCallbackARB" :
    glDebugMessageCallbackARB  = (PFNGLDEBUGMESSAGECALLBACKARBPROC) wglGetProcAddress("glDebugMessageCallbackARB");
  }
}

Отримання всіх розширень - простий спосіб

Отримати все і одразу достатньо складно. Такі бібліотеки як GLEW, GLee, gl3w спрощують нашу задачу. Наприклад, якщо Ви використовуєте GLEW, то достатньо просто додати виклик glewInit() після створення Вашого вікна і зручні змінні будуть створені:

if (GLEW_ARB_debug_output){ // Та-дам ! }

(слово обережності : debug_output є спеціальним, тому що Ви повинні дозволити це при створенні контексту. В GLFW це можна зробити за допомогою glfwOpenWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1);)

ARB чи EXT чи …

Ім’я кожного розширення містить інформацію про його доступність:

  • GL_ : всі платформи;
  • GLX_ : тільки Linux та Mac (X11);
  • WGL_ : тільки Windows

  • EXT : загальне розширення.
  • ARB : це розширення було затверджено всіма членами OpenGL Architecture Review Board (зазвичай розширення з префіксом EXT стають ARB через якийсь час).
  • NV/AMD/INTEL : Самі говорять за себе =)

Проектування з розширеннями

Проблема

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

Ви отримаєте наступний код :

if ( GLEW_NV_path_rendering ){
    glPathStringNV( ... ); // Малюємо фігуру, це просто !
}else{
    // А інакше ? Вам все ще потрібно намалювати це
    // на старих NVIDIA картах, на AMD та на INTEL !
    // І Вам потрібно буде це все написати !
}

Вибір ліміту

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

Наприклад, Braid (2D гра, де можна подорожувати в часі) містить безліч еффектів зі скручування зображення, коли Ви граєтесь з часом, але вони не працють на старих відеократах.

З OpenGL 3.3 та вище Ви вже маєте 99% інструментів які би Ви хотіли мати. Певні розширення можуть бути дуже корисними, наприклад GL_AMD_pinned_memory, але це часто не так, як наявність GL_ARB_framebuffer_object декілька років тому (використовується для рендера в текстуру) робила Вашу гру в 10 разів краще.

Якщо Ви маєте підтримувати старе залізо і OpenGL 3+ для Вас не доступне, то Вам потрібно використовувати другу версію. І Ви не можете надіятись, що всі ці чудові розширення Вам доступні і Вам доведеться з цим справитись.

Для подальшого вивчення, можете перейти за посиланням OpenGL 2.1 версія туторіала 14 - рендер в текстуру, рядок 167, де я вручну перевіряю наявність GL_ARB_framebuffer_object. Також подивіться сюди FAQ.

Висновок

Розширення OpenGL надають чудову можливість розширити можливості OpenGL на основі можливостей відеокарти.

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

Що ще почитати