¿Diferencia entre "buffer" y "array" en OpenGL?

12

Cuando leo el documento en webGL u OpenGL, se pueden ver algunos patrones en cómo se usan los nombres de funciones y objetos. Pero no puedo entender la diferencia entre el objeto de búfer y una matriz.

Hay "objetos de búfer de vértices", "objetos de matriz de vértices" e incluso algún tipo de "matriz de búfer" o "matriz de búfer".

En el contexto de OpenGL, ¿cuándo algo es "matriz" y cuándo debería llamarse "buffer"?

coobit
fuente
Alguna perspectiva, piense en buscar datos a través de la red y almacenar un registro de todo lo recibido. Debe leer el socket y colocar los datos recibidos en algún lugar para poder pasarlos, eso es un búfer. A menudo puede ser un tipo de lista simple de ámbito local, asignado dinámicamente. A veces es tan simple como un char* buffer = socketRead();(pseudocódigo). El registro, por otro lado, vive a través de todo el ciclo de vida de la aplicación. Entonces, crea una matriz en algún lugar y comienza a leer el socket, cada vez que obtiene datos, escribe esa porción en la matriz, lo que le brinda una lista ordenada de todos los datos que recibió.
Kevin

Respuestas:

5

La denominación de Vertex Array Object es algo desafortunada. Hay tres cosas diferentes que aparecen (solían aparecer) en / con / alrededor de su aplicación, y que (históricamente) se nombraron de manera diferente, con "matriz" o "buffer" en el nombre (bueno, también hay objetos framebuffer, pero lo ignoraré)

  1. Datos que viven en su aplicación, formal y fácticamente, pero que OpenGL extrae de una vez (en lugar de vertex por vertex). Érase una vez lo que llamarías matriz de vértices .
    La intención de esto era hacer que el acceso fuera más eficiente, ya que OpenGL podría copiar todo de una vez en un momento bien definido cuando prometió que los datos eran consistentes y pasarlos a AGP o lo que sea en un bloque. Esto ya no existe.
  2. Datos oscurecidos y accesibles por un identificador que puede "vincularse", es decir, activarse. Los datos pueden vivir de hecho en la memoria principal, o en la tarjeta gráfica, o trasladarse a una región mapeable PCIe, lo que sea, pero de cualquier manera que no posea formalmente (incluso si está físicamente en la RAM y si los datos provienen de su aplicación ) - a menos que lo haya "mapeado" actualmente a través de la API correspondiente, obteniendo un puntero escribible (y a veces legible). También tiene una capacidad limitada para controlar lo que sucede con los datos (puede dar algunas pistas, pero eso es todo).
    OpenGL puede mover estos datos más o menos libremente, y solo se le permite / puede copiar al / desde el búfer a través de la API correspondiente o acceder a los datos mientras se está asignando. Eso es lo que se llama un objeto de búfer ( objeto de búfer de vértices si contiene vértices, pero realmente no tiene que ser así, podrían ser datos de imagen o uniformes, solo los vértices fueron los primeros en ser apoyados, alguna vez).
    La intención de esto es garantizar que OpenGL pueda (en principio) hacer lo que quiera, incluso puede empujar el búfer sobre PCIe especulativamente incluso antes de dibujar. Eso funciona porque no posee los datos (¡OpenGL sí!) Y solo puede acceder a ellos a través de la API dada, por lo que se sabe en todo momento que los datos son válidos. El controlador incluso puede optar por desechar la memoria intermedia en la tarjeta gráfica cuando necesita memoria para algo diferente y luego restaurarla desde su copia secreta cuando sea necesario.
  3. Un nombre inapropiado realmente estúpido para el que un nombre mucho mejor sería algo como conjunto de búfer o conjunto de descriptores, este es el infame objeto de matriz de vértices . Desde su punto de vista, no es más que un conjunto de controladores de búfer agrupados bajo otro controlador oscuro (que puede vincular). Resulta que la realidad es un poco más complicada. De hecho, VAO está mucho más cerca de cómo funciona el hardware real. Las tarjetas gráficas tienen un pequeño número (a menudo algo así como 2, 4 u 8) de conjuntos de descriptores (no solo para búferes, sino también para muestreadores) con tantas entradas en cada uno, entre las cuales pueden cambiar de manera muy eficiente .
    Ahora, la intención del objeto de matriz de vértices es reducir el número de llamadas API y reducir el número de comprobaciones de consistencia que OpenGL debe hacer internamente y, por supuesto, para usar el hardware tal como funciona. Si enlaza 5 buffers, cada uno debe pasar por algunas comprobaciones posiblemente costosas, y cada uno es candidato para errores de caché en el controlador, además de que cada uno requiere comunicarse con la tarjeta gráfica para cambiar un descriptor, etc., etc. enlazar un VAO, el controlador puede (a menudo) simplemente cambiar el conjunto de descriptores en la tarjeta gráfica, y listo.
