Differenza tra "buffer" e "array" in OpenGL?


12

Quando leggo doc su webGL o OpenGL si possono vedere alcuni schemi su come vengono usati i nomi di funzioni e oggetti. Ma non riesco a capire la differenza tra oggetto buffer e un array.

Esistono "oggetti buffer vertici", "oggetti array vertici" e persino una sorta di "array buffer" o "arraybuffer".

Nel contesto OpenGL, quando qualcosa è "array" e quando invece dovrebbe essere chiamato "buffer"?


Qualche prospettiva, pensa a recuperare i dati sulla rete e archiviare un registro di tutto ciò che è stato ricevuto. Devi leggere il socket e mettere i dati ricevuti da qualche parte in modo da poterlo passare, è un buffer. Spesso può essere un tipo di elenco semplice con ambito locale, allocato dinamicamente. A volte è semplice come un char* buffer = socketRead();(pseudocodice). Il registro d'altra parte, vive per l'intero ciclo di vita dell'app. Quindi crei un array da qualche parte e inizi a leggere il socket, ogni volta che ottieni dati scrivi quel pezzo sull'array, dandoti un elenco accurato di tutti i dati che hai ricevuto.
Kevin,

Risposte:


5

La denominazione di Vertex Array Object è piuttosto sfortunata. Ci sono tre cose diverse che appaiono (usate per apparire) in / con / attorno alla tua applicazione e che sono (sono state, storicamente) nominate diversamente, con "array" o "buffer" nel nome (beh, ci sono anche oggetti framebuffer, ma lo ignorerò).

  1. Dati che risiedono nella tua applicazione, in modo formale e fattuale, ma che sono raccolti da OpenGL in una volta (al contrario di vertice per vertice). Questo era una volta ciò che chiamereste array di vertici .
    L'intento era quello di rendere l'accesso più efficiente poiché OpenGL poteva semplicemente copiare tutto in una volta in un momento ben definito quando si prometteva che i dati fossero coerenti e lo spingevano su AGP o qualunque cosa in un blocco. Questo non esiste più.
  2. Dati oscurati e accessibili da un handle che può essere "associato", ovvero reso attivo. I dati possono effettivamente vivere nella memoria principale, o sulla scheda grafica, o essere spostati in una regione mappabile PCIe, qualunque cosa, ma in entrambi i modi non possiedi formalmente (anche se si trova fisicamente nella RAM e se i dati provengono dalla tua applicazione ) - a meno che tu non l'abbia "mappato" tramite l'API corrispondente, ottenendo un puntatore scrivibile (e talvolta leggibile). Sei anche limitato nella tua capacità di controllare ciò che accade ai dati (puoi dare alcuni suggerimenti, ma è praticamente tutto).
    OpenGL può spostare questi dati in modo più o meno libero e l'utente è sempre autorizzato / in grado di copiare nel / dal buffer tramite l'API corrispondente o accedere ai dati mentre viene mappato. Questo è ciò che chiamate un oggetto buffer ( oggetto buffer vertici se contiene vertici, ma in realtà non è necessario, potrebbero anche essere dati immagine o uniformi, solo i vertici sono stati i primi ad essere supportati, una volta).
    L'intento è quello di garantire che OpenGL possa (in linea di principio) fare ciò che vuole, può persino spingere speculativamente il buffer su PCIe prima ancora di disegnare. Funziona perché non possiedi i dati (OpenGL lo fa!) E puoi accedervi solo tramite l'API fornita, quindi è noto in ogni momento che i dati sono validi. Il driver può anche scegliere di gettare via la memoria buffer sulla scheda grafica quando ha bisogno di memoria per qualcosa di diverso e successivamente ripristinarla dalla sua copia segreta quando necessario.
  3. Un nome improprio davvero stupido per il quale un nome molto migliore sarebbe qualcosa come buffer-set o set-descrittore, questo è il famigerato oggetto array di vertici . Dal tuo punto di vista, è nient'altro che una serie di handle di buffer raggruppati insieme sotto un altro handle oscuro (che puoi associare). In realtà, la realtà è un po 'più complicata. In effetti, VAO è molto più vicino a come funziona l'hardware reale. Le schede grafiche hanno un piccolo numero (spesso qualcosa come 2, 4 o 8) di set di descrittori (non solo per i buffer, ma anche per i campionatori) con così tante voci in ognuna, tra le quali possono passare in modo molto efficiente .
    Ora, l'intento dell'oggetto array di vertici è di ridurre il numero di chiamate API e di ridurre il numero di controlli di coerenza che OpenGL deve effettuare internamente e, naturalmente, per usare l'hardware come funziona. Se si associano 5 buffer, ognuno deve sottoporsi ad alcuni controlli possibilmente costosi e ognuno è un candidato per i mancati errori nella cache nel driver, inoltre ognuno richiede di comunicare con la scheda grafica per modificare un descrittore, ecc. Se invece associare un VAO, il driver può (spesso) semplicemente cambiare il descrittore impostato sulla scheda grafica ed essere fatto.

