Техническое примечание TN2080

Понимание и обнаружение функциональности OpenGL

Это Техническое примечание обсуждает функциональность OpenGL, как API разработан и как разработчики могут обнаружить и получить доступ к полномочиям средства рендеринга программного обеспечения или аппаратных средств. Это запускается путем описания подразделения между базовой и расширенной функциональностью и тестом, который может использоваться для нахождения определенных функций. Продолжает описания различных версий OpenGL. Наконец, приходит к заключению с полным примером кода, что клиенты могут использовать, чтобы гарантировать, что они должным образом отслеживают и масштабируются к полному набору функций выбранного средства рендеринга.

Введение
Базовый OpenGL API
Нахождение OpenGL версия API
Расширения OpenGL
Проверка расширения OpenGL
Изменения базовой функциональности OpenGL на версию API
Нахождение допустимого средства рендеринга для проверки функциональности
Обнаружение Функциональности с glCheck
Исходный код glCheck
История версии документа

Введение

Команды OpenGL могут быть разделены на две области, базовый API и расширения. OpenGL разработан с этим в памяти и даже если определенная команда не находится в основной спецификации, можно использовать поддерживаемое расширение для доступа к желаемой возможности. Напротив, другой 3D APIs может включать более многочисленную группу функций в их ядре, но это не гарантия поддержки GPU. Использование тех функций требует дополнительной проверки поддержки оборудования, чтобы один конец с нежелательной производительностью для команд, не имеющих поддержки оборудования в целевой системе. OpenGL гарантирует, что, если расширение будет поддерживаться в строке расширений OpenGL или через базовый API для определенного средства рендеринга, то, полную функциональность которого определенное расширение предоставлено. При взгляде на то, какая функциональность присутствует в определенной реализации, приложение должно сначала смотреть на базовую версию API для текущего средства рендеринга, затем смотреть на строку расширений..

Базовый OpenGL API

OpenGL API внутренне поддерживает определенную базовую функциональность на основе версии API. Категорическая ссылка для определенной версии является спецификацией API OpenGL, которая может быть найдена в странице спецификаций OpenGL opengl.org веб-сайта. Документация команды может также быть найдена на страницах «человека» Mac OS X и на книге «OpenGL Reference Manual».

Нахождение OpenGL версия API

OpenGL номер версии API может быть определен с помощью glGetString (GL_VERSION). Версия API основывается на возможностях средства рендеринга и является переменной на средство рендеринга. Также стоит отметить, что эта команда допустима только после того, как контекст рендеринга установлен и подключен к устройству путем присоединения drawable, потому что средство рендеринга иначе в детерминанте.

Строка версии возвращается в определенном формате с информацией об основной и вспомогательной версии, сначала сопровождаемой поставщиком определенная информация (см., что спецификация OpenGL разделяет 6.1.11). На практике требуемое пространство между этими полями может не присутствовать до Mac OS X 10.1, таким образом, разработчики должны проверить на начальную букву, числовую сопровождаемый периодом и второй числовой. Перечисление 1 показывает чтение и чистит строку версии в этой проверке случая OpenGL 1.2 или более позднюю версию API. Этот код предполагает, что контекст установлен и присоединен к drawable на рассматриваемом средстве рендеринга (это требование сохраняется для всех gl... функции).

Перечисление 1  , Находящее версию текущего средства рендеринга

#include <OpenGL/gl.h>

// get version string pointer
enum { kShortVersionLength = 32 }; // more than enough to hold the version
const GLubyte * strVersion = glGetString(GL_VERSION); // get version string
// get just the non-vendor specific part of version string
GLubyte strShortVersion [kShortVersionLength];
short i = 0;
bool fOpenGL12plus = false;
while ((((strVersion[i] <= '9') && (strVersion[i] >= '0')) ||
         (strVersion[i] == '.')) && (i < kShortVersionLength))
{ // get only basic version info (until first space or not 1-9 or .)
    strShortVersion [i] = strVersion[i];
    i++;
}
strShortVersion [i] = 0; //truncate string
// if we are not version 1.0 or 1.1 then must be 1.2 or later
if (!strstr ((const char *) strShortVersion, "1.0") &&
    !strstr ((const char *) strShortVersion, "1.1"))
    fOpenGL12plus = true;

Как только основная и вспомогательная версия убеждена, что можно искать расширенную функциональность. OpenGL предоставляет дополнительный механизм разработчикам для доступа к функциональности вне который основная спецификация посредством расширений. Немного фона на дополнительном процессе полезно в понимании проекта и функциональности и перекрытия расширений.

Расширения OpenGL

Как OpenGL расширяется API, новая функциональность обычно предоставлена посредством расширений. Они могут быть поставщиком, определенным, разных производителей, или утвержденный Architecture Review Board (ARB). Источник для получения информации о расширениях является снова страницей расширений OpenGL opengl.org веб-сайта с определенными дополнительными описаниями в Реестре Расширений OpenGL SGI. Все расширения Mac OS X детализированы в нашем руководстве по расширениям OpenGL. Обычно, расширения имеют тенденцию запускать жизнь как поставщика, определенного или разных производителей и затем перемещаться в принятие ARB или разных производителей и возможное включение в базовую спецификацию. Это не требуется, но просто продуктом инноваций и прямого прогресса с кросс-платформенным API.

Из-за этого пути принятия больше чем одно расширение может покрыть ту же основную функциональность, и средства рендеринга могут поддерживать один или больше расширений интереса. Может быть расширение ARB с той же или схожей функциональностью как поставщик определенное расширение и, как эта функциональность становится более повсеместной, это может быть перемещено в базовый OpenGL API OpenGL ARB. Как отмечено ранее, разработчики должны проверить на функциональность, желаемую и как часть базового API и как расширение, включая проверку все расширения, покрывающие желаемую функциональность. Примером этого являются операции объединителя среды текстуры, которые могут поддерживаться любой через GL_ARB_texture_env_combine или GL_EXT_texture_env_combine расширение или в ядре OpenGL 1.3, все из которых имеют очень схожую функциональность, но могут использовать различную команду и постоянный синтаксис. Так, если версия API средства рендеринга не поддерживает желаемую функциональность, исследует строку расширений, предоставленную средством рендеринга для определенного дополнительного имени, представляющего желаемую функциональность.

Наконец, в то время как существуют различные методы, которые должны быть проверены для проверки определенной функциональности, OpenGL должен продолжать экспортировать строки имени способствовавших расширений в строке расширений и продолжать поддерживать предыдущие версии расширений, экспортированных в ранних версиях Mac OS X. Таким образом никакое расширение никогда не должно удаляться из строки расширений. Это гарантирует, что разработчики в состоянии проверка на функцию с помощью текущей методологии и надежно продолжают использовать ту же методологию во всех будущих версиях Mac OS X.

Проверка расширения OpenGL

Дополнительные строки имени состоят из дополнительных имен, поддерживаемых который определенное средство рендеринга, разделенное пробелами. Строка расширений может быть длинной, и не нужно копировать ее в ограниченную длину временная строка, а скорее, проверить строку на дополнительное имя на месте. Строка имени для расширения не является именем расширений, но строкой, обозначенной полем «Name Strings» дополнительного описания. Перечисление 2 показывает пример того, как проверить строку расширений на функциональность который возможно в одном или более расширениях или версии базовой спецификации, с помощью функции удобства GLU gluCheckExtension. Отметьте, это перечисление основывается на коде, представленном в Перечислении 1.

  Проверка перечисления 2 функцию OpenGL через строку расширений и номер версии

bool fTexEnvCombine = false;
// get extensions string
const GLubyte * strExtension = glGetString (GL_EXTENSIONS);
if (gluCheckExtension ("GL_ARB_texture_env_combine", strExtension) ||
    gluCheckExtension ("GL_EXT_texture_env_combine", strExtension))
    fTexEnvCombine = true;
