2011-06-21 19 views
10

Tengo dos sistemas diferentes uno con OpenGL 1.4 y uno con 3. Mi programa usa Shaders que son parte de OpenGL 3 y solo se admiten como extensión ARB en la implementación 1.4.¿Cómo soporto las diferentes versiones de OpenGL?

Como no puedo usar las funciones de OpenGL 3 con OpenGL 1.4, ¿hay alguna manera de admitir ambas versiones de OpenGL sin escribir el mismo código OpenGL dos veces (ARB/EXT y v3)?

Respuesta

10

A menos que realmente tenga que admitir tarjetas gráficas de 10 años por alguna razón, le recomiendo que apunte a OpenGL 2.0 en lugar de 1.4 (de hecho, incluso llegaría a la versión 2.1).

Desde el uso de "shaders que son fundamentales en 3,0" necesariamente significa que los gráficos tarjeta debe ser capaz de al menos alguna versión de GLSL, esto excluye cualquier hardware que no es capaz de proporcionar al menos OpenGL 2.0. Lo que significa que si alguien tiene OpenGL 1.4 y puede ejecutar sus sombreadores, está usando controladores de 8-10 años. Hay poco que ganar (aparte de una pesadilla de soporte) de eso.

La orientación a OpenGL 2.1 es razonable, actualmente apenas existen sistemas que no lo admitan (incluso suponiendo un mínimo de OpenGL 3.2 puede ser una opción totalmente razonable).

El precio de mercado de una tarjeta compatible con OpenGL 3.3 de nivel de entrada con aproximadamente 1000 veces la potencia de procesamiento de una tarjeta OpenGL 1.4 de alto rendimiento fue de aproximadamente $ 25 hace unos dos años. Si alguna vez tiene la intención de vender su aplicación, debe preguntarse si alguien que no puede pagar (o no quiere pagar) sería alguien que razonablemente podría esperar pagar por su software.

Habiendo dicho eso, admitir OpenGL 2.xy OpenGL> 3.1 al mismo tiempo es una pesadilla, porque hay cambios no triviales en el lenguaje de sombreado que van más allá de #define in varying y que le morderán regularmente.

Por lo tanto, tengo personalmente elegido para nunca más apuntar a nada inferior a la versión 3.2 con arrays de instancia y objetos de sombreado. Esto funciona con todo el hardware que razonablemente se espera que tenga el poder de procesamiento para ejecutar una aplicación moderna, e incluye a los usuarios que eran demasiado perezosos para actualizar su controlador a 3.3, proporcionando las mismas características en una sola ruta de código. Las características de OpenGL 4.x se pueden cargar como extensión si están disponibles, lo cual está bien.
Pero, por supuesto, todo el mundo tiene que decidir por sí mismo qué zapato le queda mejor.

basta de mi, bla, bla, volviendo a la pregunta real:
Acerca de no duplicar código para las extensiones/núcleo, que en muchos casos puede usar los mismos nombres, los punteros a funciones y constantes. Sin embargo, tenga cuidado: Como una declaración general, esto es ilegal, indefinido y peligroso.
En la práctica, la mayoría de las extensiones (¡no todas!) Son idénticas a la funcionalidad principal respectiva y funcionan igual. ¿Pero cómo saber cuáles puedes usar y cuáles se comerán a tu gato? Mire gl.spec - una función que tiene una entrada alias es idéntica e indistinguible de su alias. Puede con seguridad utilizar estos de manera intercambiable.
Las extensiones que son problemáticas a menudo también tienen un comentario explicativo en alguna parte (como "Este no es un alias de PrimitiveRestartIndexNV, ya que establece el servidor en lugar del estado del cliente"), pero no confíe en éstos, confíe en alias campo.

+0

¿Hay alguna garantía de que el alias ARB esté definido si existe la funcionalidad core correspondiente? – josefx

+0

@josefx: Como una declaración general: no. No hay garantía de que si una implementación admite, por ejemplo, core 3.0, que también admite las extensiones EXT_ y ARB_ que se han convertido en núcleo. Aunque la mayoría de las veces son compatibles (en realidad no es tonto), recuerdo que sucedió una vez que quería utilizar una extensión que de repente "desapareció" en mi sistema porque era central. "Reapareció mágicamente" con el próximo lanzamiento del controlador (¿se supone que la gente se quejó?). Al menos tienes una garantía formal (errores del controlador eximidos) que si dice "Alias" en el archivo de especificación ... – Damon

+1

... que puedes usar una función como la otra, sin embargo. Por supuesto, nunca estás a salvo de una implementación defectuosa, pero no hay nada g puedes hacer frente a eso de todos modos. Las extensiones son generalmente un asunto complicado. Por ejemplo, todas las extensiones ARB tienen el prefijo ARB_. Pero algunos animales son más iguales que otros. Los "backtensions" como los llamo (los que implementan la funcionalidad 3.x en contextos 2.x y la funcionalidad 4.x en contextos 3.x) no cumplen ese esquema de nombres. Lo que, francamente, hace que la vida del programador sea innecesariamente complicada ... – Damon

3

Depende: ¿desea utilizar la funcionalidad OpenGL 3.x? No solo usa la API, sino que usa las funciones de hardware reales detrás de esa API.

De lo contrario, puede escribir contra GL 1.4 y confiar en el perfil de compatibilidad. Si lo hace, necesitará códigos de ruta separados para los diferentes niveles de hardware que pretenda admitir. Esto es estándar, solo para soportar diferentes niveles de funcionalidad de hardware.

5

Al igual que @Nicol Bolas ya te dijo, es inevitable crear dos rutas de codificación para OpenGL-3 core y OpenGL-2. El núcleo OpenGL-3 deliberadamente rompe con la compatibilidad. Sin embargo, lo que está en juego no es tan malo como podría parecer, porque la mayoría de las veces el código diferirá solo en matices y ambos recorridos de códigos se pueden escribir en un único archivo fuente y usar métodos de compilación condicional.

Por ejemplo

#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 

shaders GLSL pueden ser reutilizados similarily. El uso de macros para cambiar orrucances de identificadores predefinidos, pero depreceated o la introducción de palabras clave de la versión posterior, por ejemplo.

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

vec4f gl_Position; 
#endif 

Por lo general, tendrá un conjunto de cabeceras estándar de código de gestión de shader de su programa de construcción de la fuente final, pasó a OpenGL, por supuesto, de nuevo dependiendo del código base utilizado.

+0

Prefiero un sistema binario compatible con tantos sistemas como sea posible, así que voy a ir con la respuesta de Damon para el código de C++ y la tuya para los sombreadores. – josefx

+1

@josefx: ¡Dos rutas de codificación no implican dos binarios! Puede vincular ambas rutas en un solo binario, en el que solo el punto de entrada realiza el cambio. – datenwolf

+0

No pensé en eso. A veces odio que stackoverflow solo permita una respuesta aceptada por pregunta :(. – josefx

Cuestiones relacionadas