Hardware Instancing ab wann sinnvoll?



  • Hallo zusammen
    Ich frage mich gerade, ab wann Hardware instancing Sinn macht. Ich habe nun bspw. 100erte von Laserstrahlen, die ich aus 2 überkreuzten Planes bestehen und natürlich möchte ich diese in einem einzigen Draw Call zeichnen. Hierfür muss ich allerdings IMHO entweder die Vertexkoordinaten vorberechnen (8 Matrizenmultiplikationen) pro Laserstrahl, oder aber ich verwende einen zweiten StreamSource, wo ich die Matrizen hineinwerfe, so dass diese auf der GPU berechnet werden können. Der Speicherverbrauch spricht für Hardware instancing: 160Bytes pro Laser vs. 64 Bytes pro Laser + 160Bytes. Ich frage mich dennoch, ob diese Technik für so ganz kleine Meshes (8 Verticen) überhaupt Sinn macht...

    Mfg Samuel



  • Zu der ersten Frage habe ich noch gerade eine zweite :p Im Moment speichere ich Daten für das Deferred Rendering in einem Array und fülle damit einmal pro frame die entsprechenden Vertex Buffers. Nun frage ich mich, ob es nicht auch möglich wäre, einfach während des Rendervorgangs die VertexBuffer geöffnet zu halten und erst kurz vor dem eigentlichen Draw Call wieder zu schliessen, oder sollte man schon eigentlich einen VertexBuffer möglichst kurz geöffnet haben?



  • Ich habe mal für einfache Objekte Instancing mit dem normalem rendering verglichen (Sprites). Es hat sich nicht dort nicht wirklich gelohnt, weil die Positions/Rotationsdaten pro Obejekt den nutzen wieder verschwinden haben lassen.

    Lohnen tut es sicher aber eigentlich recht schnell. Wenn du viele Objekte hast, die prinzipiell aus den gleichen Vertexdaten bestehen und du nur noch eine Position/Rotation schicken musst, dann ist das schon recht viel besser, als wenn du jedesmal alle Vertexdaten schickst.

    Zur zweiten Frage:
    Ja, kannst du machen, aber einen Unterschied macht es imo nicht. Das aufwändige an dem ganzen ist ja der Drawcall. Alles was mit füllen zu tun hat ist nebensächlich, wenn du optimiert compilest.



  • eine Position/Rotation schicken musst

    Also es ist so, dass eigentlich jedes Objekt ein lokales Koordinatensystem hat. Das Instancing würde ich in diesem Fall nur machen, um die ca. 8000 Matrizenmultiplikationen (8 pro Laserstrahl mal 1000 Laser) von der CPU auf die GPU zu verlagern.

    Alles was mit füllen zu tun hat ist nebensächlich,

    Schon aber dann bräuchte ich eben keinen zusätzlichen Speicher mehr im RAM... Also die Antwort ist Ja, man kann einen VertexBuffer über längere Zeit locked halten, ohne Performanceeinbussen befürchten zu müssen?



  • Hardware Instancing funktioniert, Framerate selbst bei 2000 Laserbeams unverändert 🙂



  • Ok, ja die Transformation auf der GPU zu machen ist sicher auch sinnvoll. Nett ist Instancing ja auch, wenn du grosse Objekte hast. Das musst du dann nur 1x schicken und dann folgen lediglich noch eine Matrix pro Objekt für die Transformationen.

    Glücklicherweise lässt sich das ganze ja auch recht gut prüfen, ob es was bringt. 🙂

    Zusätzlichen Speicher im RAM wirst du wahrscheinlich ohnehin brauchen. Ich halte mir z.B jeden Vertexbuffer noch 1:1 im RAM, damit ich im Falle von LostDevice alles wieder korrekt herstellen kann.



  • Sehe ich das richtig, dass ich der Indexbuffer die Indices ALLER Instancen enthalten muss? Also in meinem Fall 2000 mal:

    // setup the indices
     uint16 aIdx[] = {0,1,2,2,3,0,4,5,6,6,7,4};
     memcpy(pIdx,aIdx,12*sizeof(uint16));
    

    Also dann im Prinzip so:

    uint16 aIdx[] = {0,1,2,2,3,0,4,5,6,6,7,4};
     for(uint32 i=0,c=this->cMax;i<c;++i) memcpy(&pIdx[i*12],aIdx,12*sizeof(uint16));
    

    Ich frage mich ob es Möglichkeit gäbe, diese Daten nicht redundant zu haben. Nun gut, ohne Instancing müsste ich es ja IMHO auc so machen...



  • Einen Tipp an alle, die sich ans Hardware Instancing heranwagen. Der Indexbuffer braucht nur die Indices von einer einzigen Instanz. Und die DrawIndexedPrimitive Funktion muss man so aufrufen, als ob man nur eine einzige Instanz rendern würde.



  • Ishildur schrieb:

    Einen Tipp an alle, die sich ans Hardware Instancing heranwagen. Der Indexbuffer braucht nur die Indices von einer einzigen Instanz. Und die DrawIndexedPrimitive Funktion muss man so aufrufen, als ob man nur eine einzige Instanz rendern würde.

    Das ist ja das schöne daran. 🙂

    Der Datenbus zur GK ist recht schmal und dementsprechend will man die Daten, die man rüberschiebt möglichst klein halten.

    Man kann das Verfahren auch hier nachlesen:
    http://msdn.microsoft.com/en-us/library/bb173349(VS.85).aspx



  • drakon schrieb:

    Der Datenbus zur GK ist recht schmal und dementsprechend will man die Daten, die man rüberschiebt möglichst klein halten.

    Der Bus zur Grafikkarte ist üblicherweise der dickste im ganzen System (FSB ausgenommen, auf Systemem die einen FSB haben).
    Aber natürlich hast du trotzdem Recht: man will die Daten klein halten.



  • hustbaer schrieb:

    drakon schrieb:

    Der Datenbus zur GK ist recht schmal und dementsprechend will man die Daten, die man rüberschiebt möglichst klein halten.

    Der Bus zur Grafikkarte ist üblicherweise der dickste im ganzen System (FSB ausgenommen, auf Systemem die einen FSB haben).
    Aber natürlich hast du trotzdem Recht: man will die Daten klein halten.

    Ja, war halt ein wenig schlecht umgedeutscht, dass der Bus der Flaschenhals ist.


  • Mod

    instancing wurde eigentlich dafeur "erfunden" kleine meshes effizient zu zeichnen (ohne drawcall limitiert zu werden).
    fuer particle wie deinen laser stopft man das am effizientesten einfach in einen vertexbuffer und veraendert die positionen. dafuer benutzt man normalerweise keine matritzen, da es nur vectoren in worldspace sind die dann in 2d aufgespannt werden (kann man selbst im shader machen).



  • @rapso
    Nein die Laser sind ein Mesh (ein Zylinder). Wir haben es mit überkreutzen Ebenen in allen Variationen versucht und das Result war einfach nicht gut, sobald man nah genug war. Ausserdem kann man in der Stop funktion die Kamera um jeden einzelnen Laser herumbewegen (eingefroren)


Anmelden zum Antworten