8

Un oggetto array di vertici (VAO) è un oggetto che contiene uno o più oggetti buffer di vertici ed è progettato per memorizzare le informazioni per un oggetto di rendering completo.

(estratto da khronos )

Ogni buffer tende a costituire un attributo di un array di vertici (oggetto). Un VAO può contenere molti attributi di vertice (ad es. Posizione, colore, UV). Ognuno potrebbe essere conservato nel proprio buffer, in cui il buffer indica una serie non formattata di byte contigui e dove è necessario specificare esplicitamente la dimensione (tipo) per elemento buffer sia per le chiamate OpenGL lato CPU sia per il lavoro shader lato GPU.

Questo è un modo. Gli altri modi in cui questo può funzionare sono:

  • Tutti gli attributi sono memorizzati interlacciati in un singolo buffer, OR
  • Alcuni degli attributi esistono nei propri buffer dedicati, mentre altri condividono i buffer.

Il diagramma seguente illustra questi ultimi due casi.

inserisci qui la descrizione dell'immagine

In conclusione: se la frase "array di vertici" viene utilizzata non qualificata in OpenGL, si può presumere che significhi VAO, che, in un contesto OpenGL (in particolare), è una cosa molto diversa da un buffer.

MODIFICA il tuo commento: GL_ARRAY_BUFFERindica l'intenzione di utilizzare quell'oggetto buffer per i dati degli attributi del vertice, come descritto sopra. Questo perché i buffer non vengono utilizzati solo per gli attributi dei vertici. Tuttavia, poiché è il caso d'uso più comune e si sta chiedendo dei VAO, non entrerò negli altri; qui invece c'è un elenco degli altri tipi di buffer che possono essere impostati.


Quindi i buffer sono: 1.reside in GPU, 2. il più delle volte contengono un tipo di dati (solo vertice, solo colore ect), 3. I dati sono interlacciati, ovvero 111122223333 ect. 4. non fornisce alcun metodo per accedere ai dati (non buffer [2] o buffer [vertex_3434]) Ora, gli array sono: 1.collection of buffers, 2.store informazioni su come analizzare i buffer che contiene. , dimensione di un elemento, offset, in modo che sia possibile accedere correttamente ai dati dai buffer. giusto?
coobit

1. Esistono buffer su entrambe le estremità e si trasferiscono tra CPU e GPU (avanti e indietro potenzialmente), altrimenti come si popolerebbero i dati da caricare su GPU quando si carica una mesh dal disco ?. Sì, gli elementi sono di tipo uniforme in tutto il buffer, ma a seconda della tecnologia che si sta utilizzando, ogni elemento del buffer può essere un structtipo primitivo o . I dati possono essere interfogliati o essere completamente uniformi, per buffer. Puoi indicizzarli, proprio come con un array C tradizionale sulla CPU. Oggetti array (usa questa terminologia corretta o finisci per confonderti!) ... (continua sotto)
Ingegnere

2. Sì, ed è necessario assicurarsi esplicitamente che le dichiarazioni del buffer in-shader corrispondano alle specifiche impostate sul VAO sul lato CPU: "Tutto lo stato relativo alla definizione dei dati utilizzati dal processore vertice è incapsulato in un vertice oggetto array ". (khronos docs)
Ingegnere

Quindi, solo per colpire di più ... Come hanno funzionato le persone prima che AO usasse solo BO? O AO erano sempre presenti in OpenGL ed è solo VAO che è stato introdotto più tardi quindi VBO?
coobit

@coobit io7m.com/documents/history-vertex-spec : questo ti dà un'idea delle differenze tra pipeline fissa (vecchia scuola) OpenGL, 3Dfx ecc. e pipeline moderna e programmabile OpenGL e Direct3D.
Ingegnere

5

