winterhell's picture

[solved] Switching windows focus slowdowns with GameWindow

Hi.
When I'm running an application with GameWindow and try to switch to another window I get a couple of seconds OS interface pause before the other window shows. The same thing happens when trying to get back to the GameWindow application, or minimizing/restoring it. It is more apparent when navigating with the taskbar rather than clicking on the actual window(which is impossible if you want Visual Studio/etc to be maximized). Also when starting the application it shows halfway on the taskbar and only after several seconds shows fully.

The problem is there on at least OpenTK 1.0 and 1.1 Beta 3, including the samples themselves.

I'm running Windows 7 64bit, GeForce GTX 650( on 660 Ti its the same), Visual Studio 2010.
Is this fixable?

If not, I'm willing to switch to GLControl, but would that compromise the portability to Linux and OS X?

Thanks.


Comments

Comment viewing options

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

Hm, checking from the debugger output, System.Windows.Forms is loaded before OpenTK, so gdi32 is brought in before opengl32 no matter what OpenTK does. So even if the previous patch solved the issue, that solution would not be reliable.

I have committed a final patch that changes opengl32/wgl function calls to gdi for every function that is duplicated between the two dlls: https://github.com/opentk/opentk/commit/44b8a9dbdcf2c44d1888b38c8bce9fe2.... This change is suggested by https://www.opengl.org/wiki/Platform_specifics:_Windows#The_WGL_function..., again without any real explanation why.

Sorry to keep bothering you, but can you please try this patch? If it still doesn't help, we'll have to come up with a different approach.

Edit: the red X is used by WinForms whenever a Control crashes on startup. This is expected behavior.

winterhell's picture

Thats ok, I want this issue to be solved as well. For all I know SDL is another dependency that can come to bite later when one least expects.

This time it runs., but the switching windows problem is still there :(

Its midnight here so I wont be available for some time.

the Fiddler's picture

Okay, what we need now is a trace log of which functions are being called and what their results are.

Download apitrace-mingw-latest and extract it to the folder of the OpenTK application that is failing. You may need to install 7zip or winrar to extract this file.

Now, open a commandline window and navigate to the application folder. On Windows 7, use explorer to navigate to the folder and then press shift+right-click -> "Open command window here" (this command will only appear if no files are selected in that window, so click on the whitespace to clear any selection first.)

On WinXP it's a little more annoying. Press win+r, type "cmd.exe" and then:

cd "C:\Documents and Settings\[username]\Visual Studio 2005\Projects\[projectname]\bin\Debug"

(Replace [username] and [projectname] with the correct values):

Assuming you have extracted apitrace-mingw in this folder, you can trace the application with:

apitrace-mingw\x86\bin\apitrace.exe trace [Project].exe

or

apitrace-mingw\x64\bin\apitrace.exe trace [Project].exe

(replace [Project] with the name of the application executable)

Let it run for a few seconds, minimize/restore the window and close the application. A file named [Project].trace will appear in the application folder. You can view its contents using qapitrace.exe.

Please upload this file here so I can take a look. It would be very useful to grab one trace with the native backend and one with SDL2, so we can compare if there are any differences.

Note that if you try to trace Examples.exe from OpenTK 1.1, you will need to select which example to trace in the commandline:

apitrace-mingw\x64\bin\apitrace.exe trace Examples.exe Examples.Tutorial.SimpleWindow

Edit: the traces on my system are attached below.

AttachmentSize
Examples_SDL2_Intel2000HD.trace119.51 KB
Examples_WGL_Intel2000HD.trace131.31 KB
winterhell's picture

I cant paste the text so I'm uploading the 2 files, the regular laggy version and the SLD2 .
The laggy one has 6K calls the first frame, SDL 2 has 5K, and both of yours have 4K.
It only lists the first few dozen. Is it skipping repeated calls?

AttachmentSize
Examples regular.rar193.5 KB
the Fiddler's picture

Thanks a lot, this will take some time to digest. There are some important differences visible:

  1. SDL2 calls wglChoosePixelFormatARB before destroying the temporary context. The WGL backend calls this function after destroying the temporary context. This might lead to trouble, according to the letter of the WGL spec - will fix.
  2. SDL2 is asking for a totally weird and unlikely pixel format in wglChoosePixelFormat (8bpp palletted?!) The driver responds with format 7 which is 32bpp, but this is quite unexpected. I'll have to ask on their mailing list whether this is deliberate.

Apitrace appears to ignore calls to wglGetProcAddress, which amount to roughly ~4000. Not really sure what the rest of the calls are, will have to check with their documentation.

Edit: another difference is that the WGL backend is calling SwapBuffers(Wgl.GetCurrentDC()), while SDL2 is (apparently) using a cached value. I would expect Wgl.GetCurrentDC to be essentially free (using thread-local storage) but I'm starting to wonder if this could actually make a difference.

the Fiddler's picture

I have committed a series of patches that make the initialization code in WGL more robust. These uncovered a number of issues in the current implementation that might explain a number of intermittent crashes reported over the years.

The code is available here: https://github.com/opentk/opentk/tree/wgl_issue19

There is a slight chance that these fixes might help with the slowness issue. Still investigating.

winterhell's picture

Still the same problem. Are there any event handlers that you can place somewhere or to change? The issue is persisting beyond the "frame 0" so its likely its not in the initialization code.

Also GameWindow Threaded closes itself right away.

the Fiddler's picture

Interesting, the threaded GameWindow test works fine on my test systems. Are there any messages in the debug.log file after the crash?

When using apitrace, I can reproduce the symptoms you are seeing to some extent: loading/minimizing/alt-tabbing appears to lag in a fashion similar to your description (the window icon is visible in the taskbar, but the window is slow to appear or to become focused.) Adding a call to System.Threading.Thread.Sleep(1000) causes the same symptoms.

Essentially, some function is taking too long to return, causing messages to pile up and the window to lag.

The most probable culprit is SwapBuffers(). If you comment this out, does the issue disappear? If not, try commenting out all OpenGL code - does it still lag like before?

If it is still lagging, then we know that the issue lies somewhere within the message pumping code in OpenTK.Platform.Windows.WinGLNative.cs or WinRawInput.

If the lagging stops, then the issue is caused by something within OpenTK.Platform.Windows.WinGLContext, WinGraphicsMode or WinGLNative.

This should help narrow down the issue a bit.

winterhell's picture

Its nothing in the OnRenderFrame(FrameEventArgs e). I putted a direct return in the beginning.

While its true that SwapBuffer is relatively slow, combined with one ClearBufferBit it takes 0.11 to 0.50 ms depending on the resolution (320x240 to 2560x1440).

the Fiddler's picture

Ok, this reduces the problem surface a *lot*.

TL;DR
Comment out the constructor of OpenTK.Platform.Windows.WinInputBase. Does this solve the lag?

Rationale follows. We know that the problem:

  1. manifests on multiple Windows / Nvidia configurations. No reports about Intel or AMD so far.
  2. affects both GameWindow and GLControl
  3. does not affect the SDL2 backend.
  4. does not appear to be related to OpenGL calls
  5. does not appear to be related to OpenGL initialization

This means that the problem lies somewhere in the common subset between GameWindow and GLControl, ergo WinGLContext and WinInputBase. I was strongly suspecting something was wrong in WinGLContext, simply because there is a lot of dark magic involved there. It appears I was wrong.

WinInputBase is spawning a message-only window to filter input messages on a background thread (common between GameWindow and GLControl). This thread is spawned in the default (MTA) compartment, even though it contains a message pump. This may have unintended consequences.

Let's see!