// also check for API support (short version string from above)
// if we are not version 1.0, 1.1 or 1.2 then must be 1.3 or later
if (!strstr ((const char *) strShortVersion, "1.0") &&
    !strstr ((const char *) strShortVersion, "1.1") &&
    !strstr ((const char *) strShortVersion, "1.2"))
    fTexEnvCombine = true;

Завершить, только после успешной проверки версии API или строки расширений для определенного текущего средства рендеринга должно использование приложения желаемая команда. Как только команда, как находят, поддерживается в ядре OpenGL или в расширении для средства рендеринга в использовании, никакая дальнейшая работа не требуется. Просто включайте платформу OpenGL, «gl.h» и «glext.h» заголовочные файлы и вызовите команду по мере необходимости (нет смысла в указателях функции, требуется для Mac OS X OpenGL, но они могли использоваться в зависимости от того, какие версии ОС и функции OpenGL поддерживаются любым приложением, см. QA1188: GetProcAdress и Точки входа OpenGL для получения дополнительной информации об указателях функции).

Изменения базовой функциональности OpenGL на версию API

Так как базовая функциональность OpenGL изменилась, поскольку различные версии API были приняты, для известного удобно, какая основная функциональность была добавлена с каждой версией API. Следующий список показывает изменения в базовой функциональности в различном OpenGL версии API. Также обозначенный расширение, из которого получена функциональность. Нужно консультироваться с фактической спецификацией для получения дальнейшей информации по поводу функциональности и как это реализовано, тем более, что существуют вероятные различия между реализацией, представленной в базовом API и расширением, на котором это базируется. Дополнительная подробность о базовых изменениях API может быть найдена в 1,4 приложениях D спецификации OpenGL через F.

OpenGL 1.1

OpenGL 1.1 добавляет:

OpenGL 1.2

OpenGL 1.2 добавляет:

OpenGL 1.2.1

OpenGL 1.2.1 представил расширения ARB без определенных базовых изменений API.

OpenGL 1.3

OpenGL 1.3 добавляет:

OpenGL 1.4

OpenGL 1.4 добавляет:

OpenGL 1.5

OpenGL 1.5 добавляет:

Функциональность выше требуется, чтобы присутствовать, если средство рендеринга сообщает об определенной версии независимо от того, какие расширения поддерживаются. Снова, стоит отметить, что средства рендеринга могут или могут не поддерживать расширения, которые базируется функциональность API. Например, если средство рендеринга сообщает о версии 1.3, оно может или может не поддерживать GL_ARB_texture_env_combine или GL_EXT_texture_env_combine расширения, хотя функциональность это расширение представляет, будут доступны через базовые 1,3 API.

Нахождение допустимого средства рендеринга для проверки функциональности

Как обсуждено ранее, проверение функциональности требует, чтобы средство рендеринга, присоединенное к drawable для команд OpenGL, возвратило допустимые результаты. Когда не drawable присоединенные команды OpenGL, эффективно «без OPs», таким образом возвращают недопустимые результаты. Существует пара различных методов для обеспечения допустимой среды рендеринга. Во-первых, можно создать формат пикселя, и контекст тогда присоединяют это к допустимому drawable для OS API в использовании, таком как окно, представление или экран. Так как средства рендеринга могут измениться с включением изменений дисплея, нужно также гарантировать, что используемое drawable правильно расположено на дисплей интереса (или выполните итерации через набор дисплеев интереса). В то время как, нет никакого требования для создания drawable видимого, позволяющего этому действию иметь место, не тревожа пользователя, было бы желательно иметь метод, не включающий создание drawable и который мог использоваться любым OS API (CGL, NSOpenGL или AGL).

Перечисление 3 показывает метод с помощью CGL, который доступен любому Мужественному приложению, для определения возможностей средства рендеринга на основе дисплея, даже если то приложение использует NSOpenGL или недостаток AGL CGL для его интерфейса к OpenGL. Этот код не создает drawable, но вместо этого использует маску дисплея OpenGL в формате пикселя для ограничения формата пикселя и таким образом контекста, к единственному дисплею и эквивалентно, единственному средству рендеринга. Как только этот контекст создается и установил текущие, нормальные вызовы OpenGL, будет допустимо для контекстов единственное средство рендеринга. Можно было использовать этот код при желании, чтобы циклично выполниться по доступным дисплеям и установить информацию о возможности для всех дисплеев, таким образом все средства рендеринга, не создавая drawable, ни будучи навязчивым пользователю.

Перечисление 3  , Настраивающее допустимый контекст рендеринга на дисплее

#include <OpenGL/OpenGL.h>
#include <ApplicationServices/ApplicationServices.h>

CGDirectDisplayID display = CGMainDisplayID ();
CGOpenGLDisplayMask cglDisplayMask = 
                        CGDisplayIDToOpenGLDisplayMask (display);
{ // check capabilities of display represented by display mask
    CGLPixelFormatAttribute attribs[] = {kCGLPFADisplayMask, 
                                         cglDisplayMask, NULL};
    CGLPixelFormatObj pixelFormat = NULL;
    long numPixelFormats = 0;
    CGLContextObj cglContext = 0;
    CGLContextObj curr_ctx = CGLGetCurrentContext ();

    CGLChoosePixelFormat (attribs, &pixelFormat, &numPixelFormats);
    if (pixelFormat) {
        CGLCreateContext (pixelFormat, NULL, &cglContext);
        CGLDestroyPixelFormat (pixelFormat);
        if (cglContext) {
            CGLSetCurrentContext (cglContext);
            // test functionality here
            CGLDestroyContext (cglContext);
        }
    }
    CGLSetCurrentContext (curr_ctx); // reset current CGL context
}

Теперь, когда у нас есть код, чтобы проверить версию ядра OpenGL, дополнительную строку и установить допустимое средство рендеринга на любом дисплее, мы можем расширить это для создания все включено пример проверки функциональности OpenGL, который разработчики могут использовать как есть или расширить для удовлетворения их индивидуальных потребностей. Следующие два раздела покрывают этот пример.

Обнаружение Функциональности с glCheck

glCheck является рядом подпрограмм, которые могут использоваться клиентами OpenGL для простого получения набора функций OpenGL для всех присоединенных дисплеев. Пример кода является factored дисплеем, как это - логическое подразделение возможностей оборудования. Даже при том, что два дисплея, возможно управляемые единственным устройством, никакой дисплей не будет управляться больше чем одним устройством. Код glCheck может быть установлен до использования OpenGL и затем обновлен для событий реконфигурирования дисплея. После того, как инициализированный, клиенты могут непосредственно получить доступ к структуре возможности, чтобы определить, имеет ли текущий контекст OpenGL определенную возможность. Сам пример кода содержит флаги для всего настоящего функций во время этой записи, но клиенты свободны удалить функции, которые они используют, если им нравится. Это может сохранить некоторую память, но так как код проверки функции вызывают чрезвычайно нечасто, это не требуется в целях производительности. Важно отметить, что код охватывает проверку и базовую версию OpenGL и дополнительную строку, таким образом, клиенты освобождены, чтобы просто проверить простой легкий флаг на определенную функцию. glCheck обеспечивает полную и легкую проверку на этапе выполнения, заменяющую тяжелые вызовы времени выполнения веса к glGetString и неполная проверка функции.

API очень прост и может быть вызван и от клиентов Какао и от Углерода. Используя API состоит из четырех шагов: инициализация структур и возможно подпрограмм уведомления, обновление структур, демонстрирующихся изменения конфигурации, проверка функцию или возможности по мере необходимости во время выполнения, и наконец освобождение структур и удаление любых подпрограмм уведомления на выходе.

