flopoloco's picture

5 million points with 55 FPS

I wanted to torture my PC like a boss to see how fast it can run...
OpenTK can handle 5 million points very efficiently using Vertex Buffer Objects
My system specs are Intel i5 2320, 4GB DDR3 1600, nVidia GTX 295, Windows 7 32

You can hit "Enter" to scroll between 4 different display modes to make a comparison:

  1. Immediate
  2. DisplayLists
  3. VertexArrays
  4. VertexBufferObjects
using System;
using System.Drawing;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
 
namespace OpenTKStarfield
{
	public static class FPSCounter
	{
		#region Timing
 
		private static double _time = 0.0;
		private static double _frames = 0.0;
		private static int _fps = 0;
		public static int FPS { get { return _fps; } }
 
		public static void Calculate(double time)
		{
			_time += time;
 
			if (_time < 1.0)
			{
				_frames++;
			}
			else
			{
				_fps = (int)_frames;
				_time = 0.0;
				_frames = 0.0;
			}
		}
 
		#endregion
 
		#region Display
 
		private static int fontHeight = 13;
		private static OpenTK.Graphics.TextPrinter textPrinter;
		private static Font font = new Font("Arial Black", fontHeight, FontStyle.Regular);
 
		public static void Initialize()
		{
			textPrinter = new OpenTK.Graphics.TextPrinter();
		}
 
		public static void Render(params string[] message)
		{
			textPrinter.Begin();
 
			foreach (string msg in message)
			{
				textPrinter.Print(msg, font, Color.Yellow);
				GL.Translate(0, fontHeight, 0);
			}
 
			textPrinter.End();
		}
 
		#endregion
	}
 
	class OpenTKApplication : GameWindow
	{
		#region Properties
 
		#region Camera
		Matrix4 matrixProjection, matrixModelview;	// Matrices needed for viewing our scene
		float cameraRotation = 0f;					// The rotation of camera 0-360
		float cameraDistance = 1500;				// X,Z distance of camera
		#endregion
 
		#region Render mode
		enum RenderMode						//Available render modes
		{
			Immediate,
			DisplayLists,
			VertexArrays,
			VertexBufferObjects
		}
 
		RenderMode renderMode;				// Active render mode
		#endregion
 
		#region Point data
		Vector3[] points;						// Data array that holds position of each point
		float pointDistance = 1000f;			// How far the points should be placed at random (0-x)
		uint pointsNumber = 5000000;			// Number of points we need in the scene
		#endregion
 
		#region Buffers
		int handleList;				// The id handle of list
		int handleVBO;				// The id handle of vertex buffer object
		#endregion
 
		#region Random
		Random rnd = new Random();
		#endregion
 
		#endregion
 
		protected override void OnLoad(EventArgs e)
		{
			Keyboard.KeyDown += new EventHandler<KeyboardKeyEventArgs>(Keyboard_KeyDown);
 
			GL.Enable(EnableCap.DepthTest);	
			GL.Color3(Color.FromArgb(255, 220, 220, 220));
 
			renderMode = RenderMode.Immediate;
 
			FPSCounter.Initialize();
 
			#region Generate data
			points = new Vector3[pointsNumber];
			for (int i = 0; i < points.Length; i++)
			{
				points[i] = new Vector3(
					(float)(rnd.NextDouble() - 0.5) * pointDistance,
					(float)(rnd.NextDouble() - 0.5) * pointDistance,
					(float)(rnd.NextDouble() - 0.5) * pointDistance);
			}
			#endregion
 
			#region Generate display lists
 
			handleList = GL.GenLists(1);
 
			GL.NewList(handleList, ListMode.Compile);			
				GL.Begin(BeginMode.Points);
					foreach (Vector3 p in points)
						GL.Vertex3(p);
				GL.End();
			GL.EndList();
 
			#endregion
 
			#region Generate vertex buffer object
 
			GL.GenBuffers(1, out handleVBO);
			GL.BindBuffer(BufferTarget.ArrayBuffer, handleVBO);
			GL.BufferData(BufferTarget.ArrayBuffer,
			              new IntPtr(points.Length * Vector3.SizeInBytes),
			              points, BufferUsageHint.StaticDraw);
			GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
 
			#endregion
		}
 
