XNA nói lắp đều đặn


10

Tôi đang cố gắng làm phần cứng, nhưng tôi gặp phải một số vấn đề hiệu năng lạ. Tốc độ khung hình trung bình là khoảng 45, nhưng nó cực kỳ khó hiểu.

  • Cửa sổ
  • Đồng bộ hóaWithV verticalRetrace = false
  • IsFixedTimeStep = false
  • PresentationInterval = PresentInterval.Immediate

Hình ảnh dưới đây cho thấy thời gian đo của tôi (với Stopwatch). Biểu đồ trên cùng là thời gian dành cho Drawphương thức và biểu đồ dưới cùng là thời gian từ khi kết thúc Drawcho đến khi bắt đầuUpdate Vẽ và xna thời gian

Các gai cách nhau gần như chính xác 1 giây và luôn gấp 2,3,4 hoặc 5 lần so với thời gian thông thường. Các khung hình ngay sau khi tăng đột biến không mất thời gian. Tôi đã kiểm tra rằng nó không phải là người thu gom rác.

Tôi hiện đang cung cấp một lưới gồm 12 hình tam giác và 36 đỉnh như một danh sách tam giác (tôi biết nó không tối ưu, nhưng nó chỉ để thử nghiệm) với 1 triệu trường hợp. Nếu tôi bó các cuộc gọi rút thăm nhanh thành các phần nhỏ của 250 trường hợp thì mỗi vấn đề được giảm bớt, nhưng việc sử dụng cpu tăng đáng kể. Việc chạy ở trên là 10000 ví dụ cho mỗi cuộc gọi rút thăm, điều này dễ dàng hơn nhiều trên cpu.

Nếu tôi chạy trò chơi ở chế độ toàn màn hình thì đồ thị phía dưới gần như không tồn tại, nhưng vấn đề tương tự xảy ra trong Drawphương thức này.

Đây là một hoạt động bên trong PIX , không có ý nghĩa gì với tôi cả. Dường như đối với một số khung hình không có kết xuất nào được thực hiện ...

Bất cứ ý tưởng, những gì có thể gây ra điều này?

EDIT : Theo yêu cầu, các phần có liên quan của mã kết xuất

A CubeBufferđược tạo và khởi tạo, sau đó chứa đầy các hình khối. Nếu số lượng hình khối vượt quá một giới hạn nhất định, một hình mới CubeBuffersẽ được tạo ra, v.v. Mỗi bộ đệm rút ra tất cả các trường hợp trong một cuộc gọi.

Thông tin chỉ cần một lần là static(đỉnh, bộ đệm chỉ mục và khai báo đỉnh; mặc dù cho đến nay nó không có sự khác biệt). Kết cấu là 512x512

Vẽ tranh()

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);

Khối lập phương

[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();
 }
}

Tôi không chắc liệu nó có liên quan đến thời gian từ khi kết thúc bốc thăm đến khi bắt đầu cập nhật hay không, vì chúng không được liên kết mạnh mẽ (nghĩa là nhiều bản cập nhật có thể xảy ra giữa 2 lần rút nếu trò chơi chạy chậm, đó là trường hợp vì bạn không chạy ở tốc độ 60 khung hình / giây). Chúng thậm chí có thể chạy trong các luồng riêng biệt (nhưng tôi không chắc về điều này).
Zonko

Tôi không có đầu mối thực sự, nhưng nếu nó hoạt động với lô nhỏ hơn thì rõ ràng đó là vấn đề với mã bó của bạn, hãy đăng mã XNA và HLSL có liên quan để chúng tôi có thể xem xét kỹ hơn về nó @Zonko với IsFixedTimeStep = Sai có cập nhật 1: 1 / rút cuộc gọi
Daniel Carlsson

Dưới đây là một lời giải thích cho lý do tại sao điều này xảy ra nói lắp từ Shawn Hargreaves (trong nhóm XNA): forums.create.msdn.com/forums/p/9934/53561.aspx#53561
NexAddo

Câu trả lời:


3

