Я пытаюсь сделать аппаратное копирование, но у меня странная проблема с производительностью. Средняя частота кадров составляет около 45, но это очень изменчивый.
- Оконный
- SynchronizeWithVerticalRetrace = false
- IsFixedTimeStep = false
- PresentationInterval = PresentInterval.Immediate
На изображении ниже показано мое измеренное время (с Stopwatch
). Самый верхний график - это время, проведенное в Draw
методе, а нижний график - это время от конца Draw
до началаUpdate
Шипы разнесены почти на 1 секунду и всегда в 2,3,4 или 5 раз больше обычного времени. Кадры, следующие непосредственно за шипом, совсем не занимают время. Я проверил, что это не сборщик мусора.
В настоящее время я создаю сетку, состоящую из 12 треугольников и 36 вершин в виде списка треугольников (я знаю, что это не оптимально, но только для тестирования) с 1 миллионом экземпляров. Если я сделаю групповые вызовы отрисовки по 250 экземпляров, каждая проблема будет облегчена, но использование ЦП значительно возрастет. Приведенный выше прогон составляет 10000 экземпляров на вызов отрисовки, что намного проще для процессора.
Если я запускаю игру в полноэкранном режиме, нижний график почти не существует, но та же проблема возникает сейчас в Draw
методе.
Вот бег внутри PIX , который не имеет никакого смысла для меня вообще. Похоже, что для некоторых кадров не выполняется рендеринг ...
Есть идеи, что может быть причиной этого?
РЕДАКТИРОВАТЬ : По запросу соответствующие части кода рендеринга
A CubeBuffer
создается и инициализируется, затем заполняется кубиками. Если количество кубиков превышает определенный предел, создается новый CubeBuffer
и т. Д. Каждый буфер рисует все экземпляры за один вызов.
Информация, необходимая только один раз: static
(вершина, индексный буфер и объявление вершины; хотя пока это не имеет значения). Текстура 512х512
Рисовать()
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();
}
}
источник
Ответы:
Я предполагаю, что ваша производительность связана с GPU. Вы просто просите свое графическое устройство выполнить больше работы за единицу времени, чем оно способно обработать; 36 миллионов вершин на кадр - это довольно приличное число, и аппаратное копирование может фактически увеличить объем обработки, необходимый на стороне уравнения GPU. Нарисуйте меньше полигонов.
Почему уменьшение размера партии устраняет проблему? Поскольку процессору требуется больше времени для обработки кадра, а это означает, что он тратит меньше времени на
Present()
ожидание завершения обработки графическим процессором. Это то, что я думаю, что делает во время этого перерыва в конце вашихDraw()
звонков.Причину временной задержки пробелов труднее угадать, не понимая весь код, но я не уверен, что это тоже важно. Делайте больше работы с процессором или меньше работы с графическим процессором, чтобы ваша рабочая нагрузка была менее неравномерной.
Смотрите эту статью в блоге Шона Харгривза для получения дополнительной информации.
источник
IsFixedTimeStep
установлено значение «false
Если игра работает слишком медленно», XNA будет вызыватьUpdate()
несколько раз подряд, чтобы наверстать упущенное, умышленно отбрасывая кадры в процессе.IsRunningSlowly
Установлено ли значение true во время этих кадров? Что касается странного времени - это заставляет меня задуматься немного. Вы работаете в оконном режиме? Сохраняется ли поведение в полноэкранном режиме?IsFixedTimeStep=true
. Нижний график показывает время между окончанием моего розыгрыша и началом вызова обновления следующего кадра. Кадры не сбрасываются, я вызываю draw-методы и плачу за них цену процессора (верхний график). Такое же поведение в полноэкранном режиме и в разных разрешениях.Я думаю, что у вас есть проблема с мусором ... возможно, вы создаете / уничтожаете много объектов, и что шипы - это обычная работа сборщика мусора ...
не забудьте повторно использовать все ваши структуры памяти ... и не используйте «новый» слишком часто
источник