API gráfica de bajo nivel multiplataforma

11

Al crear una abstracción del sistema, es mejor tener las API diferentes de la plataforma ocultas por una interfaz común en el nivel más bajo que tenga sentido.

Teniendo en cuenta las diferentes API de gráficos nativos modernos (sin canalización de función fija): OpenGLES 2.0+, OpengGL 3.0+, DirectX 10.0+, Xbox DirectX 9, LibGCM

Si uno fuera a crear una API gráfica de bajo nivel sin estado para sentarse sobre todos ellos, ¿cuál sería la mejor manera de hacerlo para que sea lo más delgado y rápido posible?

NocturnDragon
fuente
El requisito de que la API no tenga estado es interesante. OpenGL, por ejemplo, tiene estado, y creo que una API sin estado que lo envuelva solo tendría sentido si fuera un nivel mucho más alto, por lo que no es, por ejemplo, tener que presionar y hacer estallar las mismas matrículas para todos y cada uno superficie que rinde.
SpoonMeiser
Evitar cambios de estado inútiles aún podría implementarse en un nivel superior, como ordenar las llamadas de procesamiento según su estado antes de enviarlas al dispositivo. Y configurando el estado solo si es diferente del actual.
NocturnDragon
Sin embargo, eso no es apátrida. Tal vez me equivoque, pero lo que pienso cuando pienso en sin estado, es una API donde cada llamada no depende en absoluto de las llamadas anteriores. Eso significa que cualquier información que normalmente se almacenaría en algún lugar debe pasarse en cada llamada que necesite esa información. Para OpenGL, por ejemplo, estas serían matrices en la pila, iluminación, z-buffering y opciones de normalización.
SpoonMeiser
Sí, para cada llamada de sorteo que necesitaría, los datos de malla, el estado de fusión, las texturas a unir, los estados de muestreo, etc. Las optimizaciones podrían realizarse más tarde, sin cambiar la API. O tal vez estoy leyendo mal tu comentario ..
NocturnDragon

Respuestas:

6

El nivel más bajo que tiene sentido desde mi punto de vista es algo que habla de los recursos involucrados en el renderizado: vb / ib, superficies de renderizado, texturas, sombreadores, bloques de estado, etc.

El problema aquí es que algunos de estos deben estar en diferentes formatos, dependiendo de la API; ahí es donde se vuelve un poco complicado. La forma más fácil de evitarlo es preprocesar los recursos estáticos para la API respectiva. Para los dinámicos, use solo sombreadores para generarlos, lo que hace que sea bastante sencillo permanecer en formatos nativos.

Todo lo que haces en el nivel superior es configurar tuberías con recursos adjuntos y entregarlas a la GPU. Descubrirá que no todo se puede resumir de esa manera, especialmente si aprovecha los trucos específicos del hardware. Pero es un buen comienzo.

(Nota al margen: si trata los trucos específicos de la plataforma como un tipo especial de recurso, puede llevar todo este concepto bastante lejos).

Entonces, de alguna manera, creará dos cosas: un administrador de recursos de hardware, más un kit de herramientas para configurar un DAG de estos recursos.

Rachel Blum
fuente
Nunca pensé en tratar las cosas específicas de la plataforma como recursos. ¡Parece una muy buena idea! Gracias.
NocturnDragon
10

Dada la amplia gama de API que desea cubrir, es probable que el enfoque de ajuste típico sea ineficiente y propenso a la dificultad de mapear conceptos de API en varias otras API que pueden o no admitir funciones particulares en diversos grados.

Como resultado, el enfoque más sensato sería crear una API centrada en características . Si bien este enfoque evita que el usuario de la API utilice todas las funciones disponibles, simplifica enormemente la implementación de cada back-end y permite optimizaciones específicas de back-end que de otro modo no serían posibles.

