Ich versuche, Hardware zu instanziieren, aber ich stoße auf ein seltsames Leistungsproblem. Die durchschnittliche Framerate liegt bei 45, ist aber extrem abgehackt.
- Fenster
- SynchronizeWithVerticalRetrace = false
- IsFixedTimeStep = false
- PresentationInterval = PresentInterval.Immediate
Das Bild unten zeigt mein gemessenes Timing (mit Stopwatch
). Das oberste Diagramm ist die Zeit, die in der Draw
Methode verbracht wurde , und das unterste Diagramm ist die Zeit vom Ende Draw
bis zum Beginn vonUpdate
Die Spitzen sind fast genau 1 Sekunde voneinander entfernt und sind immer 2,3,4 oder 5 mal die übliche Zeit. Die Frames unmittelbar nach dem Spike brauchen überhaupt keine Zeit. Ich habe überprüft, dass es nicht der Müllsammler ist.
Ich instanziiere derzeit ein Netz aus 12 Dreiecken und 36 Eckpunkten als Dreiecksliste (ich weiß, dass es nicht optimal ist, aber nur zum Testen) mit 1 Million Instanzen. Wenn ich die Instanz-Draw-Aufrufe in kleine Teile von jeweils 250 Instanzen staple, wird das Problem behoben, aber die CPU-Auslastung nimmt erheblich zu. Der obige Lauf liegt bei 10000 Instanzen pro Draw-Aufruf, was für die CPU viel einfacher ist.
Wenn ich das Spiel im Vollbildmodus ausführe, ist das untere Diagramm fast nicht vorhanden, aber das gleiche Problem tritt jetzt bei der Draw
Methode auf.
Hier ist ein Lauf in PIX , der für mich überhaupt keinen Sinn ergibt . Es scheint, dass für einige Frames kein Rendering durchgeführt wird ...
Irgendeine Idee, was könnte das verursachen?
BEARBEITEN : Auf Wunsch die relevanten Teile des Rendercodes
A CubeBuffer
wird erstellt und initialisiert und dann mit Würfeln gefüllt. Wenn die Anzahl der Würfel einen bestimmten Grenzwert überschreitet, wird ein neuer CubeBuffer
erstellt und so weiter. Jeder Puffer zeichnet alle Instanzen in einem Aufruf.
Informationen, die nur einmal benötigt werden, sind static
(Scheitelpunkt, Indexpuffer und Scheitelpunktdeklaration; obwohl dies bisher keinen Unterschied macht). Die Textur ist 512x512
Zeichnen()
device.Clear(Color.DarkSlateGray);
device.RasterizerState = new RasterizerState() { };
device.BlendState = new BlendState { };
device.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true };
//samplerState=new SamplerState() { AddressU = TextureAddressMode.Mirror, AddressV = TextureAddressMode.Mirror, Filter = TextureFilter.Linear };
device.SamplerStates[0] = samplerState
effect.CurrentTechnique = effect.Techniques["InstancingTexColorLight"];
effect.Parameters["xView"].SetValue(cam.viewMatrix);
effect.Parameters["xProjection"].SetValue(projectionMatrix);
effect.Parameters["xWorld"].SetValue(worldMatrix);
effect.Parameters["cubeTexture"].SetValue(texAtlas);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
pass.Apply();
foreach (var buf in CubeBuffers)
buf.Draw();
base.Draw(gameTime);
CubeBuffer
[StructLayout(LayoutKind.Sequential)]
struct InstanceInfoOpt9
{
public Matrix World;
public Vector2 Texture;
public Vector4 Light;
};
static VertexBuffer geometryBuffer = null;
static IndexBuffer geometryIndexBuffer = null;
static VertexDeclaration instanceVertexDeclaration = null;
VertexBuffer instanceBuffer = null;
InstanceInfoOpt9[] Buffer = new InstanceInfoOpt9[MaxCubeCount];
Int32 bufferCount=0
Init()
{
if (geometryBuffer == null)
{
geometryBuffer = new VertexBuffer(Device, typeof (VertexPositionTexture), 36, BufferUsage.WriteOnly);
geometryIndexBuffer = new IndexBuffer(Device, typeof (Int32), 36, BufferUsage.WriteOnly);
vertices = new[]{...}
geometryBuffer.SetData(vertices);
indices = new[]{...}
geometryIndexBuffer.SetData(indices);
var instanceStreamElements = new VertexElement[6];
instanceStreamElements[0] = new VertexElement(sizeof (float)*0, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 1);
instanceStreamElements[1] = new VertexElement(sizeof (float)*4, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 2);
instanceStreamElements[2] = new VertexElement(sizeof (float)*8, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 3);
instanceStreamElements[3] = new VertexElement(sizeof (float)*12, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 4);
instanceStreamElements[4] = new VertexElement(sizeof (float)*16, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 5);
instanceStreamElements[5] = new VertexElement(sizeof (float)*18, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 6);
instanceVertexDeclaration = new VertexDeclaration(instanceStreamElements);
}
instanceBuffer = new VertexBuffer(Device, instanceVertexDeclaration, MaxCubeCount, BufferUsage.WriteOnly);
instanceBuffer.SetData(Buffer);
bindings = new[]
{
new VertexBufferBinding(geometryBuffer),
new VertexBufferBinding(instanceBuffer, 0, 1),
};
}
AddRandomCube(Vector3 pos)
{
if(cubes.Count >= MaxCubeCount)
return null;
Vector2 tex = new Vector2(rnd.Next(0, 16), rnd.Next(0, 16))
Vector4 l= new Vector4((float)rnd.Next(), (float)rnd.Next(), (float)rnd.Next(), (float)rnd.Next());
var cube = new InstanceInfoOpt9(Matrix.CreateTranslation(pos),tex, l);
Buffer[bufferCount++] = cube;
return cube;
}
Draw()
{
Device.Indices = geometryIndexBuffer;
Device.SetVertexBuffers(bindings);
Device.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, 36, 0, 12, bufferCount);
}
Shader
float4x4 xView;
float4x4 xProjection;
float4x4 xWorld;
texture cubeTexture;
sampler TexColorLightSampler = sampler_state
{
texture = <cubeTexture>;
mipfilter = LINEAR;
minfilter = LINEAR;
magfilter = LINEAR;
};
struct InstancingVSTexColorLightInput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
struct InstancingVSTexColorLightOutput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
float4 Light : TEXCOORD1;
};
InstancingVSTexColorLightOutput InstancingVSTexColorLight(InstancingVSTexColorLightInput input, float4x4 instanceTransform : TEXCOORD1, float2 instanceTex : TEXCOORD5, float4 instanceLight : TEXCOORD6)
{
float4x4 preViewProjection = mul (xView, xProjection);
float4x4 preWorldViewProjection = mul (xWorld, preViewProjection);
InstancingVSTexColorLightOutput output;
float4 pos = input.Position;
pos = mul(pos, transpose(instanceTransform));
pos = mul(pos, preWorldViewProjection);
output.Position = pos;
output.Light = instanceLight;
output.TexCoord = float2((input.TexCoord.x / 16.0f) + (1.0f / 16.0f * instanceTex.x),
(input.TexCoord.y / 16.0f) + (1.0f / 16.0f * instanceTex.y));
return output;
}
float4 InstancingPSTexColorLight(InstancingVSTexColorLightOutput input) : COLOR0
{
float4 color = tex2D(TexColorLightSampler, input.TexCoord);
color.r = color.r * input.Light.r;
color.g = color.g * input.Light.g;
color.b = color.b * input.Light.b;
color.a = color.a * input.Light.a;
return color;
}
technique InstancingTexColorLight
{
pass Pass0
{
VertexShader = compile vs_3_0 InstancingVSTexColorLight();
PixelShader = compile ps_3_0 InstancingPSTexColorLight();
}
}
quelle
Antworten:
Ich vermute, dass Ihre Leistung GPU-gebunden ist. Sie fordern Ihr Grafikgerät lediglich auf, mehr Arbeit pro Zeiteinheit zu erledigen, als es verarbeiten kann. 36 Millionen Scheitelpunkte pro Frame sind eine recht anständige Zahl, und Hardware-Instanzen können den Verarbeitungsaufwand auf der GPU-Seite der Gleichung tatsächlich erhöhen. Zeichne weniger Polygone.
Warum verschwindet das Problem, wenn die Chargengröße reduziert wird? Weil die CPU länger braucht, um einen Frame zu verarbeiten, was bedeutet, dass sie weniger Zeit damit verbringt, darauf zu
Present()
warten, dass die GPU das Rendern beendet. Das ist es, was ich denke, während dieser Lücke am Ende IhrerDraw()
Anrufe.Der Grund für das spezifische Timing der Lücken ist schwerer zu erraten, ohne den gesamten Code zu verstehen, aber ich bin mir auch nicht sicher, ob es wichtig ist. Arbeiten Sie mehr an der CPU oder weniger an der GPU, damit Ihre Arbeitslast weniger ungleichmäßig ist.
Weitere Informationen finden Sie in diesem Artikel auf Shawn Hargreaves 'Blog.
quelle
IsFixedTimeStep
Einstellungfalse
: Wenn das Spiel zu langsam läuft, ruft XNAUpdate()
mehrmals hintereinander auf, um aufzuholen, und lässt dabei absichtlich Frames fallen. WirdIsRunningSlowly
während dieser Frames auf true gesetzt? Was das seltsame Timing angeht - ich wundere mich ein bisschen. Laufen Sie im Fenstermodus? Bleibt das Verhalten im Vollbildmodus bestehen?IsFixedTimeStep=true
. Das untere Diagramm zeigt die Zeit zwischen dem Ende meiner Ziehung und dem Beginn des Aktualisierungsaufrufs des nächsten Frames. Die Frames werden nicht gelöscht, ich rufe die Draw-Methoden auf und bezahle den CPU-Preis dafür (oberes Diagramm). Gleiches Verhalten im Vollbildmodus und bei allen Auflösungen.Ich denke, Sie haben ein Müllproblem ... Vielleicht erstellen / zerstören Sie viele Objekte und diese Spitzen sind die Routine für die Müllsammler-Arbeit ...
Stellen Sie sicher, dass Sie alle Ihre Speicherstrukturen wiederverwenden ... und verwenden Sie "neu" nicht zu oft
quelle