Damon
fuente
8

Un objeto Vertex Array (VAO) es un objeto que contiene uno o más objetos Vertex Buffer y está diseñado para almacenar la información de un objeto renderizado completo.

(sacado de khronos )

Cada búfer tiende a constituir un atributo de una matriz de vértices (objeto). Un VAO puede contener muchos atributos de vértice (por ejemplo, posición, color, UV). Cada uno puede mantenerse en su propio búfer, donde el búfer indica una serie sin formato de bytes contiguos, y donde necesita especificar explícitamente el tamaño (tipo) por elemento de búfer para las llamadas OpenGL del lado de la CPU y el trabajo del sombreador del lado de la GPU.

Esa es una forma. Las otras formas en que esto puede funcionar son:

  • Todos los atributos se almacenan intercalados en un único búfer, O
  • Algunos de los atributos existen en sus propios buffers dedicados, mientras que otros comparten buffers.

El siguiente diagrama ilustra estos dos últimos casos.

ingrese la descripción de la imagen aquí

En pocas palabras: si la frase "matriz de vértices" se usa sin calificar en OpenGL, puede suponer que significa VAO, lo que, en un contexto de OpenGL (específicamente) es una cosa muy diferente de un búfer.

EDITAR re su comentario: GL_ARRAY_BUFFERindica una intención de usar ese objeto de búfer para los datos de atributos de vértice, como se describió anteriormente. Esto se debe a que los búferes no se usan solo para los atributos de vértice. Sin embargo, como es el caso de uso más común y usted está preguntando acerca de VAO, no entraré en los otros; Sin embargo, aquí hay una lista de los otros tipos de buffers que se pueden configurar.

Ingeniero
fuente
Por lo tanto, los buffers son: 1.resid en GPU, 2. la mayoría de las veces contienen un tipo de datos (solo vértice, solo color ect), 3.Los datos están intercalados, es decir, 111122223333 ect. 4. no proporcione ningún método para acceder a los datos (no el búfer [2] o el búfer [vertex_3434]) Ahora, las matrices son: 1. colección de búferes, 2. almacena información sobre cómo analizar los búferes que contiene. , tamaño de un elemento, compensaciones, por lo que se puede acceder correctamente a los datos de los buffers, ¿verdad?
coobit
1. Existen almacenamientos intermedios en ambos extremos y se transfieren entre la CPU y la GPU (potencialmente de un lado a otro), de lo contrario, ¿cómo llenaría los datos para cargarlos en la GPU al cargar una malla desde el disco? Sí, los elementos son de tipo uniforme en todo el búfer, pero dependiendo de la tecnología que esté utilizando, cada elemento del búfer puede ser primitivo o de structtipo. Los datos pueden estar intercalados o ser completamente uniformes, por búfer. Puede indexarlos, al igual que con una matriz C tradicional en la CPU. Arregle objetos (¡use esta terminología correcta o termine confundiéndose!) ... (continúa a continuación)
Ingeniero
2. Sí, y debe asegurarse explícitamente de que sus declaraciones de búfer en el sombreador coincidan con las especificaciones que configuró en su VAO en el lado de la CPU: "Todos los estados relacionados con la definición de datos utilizados por el procesador de vértices están encapsulados en un vértice objeto de matriz ". (khronos docs)
Ingeniero el
Entonces, para dar en el clavo más ... ¿Cómo trabajaban las personas antes de que AO solo usara BO? ¿O AO siempre estuvo presente en OpenGL y es solo VAO que se introdujo más tarde que VBO?
Coobit
@coobit io7m.com/documents/history-vertex-spec : esto le da una idea de las diferencias entre OpenGL, 3Dfx, etc.
Ingeniero
5

