masterchi schreef op vrijdag 30 oktober 2009 @ 12:29:
[...]
Eigenlijk kan je de RV870 beter vergelijken met een 20-core processor ipv 320. Er is een thread command processor die op dit niveau de 20 cores van de GPU aanstuurt. Ik denk dat er inderdaad wel genoeg werk is om 20-cores te gebruiken. Maar het feit blijft dat er 2x zo weinig werk is per core. De overhead daarentegen blijft hetzelfde in vorm van bijvoorbeeld shader programma's inladen. Ook moeten er nu 20 cores aangestuurd worden dus de thread command processor(of hoe dat ding ook heet) heeft meer te doen en dit stuk is sequentieel.
Daarom is de thread dispatcher ook verbeterd als ik me het artikel van Anandtech goed herinner (zie bron vermeld in eerdere post). Ga er maar vanuit dat dit soort zaken ook allemaal aangepakt zijn, anders kan je inderdaad met een bottleneck komen te zitten (het is al een tijd geleden dat ik dat artikel van Anand heb gelezen, maar daar wordt heel uitvoerig besproken welke zaken verbeterd zijn). AMD begrijpt wel dat als je het aantal shader units verdubbelt, dat je er dan wel voor moet zorgen dat die shader units het werk snel genoeg aangeleverd moeten krijgen.
Verder als die er 4 shader programmas op een pixel moet opereren binnen een frame zal dat wel in een sequentiele volgorde moeten. Als het in verschillende volgorde gaat gebeuren krijg je corrupte output. Dus het parallisme gaat niet omhoog wanneer er meer shading per pixel moet worden gedaan.
Dat klopt natuurlijk, maar de gpu hoeft niet te wachten tot pixel B klaar is met pass 1 voordat hij kan beginnen met pass 2 op pixel A (die pass 1 al eerder voltooid had). Deels heb je hier als programmeur ook een verantwoordelijkheid.
Ook is de pixel shading stap niet de enige stap in de graphics pipeline. Andere stappen zijn bijvoorbeeld vertex shading, geometry shading, rasterization, texturemapping en clipping. De stappen in de pipeline gebeuren achter elkaar. Ik ben geen expert van wat er in deze stappen moet gebeuren, maar het is redelijk om te denken dat niet alle stappen in graphics pipeline even parallel zijn.
Het uitvoeren van deze stappen is inderdaad sequentieel in plaats van parallel. Overigens kost de pixel shading stap over het algemeen wel de meeste rekenkracht van alle stappen. Ga maar eens na:
vertex shading: misscchien 100.000 polygonen in een frame?
geometry shading: doe je op die 100.000 polygonen (of een gedeelte ervan)
fragment shading: doe je op alle pixels op het scherm (~1.7 miljoen bij 1680x1050) en vaak zijn deze programma's ook nog eens de meest complexe omdat je hier lichteffecten toe gaat voegen, etc. (naar schatting is een gemiddelde fragment shader zeker 10x zo complex als een gemiddelde vertex/geometry shader). Vergeet daarnaast niet dat je waarschijnlijk overhead hebt: polygon A wordt gerenderd, de fragment shader wordt toegepast op de pixels van polygon A, maar vervolgens komt er een polygon B die polygon A geheel bedekt, al het werk voor niets! Hhier zijn technieken voor om dit zoveel mogelijk te voorkomen, want dit is verschrikkelijk duur: je kunt een early z-pass doen, dit betekend alle polygonen naar de gpu sturen en het enige wat je doet is de z-buffer vullen. Vervolgens stuur je alle polygonen nogmaals naar de gpu, de z-buffer zorgt er nu voor dat alle pixels die niet zichtbaar zijn ook niet naar de fragment shader gestuurd worden (let op: het is dus goedkoper om alle polygonen twee keer naar de gpu te sturen om zo die overhead te voorkomen! Dit geeft wel aan hoeveel tijd er gemiddeld in een fragment shader gaat zitten denk ik).
Vervolgens ga je vaak nog allerlei post-processing effecten toepassen (out-of-focus blur, haze, druppels op de camera, bedenk het maar zo gek...) die ook allemaal per pixel zijn.
Dus gemiddeld zal er een lagere speedup zijn dan pixel shading bijvoorbeeld. Ik hoop dat iemand hier licht op kan schijnen. Ik heb wel een vakje Computer Graphics gevolgd, maar ik weet niet welke stappen er op de GPU gebeuren en welke op de CPU. Bijvoorbeeld iets als polygon sorting om te bepalen welke objecten zichtbaar zijn, is een redelijk sequentiele actie.
Ik heb een vak advanced computer graphics gevolgd en als hobby ben ik bezig met het programmeren in OpenGL en programmeer ik ook gpgpu dingen. Polygon sorting wordt niet gedaan op de gpu. De gpu is een dom ding die alles gewoon naar het scherm knalt. Er is echter een z-buffer op de gpu, in die z-buffer wordt de z waarde van de dichtsbijzijnde pixel onthouden. De rasterizer zorgt er vervolgens voor dat als een pixel/fragment een z-waarde heeft verder weg ligt dan de huidige dichtstbijzijnde pixel/fragment, niet gerenderd wordt. Daarom zie je toch altijd het juiste object vooraan terwijl de volgorde waarin polygonen gerenderd worden willekeurig is (en daarom kun je dus een techniek toepassen als early-z-pass). Een geoptimaliseerd programma sorteerd (meestal op object niveau) op de cpu, of eventueel met gpgpu technieken (dit zal meer en meer met OpenCL/DirectX compute gedaan gaan worden waarschijnlijk) (dat sorteren wordt gedaan om dubbel werk voor de gpu zoveel mogelijk te voorkomen... iets wat je niet ziet wil je liever gewoon niet renderen, dus als je een object dat dichtbij is eerst rendert, dan zal z-culling er in ieder geval voor zorgen dat achterliggende pixels gewoon overgeslagen worden). Wil je iets renderen wat doorzichtig is, dan is (weliswaar afhankelijk van de methode waarmee je de kleuren blend) de volgorde van polygonen wél van belang (je wilt de achterste
polygon pixel eerst renderen, dan de op één na achterste, enz.). Anders komt de transparency niet realistisch over.
Als laatste ga je niet een pixel of vertex per keer sturen om te shaden naar een (van de 20) cores, maar stuur je een group van 1024 of iets dergelijks. Je wilt je batch sizes zo groot mogelijk houden om opstart overhead zo klein mogelijk te houden. Hierdoor zal het praktische parallelisme een groot stuk lager zijn. Vaak zie je dat bij lage resoluties een graphics kaart niet helemaal tot zijn recht komt. Dat heeft niet alleen te maken met de CPU bottleneck.
Dat zeg ik toch ook niet? Maar dan nog... ook al bevinden al je objecten zich in één grote batch (ideaal, hoef je niet op die langzame processor te wachten!), dan zal de gpu (de thread dispatcher waarschijnlijk) al die objecten verdelen over de beschikbare shader units om:
vertex shading -> geometry shading -> tesselation -> rasterization -> fragment shading -> blending
te doen (kan zijn dat ik iets mis in de pipeline of de volgorde achteraan niet helemaal 100% klopt). Natuurlijk: als je maar één polygon hebt, dan kun je die maar aan één shader unit geven om de vertex shading te doen. Maar hoe vaak zal het nou voorkomen dat je slechts één polygon hebt? Tegenwoordig heb je eerder duizenden of tienduizenden polygonen in een scene (als het er geen 100.000 zijn).
Stel dat je een batch hebt met 10.000 polygonen, dan zal de thread dispatcher de polygonen over de 320 shader units verdelen. Vervolgens doen die vertex shading, en eventueel wordt er nog meer geometry gegenereerd in de geometry shader en de tesselator. Daarna zal de rasterizer er pixeltjes (of fragments als anti aliasing gebruikt wordt) van maken die allemaal via de thread-dispatcher weer hun weg vinden naar de shader units om de fragment shader stap uit te voeren.
Maar nogmaals ik ben geen expert op gebied van graphics. Mijn achtergrond ligt meer in parallel programming en computer architecture. Ik wil alleen aangeven dat het aantal shader units verdubbelen in de vorm van welke we zien in rv670->rv770->rv870 een zelfde soort actie is als het aantal cores in een CPU verdubbelen. Eens houdt het nut er van op en hoe dichter we tegen de practische limieten lopen meer efficientie verlies er is. Volgens mij was de rv770 ook niet 2.5 keer zo snel als de rv670. Meer in de buurt van 2. Een nog mooier voorbeeld is dat een hd5850 op clocks van hd5870 niet 10% langzamer is, maar meer in de buurt van enkele procenten. (geen bron, maar had het ergens gelezen)
Ik weet er hobbymatig (en gedeeltelijk ook vanuit mijn opleiding) redelijk veel van af denk ik. Maar ik zal mezelf ook geen expert noemen. Ik denk toch dat het even anders ligt dan bij een cpu. Natuurlijk is er ergens een limiet, maar rasterization is zo'n enorm parallel proces (voornamelijk door het grote aantal pixels en het grote aantal polygonen in een scene die je door de z-buffer in willekeurige volgorde kunt renderen) dat we nog lang niet aan die limieten zitten.
Ik denk dat je er vanuit kunt gaan dat een gpu in een typische game met veel gemak duizenden threads tegelijk kan gebruiken.
Ben je ondertussen overtuigd?

Mijn `onderbuik' gevoel is voornamelijk gebasseerd op kennis van typische waarden in games (hoeveel polygonen heb je, hoeveel instructies kost het om een shader programma uit te voeren, hoe maak je lichteffecten en hoe creeër je post-processing effecten), daarnaast gebruik ik wat ik weet over de pipeline van de gpu (die kennis is niet 100%, maar wat ik weet komt in ieder geval wel aardig in de richting denk ik).
Zoals je ziet kost het een flinke lap tekst om dit alles te onderbouwen, vandaar dat ik in eerste instantie de zaak afgedaan had met een `ik denk niet dat het zo is'.
[
Voor 5% gewijzigd door
The Flying Dutchman op 30-10-2009 14:05
]