Tôi đoán rằng hiệu suất của bạn bị ràng buộc bởi GPU. Bạn chỉ đơn giản yêu cầu thiết bị đồ họa của bạn thực hiện nhiều công việc trên mỗi đơn vị thời gian hơn khả năng xử lý; 36 triệu đỉnh trên mỗi khung là một con số khá ổn định và việc tăng tốc phần cứng thực sự có thể làm tăng lượng công việc xử lý cần thiết ở phía GPU của phương trình. Vẽ ít đa giác hơn.

Tại sao việc giảm kích thước lô làm cho vấn đề biến mất? Bởi vì nó làm cho CPU mất nhiều thời gian hơn để xử lý khung hình, điều đó có nghĩa là nó sẽ tốn ít thời gian hơn Present()để chờ GPU hoàn thành kết xuất. Đó là những gì tôi nghĩ rằng nó đang thực hiện trong khoảng cách đó vào cuối các Draw()cuộc gọi của bạn .

Lý do đằng sau thời gian cụ thể của các khoảng trống là khó khăn hơn để không thể hiểu toàn bộ mã, nhưng tôi cũng không chắc nó cũng quan trọng. Làm nhiều công việc hơn trên CPU, hoặc làm việc ít hơn với GPU, để khối lượng công việc của bạn ít không đồng đều.

Xem bài viết này trên blog của Shawn Hargreaves để biết thêm thông tin.


2
Nó chắc chắn là GPU bị ràng buộc. Ứng dụng về cơ bản là một điểm chuẩn, để khám phá các phương pháp vẽ khác nhau. Một kích thước lô nhỏ hơn với cùng một số đỉnh được vẽ sẽ mất nhiều thời gian hơn trên CPU, nhưng tải GPU sẽ giống nhau, phải không? Ít nhất tôi sẽ mong đợi một thời gian nhất quán giữa các khung, tùy thuộc vào tải (không thay đổi giữa các khung) và không phải là khoảng thời gian trễ và tức thời như vậy (hoặc không hiển thị, xem PIX).
Darcara

Nếu tôi diễn giải chính xác biểu đồ của bạn, các khung được hiển thị ngay lập tức là một phần chức năng của Khung XNA. Với IsFixedTimeStepcài đặt thành false, Nếu trò chơi chạy quá chậm, XNA sẽ gọi Update()nhiều lần liên tiếp để bắt kịp, cố tình thả khung trong quá trình. Được IsRunningSlowlyđặt thành đúng trong các khung này? Đối với thời gian kỳ lạ - nó làm tôi tự hỏi một chút. Bạn đang chạy trong chế độ cửa sổ? Liệu các hành vi vẫn tồn tại trong chế độ toàn màn hình?
Cole Campbell

cuộc gọi bắt kịp chỉ xảy ra trên IsFixedTimeStep=true. Biểu đồ phía dưới hiển thị thời gian giữa khi kết thúc bản vẽ của tôi và bắt đầu cuộc gọi cập nhật của khung tiếp theo. Các khung không bị rơi, tôi gọi các phương thức vẽ và trả giá CPU cho chúng (biểu đồ trên cùng). Hành vi tương tự trong toàn màn hình và trên các nghị quyết.
Darcara

Bạn nói đúng, lỗi của tôi. Tôi sợ rằng tôi đã cạn kiệt ý tưởng của mình tại thời điểm này.
Cole Campbell

2

Tôi nghĩ rằng bạn có một vấn đề rác ... có thể bạn đang tạo / hủy cho nhiều đối tượng và gai đó là thói quen của người thu gom rác hoạt động ...

hãy chắc chắn sử dụng lại tất cả các cấu trúc bộ nhớ của bạn ... và đừng sử dụng 'mới' quá thường xuyên


Đã kiểm tra rằng trong ProcessExplorer và CLRProfiler, và gc sẽ chạy như vậy cứ sau 10 giây và không dài đến 75ms.
Darcara

1
Bạn chắc chắn không muốn tạo RasterizerState, BlendState và DepthStpsonState mới cho mọi khung hình bất kể đó có phải là nguyên nhân khiến việc hiển thị của bạn bị chậm lại hay không. Nó chắc chắn sẽ không giúp ích gì, theo bài viết này blog.msdn.com/b/shawnhar/archive/2010/04/02/NH Bạn nên tạo trạng thái bạn sẽ sử dụng một lần khi tải và áp dụng lại chúng khi cần.
Trò chơi chaoo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.