Инициализация и для Какао и для Углерода выполняется с кодом, показанным в Перечислении 4. Этот код устанавливает глобальные переменные для хранения списка структур, числа активных дисплеев и универсального указателя процедуры для подпрограммы уведомления обновления, если используется. Приложения являются бесплатными хранить эту информацию, как им нравится, глобальные переменные используются для простоты в этой реализации в качестве примера. getCurrentCaps подпрограмма установки и обновления, сначала проверяющая, чтобы видеть, были ли возможности OpenGL ранее получены и если так, изменили их. HaveOpenGLCapsChanged подпрограмма довольно легка и ищет дополнительные дисплеи, или геометрия изменяются для указания изменения конфигурации дисплея. Если было изменение, мы освобождаем текущие структуры данных и продолжаем вниз нормальный путь инициализации. Сама инициализация проста, но не легка. Сначала мы передаем NULL как указатель структуры для установки флага этого, мы просто ищем число дисплеев, которые будут использоваться в выделении памяти структуры. Мы тогда выделяем память для дисплеев * размер GLCaps структура и пасует назад это в CheckOpenGLCaps подпрограмма для фактического получения прописных букв.

Перечисление 4  , инициализирующее структуры возможностей OpenGL

#include <stdlib.h>
#include <Carbon/Carbon.h>
#include <ApplicationServices/ApplicationServices.h>

#include "glCheck.h" // header code in Listing 8

// configuration info globals
GLCaps * gDisplayCaps = NULL; // array of GLCaps
CGDisplayCount gNumDisplays = 0; // number of displays

// related DM change notification 
// (required for display config change notifications)
DMExtendedNotificationUPP gConfigEDMUPP = NULL;

static void getCurrentCaps (void)
{
  if (gDisplayCaps && 
      HaveOpenGLCapsChanged (gDisplayCaps, gNumDisplays)) { // if changed
    free (gDisplayCaps); // set up to build new ones
    gDisplayCaps = NULL;
  }
  if (!gDisplayCaps) { // if we do not have caps
    // will just update number of displays
    CheckOpenGLCaps (0, NULL, &gNumDisplays); 
    gDisplayCaps = (GLCaps*) malloc (sizeof (GLCaps) * gNumDisplays);
    CheckOpenGLCaps (gNumDisplays, gDisplayCaps, &gNumDisplays);
  }
}

В то время как getCurrentCaps подпрограмма инициализации может позвониться в любое время, она включает существенное количество поисков строки, делающих его не особенно подходящий для выполнения на высоком показателе. Рекомендуется вызвать getCurrentCaps когда конфигурации дисплея изменяются, после того, как клиенты запускаются до выбора путей выполнения кода OpenGL и затем. Это не требуется, чтобы вызывать getCurrentCaps каждый кадр, или на каждом обновленном событии. Для приложений Какао этому рекомендуют один вызов getCurrentCaps от awakeFromNib первоначально и или установка метод обновления OpenGLView процедуры уведомления или использования менеджера дисплея Углерода при использовании процедуры уведомления не желаема. Используя update метод имеет вниз сторона проверки изменения дисплея чаще, чем необходимый, но HaveOpenGLCapsChanged проверка должна поддержать издержки на низком уровне. Приложения углерода могут вызвать getCurrentCaps первоначально в основном или другом расположении до выбора, который функции OpenGL использовать. Обновления обрабатываются в похожем методе для Какао, хотя для Углерода нужно просто использовать процедуру уведомления во всех случаях. Перечисление 5 и Перечисление 6 показывают код инициализации Какао и Углерода.

  Код инициализации какао перечисления 5

#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h> // for display manager functionality

#pragma mark ---- Display Manager Event Handling ----
// if notification procedures are used...

// update our GL configuration info based on display change notification
void handleConfigDMEvent (void *userData, short msg, void *notifyData)
{
  if (kDMNotifyEvent == msg) { // post change notifications only
    getCurrentCaps (); // from Listing 4
  }
}

// ---------------------------------

// called for window resizes, moves and display changes 
// (resize, depth and display config change)
// not required if an application is using display change notifications

- (void) update
{
  [super update];

  // do any application update stuff here...

  if (![self inLiveResize]) { // if not doing live resize
    // this call checks to see if the current config changed in a
    //   reasonably lightweight way to prevent expensive allocations
    getCurrentCaps (); // from Listing 4
  }
}

// ---------------------------------

- (void) awakeFromNib
{
  // do app initialization stuff here...

  // initialize OpenGL capabilities 
  // (this could be anytime prior to deciding on OpenGL code paths)
  // get current GL capabilities for all displays
  getCurrentCaps (); // from Listing 4

  // configure display change notification (if desired)
  gConfigEDMUPP = NewDMExtendedNotificationUPP (handleConfigDMEvent);
  DMRegisterExtendedNotifyProc (gConfigEDMUPP, NULL, NULL, &psn);
}

  Код инициализации углерода перечисления 6

#include <Carbon/Carbon.h> // for display manager functionality

#pragma mark ---- Display Manager Event Handling ----

// update our GL configuration info based on display change notification
void handleConfigDMEvent (void *userData, short msg, void *notifyData)
{
  if (kDMNotifyEvent == msg) { // post change notifications only
    getCurrentCaps (); // from Listing 4
  }
}

// ---------------------------------

main ()
{
  // do client initialization stuff...

  // initialize OpenGL capabilities
  // get current GL capabilities for all displays
  getCurrentCaps (); // from Listing 4

  // configure display change notification
  gConfigEDMUPP = NewDMExtendedNotificationUPP (handleConfigDMEvent);
  DMRegisterExtendedNotifyProc (gConfigEDMUPP, NULL, NULL, &psn);

  // client run loop...

  // client exit stuff...
}

Проверка определенные возможности легка и довольно проста выполнить. Обработанный разработан, чтобы использоваться по мере необходимости во время выполнения приложения во время генерации кадра. Перечисление 7 и Перечисление 8 показывают проверку возможностей Какао и Углерода, в частности в этом случае для GL_EXT_texture_rectangle (непитание двух поддержки текстурирования) функция. Предполагается, что приложения кэшировали значения текущего контекста и его формата пикселя. Пример предполагает, что они сохранены в self для примера Какао и глобально в случае Углерода, хотя приложения являются бесплатными сохранить их, как они требуют. Настоящее методологии является тем же в обоих случаях. Клиенты определят идентификацию средства рендеринга для текущего контекста на основе текущего виртуального формата экрана и идентификации средства рендеринга формата пикселя.

Как только приложение имеет текущую идентификацию средства рендеринга, которую они могут пересечь массив возможностей, найти структуру интереса путем соответствия средства рендеринга и затем непосредственно искать желаемую функцию. Этот индекс массива может тогда использоваться непосредственно для всего определения функции OpenGL, пока одно из двух событий не имеет место, ни один, который обновление контекста необходимо (см. Технические Вопросы и ответы QA1209, 'Обновляя Контексты OpenGL' для получения информации о том, когда обновления контекстов необходимы), или изменение конфигурации дисплея происходит, который может изменить массив конфигурации. Перечисление 7 исследования и Перечисление 8 для определенных подробных данных этой реализации в качестве примера.

  Функции Listing 7 Testing OpenGL с glCheck и Какао

#include <Cocoa/Cocoa.h>
// assumes initialization code from Listing 4

{
  // this finds the correct renderer via context virtual screen
  //  and pixel format renderer list then checks the capabilities list
  //  for texture rectangle capability (for example) it assumes gDisplayCaps
  //  and gNumDisplays are defined and initialized

  BOOL hasCap = NO;
  long renderer;

  // match renderer using pixel format and context virtual screen
  [[self pixelFormat] getValues:&renderer 
                      forAttribute:NSOpenGLPFARendererID 
                      forVirtualScreen:
                        [[self openGLContext] currentVirtualScreen]];
  for (i = 0; i < gNumDisplays; i++) {
    if ((renderer == gDisplayCaps[i].rendererID) && // if we match
        gDisplayCaps[i].fTexRect) { // and have the capability
      hasCap = YES;
      break;
    }
  }
}

  Функции Listing 8 Testing OpenGL с glCheck и Углеродом

