2017-03-03 4 views
1

Ich habe versucht, Rendering in meinem Spiel zu beschleunigen, aber nur geschafft, es langsamer zu machen, und ich bin ratlos, wie das passiert ist. Ich zeichne etwas Gelände in einem 2D-Spiel, also stell dir lange Streifen über den Bildschirm verschiedener Texturen vor.Abysmal Metall Rendering Geschwindigkeit

Die vorherige Implementation würde die verschiedenen Texturen zusammentragen und durch diese durchlaufen und Dreiecke zeichnen, die mit der Textur auf eine unterschiedliche Art und Weise verbunden sind, was, wie Sie sich vorstellen können, in einer Unmenge von Draw-Aufrufen resultierte und gezwungen wurde, einige der Uniformen mehrfach zu wechseln während des gesamten Prozesses, wenn wir uns um die Kante wickelten.

Also, was ich getan habe, war alle Texturen zusammen zu packen, so dass ich sie nicht ändern müsste und große Schwaden von Dreiecken auf einmal zeichnen könnte. Dadurch wurde die Zeichenzählung von fast 4000 auf weniger als 1000 verringert (wie mit dem Erfassungsrahmen-Tool in Xcode gemessen), der Frame wurde jedoch erheblich verlangsamt. Also wird die gleiche Szene mit der gleichen Anzahl von Dreiecken gerendert, aber die fps gingen von etwa 40 auf 10.

Bevor es mehr als tausend einfache drawPrimitives(.Triangle ... mit nur 5 oder 6 Dreiecke auf einmal war es jetzt nur ein einige hundert Aufrufe, die jedes Mal über 100 Dreiecke zeichnen.

zum Beispiel [drawPrimitives: 3 VertexStart: 1944 VertexCount: 348 instanceCount: 116], die berichtet, dass es 1,93 ms dauert, das zu tun.

auf einem Frame-Capture zeigt es diese Aufrufe Zeichnung 100 oder so 2 + ms nehmen! Warum so lange!! Was mir super komisch vorkommt, da es einen Quad in ungefähr 3 Mikrosekunden machen kann. Wenn es skaliert würde, würde ich mir vorstellen, dass dieser Streifen nur .2ms

Die Shader sind die gleichen zwischen den beiden Implementierungen und sind super einfach. Ich profilierte den Code, der die Dreiecke vorbereitet, und es ist schneller. Das einzige, worauf ich hinweisen kann, sind die tatsächlichen Aufrufe von drawPrimitives, aber ich kann nicht herausfinden, warum es jetzt herunterkommt.

Warum also 4 mal weniger Anrufe, was eine 3 mal längere Bildrate zur Folge hat? Was fehlt mir, warum das so langsam geht? Ich bin effizienter !!!

bearbeiten Hier ist der Shader-Code:

vertex TerrainFragmentIn terrainVertex(const device TerrainVertex* verts [[ buffer(0) ]], 
          uint v_id [[ vertex_id ]], 
          constant Constants &mvp [[buffer(1)]], 
          constant ModelMatrix &modelMat [[buffer(2)]] 
          ) { 
    TerrainVertex vert = verts[v_id]; 

    TerrainFragmentIn outVertex; 
    outVertex.position = mvp.viewProjectionMatrix * modelMat.modelMatrix * float4(vert.position.x,vert.position.y,0,1); 
    outVertex.shadow = vert.shadow; 
    outVertex.uv = vert.tex; 
    return outVertex; 
} 

fragment float4 terrainFragment(TerrainFragmentIn inFrag [[stage_in]], 
          texture2d<float, access::sample> colorTexture [[ texture(0) ]], 
          sampler colorSampler [[ sampler(0) ]]) { 
    float4 color = colorTexture.sample(colorSampler, inFrag.uv); 
    color *= float4(inFrag.shadow,inFrag.shadow,inFrag.shadow,1.0); 

    return color * 2; 
} 

Diese Strukturen sind als solche definiert und gleich auf der schnellen Seite:

struct TerrainVertex { 
    float2 position [[ attribute(0) ]]; 
    float2 tex  [[ attribute(1) ]]; 
    float shadow [[ attribute(2) ]]; 
}; 

struct Constants { 
    float4x4 viewProjectionMatrix; 
}; 

struct ModelMatrix { 
    float4x4 modelMatrix; 
}; 

Es gibt fast keine Zustandsänderung 90 zwischen % die Aufrufe DrawCalls

Jedes Dreieck ist um 2 0x30 Pixel. Bei diesen Aufrufen mache ich keine Mischung. Ich wünschte eigentlich, ich würde Diagnose oder Warnungen/Fehler auf der Erfassung bekommen, aber nein, leider nichts. Ich teste auf einem rMPB mit 10.12.3. Ich habe noch nicht auf iOS versucht.

Antwort

1

In Ihrem Screenshot es die Instanz Zahl zeigt, 120

In Ihrer Anrufe auf drawPrimitives, haben Sie die instanceCount Parameter als primitive Zählereinstellung (es sieht aus wie es). Wenn dies der Fall ist, liefert jeder Zeichnungsaufruf 120 * 120 = 14400 Dreiecke, was erklären würde, warum das Konsolidieren von Zeichnungsaufrufen die Framerate für Sie verschlechtert, wenn Sie jedes Mal Dreiecke-Quadrat-Primitive zeichnen.

Wenn Sie keine Instanzierung verwenden (und Ihre Shader schlagen vor, dass dies nicht der Fall ist), sollten Sie instanceCount auf 1 setzen.

+1

Das war es !. Ging von 6/9 fps auf 60! Genial. Es schien seltsam, dass ich die Anzahl der Dreiecke und die Anzahl der Verts angeben musste. Ich wünschte, das hätte eine Warnung ausgegeben, als würdest du etwas Dummes tun, du solltest das nicht anrufen! Ich wünschte, ich könnte mehr als einmal abstimmen! Vielen Dank – utahwithak