fdncred's picture

[Solved] Pegged CPU with glControl Tutorial?

Is this Tutorial http://www.opentk.com/doc/chapter/2/glcontrol supposed to max out one of my CPUs?

Another way to ask is why does this tutorial take 100% CPU. I'm not doing anything special. Here's my code.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using System.Diagnostics;
 
namespace GLApp
{
    public partial class GLApp : Form
    {
        bool bIsLoaded = false;
        int x = 0, y = 0;
        float rotation = 0;
        Stopwatch sw = new Stopwatch(); // available to all event handlers
        double accumulator = 0;
        int idleCounter = 0;
 
        public GLApp()
        {
            InitializeComponent();
        }
 
        private void glControl1_Load(object sender, EventArgs e)
        {
            bIsLoaded = true;
            GL.ClearColor(Color.SkyBlue); // Yey! .NET Colors can be used directly!
            SetupViewport();
            Application.Idle += new EventHandler(Application_Idle);
            sw.Start(); // start at application boot
            x = glControl1.Width / 2;
            y = glControl1.Height / 2;
        }
 
        void Application_Idle(object sender, EventArgs e)
        {
            double milliseconds = ComputeTimeSlice();
            Accumulate(milliseconds);
            Animate(milliseconds);
        }
 
        private double ComputeTimeSlice()
        {
            sw.Stop();
            double timeslice = sw.Elapsed.TotalMilliseconds;
            sw.Reset();
            sw.Start();
            return timeslice;
        }
 
        private void Animate(double milliseconds)
        {
            float deltaRotation = (float)milliseconds / 20.0f;
            rotation += deltaRotation;
            glControl1.Invalidate();
        }
 
        private void glControl1_Resize(object sender, EventArgs e)
        {
            if (!bIsLoaded)
                return;
 
            SetupViewport();
            glControl1.Invalidate();
        }
 
        private void Accumulate(double milliseconds)
        {
            idleCounter++;
            accumulator += milliseconds;
            if (accumulator > 1000)
            {
                toolStripStatusLabel1.Text = String.Format("FPS: {0} X: {1} Y: {2}", idleCounter.ToString(), x, y);
                accumulator -= 1000;
                idleCounter = 0; // don't forget to reset the counter!
            }
        }
 
        private void Render()
        {
            if (!bIsLoaded) // Play nice
                return;
 
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadIdentity();
 
            GL.Translate(x, y, 0); // position triangle according to our x variable
            if (glControl1.Focused)
                GL.Color3(Color.Yellow);
            else
                GL.Color3(Color.Blue);
            GL.Rotate(rotation, Vector3.UnitZ); // OpenTK has this nice Vector3 class!
 
            GL.Begin(BeginMode.Triangles);
            GL.Vertex2(10, 20);
            GL.Vertex2(100, 20);
            GL.Vertex2(100, 50);
            GL.End();
 
            glControl1.SwapBuffers();
        }
 
        private void glControl1_Paint(object sender, PaintEventArgs e)
        {
            Render();
        }
 
        private void SetupViewport()
        {
            int w = glControl1.Width;
            int h = glControl1.Height;
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();
            GL.Ortho(0, w, 0, h, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
            GL.Viewport(0, 0, w, h); // Use all of the glControl painting area
        }
 
        private void glControl1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.W)
                y++;
            if (e.KeyCode == Keys.S)
                y--;
            if (e.KeyCode == Keys.D)
                x++;
            if (e.KeyCode == Keys.A)
                x--;
            glControl1.Invalidate();
        }
    }
}

Comments

Comment viewing options

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

This code will also hit 100% usage:

class Program
{
    public static void Main()
    {
        while (true)
        { }
    }
}

As it happens, both the tutorial and your code are essentially equivalent to this code.

If you wish to reduce CPU usage, you will need to sleep once you hit your target framerate. You can do this in one of two ways:

  • Enable vsync via glControl1.Context.VSync = true
  • Use System.Threading.Thread.Sleep(n) where n is the amount of milliseconds you have to spare.

The former is more accurate but may not work on some drivers (and can be overridden by the user via his driver options). The latter is more generic but has a tendency to overshoot and sleep more than you expect.

Edit: added this to the FAQ and wrote a book page on CPU usage. Refer to that for more information.

fdncred's picture

Thanks. That helps. I figured since I was hitting 3300 FPS I would need to throttle it somehow. Now I know. Great writeup on Avoiding 100% CPU.