#include <agl/agl.h>
// assumes initialization code from Listing 4

{
  // this finds the correct renderer via context virtual screen
  //  and pixel format renderer list then checks the capabilities list
  //  for texture rectangle capability (for example) it assumes gDisplayCaps
  //  and gNumDisplays are defined and initialized

  Boolean hasCap = false;
  GLint renderer = 0;

  // match renderer using pixel format and context virtual screen
  AGLPixelFormat pf = aglPixFmt; // first PF
  GLint pfVS = 0, currVS = aglGetVirtualScreen (aglContext); // current VS
  aglDescribePixelFormat (pf, AGL_VIRTUAL_SCREEN, &pfVS); // get VS for PF
  while ((pfVS != currVS) && pf) { // while PF's and the VS's do not match
    pf = aglNextPixelFormat (pf); // get next PF
    aglDescribePixelFormat (pf, AGL_VIRTUAL_SCREEN, &pfVS); // get VS
  }
  if (pf) // if we matched VS (we should)
    aglDescribePixelFormat(pf, AGL_RENDERER_ID, &renderer); // get rend
  for (i = 0; i < gNumDisplays; i++) {
    if ((renderer == gDisplayCaps[i].rendererID) && // if we match
        DisplayCaps[i]. fTexRect) { // and have the capability
      hasCap = YES;
      break;
    }
  }
}

Наконец, Перечисление 9 показывает общий код, который должен быть выполнен на выходе к выделенной свободной памяти и расположить любые обратные вызовы, которые мы установили. Перечисление принимает те же глобальные переменные, используемые в предыдущих примерах кода.

Перечисление 9  , располагающее записи возможности OpenGL и уведомления

#include <stdlib.h>
#include <Carbon/Carbon.h>
// assumes initialization code from Listing 4

// if notification installed, remove display change notification
if (gConfigEDMUPP) { // dispose UPP for DM notifications
  DisposeDMExtendedNotificationUPP (gConfigEDMUPP);
  gConfigEDMUPP = NULL;
}

// free memory for display capabilities records
if (gDisplayCaps) {
  free (gDisplayCaps);
  gDisplayCaps = NULL;
}

Исходный код glCheck

glcheck пример кода в Перечислении 10 и Перечислении 11 показывает реализацию в качестве примера проверки возможностей, обсужденной в этом техническом примечании. Этот пример кода имеет заголовочный файл, определяющий простую структуру с помощью базируемых флагов функции, показывающих, какие возможности, которыми обладает определенное средство рендеринга, детализированы в Перечислении 10.

Перечисление 10  код проверки возможностей OpenGL: glCheck.h

// glcheck allows developer to check the hardware capabilities of all GPU's
// returning an array of records reflecting the attached hardware. This
// list can be regenerated on Display Manager notifications to keep the
// client update to on capabilities and setup changes. This is provided as
// sample to allow developers the freedom to check as few or as many
// conditions and capabilities as they would like or add their own checks

#include <Carbon/Carbon.h>

#include <ApplicationServices/ApplicationServices.h>

typedef struct {
  // developers can add capabilities as required

  CGDirectDisplayID cgDisplayID; // CG display ID (main identifier)
  unsigned long displayID; // QD display ID
  GDHandle hGDevice; // graphics device handle
  CGOpenGLDisplayMask cglDisplayMask; // CGL display mask

  // current (at time of look up) device geometry
  long deviceWidth; // pixel width
  long deviceHeight; // pixel width
  long deviceOriginX; // left location of device (relative to main device)
  long deviceOriginY; // upper location of device (relative to main device)
  short deviceDepth; // pixel depth in bits
  short deviceRefresh; // integer refresh rate in Hz

  // Renderer info
  long deviceVRAM; // video memory in bytes
  long deviceTextureRAM; // uses current mode (geometry, pixel depth, etc.)
  unsigned long rendererID; // renderer ID
  char strRendererName [256]; // name of hardware renderer
  char strRendererVendor [256]; // name of hardware renderer vendor
  char strRendererVersion [256]; // string rep of hardware renderer version
  bool fullScreenCapable; // does device support full screen
  // can add more device specs as you want

  // Renderer Caps
  long textureUnits; // standard gl path max number of texture units
  long maxTextureSize; // maximum 1D and 2D texture size supported
  long max3DTextureSize; // maximum 3D texture size supported
  long maxCubeMapTextureSize; // maximum cube map texture size supported
  long maxRectTextureSize; // maximum rectangular texture size supported

  // OpenGL version support
  unsigned short glVersion; // bcd gl version (ie. 1.4 is 0x0140)


  // Functionality
  bool fSpecularVector; // GL_APPLE_specular_vector
  bool fTransformHint; // GL_APPLE_transform_hint 
  bool fPackedPixels; // GL_APPLE_packed_pixels or 1.2+
  bool fClientStorage; // GL_APPLE_client_storage
  bool fYCbCr; // GL_APPLE_ycbcr_422 (YUV texturing)
  bool fTextureRange; // GL_APPLE_texture_range (AGP texturing)
  bool fFence; // GL_APPLE_fence
  bool fVAR; // GL_APPLE_vertex_array_range
  bool fVAO; // GL_APPLE_vertex_array_object
  bool fElementArray; // GL_APPLE_element_array
  bool fVPEvals; // GL_APPLE_vertex_program_evaluators
  bool fFloatPixels; // GL_APPLE_float_pixels
  bool fFlushRenderer; // GL_APPLE_flush_render
  bool fPixelBuffer; // GL_APPLE_pixel_buffer
  bool fImaging; // GL_ARB_imaging (not required in 1.2+)
  bool fTransposeMatrix; // GL_ARB_transpose_matrix or 1.3+
  bool fMultitexture; // GL_ARB_multitexture or 1.3+
  bool fTexEnvAdd; // GL_ARB_texture_env_add, GL_EXT_texture_env_add or 1.3+
  bool fTexEnvCombine; // GL_ARB_texture_env_combine or 1.3+
  bool fTexEnvDot3; // GL_ARB_texture_env_dot3 or 1.3+
  bool fTexEnvCrossbar; // GL_ARB_texture_env_crossbar or 1.4+
  bool fTexCubeMap; // GL_ARB_texture_cube_map or 1.3+
  bool fTexCompress; // GL_ARB_texture_compression or 1.3+
  bool fMultisample; // GL_ARB_multisample or 1.3+ (Anti-aliasing)
  bool fTexBorderClamp; // GL_ARB_texture_border_clamp or 1.3+
  bool fPointParam; // GL_ARB_point_parameters or 1.4+
  bool fVertexProg; // GL_ARB_vertex_program
  bool fFragmentProg; // GL_ARB_fragment_program
  bool fTexMirrorRepeat; // GL_ARB_texture_mirrored_repeat or 1.4+
  bool fDepthTex; // GL_ARB_depth_texture or 1.4+
  bool fShadow; // GL_ARB_shadow or 1.4+
  bool fShadowAmbient; // GL_ARB_shadow_ambient
  bool fVertexBlend; // GL_ARB_vertex_blend
  bool fWindowPos; // GL_ARB_window_pos or 1.4+
  bool fTex3D; // GL_EXT_texture3D or 1.2+
  bool fClipVolHint; // GL_EXT_clip_volume_hint
  bool fRescaleNorm; // GL_EXT_rescale_normal or 1.2+
  bool fBlendColor; // GL_EXT_blend_color or GL_ARB_imaging
  bool fBlendMinMax; // GL_EXT_blend_minmax or GL_ARB_imaging
  bool fBlendSub; // GL_EXT_blend_subtract or GL_ARB_imaging
  bool fCVA; // GL_EXT_compiled_vertex_array
  bool fTexLODBias; // GL_EXT_texture_lod_bias or 1.4+
  bool fABGR; // GL_EXT_abgr
  bool fBGRA; // GL_EXT_bgra or 1.2+
  bool fTexFilterAniso; // GL_EXT_texture_filter_anisotropic
  bool fPaletteTex; // GL_EXT_paletted_texture
  bool fShareTexPalette; // GL_EXT_shared_texture_palette
  bool fSecColor; // GL_EXT_secondary_color or 1.4+
  bool fTexCompressS3TC; // GL_EXT_texture_compression_s3tc
  bool fTexRect; // GL_EXT_texture_rectangle
  bool fFogCoord; // GL_EXT_fog_coord
  bool fDrawRangeElements; // GL_EXT_draw_range_elements
  bool fStencilWrap; // GL_EXT_stencil_wrap or 1.4+
  bool fBlendFuncSep; // GL_EXT_blend_func_separate or 1.4+
  bool fMultiDrawArrays; // GL_EXT_multi_draw_arrays or 1.4+
  bool fShadowFunc; // GL_EXT_shadow_funcs
  bool fStencil2Side; // GL_EXT_stencil_two_side
  bool fColorSubtable; // GL_EXT_color_subtable or GL_ARB_imaging
  bool fConvolution; // GL_EXT_convolution or GL_ARB_imaging
  bool fHistogram; // GL_EXT_histogram or GL_ARB_imaging
  bool fColorTable; // GL_SGI_color_table or GL_ARB_imaging
  bool fColorMatrix; // GL_SGI_color_matrix
  bool fTexEdgeClamp; // GL_SGIS_texture_edge_clamp or 1.2+
  bool fGenMipmap; // GL_SGIS_generate_mipmap or 1.4+
  bool fTexLOD; // GL_SGIS_texture_lod or 1.2+
  bool fPointCull; // GL_ATI_point_cull_mode
  bool fTexMirrorOnce; // GL_ATI_texture_mirror_once
  bool fPNtriangles; // GL_ATI_pn_triangles or GL_ATIX_pn_triangles
  bool fTextFragShader; // GL_ATI_text_fragment_shader
  bool fBlendEqSep; // GL_ATI_blend_equation_separate
  bool fBlendWeightMinMax; // GL_ATI_blend_weighted_minmax
  bool fCombine3; // GL_ATI_texture_env_combine3
  bool fSepStencil; // GL_ATI_separate_stencil
  bool fArrayRevComps4Byte; // GL_ATI_array_rev_comps_in_4_bytes
  bool fPointSprite; // GL_NV_point_sprite
  bool fRegCombiners; // GL_NV_register_combiners
  bool fRegCombiners2; // GL_NV_register_combiners2
  bool fTexEnvCombine4; // GL_NV_texture_env_combine4
  bool fBlendSquare; // GL_NV_blend_square or 1.4+
  bool fFogDist; // GL_NV_fog_distance
  bool fMultisampleFilterHint; // GL_NV_multisample_filter_hint
  bool fTexGenReflect; // GL_NV_texgen_reflection
  bool fTexShader; // GL_NV_texture_shader
  bool fTexShader2; // GL_NV_texture_shader2
  bool fTexShader3; // GL_NV_texture_shader3
  bool fDepthClamp; // GL_NV_depth_clamp
  bool fLightMaxExp; // GL_NV_light_max_exponent
  bool fConvBorderModes; // GL_HP_convolution_border_modes or GL_ARB_imaging
  bool fRasterPosClip; // GL_IBM_rasterpos_clip
} GLCaps;

