public void FlushRequests(IGameContext gameContext, IRenderContext renderContext)
{
LastBatchCount = 0;
LastApplyCount = 0;
LastBatchSaveCount = 0;
if (renderContext.IsCurrentRenderPass<I3DBatchedRenderPass>())
{
using (_profiler.Measure("render-flush"))
{
foreach (var kv in _requestLookup)
{
if (_requestInstances[kv.Key].Count == 0)
{
continue;
}
LastBatchCount++;
LastBatchSaveCount += (ulong)(_requestInstances[kv.Key].Count - 1);
var request = kv.Value;
int pc;
SetupForRequest(renderContext, request, out pc, false);
request.Effect.NativeEffect.Parameters["View"]?.SetValue(renderContext.View);
request.Effect.NativeEffect.Parameters["Projection"]?.SetValue(renderContext.Projection);
#if PLATFORM_WINDOWS
var allowInstancedCalls = false;
#else
var allowInstancedCalls = false;
#endif
if (allowInstancedCalls &&
request.Effect.NativeEffect.Techniques[request.TechniqueName + "Batched"] != null)
{
#if PLATFORM_WINDOWS
if (_vertexBuffer == null ||
_requestInstances[kv.Key].Count > _vertexBufferLastInstanceCount)
{
_vertexBuffer?.Dispose();
_vertexBuffer = new VertexBuffer(
renderContext.GraphicsDevice,
_vertexDeclaration,
_requestInstances[kv.Key].Count,
BufferUsage.WriteOnly);
_vertexBufferLastInstanceCount = _requestInstances[kv.Key].Count;
}
var matrices = _requestInstances[kv.Key];
_vertexBuffer.SetData(matrices.ToArray(), 0, matrices.Count);
renderContext.GraphicsDevice.SetVertexBuffers(
new VertexBufferBinding(request.MeshVertexBuffer),
new VertexBufferBinding(_vertexBuffer, 0, 1));
foreach (var pass in request.Effect.NativeEffect.Techniques[request.TechniqueName + "Batched"].Passes)
{
pass.Apply();
renderContext.GraphicsDevice.DrawInstancedPrimitives(
request.PrimitiveType,
0,
0,
request.MeshVertexBuffer.VertexCount,
0,
pc,
matrices.Count);
}
#endif
}
else
{
// If there's less than 5 instances, just push the draw calls to the GPU.
if (_requestInstances[kv.Key].Count <= 5 || !request.SupportsComputingInstancesToCustomBuffers)
{
renderContext.GraphicsDevice.SetVertexBuffer(request.MeshVertexBuffer);
foreach (var instance in _requestInstances[kv.Key])
{
request.Effect.NativeEffect.Parameters["World"]?.SetValue(instance);
foreach (var pass in request.Effect.NativeEffect.Techniques[request.TechniqueName].Passes)
{
pass.Apply();
LastApplyCount++;
renderContext.GraphicsDevice.DrawIndexedPrimitives(
request.PrimitiveType,
0,
0,
pc);
}
}
}
else
{
var buffersNeedComputing = false;
var vertexBuffer = _renderAutoCache.AutoCache("renderbatcher-" + kv.Key, new object[]
{
_requestInstances[kv.Key].Count,
request.MeshVertexBuffer.VertexCount,
request.MeshVertexBuffer.VertexDeclaration
}, gameContext, () =>
{
buffersNeedComputing = true;
return new VertexBuffer(
renderContext.GraphicsDevice,
request.MeshVertexBuffer.VertexDeclaration,
_requestInstances[kv.Key].Count*request.MeshVertexBuffer.VertexCount,
BufferUsage.WriteOnly);
});
var indexBuffer = _renderAutoCache.AutoCache("renderbatcher-" + kv.Key, new object[]
{
_requestInstances[kv.Key].Count,
request.MeshVertexBuffer.VertexCount,
}, gameContext, () =>
{
buffersNeedComputing = true;
return new IndexBuffer(
renderContext.GraphicsDevice,
IndexElementSize.ThirtyTwoBits,
_requestInstances[kv.Key].Count*request.MeshIndexBuffer.IndexCount,
BufferUsage.WriteOnly);
});
if (buffersNeedComputing)
{
// Compute a pre-transformed vertex and index buffer for rendering.
request.ComputeInstancesToCustomBuffers(
_requestInstances[kv.Key],
vertexBuffer,
indexBuffer);
}
renderContext.GraphicsDevice.SetVertexBuffer(vertexBuffer);
renderContext.GraphicsDevice.Indices = indexBuffer;
request.Effect.NativeEffect.Parameters["World"]?.SetValue(Matrix.Identity);
foreach (
var pass in
request.Effect.NativeEffect.Techniques[request.TechniqueName].Passes
)
{
pass.Apply();
renderContext.GraphicsDevice.DrawIndexedPrimitives(
request.PrimitiveType,
0,
0,
pc * _requestInstances[kv.Key].Count);
}
}
}
_requestInstances[kv.Key].Clear();
}
_requestLookup.Clear();
_requestInstances.Clear();
}
}
}