এক্সএনএ নিয়মিত বিরতিতে তোতলা


10

আমি হার্ডওয়্যার ইনস্ট্যান্সিং করার চেষ্টা করছি তবে আমি কিছু অদ্ভুত পারফরম্যান্স সমস্যা হিট করছি। গড় ফ্রেমরেট 45 এর কাছাকাছি, তবে এটি অত্যন্ত চপ্পল।

  • বাতায়নযুক্ত
  • SyncronizeWithVericalRetrace = মিথ্যা
  • ইসফিক্সডটাইমস্টেপ = মিথ্যা
  • উপস্থাপনা-অন্তর্ভুক্ত = উপস্থাপনা

নীচের চিত্রটি আমার পরিমাপের সময় (সহ Stopwatch) দেখায় । শীর্ষস্থানীয় গ্রাফটি Drawপদ্ধতিতে ব্যয় করা সময় এবং নীচের গ্রাফটি শেষ থেকে Drawশুরু না হওয়া পর্যন্ত সময়Update আঁকুন এবং এক্সএনএ টাইমিং

স্পাইকগুলি প্রায় 1 সেকেন্ডের ব্যবধানে দূরে থাকে এবং সর্বদা স্বাভাবিক সময়ের সাথে 2,3,4 বা 5 বার থাকে। তত্ক্ষণাত্ স্পাইক অনুসারে ফ্রেমগুলি মোটেই সময় নেয় না। আমি দেখেছি এটি আবর্জনা সংগ্রহকারী নয়।

আমি বর্তমানে একটি ত্রিভুজ তালিকা হিসাবে 12 টি ত্রিভুজ এবং 36 টি সূক্ষ্ম সমন্বয়ে একটি জাল ইনস্ট্যান্স করছি (আমি জানি এটি অনুকূল নয়, তবে এটি কেবল পরীক্ষার জন্য) 1 মিলিয়ন দৃষ্টান্ত দিয়ে। আমি যদি ইনস্ট্যান্সিংয়ের কলগুলিকে 250 টি দৃষ্টান্তের ছোট্ট অংশগুলিতে কল করি তবে প্রতিটি সমস্যা উপশম হয় তবে সিপিইউ ব্যবহার উল্লেখযোগ্যভাবে বৃদ্ধি পায়। উপরের রানটি প্রতি কল কল 10000 ইনস্টেন্সে, যা সিপুতে খুব সহজ।

আমি যদি গেমটি পুরো স্ক্রিনে চালিত করি তবে নীচের গ্রাফটি প্রায় অস্তিত্বহীন, তবে Drawপদ্ধতিতে এখন একই সমস্যা দেখা দেয় ।

এখানে পিআইএক্সের ভিতরে একটি রান রয়েছে যা আমার কাছে মোটেই বোঝায় না। কিছু ফ্রেমের জন্য মনে হচ্ছে কোনও রেন্ডারিং করা হয়নি ...

কোন ধারণা, কি কারণ হতে পারে?

সম্পাদনা : অনুরোধ হিসাবে, রেন্ডার কোড সম্পর্কিত প্রাসঙ্গিক অংশ

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

আমি নিশ্চিত নই যে এটি ড্রয়ের শেষ থেকে শুরু করে আপডেটের সূচনা পর্যন্ত শুরু হয়েছে, যেহেতু তারা দৃ strongly়ভাবে লিঙ্কযুক্ত নয় (যেমন গেমটি ধীরে ধীরে চালিত হয় তবে 2 টি ড্রয়ের মধ্যে অনেকগুলি আপডেট ঘটতে পারে, যা আপনি চালাচ্ছেন না এমন ক্ষেত্রে অবশ্যই এটি হওয়া উচিত 60 এফপিএসে)। তারা এমনকি পৃথক থ্রেডে চালাতে পারে (তবে আমি এটি সম্পর্কে নিশ্চিত নই)।
জোনকো

আমার কোনও সত্যিকারের ক্লু এটিম নেই, তবে এটি যদি আপনার ব্যাচিং কোডটির সাথে আপাতদৃষ্টিতে সমস্যাটি আরও ছোট করে কাজ করে তবে প্রাসঙ্গিক এক্সএনএ এবং এইচএলএসএল কোড পোস্ট করুন যাতে আমরা এটিকে আরও কাছাকাছি দেখতে পারি ইসফিক্সডটাইমস্টেপ এর সাথে = জোনকো: 1 আপডেট রয়েছে 1 / কল কল করুন
ড্যানিয়েল কার্লসন

এখানে কেন এই তোতলামি (XNA দলের দিকে) শন হারগ্রিভস থেকে হলেও একটি ব্যাখ্যা forums.create.msdn.com/forums/p/9934/53561.aspx#53561
NexAddo

উত্তর:


3

আমি অনুমান করছি যে আপনার পারফরম্যান্সটি জিপিইউ-আবদ্ধ। আপনি কেবল নিজের গ্রাফিক্স ডিভাইসটি পরিচালনা করতে সক্ষম হওয়ার চেয়ে ইউনিট সময়ে আরও বেশি কাজ করতে বলছেন; ফ্রেম প্রতি 36 মিলিয়ন উল্লম্ব একটি চমত্কার শালীন সংখ্যা, এবং হার্ডওয়্যার ইনস্ট্যান্সিং আসলে সমীকরণের জিপিইউ দিকে প্রয়োজনীয় প্রক্রিয়াজাতকরণের পরিমাণ বাড়িয়ে তুলতে পারে। কম বহুভুজ আঁকুন।