// this does a reasonable check to see if things have changed without being 
// too heavy weight; returns 1 if changed 0 if not
// checks num displays, displayID, displayMask, each display geometry and 
// renderer VRAM and ID
unsigned char HaveOpenGLCapsChanged (GLCaps aDisplayCaps[], 
                                     CGDisplayCount dspyCnt);


// This will walk all active displays and gather information about their
// hardware renderer 

// An array length (maxDisplays) and array of GLCaps are passed in. Up to
// maxDisplays of the array are filled in with the displays meeting the
// specified criteria. The actual number of displays filled in is returned
// in dspyCnt. Calling this function with maxDisplays of 0 will just
// return the number of displays in dspyCnt.

// Developers should note this is NOT an exhaustive list of all the
// capabilities one could query, nor a required set of capabilities,
// feel free to add or subtract queries as you find helpful for your 
// application/use.

// one note on mirrored displays... if the display configuration is 
// changed it is possible (and likely) that the current active display
// in a mirrored configuration (as identified by the OpenGL Display Mask)
// will change if the mirrored display is removed. 
// This is due to the preference of selection the external display as 
// the active display. This may affect full screen apps which should 
// always detect display configuration changes and respond accordingly.

void CheckOpenGLCaps (CGDisplayCount maxDisplays, 
                      GLCaps * aDisplayCaps, 
                      CGDisplayCount * dspyCnt);

Исходный код, как показано в Перечислении 11, имеет много разделов. В первом разделе дисплеи перечислены и выполнены с помощью итераций при приведении к таблица со структурой возможностей для каждого дисплея. Следующая информация раздела собирается о каждом дисплее и средстве рендеринга поочередно. Сначала основной CoreGraphics и Углерод выводят на экран информацию для упрощения использования или приложениями Какао или Углерода. Затем, информация об устройстве Углерода используется для получения полного экрана средства рендеринга и пределов памяти. Наконец мы используем наш код CGL, чтобы создать контекст рендеринга и получить определенную информацию OpenGL для всей поддерживаемой функциональности и некоторых пределов в качестве примера. Разработчики свободны сократить или развернуть эту проверку как требуется их определенное приложение. Наконец, как покрыто ранее, CheckOpenGLCaps не разработан для производительности критические разделы кода, рекомендуется, чтобы эту подпрограмму вызвали один раз после того, как приложение запускается и затем на любых изменениях конфигурации дисплея и для клиентов для прямого доступа к значениям параметра, как обрисовано в общих чертах ранее.

Перечисление 11  код проверки возможностей OpenGL: glCheck.c

#include "glCheck.h"

#include <OpenGL/OpenGL.h>
#include <AGL/agl.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <OpenGL/glext.h>

#include <string.h>

// -------------------------

// local CF dictionary routines

static long _getDictLong (CFDictionaryRef refDict, CFStringRef key)
{
  long int_value;
  CFNumberRef num_value = (CFNumberRef)CFDictionaryGetValue(refDict, key);
  if (!num_value) // if can't get a number for the dictionary
    return -1; // fail
  // or if cant convert it
  if (!CFNumberGetValue(num_value, kCFNumberLongType, &int_value)) 
    return -1; // fail
  return int_value; // otherwise return the long value
}

static double _getDictDouble (CFDictionaryRef refDict, CFStringRef key)
{
  double double_value;
  CFNumberRef num_value = (CFNumberRef)CFDictionaryGetValue(refDict, key);
  if (!num_value) // if can't get a number for the dictionary
    return -1; // fail
  // or if cant convert it
  if (!CFNumberGetValue(num_value, kCFNumberDoubleType, &double_value)) 
    return -1; // fail
  return double_value; // otherwise return the long value
}

// -------------------------

// this does a reasonable check to see if things have changed without being 
// too heavy weight; returns 1 if changed 0 if not
// checks num displays, displayID, displayMask, each display geometry and 
// renderer VRAM and ID

