XNA การพูดติดอ่างในช่วงเวลาปกติ


10

ฉันพยายามที่จะทำฮาร์ดแวร์ instancing แต่ฉันตีปัญหาประสิทธิภาพการทำงานที่แปลก อัตราเฟรมเฉลี่ยอยู่ที่ประมาณ 45 แต่มันขาด ๆ หาย ๆ อย่างมาก

  • หน้าต่าง
  • SynchronizeWithVerticalRetrace = false
  • IsFixedTimeStep = false
  • PresentationInterval = PresentInterval.Immediate

ภาพด้านล่างแสดงเวลาที่ฉันวัดได้ (พร้อมStopwatch) กราฟระดับบนสุดคือเวลาที่ใช้ในDrawวิธีการและกราฟด้านล่างเป็นเวลาตั้งแต่สิ้นสุดDrawจนจบUpdate วาดและระยะเวลา xna

เดือยแหลมนั้นอยู่ห่างกันเกือบ 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();
 }
}

ฉันไม่แน่ใจว่าเกี่ยวข้องกับเวลาตั้งแต่สิ้นสุดการดึงจนถึงจุดเริ่มต้นการอัปเดตหรือไม่เนื่องจากมีการเชื่อมโยงอย่างรุนแรง (เช่นการอัปเดตจำนวนมากสามารถเกิดขึ้นระหว่าง 2 เสมอถ้าเกมทำงานช้าซึ่งต้องเป็นกรณีตั้งแต่คุณไม่ได้ทำงาน ที่ 60 fps) พวกเขาอาจทำงานในหัวข้อแยกกัน (แต่ฉันไม่แน่ใจเกี่ยวกับเรื่องนี้)
Zonko

ฉันไม่มีเงื่อนงำที่แท้จริง แต่ถ้ามันใช้งานได้กับการแบตช์ขนาดเล็กมันก็มีปัญหากับรหัสแบทช์ของคุณโพสต์รหัส XNA และ HLSL ที่เกี่ยวข้องเพื่อให้เราสามารถมองอย่างใกล้ชิดมากขึ้น @Zonko กับ IsFixedTimeStep = False / รับสาย
Daniel Carlsson

นี่คือคำอธิบายว่าทำไมการพูดติดอ่างนี้เกิดขึ้นจาก Shawn Hargreaves (ในทีม xna): forums.create.msdn.com/forums/p/9934/53561.aspx#53561
NexAddo

คำตอบ:


3

ฉันคาดเดาว่าประสิทธิภาพของคุณจะผูกกับ GPU คุณเพียงแค่ขอให้อุปกรณ์กราฟิกของคุณทำงานได้มากขึ้นต่อหน่วยเวลามากกว่าที่จะสามารถจัดการได้ 36 ล้าน vertices ต่อเฟรมเป็นตัวเลขที่ค่อนข้างดีและการติดตั้งฮาร์ดแวร์สามารถเพิ่มปริมาณงานการประมวลผลที่จำเป็นในด้าน GPU ของสมการได้ วาดรูปหลายเหลี่ยมน้อยลง

ทำไมการลดขนาดแบทช์ทำให้ปัญหาหายไป เพราะมันทำให้ซีพียูใช้เวลาในการประมวลผลเฟรมนานกว่าซึ่งหมายความว่าใช้เวลาน้อยลงในการPresent()รอให้ GPU ทำการเรนเดอร์ให้เสร็จ นั่นคือสิ่งที่ฉันคิดว่ามันทำในช่วงช่องว่างนั้นในตอนท้ายของคุณDraw()โทร

เหตุผลที่อยู่เบื้องหลังช่วงเวลาที่เฉพาะเจาะจงของช่องว่างนั้นยากที่จะศักดิ์สิทธิ์โดยไม่เข้าใจรหัสทั้งหมด แต่ฉันไม่แน่ใจว่ามันเป็นสิ่งสำคัญเช่นกัน ทำงานบน CPU มากขึ้นหรือทำงานน้อยลงใน GPU เพื่อให้ปริมาณงานของคุณไม่สม่ำเสมอ