Questa terminologia è radicata nella storia di OpenGL. La cosa importante da ricordare è che, per la maggior parte delle versioni GL che sono rilevanti qui, OpenGL si è evoluto in modo incrementale e aggiungendo nuove funzionalità a un'API già esistente anziché modificare l'API.

La prima versione di OpenGL non aveva nessuno di questi tipi di oggetti. Il disegno è stato ottenuto emettendo più chiamate glBegin / glEnd e un problema con questo modello era che era molto inefficiente, in termini di overhead delle chiamate di funzione.

OpenGL 1.1 ha fatto i primi passi per risolvere questo problema introducendo array di vertici. Invece di specificare direttamente i dati del vertice, ora è possibile generarli da array C / C ++, da cui il nome. Quindi un array di vertici è proprio questo: un array di vertici e lo stato GL richiesti per specificarli.

La successiva grande evoluzione è arrivata con GL 1.5 e ha consentito l'archiviazione dei dati dell'array di vertici nella memoria GPU piuttosto che nella memoria di sistema ("lato client"). Un punto debole delle specifiche dell'array di vertici GL 1.1 era che l'intero set di dati di vertici doveva essere trasferito alla GPU ogni volta che si voleva usarlo; se fosse già sulla GPU, questo trasferimento potrebbe essere evitato e si potrebbero ottenere potenziali miglioramenti delle prestazioni.

Quindi è stato creato un nuovo tipo di oggetto GL per consentire la memorizzazione di questi dati nella GPU. Proprio come un oggetto texture viene utilizzato per l'archiviazione dei dati texture, un oggetto buffer vertici memorizza i dati vertici. Questo è in realtà solo un caso speciale di un tipo di oggetto buffer più generale che può memorizzare dati non specifici.

L'API per l'utilizzo degli oggetti buffer vertici è stata supportata dalle API dell'array di vertici già esistenti, motivo per cui vengono visualizzate cose strane come la conversione degli offset di byte in puntatori. Quindi ora abbiamo un'API per array di vertici che memorizza solo lo stato, con i dati provenienti da oggetti buffer anziché da array in memoria.

Questo ci porta quasi alla fine della nostra storia. L'API risultante era piuttosto dettagliata quando si trattava di specificare lo stato dell'array di vertici, quindi un'altra via di ottimizzazione era quella di creare un nuovo tipo di oggetto che raccolse tutto questo stato insieme, consentisse più cambiamenti di stato dell'array di vertici in una singola chiamata API e consentisse GPU per eseguire potenzialmente ottimizzazioni grazie alla possibilità di sapere in anticipo quale stato sarebbe stato utilizzato.

Immettere l'oggetto array vertice, che raccoglie tutto questo insieme.

Quindi, per riassumere, un array di vertici ha iniziato la vita come una raccolta di stati e dati (memorizzati in un array) con cui disegnare. Un buffer di vertici sostituisce l'archiviazione di array in memoria con un tipo di oggetto GL, lasciando l' array di vertici solo in stato. Un oggetto array vertice è solo un oggetto contenitore per questo stato, che consente di modificarlo più facilmente e con meno chiamate API.


0

Non ho lavorato con OpenGL per un po ', quindi potrei avere solo metà ragione. In generale: i buffer memorizzano un array di memoria non formattata. Un array è un termine generale di memoria contigua.

Un buffer deve essere associato al contesto, mentre un array è solo un array di dati. Se ricordo bene, i dati nel buffer devono essere copiati sulla scheda grafica (da qui la rilegatura).

Spero che questo aiuti un po '


Cos'è allora GL_ARRAY_BUFFER? Perché è stato chiamato così? Secondo la tua ipotesi è "memoria contigua non formattata" :)
coobit

Bene, questo esempio particolare è solo un id per un buffer (a cui si associa l'array). Il buffer di array (nel tuo esempio) viene utilizzato per gli attributi dei vertici, quindi fondamentalmente si lega l'array degli attributi dei vertici a un buffer. Sembra confuso, quindi lascia che ti faccia un esempio. Hai un array sul lato CPU che potrebbe essere colore, normale, posizioni, ecc. E ora vuoi che la GPU acceda ad esso. Quello è quando arriva bindBuffer, fondamentalmente mappando il tuo "cpu-array" sul "gpu-array".
Juicef,

Quanto al perché è stato chiamato così, non posso rispondere. Suppongo che sia perché hai una serie di dati diversi che vanno lì, a colori, normali, ecc.
Juicef
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.