Come funziona l'aggiornamento di un buffer di profondità nella GPU?


10

In questo momento sto cercando di implementare una sorta di buffer di profondità nel software e ho un grosso problema quando ci scrivo. Avere un mutex è assolutamente eccessivo. Quindi ho creato un numero di mutex pari al numero di thread. Sto bloccando un mutex basato sul pixel corrente (pixel_index% mutexes_number) e questo funziona meglio, ma è ancora molto lento. E mi chiedo come sia fatto in una vera GPU? Esiste un algoritmo intelligente o un hardware che lo gestisce?

Risposte:


9

Hardware altamente specializzato lo gestisce. Una strategia tipica è quella per una GPU di rasterizzare i riquadri e memorizzare le informazioni sulla profondità in formati compressi (ad esempio l'equazione z quando un poligono copre completamente un riquadro). Ciò consente di testare su un'intera piastrella contemporaneamente; altri trucchi HW interessanti includono test di profondità prima dell'esecuzione del pixel shader (presupponendo che le condizioni lo consentano - lo shader non può scrivere un valore di profondità). Potresti considerare qualcosa di simile nel software, come avere ogni thread "possedere" un sottoinsieme di tessere e percorrere ciascuna primitiva in modo indipendente, oppure imitare strategie multi-gpu come frame alternati o linee raster alternate.


11

In una GPU reale, invece di avere più core che provano a leggere / scrivere la stessa regione del buffer di profondità e tentano di sincronizzarsi tra loro, il buffer di profondità è diviso in riquadri (come 16 × 16 o 32 × 32) e ciascuno il riquadro è assegnato a un singolo core. Quel nucleo è quindi responsabile di tutta la rasterizzazione in quella tessera: tutti i triangoli che toccano quella tessera saranno rasterizzati (all'interno di quella tessera) dal nucleo proprietario. Quindi non vi è alcuna interferenza tra i core e non è necessario che si sincronizzino quando accedono alla loro parte del framebuffer.

Ciò implica che i triangoli che toccano più tessere dovranno essere rasterizzati da più nuclei. Pertanto, esiste un passaggio di ridistribuzione del lavoro tra l'elaborazione della geometria (operazioni su vertici e triangoli) e l'elaborazione dei pixel.

Nella fase della geometria, ciascun nucleo potrebbe elaborare un blocco di primitive di input; quindi per ciascuna primitiva, può determinare rapidamente quali tessere tocca la primitiva (questa è chiamata "rasterizzazione grossolana") e aggiungere la primitiva a una coda per ogni nucleo che possiede una delle tessere interessate.

Quindi, nella fase pixel, ogni core può leggere l'elenco delle primitive nella sua coda, calcolare la copertura dei pixel per le tessere che possiede il core e procedere al test di profondità, all'ombreggiatura dei pixel e all'aggiornamento del framebuffer, senza necessità di ulteriore coordinamento con altri core.

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.