Zsar's picture

Wrong Version? Wrong Documentation? Wrong Idea?

Environment:

  • NVIDIA GeForce 310M
  • Intel Core i3 CPU
  • Windows 7 Professional SP1 x64
  • Mono C# compiler version 3.0.8.0 (Mono 3.0.9)
  • OpenTK 1.0 stable (from here)
  • Video Driver nv 9.18.13.697

My last C# Project is a couple of years old, so I may be a bit rusty - mayhap I forgot something important, but assuming I did not:

Here is stated for OpenTK version 0.9.x-dev:

the Fiddler wrote:

The game loop is now completely optional. You can inherit from NativeWindow to provide a completely custom game loop, or inherit from GameWindow and override the Run() method.

This appears, however, not to be the case in my version: To be overriden, run must be tagged as virtual or override and it is neither.
... Mayhap this was just bad wording and I am supposed to hide the method? Unfortunately it calls private members of OpenTK.GameWindow (update_watch, render_watch, DispatchUpdateAndRenderFrame) before entering the loop, so I cannot reimplement all the functionality but that.

I assume this as source. Sure enough, mcs tells me that I cannot override run. As I care little whether it is overriden or just hidden, this is merely noteworthy, not defeating. The inability to preserve the non-loop part of run however is disheartening: I would need to duplicate perfectly fine though inaccessible ressources.

Now, this discrepance aside, mayhap I do not need to modify the game loop. I have assumed this necessity from reading this article about CPU load: Enabling VSync had no discernable effect.

Source\Quickstart\Game.cs:

        /// <summary>Creates a 800x600 window with the specified title.</summary>
        public Game()
            : base(800, 600, GraphicsMode.Default, "OpenTK Quick Start Sample")
        {
            VSync = VSyncMode.On;
        }

This should, as far as I understand, be equivalent to "GraphicsContext.CurrentContext.VSync = true".

When I built a software renderer in Java, I had already utilised the second way mentioned - in the main thread. As the article holds no information about where I am supposed to sleep the Thread, I merely concluded that the most obvious location would be the right one. I may be wrong.

Concise:
If the run method can be overriden, I do not have the right version of OpenTK.
If the run method may be overriden, the ressources it uses must be at most protected.
If the run method is not supposed to be overriden, the Sleep call must happen elsewhere.
If I have the right version of OpenTK, the advise that enabling VSync prevents full CPU usage is deprecated.

What is right, what is wrong, what shall I do?

For completeness:

    public new void Run(double updatesPerSecond, double framesPerSecond)
    {
      base.EnsureUndisposed();
 
      try
      {
        if (updatesPerSecond < 0.0 || updatesPerSecond > 200.0)
          throw new ArgumentOutOfRangeException("updatesPerSecond", updatesPerSecond,
                                                "Parameter should be inside the range [0.0, 200.0]");
        if(framesPerSecond < 0.0 || framesPerSecond > 200.0)
          throw new ArgumentOutOfRangeException("framesPerSecond", framesPerSecond,
                                                "Parameter should be inside the range [0.0, 200.0]");
 
        base.TargetUpdateFrequency = updatesPerSecond;
        base.TargetRenderFrequency = framesPerSecond;
 
        base.Visible = true;
        this.OnLoad(EventArgs.Empty); // was OnLoadInternal - another private method, which luckily only calls OnLoad in turn
        this.OnResize(EventArgs.Empty);
 
        base.Move   += DispatchUpdateAndRenderFrame;
        base.Resize += DispatchUpdateAndRenderFrame;
 
        Debug.Print("Entering main loop.");
        update_watch.Start();
        render_watch.Start();
        do // should work this way... once the rest works, that is
        {
          base.ProcessEvents(false);
 
          DispatchUpdateAndRenderFrame(this, EventArgs.Empty);
          System.Threading.Thread.Sleep(0);
        }
        while(base.Exists && !base.IsExiting);
      }
      finally
      {
        base.Move -= DispatchUpdateAndRenderFrame;
        base.Resize -= DispatchUpdateAndRenderFrame;
      }
    }

produces

Game.cs(127,24): error CS0103: The name `DispatchUpdateAndRenderFrame' does not
exist in the current context
Game.cs(128,24): error CS0103: The name `DispatchUpdateAndRenderFrame' does not
exist in the current context
Game.cs(131,14): error CS0117: `OpenTK.GameWindow' does not contain a definition
 for `update_watch'
D:\Projekte\C#\Spiel\OpenTK.dll (Location of the symbol related to previous erro
r)
Game.cs(132,14): error CS0117: `OpenTK.GameWindow' does not contain a definition
 for `render_watch'