También simplifica enormemente la administración de funcionalidades no compatibles para el usuario de la API; ya no tienen que verificar si la función X existe y determinar qué características están afectadas, sino que solo necesitan consultar la característica en sí para ver si es compatible con la configuración actual. Incluso si admite modos parciales o limitados para las características, el contexto proporcionado hace que sea mucho más fácil de administrar.

En términos de crear un renderizador sin estado (también conocido como basado en el envío ), normalmente se usa una clave de 64 bits para empaquetar y enviar comandos para el procesamiento. A partir de ese momento, existe una gran flexibilidad en términos de cómo ejecutar comandos y qué información enviar dependiendo de las características y capacidades que desee admitir.

Jason Kozak
fuente
Esta es realmente una buena idea. Y es parte del diseño que estoy tratando de crear, pero lo que tenía en mente era implementar estas características sobre una API común de bajo nivel. Pero puede ser el caso de que para algunas características aún necesite profundizar en la API nativa para algunos casos más particulares.
NocturnDragon
Parte de la idea es evitar construir una API común de bajo nivel y tener que lidiar con el ajuste con un enfoque de mínimo común denominador. Al subir el nivel de abstracción a un nivel superior, restringe un poco el conjunto de características, pero también obtiene la capacidad de explotar cada plataforma. Para manejar la necesidad ocasional de un acceso más profundo, prefiero proporcionar un encabezado que exponga los encabezados de la plataforma y algunos ayudantes internos; puede romper versión por versión, pero está ahí si la necesita.
Jason Kozak
1

Para empezar, cada API hace las cosas de manera diferente, por lo que debería ser evidente que sería difícil ajustar todas las API anteriores. Dicho esto, a veces es necesario hacerlo: en algún momento un juego simplemente necesita ejecutarse en más de una plataforma, independientemente de lo difícil que sea hacerlo.

Creo que la mejor manera de hacerlo es idear la funcionalidad que se puede implementar en todas las API subyacentes y resumir eso y solo eso. Si está desarrollando un juego multiplataforma, no implementaría todas las funciones oscuras que admite cada API, solo implementaría lo que necesita. Esto también ayuda a mantener la API pequeña y rápida.

Para evitar el desorden de la implementación de cada API diferente que se empaqueta en la salida, la compilación debe hacerse con archivos de encabezado neutral de plataforma y archivos de código específicos de plataforma. Entonces, el archivo de código específico para la plataforma de destino sería el único compilado que mantiene la API pequeña.

Sean James
fuente
-4

Es posible que desee consultar la biblioteca SDL o Allegro . Ambas son bibliotecas de juegos de bajo nivel y altamente portátiles, que tienen una forma de conectarlas en un contexto OpenGL para que pueda renderizar sus gráficos allí. SDL tiene la fama de ser utilizado por Loki Games para portar algunos juegos populares de la década de 2000 a Linux, y Allegro tiene mucho tiempo funcionando y tiene una gran comunidad de desarrolladores de juegos aficionados.

chiguire
fuente
44
Esto realmente no responde la pregunta, sin mencionar que es muy posible ajustar tanto OpenGL como DirectX (ver Ogre3D, Irrlicht, etc.).
Jason Kozak
Considera los juegos que has jugado. ¿Cuántos de ellos tienen opciones para usar DirectX u OpenGL? Así es como muchos crean envoltorios para que las dos bibliotecas puedan soportar cualquiera de ellos. Tienes una imaginación limitada. :-P
Ricket
Reconozco que hay algunos juegos que te permiten elegir si quieres renderizar gráficos con OpenGL o DirectX, pero la pregunta es sobre una API multiplataforma, así que creo que la respuesta es adecuada, editaré el primer párrafo, aunque.
chiguire
1
La pregunta es sobre una API de bajo nivel sin estado multiplataforma. SDL y Allegro no tienen nada que ver con eso.
NocturnDragon
@NocturnDragon: el título de la pregunta es un poco engañoso. A primera vista, esperaba que la pregunta fuera sobre las opciones de API disponibles, y supongo que este respondedor también lo hizo.
a_m0d