Hi community,
I’m working on a minecraft-ish 3D engine with lots, lots, LOTS of cubic voxel objects. Well, basically just three sides of a cube, made out of 6 triangles, but that shouldn’t bother us right now. The point is, everything pretty much depends on how fast primitives can be drawn.
Therefore I ran some tests MonoGame vs. XNA. Very basic tests with just 6 primitives for a start and a frame counter. IsFixedTimeStep = false; graphics.SynchronizeWithVerticalRetrace = false. Let’s see, what my Windows system is capable of…
XNA: 8600 - 8900 fps
Monogame: 300 - 8800 fps
Under XNA the framerate ist relatively constant between 8800-8900 fps most of the time with some sudden drops every ten seconds to 8600 fps, which is the usual garbage collection, I guess. The behaviour under MonoGame (with the exact same code!) is very strange, though. It starts out at 8800-8900 fps, but drops to 300 fps within a second. It stays this low for 3-4 seconds, jumps up to 8800 fps for another seconds, just to fall back to 300 again. And so on…
Testing maximum primitives in 1/60 sec:
With XNA I got 4.2 million primitives on screen with 60+ fps.
With MonoGame I have to reduce that to just a few thousand primitives, to stay above 60 fps
- I removed the framecounter and rotated the object instead to sort out
any problems with the spritefont or the counter. Same effect: With
XNA the objects spin is fast and constant, with MonoGame its fast,
slooooow, fast, slooooooow … Its not the counter. - I changed the primitives from indexed vertices to non-indexed. No
difference. - I tested it with other graphic adapters (nVidia, AMD, Intel) on other
systems (Win 7, Win 8). The numbers change, but the tremendous
difference stays. - I switched over to MonoGame/OpenGL. Not helping.
Does anyone made the same experiences?
Is it me or is it MonoGame?
Here’s my test program. Nothing fancy:
public class Game1 : Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; SpriteFont arial; VertexPositionColor[] vertices; VertexBuffer vertexBuffer; IndexBuffer indexBuffer; float angle;
BasicEffect basicEffect; Matrix world = Matrix.CreateTranslation(0, 0, 0); Matrix view = Matrix.CreateLookAt(new Vector3(2, -2, 3), new Vector3(0, 0, 0), new Vector3(0, 1, 0)); Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 800f / 480f, 0.01f, 100f);
// Framerate Counter private float felapsed; private float fframeRate; private float fframes;
public Game1() : base() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; IsFixedTimeStep = false; graphics.SynchronizeWithVerticalRetrace = false; }
protected override void Initialize() { graphics.PreferredBackBufferWidth = 800; graphics.PreferredBackBufferHeight = 600; graphics.IsFullScreen = false; graphics.ApplyChanges(); Window.Title = "Hi there!";
base.Initialize(); }
protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); basicEffect = new BasicEffect(GraphicsDevice); arial = Content.Load<SpriteFont>("Fonts/arial"); angle = 0;
SetUpVertices(); }
protected override void UnloadContent() { }
private void SetUpVertices() { vertices = new VertexPositionColor[7];
vertices[0] = new VertexPositionColor(new Vector3(0.00f, 0.00f, 0.00f), new Color(50, 50, 250)); vertices[1] = new VertexPositionColor(new Vector3(-0.15f, -0.26f, 0.00f), new Color(0, 0, 200)); vertices[2] = new VertexPositionColor(new Vector3(0.15f, -0.26f, 0.00f), new Color(50, 50, 200)); vertices[3] = new VertexPositionColor(new Vector3(0.30f, 0.00f, 0.00f), new Color(80, 80, 250)); vertices[4] = new VertexPositionColor(new Vector3(0.15f, 0.26f, 0.00f), new Color(100, 100, 250)); vertices[5] = new VertexPositionColor(new Vector3(-0.15f, 0.26f, 0.00f), new Color(50, 50, 200)); vertices[6] = new VertexPositionColor(new Vector3(-0.30f, 0.00f, 0.00f), new Color(0, 0, 250));
vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), vertices.Length, BufferUsage.WriteOnly); vertexBuffer.SetData<VertexPositionColor>(vertices);
short[] indices = new short[18]; indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 0; indices[4] = 2; indices[5] = 3; indices[6] = 0; indices[7] = 3; indices[8] = 4; indices[9] = 0; indices[10] = 4; indices[11] = 5; indices[12] = 0; indices[13] = 5; indices[14] = 6; indices[15] = 0; indices[16] = 6; indices[17] = 1;
indexBuffer = new IndexBuffer(graphics.GraphicsDevice, typeof(short), indices.Length, BufferUsage.WriteOnly); indexBuffer.SetData(indices);
}
protected override void Update(GameTime gameTime) { // Framerate counter felapsed += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (felapsed > 1.0f) { felapsed -= 1.0f; fframeRate = fframes; fframes = 0; } else { fframes += 1; }
KeyboardState keyState = Keyboard.GetState(); if (keyState.IsKeyDown(Keys.Left)) angle += 0.01f; if (keyState.IsKeyDown(Keys.Right)) angle -= 0.01f;
base.Update(gameTime); }
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend); spriteBatch.DrawString(arial, fframeRate.ToString("Frames per Second: " + "0"), new Vector2(20, 20), Color.White, 0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f); spriteBatch.End();
float angle2 = Convert.ToSingle(Math.Sin(angle)); float angle3 = Convert.ToSingle(Math.Cos(angle)); view = Matrix.CreateLookAt(new Vector3(2, angle3 * 5, angle2 * 5), new Vector3(0, 0, 0), new Vector3(0, 1, 0)); basicEffect.World = world; basicEffect.View = view; basicEffect.Projection = projection; basicEffect.VertexColorEnabled = true;
GraphicsDevice.SetVertexBuffer(vertexBuffer); GraphicsDevice.Indices = indexBuffer;
RasterizerState rasterizerState = new RasterizerState(); rasterizerState.CullMode = CullMode.None; //rasterizerState.FillMode = FillMode.WireFrame; GraphicsDevice.RasterizerState = rasterizerState;
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes) { pass.Apply(); GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 6); }
base.Draw(gameTime); } }