Esta terminología se basa en la historia de OpenGL. Lo que es importante recordar es que, para la mayoría de las versiones de GL que son relevantes aquí, OpenGL evolucionó gradualmente y al agregar nuevas funcionalidades a una API ya existente en lugar de cambiar la API.

La primera versión de OpenGL no tenía ninguno de estos tipos de objetos. El dibujo se logró mediante la emisión de múltiples llamadas glBegin / glEnd, y un problema con este modelo fue que era muy ineficiente, en términos de sobrecarga de llamadas de función.

OpenGL 1.1 dio los primeros pasos para abordar esto mediante la introducción de matrices de vértices. En lugar de especificar directamente los datos de vértice, ahora puede obtenerlos de matrices C / C ++, de ahí el nombre. Entonces, una matriz de vértices es solo eso: una matriz de vértices y el estado GL requerido para especificarlos.

La siguiente evolución importante vino con GL 1.5 y permitió almacenar datos de matriz de vértices en la memoria de la GPU en lugar de en la memoria del sistema ("lado del cliente"). Una debilidad de la especificación de matriz de vértices GL 1.1 era que el conjunto completo de datos de vértices tenía que transferirse a la GPU cada vez que deseaba usarlo; si ya estaba en la GPU, entonces esta transferencia podría evitarse y se podrían lograr ganancias potenciales de rendimiento.

Por lo tanto, se creó un nuevo tipo de objeto GL para permitir el almacenamiento de estos datos en la GPU. Al igual que un objeto de textura se usa para almacenar datos de textura, un objeto de búfer de vértice almacena datos de vértice. En realidad, esto es solo un caso especial de un tipo de objeto de almacenamiento intermedio más general que puede almacenar datos no específicos.

La API para usar objetos de búfer de vértices estaba respaldada en la API de matrices de vértices ya existente, por lo que ve cosas extrañas como convertir desplazamientos de bytes en punteros. Entonces, ahora tenemos una API de matrices de vértices que solo almacena el estado, y los datos se obtienen de objetos de búfer en lugar de matrices en memoria.

Esto nos lleva casi al final de nuestra historia. La API resultante fue bastante detallada a la hora de especificar el estado de la matriz de vértices, por lo que otra vía de optimización fue crear un nuevo tipo de objeto que reuniera todo este estado, permitiera múltiples cambios de estado de la matriz de vértices en una sola llamada de API y permitió GPU potencialmente realizar optimizaciones debido a poder saber qué estado se iba a utilizar antes de tiempo.

Ingrese el objeto de matriz de vértices, que recopila todo esto junto.

Entonces, para resumir, una matriz de vértices comenzó como una colección de estado y datos (almacenados en una matriz) para dibujar. Un búfer de vértices reemplaza el almacenamiento de la matriz en memoria con un tipo de objeto GL, dejando la matriz de vértices solo en estado. Un objeto de matriz de vértices es solo un objeto contenedor para este estado, lo que permite cambiarlo más fácilmente y con menos llamadas a la API.

Maximus Minimus
fuente
0

Hace tiempo que no trabajo con OpenGL, por lo que solo podría tener la mitad de la razón. En términos generales: los almacenamientos intermedios almacenan una matriz de memoria sin formato. Una matriz es un término general de memoria contigua.

Un búfer debe estar vinculado al contexto, mientras que una matriz es solo una matriz de datos. Si recuerdo correctamente, los datos en el búfer deben copiarse en la tarjeta gráfica (de ahí el enlace).

Espero que esto ayude un poco

Jugo
fuente
¿Qué es GL_ARRAY_BUFFER entonces? ¿Por qué se llama así? Según su hipótesis, es "memoria contigua sin formato" :)
coobit
Bueno, este ejemplo en particular es solo una identificación de un búfer (al que vincula su matriz). El Array Buffer (en su ejemplo) se usa para atributos de vértice, por lo que básicamente vincula su matriz de atributos de vértice a un búfer. Suena confuso, así que déjame darte un ejemplo. Tiene una matriz en el lado de la CPU que puede ser de color, normal, posiciones, etc., y ahora desea que la gpu acceda a ella. Eso es cuando entra el bindBuffer, básicamente mapeando su "matriz de cpu" a la "matriz de gpu".
Juicef
En cuanto a por qué se llama así, no puedo responder eso. Supongo que es porque tiene una variedad de datos diferentes que van allí, color, normal, etc.
Juicef