sfurlani's picture

Screen Synchronization Help

Hello,

I'm very new to graphics programming, and I need to do this:

http://software.intel.com/en-us/articles/video-frame-display-synchroniza...

I need to time the screen redraws with an external device. Pointers? I can't find anything for WaitForVerticalRetrace() or Flip() on any of the searches here. Again, I'm very new so any primers, etc. would be useful.

Thanks!

-Stephen


Comments

Comment viewing options

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

OpenGL uses the name 'SwapBuffers' instead 'Flip'. You can use GraphicsContext.VSync = true; to enable vertical retrace synchronization. Enabling VSync will synchronize plain and stereo rendering on both primary and secondary devices (monitors, projectors, ...).

Caveats:

  • VSync may not work on windowed applications. This is driver- and OS-dependent.
  • VSync will not synchronize clustered rendering or multiple GPUs. You will have to use the 'swap groups' extension, which is not exposed by OpenTK yet (this extension was added to drivers only recently).
  • OpenTK does not provide anything equivalent to WaitForVerticalRetrace() (a blocking call that waits until a retrace occurs). Typical VSync is both faster and more reliable.

What exactly are you trying to achieve?

sfurlani's picture

Thanks for replying! What I'm doing falls into two categories:

A) I need to be able to draw a scene, wait a specified number of Monitor refreshes, and then draw another scene. I have to present a "checkerboard" stimulus (alternates black/white boxes) at about 15hz on a monitor refreshrate of 75hz without any tearing. I've tried setting the RenderFrame rate to 15hz, and alternating every render frame, (with vsync). And then I tried setting the RenderRate to 75Hz and changing the colors only once every 4 renders. Neither of these options worked, and the timing of the RenderFrame is fairly random (> 1 ms, 2 ms sometimes).
(I'm using the quickstart example, the EXT\framebuffer example won't work on my piddly graphics card here).

B) I have to know exactly when the first redraw occurs, in order to make sure that the instrumentation amplifier is timed correctly (<1 ms error).

I do have some other questions, if SwapBuffer is just like Flip, then why am I getting tearing? Does the videocard not support vsync?

-S!
--------------------------------------------
a. Mobile Intel 945GM
b. Intel Core2 T7200
c. XP pro
d. .NeT 3.5
e. version A05 (as provided by dell)

the Fiddler's picture

I see. Some clarifications first: the RenderFrequency property is a "soft" limiter. It will limit the rate of RenderFrame events, but it will not sync them to the monitor's refresh rate.

What you need to do:

  1. Make sure you are using a CRT monitor. TFTs are completely unsuitable for this task.
  2. Create a Fullscreen GameWindow (use GameWindowFlags.Fullscreen on its constructor).
  3. Set its RenderFrequency to 0 (i.e. unlimited). You can do this either by calling GameWindow.Run() with 0 its second parameter or by setting the property to 0 manually in the GameWindow constructor.
  4. Set GameWindow.VSync = VSyncMode.On. This is a "hard" limiter that will bind RenderFrame events to your monitor's refresh rate.
  5. Render the same checkerboard pattern for 4 frames and change it every fifth frame (75Hz / 5 = 15Hz update rate for the pattern).

This will accomplish goal A. Check your driver options and ensure the "vsync" or "vertical synchronization" option is *not* set to "force disabled". It should be either "application defined" or "force enabled" (the exact strings may read differently).

Goal B is a little more tricky: graphics drivers may buffer one or more frames to improve performance. I don't know if the intel drivers allow you to control this (nvidia and ati drivers do), but check for and *disable* any option that reads similar "triple buffering".

Using regular double buffering and assuming ideal conditions (constant 75Hz framerate, CRT monitor), this will give you an error margin of 0-15ms between a call to SwapBuffers() and the appearance of the result on screen. Far from ideal.

The next part is pure speculation, so you'll have to experiment:

  • If SwapBuffers() is a blocking call, you can generate a sync event with a great deal of certainty: just wait for SwapBuffers() to return.
  • However, some drivers try to improve performance by returning from SwapBuffers() immediately. These drivers will typically block on the *next* OpenGL command after SwapBuffers() and only if the swap hasn't already occurred. (This is quite useful for typical applications, because you can place CPU-consuming tasks right after a SwapBuffers() for free).
  • A more accurate solution you can split the VGA cable that connects your monitor and detect its the vblank signal. This will give you the best possible accuracy, but it's slightly more difficult to implement.
  • Finally, there might be some WGL/GLX/AGL extension that notifies you of swap events. I've never seen such a thing, however.
sfurlani's picture

Hrmm, that's rather disappointing on Goal B.

The old version of our software (VC6/Dx8.1) doesn't run on my laptop, so I'll need to get a better card before testing Goal A.

Thanks so much! If I figure out Goal B, I'll let you know.

-S!

--------------------------------------------
a. Mobile Intel 945GM
b. Intel Core2 T7200
c. XP pro
d. .NeT 3.5
e. version A05 (as provided by dell)

sfurlani's picture

I have another question:

Instead of re-drawing the entire scene every frame, can I just point to something in memory and say "use this." And instead change the pallette so that black --> white, and then white --> black?

-S!

--------------------------------------------
a. Mobile Intel 945GM
b. Intel Core2 T7200
c. XP pro
d. .NeT 3.5
e. version A05 (as provided by dell)

the Fiddler's picture

Assuming you are rendering the pattern as a textured quad, you could try this:

GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.OneMinusSrcColor, BlendingFactorDest.Zero);

A quick google search also returned this snippet, which doesn't require blending:

GL.Enable(EnableCap.ColorLogicOp);
GL.LogicOp(LogicOp.CopyInverted);

The latter is decidedly GL1-specific (i.e. it will not run on forward-compatible GL3 contexts), but that shouldn't be a problem for the foreseeable future.