ฉันพยายามที่จะทำฮาร์ดแวร์ instancing แต่ฉันตีปัญหาประสิทธิภาพการทำงานที่แปลก อัตราเฟรมเฉลี่ยอยู่ที่ประมาณ 45 แต่มันขาด ๆ หาย ๆ อย่างมาก
- หน้าต่าง
- SynchronizeWithVerticalRetrace = false
- IsFixedTimeStep = false
- PresentationInterval = PresentInterval.Immediate
ภาพด้านล่างแสดงเวลาที่ฉันวัดได้ (พร้อมStopwatch
) กราฟระดับบนสุดคือเวลาที่ใช้ในDraw
วิธีการและกราฟด้านล่างเป็นเวลาตั้งแต่สิ้นสุดDraw
จนจบUpdate
เดือยแหลมนั้นอยู่ห่างกันเกือบ 1 วินาทีและมักจะ 2,3,4 หรือ 5 เท่าของเวลาปกติ เฟรมทันทีหลังจากขัดขวางไม่ใช้เวลาเลย ฉันตรวจสอบแล้วว่าไม่ใช่ตัวรวบรวมขยะ
ขณะนี้ฉันกำลังวางตาข่ายที่ประกอบด้วยสามเหลี่ยม 12 รูปและจุดยอด 36 จุดเป็นรายการรูปสามเหลี่ยม (ฉันรู้ว่ามันไม่เหมาะ แต่เป็นเพียงการทดสอบ) โดยมี 1 ล้านอินสแตนซ์ ถ้าฉันแบทช์อินสแตนซ์การดึงการโทรออกเป็นส่วนเล็ก ๆ ของ 250 อินสแตนซ์แต่ละปัญหาจะบรรเทา แต่การใช้ cpu เพิ่มขึ้นอย่างมีนัยสำคัญ การเรียกใช้ข้างต้นอยู่ที่ 10,000 อินสแตนซ์ต่อการเรียกแบบดึงซึ่งง่ายกว่าบน cpu
ถ้าฉันเล่นเกมแบบเต็มหน้าจอกราฟด้านล่างเกือบจะไม่มีตัวตน แต่ปัญหาเดียวกันนี้เกิดขึ้นในDraw
วิธีการ
นี่คือการวิ่งภายใน PIXซึ่งไม่สมเหตุสมผลสำหรับฉันเลย ดูเหมือนว่าในบางเฟรมจะไม่มีการเรนเดอร์ ...
มีความคิดอะไรที่ทำให้เกิดสิ่งนี้
แก้ไข : ตามที่ร้องขอส่วนที่เกี่ยวข้องของรหัสการแสดงผล
A CubeBuffer
ถูกสร้างและเริ่มต้นแล้วเต็มไปด้วยลูกบาศก์ หากจำนวนลูกบาศก์สูงกว่าขีด จำกัด ที่กำหนดใหม่CubeBuffer
จะมีการสร้างใหม่และอื่น ๆ แต่ละบัฟเฟอร์ดึงอินสแตนซ์ทั้งหมดในการโทรครั้งเดียว
ข้อมูลที่จำเป็นเพียงครั้งเดียวคือstatic
(จุดยอด, ดัชนีบัฟเฟอร์และการประกาศจุดสุดยอด; ถึงแม้ว่ามันจะไม่ทำให้เกิดความแตกต่าง) พื้นผิวคือ 512x512
วาด()
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();
}
}