D:\Projekte\C#\Spiel\OpenTK.dll (Location of the symbol related to previous erro
r)
Game.cs(137,11): error CS0103: The name `DispatchUpdateAndRenderFrame' does not
exist in the current context
Game.cs(144,22): error CS0103: The name `DispatchUpdateAndRenderFrame' does not
exist in the current context
Game.cs(145,24): error CS0103: The name `DispatchUpdateAndRenderFrame' does not
exist in the current context
Compilation failed: 7 error(s), 0 warnings

Compiling without the run method yields a working Game.exe.
Compiled with: @mcs Game.cs -reference:OpenTK.dll,System.Drawing.dll

Addendum:
The source that shipped with my OpenTK version lacks these:

Move += DispatchUpdateAndRenderFrame;
Resize += DispatchUpdateAndRenderFrame;

but still has those:

Move -= DispatchUpdateAndRenderFrame;
Resize -= DispatchUpdateAndRenderFrame;

... Those serve no purpose then, right?
- Also means the online source linked above is either newer or older but definitely not equal the local source...


Comments

Comment viewing options

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

Don't download the pre-built OpenTK. That version is from 2010 and no longer works on many platforms. I generally don't make any assumptions based on those version numbers, although the code you have probably is newer than the post you cited. It's more likely that the behavior changed again since that time.

I would recommend getting the source from either the OpenTK SVN or the more up to date (but unofficial) github repository: https://github.com/andykorth/opentk

With Windows 7 you'll need to implement the fixes in github anyway to get working input.

I personally recommend using VSync to aid in timing your game loop. I'm not sure why it didn't seem to have any effect for you. I don't believe that advice should be deprecated, maybe it's just a bug.. (or you've got driver overrides that force vsync off, etc).


Also means the online source linked above is either newer or older but definitely not equal the local source...

If you need accurate documentation, I recommend building OpenTK from source, then using the source code you have as the documentation. Online source code could be any version. Online documentation probably references multiple versions.

Zsar's picture

Bah, I had begun to suspect something along these lines.
... Now to figure out how to build it - the manual only states "let the tool do it for you", as usual. I wonder why people keep writing such self-evident instructions and always seem to forget to mention how to do the hard things.
Eh, this be of no concern to you, thank you for the heads-up... and, if I correctly interprete the name of this repository, for the working library.

Zsar's picture

Mmh, chickened out and built it with msbuild. 117 warnings - should I feel warned?

A bunch of harmless nuisances and hand-made warnings aside, these seem to be pretty straightforward to correct:

  • DisplayDevice.cs(84,55): warning CS0618:
    • 'OpenTK.DisplayResolution.Bounds' ist veraltet: 'This property will return invalid results if a monitor changes resolution. Use DisplayDevice.Bounds instead.'
  • DisplayResolution.cs(156,51): warning CS0618:
    • 'OpenTK.DisplayResolution.Bounds' ist veraltet: 'This property will return invalid results if a monitor changes resolution. Use DisplayDevice.Bounds instead.'
  • DisplayResolution.cs(190,20): warning CS0618:
    • 'OpenTK.DisplayResolution.Bounds' ist veraltet: 'This property will return invalid results if a monitor changes resolution. Use DisplayDevice.Bounds instead.'
  • GameWindow.cs(911,17): warning CS0618:
    • 'OpenTK.Graphics.IGraphicsContext.VSync' ist veraltet: 'Use SwapInterval property instead.'
  • Platform\Windows\WinDisplayDevice.cs(152,25): warning CS0618:
    • 'OpenTK.DisplayResolution.Bounds' ist veraltet: 'This property will return invalid results if a monitor changes resolution. Use DisplayDevice.Bounds instead.'
  • Input\KeyboardDevice.cs(55,26): warning CS3001: Der Argumenttyp 'uint' ist nicht CLS-kompatibel.
  • Platform\Dummy\DummyGLContext.cs(26,14): warning CS0169:
    • Das Feld 'OpenTK.Platform.Dummy.DummyGLContext.vsync' wird nie verwendet.
    • (field never used)
  • Platform\MacOS\AglContext.cs(53,23): warning CS0169:
    • Das Feld 'OpenTK.Platform.MacOS.AglContext.device' wird nie verwendet.
    • (field never used)
  • Platform\Windows\WinGLNative.cs(61,38): warning CS0649:
    • Dem Feld 'OpenTK.Platform.Windows.WinGLNative.ModalLoopCallback' wird nie etwas zugewiesen, und es hat immer seinen Standardwert von 'null'.
    • (field never used or initialised)

Should I?

... Minimised program still takes up all processing power of one core. The issue persists.