unsigned char HaveOpenGLCapsChanged (GLCaps aDisplayCaps[], 
                                     CGDisplayCount dspyCnt)
{
  CGDisplayCount maxDisplays = 32;
  CGDirectDisplayID activeDspys[32];
  CGDisplayErr error;
  short i;
  CGDisplayCount newDspyCnt = 0;

  if (NULL == aDisplayCaps) return 1;

  error = CGGetActiveDisplayList(maxDisplays, activeDspys, &newDspyCnt);
  // if error getting list mark as changed
  if (error) return 1; 
  // if number of displays not equal
  if (dspyCnt != newDspyCnt) return 1;

  for (i = 0; i < dspyCnt; i++) {
    // get device ids
    if (aDisplayCaps[i].cgDisplayID != activeDspys[i]) return 1;
    if (aDisplayCaps[i].cglDisplayMask != 
        CGDisplayIDToOpenGLDisplayMask(activeDspys[i])) return 1;

    // get current geometry
    {
      CGRect displayRect = CGDisplayBounds (activeDspys[i]);
      // get mode dictionary
      CFDictionaryRef dispMode = CGDisplayCurrentMode (activeDspys[i]);
      // check for all geometry matches 
      if (aDisplayCaps[i].deviceWidth != (long) displayRect.size.width)
        return 1; 
      if (aDisplayCaps[i].deviceHeight != (long) displayRect.size.height) 
        return 1; 
      if (aDisplayCaps[i].deviceOriginX != (long) displayRect.origin.x) 
        return 1; 
      if (aDisplayCaps[i].deviceOriginY != (long) displayRect.origin.y) 
        return 1; 
      if (aDisplayCaps[i].deviceDepth != 
                 (short) _getDictLong (dispMode,  kCGDisplayBitsPerPixel)) 
        return 1; 
      if (aDisplayCaps[i].deviceRefresh != 
          (short)(_getDictDouble (dispMode, kCGDisplayRefreshRate) + 0.5)) 
        return 1; // round to GLint
    }

    // get renderer info based on gDevice
    {
      CGLRendererInfoObj info;
      long j, numRenderers = 0, rv = 0;
      CGLError err = 0;
      long deviceVRAM; // video memory in bytes
      unsigned long rendererID; // renderer ID

      err = CGLQueryRendererInfo (aDisplayCaps[i].cglDisplayMask, 
                                  &info, &numRenderers);
      if(0 == err) {
        CGLDescribeRenderer (info, 0, kCGLRPRendererCount, &numRenderers);
        for (j = 0; j < numRenderers; j++) {
          // find accelerated renderer (assume only one)
          CGLDescribeRenderer (info, j, kCGLRPAccelerated, &rv); 
          if (true == rv) { // if accelerated
            // what is the renderer ID
            CGLDescribeRenderer (info, j, kCGLRPRendererID, &rendererID); 
            if (rendererID != aDisplayCaps[i].rendererID) // check match
              return 1;
            // what is the VRAM
            CGLDescribeRenderer (info, j, kCGLRPVideoMemory, &deviceVRAM); 
            if (deviceVRAM != aDisplayCaps[i].deviceVRAM) // check match
              return 1;
            break; // done
          }
        }
      }
      CGLDestroyRendererInfo (info);
    }
  }
  return 0;
}

// -------------------------

// This will walk all active displays and gather information about their
// hardware renderer 

// An array length (maxDisplays) and array of GLCaps are passed in. Up to
// maxDisplays of the array are filled in with the displays meeting the
// specified criteria. The actual number of displays filled in is returned
// in dspyCnt. Calling this function with maxDisplays of 0 will just
// return the number of displays in dspyCnt.

// Developers should note this is NOT an exhaustive list of all the
// capabilities one could query, nor a required set of capabilities,
// feel free to add or subtract queries as you find helpful for your 
// application/use.

// one note on mirrored displays... if the display configuration is 
// changed it is possible (and likely) that the current active display
// in a mirrored configuration (as identified by the OpenGL Display Mask)
// will change if the mirrored display is removed. 
// This is due to the preference of selection the external display as 
// the active display. This may affect full screen apps which should 
// always detect display configuration changes and respond accordingly.