ดูบทความนี้ในบล็อกของ Shawn Hargreaves สำหรับข้อมูลเพิ่มเติม


2
มันเป็น GPU ที่ถูกผูกไว้อย่างแน่นอน แอพนี้เป็นพื้นฐานในการสำรวจวิธีการวาดที่แตกต่างกัน ขนาดแบทช์ที่เล็กกว่าที่มีจำนวนจุดยอดเท่ากันจะใช้เวลานานกว่าในซีพียู แต่การโหลดของ GPU ควรเหมือนกันใช่ไหม? อย่างน้อยฉันก็คาดหวังว่าเวลาที่สอดคล้องกันระหว่างเฟรมขึ้นอยู่กับโหลด (ซึ่งไม่เปลี่ยนระหว่างเฟรมเลย) และไม่ใช่ช่วงเวลาปกติของความล่าช้าและทันที (หรือไม่มีการเรนเดอร์ให้ดู PIX)
Darcara

หากฉันตีความกราฟของคุณอย่างถูกต้องเฟรมที่แสดงผลทันทีเป็นส่วนหนึ่งของฟังก์ชันของ XNA Framework ด้วยการIsFixedTimeStepตั้งค่าไว้falseหากเกมทำงานช้าเกินไป XNA จะเรียกUpdate()หลายครั้งติดต่อกันเพื่อติดตามเฟรมที่หล่นในกระบวนการโดยเจตนา ถูกIsRunningSlowlyตั้งค่าเป็นจริงในช่วงเฟรมเหล่านี้หรือไม่ สำหรับช่วงเวลาแปลก ๆ - มันทำให้ฉันแปลกใจนิดหน่อย คุณกำลังทำงานในโหมดหน้าต่างหรือไม่? พฤติกรรมนั้นยังคงอยู่ในโหมดเต็มหน้าจอหรือไม่?
Cole Campbell

IsFixedTimeStep=trueเครื่องปรุงรสโทรเกิดขึ้นเฉพาะใน กราฟด้านล่างแสดงเวลาระหว่างการสิ้นสุดการเสมอของฉันและการเริ่มต้นการเรียกการอัปเดตของเฟรมถัดไป เฟรมไม่หลุดฉันเรียกวิธีการวาดและชำระราคา CPU สำหรับพวกเขา (กราฟด้านบน) พฤติกรรมเดียวกันในแบบเต็มหน้าจอและข้ามความละเอียด
Darcara

คุณพูดถูกความผิดของฉัน ฉันกลัวว่าตอนนี้ความคิดของฉันจะหมดไป
Cole Campbell

2

ฉันคิดว่าคุณมีปัญหาขยะ ... บางทีคุณกำลังสร้าง / ทำลายวัตถุหลายอย่างและ spikes นั้นเป็นกิจวัตรเก็บขยะที่ทำงาน ...

อย่าลืมนำโครงสร้างหน่วยความจำทั้งหมดของคุณกลับมาใช้ใหม่ ... และอย่าใช้ 'ใหม่' บ่อยเกินไป


ตรวจสอบแล้วว่าใน ProcessExplorer และ CLRProfiler และ gc ทำงานเหมือนทุกๆ 10 วินาทีและไม่นานเกือบ 75ms
Darcara

1
คุณไม่ต้องการสร้าง RasterizerState, BlendState และ DepthStencilState ใหม่ทุกเฟรมโดยไม่คำนึงว่าเป็นสาเหตุของการชะลอการแสดงผลของคุณหรือไม่ แน่นอนว่ามันจะไม่ช่วยตามบทความนี้blogs.msdn.com/b/shawnhar/archive/2010/04/02/ ......คุณควรสร้างสถานะที่คุณจะใช้เพียงครั้งเดียวในการโหลดและนำไปใช้ใหม่เมื่อจำเป็น
เกม dadoo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.