ব্যাচের আকার হ্রাস করা সমস্যা কেন দূরে সরে যায়? কারণ এটি কোনও ফ্রেম প্রসেস করতে সিপিইউকে আরও বেশি সময় দেয়, যার অর্থ Present()জিপিইউ রেন্ডারিং শেষ করার অপেক্ষায় বসে বেশি সময় ব্যয় করে। আপনার Draw()কলগুলির শেষে সেই ব্যবধানের সময় এটি আমার মনে হয় ।

শূন্যতার নির্দিষ্ট সময়ের পিছনের কারণটি পুরো কোডটি না বুঝেই divineশিক পক্ষে শক্ত, তবে আমি নিশ্চিত নই যে এটিও গুরুত্বপূর্ণ। সিপিইউতে আরও কাজ করুন, বা জিপিইউতে কম কাজ করুন, যাতে আপনার কাজের চাপ কম অসম হয়।

আরও তথ্যের জন্য শন হারগ্রিভসের ব্লগে এই নিবন্ধটি দেখুন ।


2
এটি অবশ্যই জিপিইউ আবদ্ধ। বিভিন্ন অঙ্কন পদ্ধতি অন্বেষণ করার জন্য অ্যাপ্লিকেশনটি মূলত একটি মানদণ্ড। একই পরিমাণে উল্লম্ব অঙ্কিত একটি ছোট ব্যাচের আকার সিপিইউতে বেশি সময় লাগবে, তবে জিপিইউ-লোড একই হওয়া উচিত, না? কমপক্ষে আমি ফ্রেমের মধ্যে একটি সামঞ্জস্যপূর্ণ সময় আশা করবো, লোডের উপর নির্ভর করে (যা ফ্রেমের মধ্যে একেবারেই পরিবর্তিত হয় না) এবং ল্যাগ এবং তাত্ক্ষণিকের নিয়মিত বিরতি নয় (বা কোনও রেন্ডারিং নয়, পিআইএক্স দেখুন)।
দারকারা

যদি আমি আপনার গ্রাফগুলি সঠিকভাবে ব্যাখ্যা করি তবে তাত্ক্ষণিকভাবে রেন্ডার করা ফ্রেমগুলি এক্সএনএ ফ্রেমওয়ার্কের কার্যকারিতার অংশ। সঙ্গে IsFixedTimeStepসেট false, খেলা খুব ধীরে চলছে করা হয়, তাহলে XNA ডাকব Update()একাধিক বার একটি সারিতে ধরতে, ইচ্ছাকৃতভাবে প্রক্রিয়ায় ফ্রেম ড্রপ। হয় IsRunningSlowlyএই ফ্রেম সময় সত্যতে সেট? অদ্ভুত সময় হিসাবে - এটি আমাকে কিছুটা অবাক করে তোলে। আপনি কি উইন্ডোড মোডে চলছে? আচরণটি কি ফুলস্ক্রিন মোডে স্থির থাকে?
কোল ক্যাম্পবেল

ক্যাচআপ কলগুলি কেবলমাত্র ঘটে IsFixedTimeStep=true। নীচের গ্রাফটি আমার অঙ্কনের শেষ এবং পরবর্তী ফ্রেমের আপডেট কলের শুরুর মধ্যবর্তী সময় দেখায়। ফ্রেমগুলি বাদ দেওয়া হয় না, আমি অঙ্কন পদ্ধতিগুলি কল করি এবং তাদের জন্য সিপিইউ মূল্য প্রদান করি (শীর্ষ গ্রাফ)। পূর্ণস্ক্রিনে এবং রেজোলিউশন জুড়ে একই আচরণ।
দারকারা

আপনি ঠিক বলেছেন, আমার ভুল। আমি ভয় করি আমি এই মুহুর্তে আমার ধারণাগুলি শেষ করে দিয়েছি।
কোল ক্যাম্পবেল

2

আমি মনে করি আপনার একটি আবর্জনাজনিত সমস্যা আছে ... সম্ভবত আপনি অনেকগুলি অবজেক্ট তৈরি / ধ্বংস করছেন এবং স্পাইকগুলি হ'ল আবর্জনা সংগ্রহকারী রুটিন কাজ করছে ...

আপনার সমস্ত মেমরি স্ট্রাকচার পুনরায় ব্যবহার করতে ভুলবেন না ... এবং খুব বেশি 'নতুন' ব্যবহার করবেন না


প্রসেসএক্সপ্লোরার এবং সিএলআরপ্রফিলারের মধ্যে ইতিমধ্যে যাচাই করা হয়েছে এবং জিসি প্রতি 10 সেকেন্ডের মতো একবার চলছে এবং প্রায় 75 মিলিমিটারের মতো নয়।
দারকারা

1
এটি আপনার রেন্ডারিং মন্দার কারণ কিনা তা নির্বিশেষে আপনি অবশ্যই প্রতিটি ফ্রেম কোনও নতুন রাস্টারাইজার স্টেট, ব্লেন্ডস্টেট এবং ডিপথস্টেনসিল স্টেট তৈরি করতে চান না। এটি নিখুঁতভাবে সহায়তা করবে না, এই নিবন্ধ অনুসারে ব্লগস.এমএসডিএন / বি / শশ্নাহার / অর্কিভ / ২০০০/০৪/২০১২ আপনি আপনার যে অবস্থা তৈরি করবেন তা লোডের সময় একবার ব্যবহার করা উচিত এবং প্রয়োজনের সময় সেগুলি আবার প্রয়োগ করতে হবে।
দাদু গেমস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.