void CheckOpenGLCaps (CGDisplayCount maxDspys, 
                      GLCaps dCaps[], 
                      CGDisplayCount * dCnt)
{
  CGLContextObj curr_ctx = 0;
  CGDirectDisplayID dspys[32];
  CGDisplayErr err;
  short i;
  short size = sizeof (GLCaps);

  // no devices
  *dCnt = 0;

  if (maxDspys == 0) { // find number of displays
    *dCnt = 0;
    err = CGGetActiveDisplayList (32, dspys, dCnt);
    if (err) // err getting list
      *dCnt = 0; // 0 displays since can't correctly find any
    // zero list to ensure the routines are used correctly
    memset (dspys, 0, sizeof (CGDirectDisplayID) * *dCnt);
    return; // return dCnt
  }
  if (NULL == dCaps) return;

  err = CGGetActiveDisplayList(maxDspys, dspys, dCnt);
  if (err) return; // err getting list
  if (0 == *dCnt) return; // no displays

  memset (dCaps, 0, size * *dCnt); // zero memory

  for (i = 0; i < *dCnt; i++) {
    // get device ids
    dCaps[i].cgDisplayID = dspys[i];
    dCaps[i].cglDisplayMask = CGDisplayIDToOpenGLDisplayMask(dspys[i]);

    { // get current geometry
      CGRect displayRect = CGDisplayBounds (dspys[i]);
      // get mode dictionary
      CFDictionaryRef dispMode = CGDisplayCurrentMode (dspys[i]); 
      dCaps[i].deviceWidth = (long) displayRect.size.width; 
      dCaps[i].deviceHeight = (long) displayRect.size.height; 
      dCaps[i].deviceOriginX = (long) displayRect.origin.x; 
      dCaps[i].deviceOriginY = (long) displayRect.origin.y; 
      dCaps[i].deviceDepth = (short) _getDictLong (dispMode, 
                                              kCGDisplayBitsPerPixel); 
      dCaps[i].deviceRefresh = (short) (_getDictDouble (dispMode,
                                        kCGDisplayRefreshRate) + 0.5); 
    }

    { // find gDevice device by bounds
      GDHandle hGD;
      for (hGD = GetDeviceList (); hGD; hGD = GetNextDevice (hGD))
      {
        if (!TestDeviceAttribute (hGD, screenDevice) ||
            !TestDeviceAttribute (hGD, screenActive))
          continue;

        // if postion and sizes match
        if (((*hGD)->gdRect.top == dCaps[i].deviceOriginY) &&
          ((*hGD)->gdRect.left == dCaps[i].deviceOriginX) &&
          (((*hGD)->gdRect.bottom - (*hGD)->gdRect.top) ==
                                                  dCaps[i].deviceHeight) &&
          (((*hGD)->gdRect.right - (*hGD)->gdRect.left) ==
                                                  dCaps[i].deviceWidth)) {
          dCaps[i].hGDevice = hGD;
          break;
        }
      }
      if (dCaps[i].hGDevice == NULL)
        return; // err
      if (noErr != DMGetDisplayIDByGDevice (dCaps[i].hGDevice,
                                            &dCaps[i].displayID, false))
        dCaps[i].displayID = 0; // err getting display ID
    }


    { // get renderer info based on gDevice
      CGLRendererInfoObj info;
      long j, numRenderers = 0, rv = 0;
      CGLError err = 0;

      err = CGLQueryRendererInfo (dCaps[i].cglDisplayMask, 
                                  &info, 
                                  &numRenderers);
      if(0 == err) {
        CGLDescribeRenderer (info, 0, kCGLRPRendererCount, &numRenderers);
        for (j = 0; j < numRenderers; j++) {
          // find accelerated renderer (assume only one)
          CGLDescribeRenderer (info, j, kCGLRPAccelerated, &rv); 
          if (true == rv) { // if accelerated
            // what is the renderer ID
            CGLDescribeRenderer (info, j, kCGLRPRendererID,
                                 &dCaps[i].rendererID);
            // can we do full screen?
            CGLDescribeRenderer (info, j, kCGLRPFullScreen, &rv); 
            dCaps[i].fullScreenCapable = (bool) rv;
            // what is the VRAM?
            CGLDescribeRenderer (info, j, kCGLRPVideoMemory,
                                 &dCaps[i].deviceVRAM);
            // what is the current texture memory? 
            CGLDescribeRenderer (info, j, kCGLRPTextureMemory,
                                 &dCaps[i].deviceTextureRAM);
            break; // done
          }
        }
      }
      CGLDestroyRendererInfo (info);
    }

    { // build context and context specific info
      CGLPixelFormatAttribute attribs[] = { kCGLPFADisplayMask,
                                            dCaps[i].cglDisplayMask, 
                                            NULL };
      CGLPixelFormatObj pixelFormat = NULL;
      long numPixelFormats = 0;
      CGLContextObj cglContext;

      curr_ctx = CGLGetCurrentContext (); // get current CGL context
      CGLChoosePixelFormat (attribs, &pixelFormat, &numPixelFormats);
      if (pixelFormat) {
        CGLCreateContext(pixelFormat, NULL, &cglContext);
        CGLDestroyPixelFormat (pixelFormat);
        CGLSetCurrentContext (cglContext);
        if (cglContext) {
          const GLubyte * strExt;
          const GLubyte * strRend;
          const GLubyte * strVers;
          const GLubyte * strVend;

          // get renderer strings
          strRend = glGetString (GL_RENDERER);
          strncpy (dCaps[i].strRendererName, strRend, 255);
          strVend = glGetString (GL_VENDOR);
          strncpy (dCaps[i].strRendererVendor, strVend, 255);
          strVers = glGetString (GL_VERSION);
          strncpy (dCaps[i].strRendererVersion, strVers, 255);
          { // get BCD version
            short j = 0;
            short shiftVal = 8;
            while (((strVers[j] <= '9') && (strVers[j] >= '0')) ||
                                            (strVers[j] == '.')) { 
            // get only basic version info (until first non-digit or non-.)
              if ((strVers[j] <= '9') && (strVers[j] >= '0')) {
                dCaps[i].glVersion += (strVers[j] - '0') << shiftVal;
                shiftVal -= 4;
              }
              j++;
            }
          }
          strExt = glGetString (GL_EXTENSIONS);

          // get caps
          glGetIntegerv (GL_MAX_TEXTURE_UNITS, 
                         &dCaps[i].textureUnits);
          glGetIntegerv (GL_MAX_TEXTURE_SIZE,
                         &dCaps[i].maxTextureSize); 
          glGetIntegerv (GL_MAX_3D_TEXTURE_SIZE, 
                         &dCaps[i].max3DTextureSize);
          glGetIntegerv (GL_MAX_CUBE_MAP_TEXTURE_SIZE, 
                         &dCaps[i].maxCubeMapTextureSize);

          // get functionality info
          dCaps[i].fSpecularVector = 
            gluCheckExtension ("GL_APPLE_specular_vector", strExt);
          dCaps[i].fTransformHint = 
            gluCheckExtension ("GL_APPLE_transform_hint", strExt);
          dCaps[i].fPackedPixels = 
            gluCheckExtension ("GL_APPLE_packed_pixels", strExt) || 
            gluCheckExtension ("GL_APPLE_packed_pixel", strExt) || 
            (dCaps[i].glVersion >= 0x0120);
          dCaps[i].fClientStorage = 
            gluCheckExtension ("GL_APPLE_client_storage", strExt);
          dCaps[i].fYCbCr = 
            gluCheckExtension ("GL_APPLE_ycbcr_422", strExt);
          dCaps[i].fTextureRange = 
            gluCheckExtension ("GL_APPLE_texture_range", strExt);
          dCaps[i].fFence = 
            gluCheckExtension ("GL_APPLE_fence", strExt);
          dCaps[i].fVAR = 
            gluCheckExtension ("GL_APPLE_vertex_array_range", strExt);
          dCaps[i].fVAO = 
            gluCheckExtension ("GL_APPLE_vertex_array_object", strExt);
          dCaps[i].fElementArray = 
            gluCheckExtension ("GL_APPLE_element_array", strExt);
          dCaps[i].fVPEvals = 
            gluCheckExtension("GL_APPLE_vertex_program_evaluators",strExt);
          dCaps[i].fFloatPixels = 
            gluCheckExtension ("GL_APPLE_float_pixels", strExt);
          dCaps[i].fFlushRenderer = 
            gluCheckExtension ("GL_APPLE_flush_render", strExt);
          dCaps[i].fPixelBuffer = 
            gluCheckExtension ("GL_APPLE_pixel_buffer", strExt);
          dCaps[i].fImaging = 
            gluCheckExtension ("GL_ARB_imaging", strExt);
          dCaps[i].fTransposeMatrix = 
            gluCheckExtension ("GL_ARB_transpose_matrix", strExt) ||
            (dCaps[i].glVersion >= 0x0130);
          dCaps[i].fMultitexture = 
            gluCheckExtension ("GL_ARB_multitexture", strExt) ||
            (dCaps[i].glVersion >= 0x0130);
          dCaps[i].fTexEnvAdd = 
            gluCheckExtension ("GL_ARB_texture_env_add", strExt) ||
            gluCheckExtension ("GL_EXT_texture_env_add", strExt) ||
            (dCaps[i].glVersion >= 0x0130);
          dCaps[i].fTexEnvCombine = 
            gluCheckExtension ("GL_ARB_texture_env_combine", strExt) ||
            (dCaps[i].glVersion >= 0x0130);
          dCaps[i].fTexEnvDot3 = 
            gluCheckExtension ("GL_ARB_texture_env_dot3", strExt) ||
            (dCaps[i].glVersion >= 0x0130);
          dCaps[i].fTexEnvCrossbar = 
            gluCheckExtension ("GL_ARB_texture_env_crossbar", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fTexCubeMap = 
            gluCheckExtension ("GL_ARB_texture_cube_map", strExt) ||
            (dCaps[i].glVersion >= 0x0130);
          dCaps[i].fTexCompress = 
            gluCheckExtension ("GL_ARB_texture_compression", strExt) ||
            (dCaps[i].glVersion >= 0x0130);
          dCaps[i].fMultisample = 
            gluCheckExtension ("GL_ARB_multisample", strExt) ||
            (dCaps[i].glVersion >= 0x0130);
          dCaps[i].fTexBorderClamp = 
            gluCheckExtension ("GL_ARB_texture_border_clamp", strExt) ||
            (dCaps[i].glVersion >= 0x0130);
          dCaps[i].fPointParam = 
            gluCheckExtension ("GL_ARB_point_parameters", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fVertexProg = 
            gluCheckExtension ("GL_ARB_vertex_program", strExt);
          dCaps[i].fFragmentProg = 
            gluCheckExtension ("GL_ARB_fragment_program", strExt);
          dCaps[i].fTexMirrorRepeat = 
            gluCheckExtension ("GL_ARB_texture_mirrored_repeat", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fDepthTex = 
            gluCheckExtension ("GL_ARB_depth_texture", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fShadow = 
            gluCheckExtension ("GL_ARB_shadow", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fShadowAmbient = 
            gluCheckExtension ("GL_ARB_shadow_ambient", strExt);
          dCaps[i].fVertexBlend = 
            gluCheckExtension ("GL_ARB_vertex_blend", strExt);
          dCaps[i].fWindowPos = 
            gluCheckExtension ("GL_ARB_window_pos", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fTex3D = 
            gluCheckExtension ("GL_EXT_texture3D", strExt) ||
            (dCaps[i].glVersion >= 0x0120);
          dCaps[i].fClipVolHint = 
            gluCheckExtension ("GL_EXT_clip_volume_hint", strExt);
          dCaps[i].fRescaleNorm = 
            gluCheckExtension ("GL_EXT_rescale_normal", strExt) ||
            (dCaps[i].glVersion >= 0x0120);
          dCaps[i].fBlendColor = 
            gluCheckExtension ("GL_EXT_blend_color", strExt) ||
            gluCheckExtension ("GL_ARB_imaging", strExt);
          dCaps[i].fBlendMinMax = 
            gluCheckExtension ("GL_EXT_blend_minmax", strExt) ||
            gluCheckExtension ("GL_ARB_imaging", strExt);
          dCaps[i].fBlendSub = 
            gluCheckExtension ("GL_EXT_blend_subtract", strExt) ||
            gluCheckExtension ("GL_ARB_imaging", strExt);
          dCaps[i].fCVA = 
            gluCheckExtension ("GL_EXT_compiled_vertex_array", strExt);
          dCaps[i].fTexLODBias = 
            gluCheckExtension ("GL_EXT_texture_lod_bias", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fABGR = 
            gluCheckExtension ("GL_EXT_abgr", strExt);
          dCaps[i].fBGRA = 
            gluCheckExtension ("GL_EXT_bgra", strExt) ||
            (dCaps[i].glVersion >= 0x0120);
          dCaps[i].fTexFilterAniso = 
            gluCheckExtension ("GL_EXT_texture_filter_anisotropic",strExt);
          dCaps[i].fPaletteTex = 
            gluCheckExtension ("GL_EXT_paletted_texture", strExt);
          dCaps[i].fShareTexPalette = 
            gluCheckExtension ("GL_EXT_shared_texture_palette", strExt);
          dCaps[i].fSecColor = 
            gluCheckExtension ("GL_EXT_secondary_color", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fTexCompressS3TC = 
            gluCheckExtension ("GL_EXT_texture_compression_s3tc", strExt);
          dCaps[i].fTexRect = 
            gluCheckExtension ("GL_EXT_texture_rectangle", strExt);
          dCaps[i].fFogCoord = 
            gluCheckExtension ("GL_EXT_fog_coord", strExt);
          dCaps[i].fDrawRangeElements = 
            gluCheckExtension ("GL_EXT_draw_range_elements", strExt);
          dCaps[i].fStencilWrap = 
            gluCheckExtension ("GL_EXT_stencil_wrap", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fBlendFuncSep = 
            gluCheckExtension ("GL_EXT_blend_func_separate", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fMultiDrawArrays = 
            gluCheckExtension ("GL_EXT_multi_draw_arrays", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fShadowFunc = 
            gluCheckExtension ("GL_EXT_shadow_funcs", strExt);
          dCaps[i].fStencil2Side = 
            gluCheckExtension ("GL_EXT_stencil_two_side", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fColorSubtable = 
            gluCheckExtension ("GL_EXT_color_subtable", strExt) || 
            gluCheckExtension ("GL_ARB_imaging", strExt);
          dCaps[i].fConvolution = 
            gluCheckExtension ("GL_EXT_convolution", strExt) || 
            gluCheckExtension ("GL_ARB_imaging", strExt);
          dCaps[i].fHistogram = 
            gluCheckExtension ("GL_EXT_histogram", strExt) || 
            gluCheckExtension ("GL_ARB_imaging", strExt);
          dCaps[i].fColorTable = 
            gluCheckExtension ("GL_SGI_color_table", strExt) || 
            gluCheckExtension ("GL_ARB_imaging", strExt);
          dCaps[i].fColorMatrix = 
            gluCheckExtension ("GL_SGI_color_matrix", strExt) || 
            gluCheckExtension ("GL_ARB_imaging", strExt);
          dCaps[i].fTexEdgeClamp = 
            gluCheckExtension ("GL_SGIS_texture_edge_clamp", strExt) ||
            (dCaps[i].glVersion >= 0x0120);
          dCaps[i].fGenMipmap = 
            gluCheckExtension ("GL_SGIS_generate_mipmap", strExt);
          dCaps[i].fTexLOD = 
            gluCheckExtension ("GL_SGIS_texture_lod", strExt) ||
            (dCaps[i].glVersion >= 0x0120);
          dCaps[i].fPointCull = 
            gluCheckExtension ("GL_ATI_point_cull_mode", strExt);
          dCaps[i].fTexMirrorOnce = 
            gluCheckExtension ("GL_ATI_texture_mirror_once", strExt);
          dCaps[i].fPNtriangles = 
            gluCheckExtension ("GL_ATI_pn_triangles", strExt) ||
            gluCheckExtension ("GL_ATIX_pn_triangles", strExt);
          dCaps[i].fTextFragShader = 
            gluCheckExtension ("GL_ATI_text_fragment_shader", strExt);
          dCaps[i].fBlendEqSep = 
            gluCheckExtension ("GL_ATI_blend_equation_separate", strExt);
          dCaps[i].fBlendWeightMinMax = 
            gluCheckExtension ("GL_ATI_blend_weighted_minmax", strExt);
          dCaps[i].fCombine3 = 
            gluCheckExtension ("GL_ATI_texture_env_combine3", strExt);
          dCaps[i].fSepStencil = 
            gluCheckExtension ("GL_ATI_separate_stencil", strExt);
          dCaps[i].fArrayRevComps4Byte = 
            gluCheckExtension ("GL_ATI_array_rev_comps_in_4_bytes",strExt);
          dCaps[i].fPointSprite = 
            gluCheckExtension ("GL_NV_point_sprite", strExt);
          dCaps[i].fRegCombiners = 
            gluCheckExtension ("GL_NV_register_combiners", strExt);
          dCaps[i].fRegCombiners2 = 
            gluCheckExtension ("GL_NV_register_combiners2", strExt);
          dCaps[i].fTexEnvCombine4 = 
            gluCheckExtension ("GL_NV_texture_env_combine4", strExt);
          dCaps[i].fBlendSquare = 
            gluCheckExtension ("GL_NV_blend_square", strExt) ||
            (dCaps[i].glVersion >= 0x0140);
          dCaps[i].fFogDist = 
            gluCheckExtension ("GL_NV_fog_distance", strExt);
          dCaps[i].fMultisampleFilterHint = 
            gluCheckExtension ("GL_NV_multisample_filter_hint", strExt);
          dCaps[i].fTexGenReflect = 
            gluCheckExtension ("GL_NV_texgen_reflection", strExt);
          dCaps[i].fTexShader = 
            gluCheckExtension ("GL_NV_texture_shader", strExt);
          dCaps[i].fTexShader2 = 
            gluCheckExtension ("GL_NV_texture_shader2", strExt);
          dCaps[i].fTexShader3 = 
            gluCheckExtension ("GL_NV_texture_shader3", strExt);
          dCaps[i].fDepthClamp = 
            gluCheckExtension ("GL_NV_depth_clamp", strExt);
          dCaps[i].fLightMaxExp = 
            gluCheckExtension ("GL_NV_light_max_exponent", strExt);
          dCaps[i].fRasterPosClip = 
            gluCheckExtension ("GL_IBM_rasterpos_clip", strExt);
          dCaps[i].fConvBorderModes = 
            gluCheckExtension ("GL_HP_convolution_border_modes", strExt) ||
            gluCheckExtension ("GL_ARB_imaging", strExt);

          if (dCaps[i].fTexRect) // only check if extension supported
            glGetIntegerv (GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT,
                           &dCaps[i].maxRectTextureSize);
          else
            dCaps[i].maxRectTextureSize = 0;

          CGLDestroyContext (cglContext);
        }
      }
      CGLSetCurrentContext (curr_ctx); // reset current CGL context
    }
  }
}

Это завершает обсуждение функциональности OpenGL. Понимание отношения ядра к расширенным командам является ключевым для простой навигации и использования OpenGL на всех поддерживаемых платформах. Это Техническое примечание обсудило базовую и расширенную функциональность и как определить, поддерживается ли определенная функция. Кроме того, создание допустимых контекстов рендеринга было обсуждено в контексте интерфейса Mac OS X OpenGL API's. Наконец, конкретный пример того, как полностью проверить на доступные системные средства рендеринга и их функциональность, предоставлен.



История версии документа


ДатаПримечания
29.12.2003

Новый документ, обсуждающий OpenGL проект API, и как получить доступ к полномочиям аппаратных и программных средств рендеринга.