		void Keyboard_KeyDown(object sender, KeyboardKeyEventArgs e)
		{
			if (e.Key == Key.Enter)
			{
				if ((int)renderMode < Enum.GetValues(typeof(RenderMode)).Length - 1)
					renderMode++;
				else
					renderMode = 0;
			}
		}
 
		protected override void OnUpdateFrame(FrameEventArgs e)
		{
			base.OnUpdateFrame(e);
 
			FPSCounter.Calculate(e.Time);
		}
 
		protected override void OnRenderFrame(FrameEventArgs e)
		{
			#region Camera
 
			GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
			cameraRotation = (cameraRotation < 360f) ? (cameraRotation + 1f * (float)e.Time) : 0f;
			Matrix4.CreateRotationY(cameraRotation, out matrixModelview);
			matrixModelview *= Matrix4.LookAt(cameraDistance, 0, -cameraDistance, 0f, 0f, 0f, 0f, 1f, 0f);
			GL.MatrixMode(MatrixMode.Modelview);
			GL.LoadMatrix(ref matrixModelview);
 
			#endregion
 
			#region Render mode
			switch (renderMode)
			{
				case RenderMode.Immediate:
 
					GL.Begin(BeginMode.Points);
						foreach (Vector3 p in points)
							GL.Vertex3(p);			
					GL.End();
 
					break;
 
				case RenderMode.DisplayLists:
 
					GL.CallList(handleList);
 
					break;
 
				case RenderMode.VertexArrays:
 
					GL.EnableClientState(EnableCap.VertexArray);			
					GL.VertexPointer(3, VertexPointerType.Float, 0, points);		
					GL.DrawArrays(BeginMode.Points, 0, points.Length);
					GL.DisableClientState(EnableCap.VertexArray);
 
					break;
 
				case RenderMode.VertexBufferObjects:
 
					GL.EnableClientState(EnableCap.VertexArray);
					GL.BindBuffer(BufferTarget.ArrayBuffer, handleVBO);
					GL.VertexPointer(3, VertexPointerType.Float, 0, 0);
					GL.DrawArrays(BeginMode.Points, 0, points.Length);
					GL.DisableClientState(EnableCap.VertexArray);
					GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
 
					break;
			}
			#endregion
 
 
			FPSCounter.Render(new string[] {
				"FPS   : " + FPSCounter.FPS.ToString(),
				"Render: " + Enum.GetName(typeof(RenderMode), renderMode).ToString(),
				"Stars : " + pointsNumber.ToString()
			});
 
			SwapBuffers();
		}
 
		protected override void OnResize(EventArgs e)
		{
			GL.Viewport(0, 0, Width, Height);
			matrixProjection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, Width / (float)Height, 1f, cameraDistance * 2);
			GL.MatrixMode(MatrixMode.Projection);
			GL.LoadMatrix(ref matrixProjection);
		}
	}
 
	class Program
	{
		public static void Main(string[] args)
		{
			using (OpenTKApplication app = new OpenTKApplication())
			{
				app.Run();
			}
		}
	}
}
Images

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
n8dog's picture

Nice program! I only got 34fps with my Intel i7-2630QM, 8GB DDR3 1600, nVidia GT540M, Windows 7 64. I'm jealous that you got 55fps, what could be accounting for the difference?

jrwatts's picture

I believe you will find that the GTX295 is much faster than the GT540M, despite being a few years older; it was the absolute top of the line when it was released, while the 540M is pretty low end.

n8dog's picture

You must be right. According to my card has a performance test of 723 and his is 1722. Its time I learn my place in the video card world :)

n8dog's picture

I think the spam filter took the link out of my post so I'll rephrase:
You must be right. According to videocardbenchmark.net website, my card has a performance test of 723 and his is 1722. Its time I learn my place in the video card world :)

flopoloco's picture

In the following months I will buy a new GPU (around 200 euros) because I need to jump to OpenGL 4.0 eye-candy. Too bad I will have to waste my GTX295... Perhaps I will sell it for 100 euros or less.