Как я могу поддерживать разные версии OpenGL?

У меня две разные системы: одна с OpenGL 1.4 и одна с 3. Моя программа использует шейдеры, которые являются частью OpenGL 3 и поддерживаются только как расширение ARB в реализации 1.4.

Так как я не могу использовать функции OpenGL 3 с OpenGL 1.4, есть ли способ поддерживать обе версии OpenGL без одновременного написания одного и того же кода OpenGL (ARB/EXT и v3)?

Ответ 1

Если вам по какой-то причине не нужна поддержка 10-летних видеокарт, я настоятельно рекомендую настроить OpenGL 2.0 вместо 1.4 (фактически, я даже дошел до версии 2.1).

Поскольку использование "шейдеров, являющихся ядром в версии 3.0", обязательно означает, что графическая карта должна иметь хотя бы некоторую версию GLSL, это исключает любое аппаратное обеспечение, которое не способно обеспечить хотя бы OpenGL 2.0. Это означает, что если у кого-то есть OpenGL 1.4 и вы можете запускать свои шейдеры, он использует 8-10-летние драйверы. Из этого можно немного выиграть (кроме кошмара поддержки).

Targeting OpenGL 2.1 разумно, в настоящее время практически нет систем, которые не поддерживают это (даже если предположить, что минимум OpenGL 3.2 может быть вполне разумным выбором).

Рыночная цена для совместимой с OpenGL 3.3 совместимой карты начального уровня с примерно 1000x вычислительной мощностью высокопроизводительной карты OpenGL 1.4 составляла около 25 долларов США примерно два года назад. Если вы когда-либо собираетесь продавать свою заявку, вы должны спросить себя, может ли кто-то, кто не может позволить себе (или не хочет себе этого позволить), это тот, кого вы разумно ожидаете заплатить за свое программное обеспечение.

Сказав, что поддержка OpenGL 2.x и OpenGL > 3.1 в то же время является кошмаром, потому что есть нетривиальные изменения в языке затенения, которые выходят далеко за пределы #define in varying и которые будут регулярно вас кусать.

Поэтому я лично решил никогда больше не нацеливаться на меньшее, чем версия 3.2, с массивными массивами и объектами шейдеров. Это работает со всем оборудованием, которое можно разумно ожидать, имея вычислительную мощность для запуска современного приложения, и оно включает пользователей, которые слишком ленивы, чтобы обновить свой драйвер до 3.3, предоставляя одни и те же функции в одном пути кода. Возможности OpenGL 4.x можно загрузить как расширение, если оно доступно, и это нормально.
Но, конечно, каждый должен решить для себя, какая обувь подходит лучше всего.

Хватит моего бла-бла, вернемся к актуальному вопросу:
О том, чтобы не дублировать код для расширений/ядро, во многих случаях можно использовать те же имена, указатели на функции и константы. Однако будьте предупреждены: в качестве общего заявления это незаконно, undefined и опасно.
На практике большинство (не всех!) Расширений идентичны соответствующим функциональным возможностям ядра и работают одинаково. Но как узнать, какие из них вы можете использовать, а какие будут есть вашу кошку? Посмотрите gl.spec - функция, которая имеет запись alias, идентична и неотличима от ее псевдонима. Вы можете безопасно использовать эти взаимозаменяемые. Часто возникающие проблемы часто содержат пояснительный комментарий (например, "Это не псевдоним PrimitiveRestartIndexNV, поскольку он устанавливает сервер вместо состояния клиента".), Но не полагайтесь на них, полагайтесь на поле alias.

Ответ 2

Как уже сказал вам @Nicol Bolas, неизбежно создать две кодировки для ядра OpenGL-3 и OpenGL-2. Ядро OpenGL-3 намеренно ломается от совместимости. Однако ставки не так плохи, как может показаться, потому что большую часть времени код будет отличаться только нюансами, а обе кодировки могут быть записаны в одном исходном файле и с использованием методов условной компиляции.

Например

#ifdef OPENGL3_CORE
    glVertexAttribPointer(Attribute::Index[Position], 3, GL_FLOAT, GL_FALSE, attribute.position.stride(), attribute.position.data());
    glVertexAttribPointer(Attribute::Index[Normal], 3, GL_FLOAT, GL_FALSE, attribute.position.stride(), attribute.position.data());

#else
    glVertexPointer(3, GL_FLOAT, attribute.position.stride(), attribute.position.data());
    glNormalPointer(GL_FLOAT, attribute.normal.stride(), attribute.normal.data());
#endif

Шейдеры GLSL можно использовать повторно. Использование макросов для изменения orrucances предопределенных, но обесцвеченных идентификаторов или введения более поздних версий, например,

#ifdef USE_CORE
#define gl_Position position
#else
#define in varying
#define out varying
#define inout varying

vec4f gl_Position;
#endif

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

Ответ 3

Это зависит от того, хотите ли вы использовать OpenGL 3.x? Не просто использовать API, но и использовать фактические аппаратные функции за этим API.

Если нет, вы можете просто написать против GL 1.4 и опираться на профиль совместимости. Если вы это сделаете, вам понадобятся отдельные кодеки для разных уровней аппаратного обеспечения, которые вы собираетесь поддерживать. Это стандарт, только для поддержки различных уровней функциональности оборудования.