I used WS_EX_COMPOSITED to get rid of my redrawing flicker, but it resulted in sluggish response

A customer enabled the WS_EX_COMPOSITED extended window style in order to solve a flickering problem with their application. That worked great, but they found that it had an unwanted side effect: when the user grabs the scroll bar and starts scrolling up and down the document, the UI does not update smoothly. The customer hoped for some tips on how they could get the no-flicker benefit of WS_EX_COMPOSITED without incurring the sluggish-UI penalty.

One of my colleagues explained: The WS_EX_COMPOSITED extended style enables double-buffering on the window. This means that the control renders into an off-screen buffer, and only when rendering is complete is the result copied to the screen. This avoids flicker because only a completely-drawn control is put on the screen; you never see the control in a partially-drawn state.

The thing is, in order for this to work, the system needs to know when rendering is complete. Otherwise it doesn't know when it's time to copy the back-buffer to the screen.

The rule is that the system assumes that you're done rendering when you release the DC. (Or when you call End­Paint, which is the moral equivalent of releasing the DC.)

But there are some programs which acquire a DC and never release it. They just draw into it whenever they feel like drawing. In that case, the system has a fail-safe timeout and copies the back-buffer to the screen after 100ms, and again every 100ms thereafter.

If you're getting slugging UI updates with the WS_EX_COMPOSITED extended window style, check that you're properly releasing your device contexts as soon as you're ready for them to be presented. Don't acquire a DC and just hang onto it for convenience. If you do that, then the system doesn't know when you're finished drawing, and it will copy from the back-buffer to the screen at 10 frames per second, which will feel sluggish.

Comments (18)
  1. Joshua says:

    I’m only getting about 10FPS anyway.

  2. AberAber says:

    This seems to be very useful information and may be a common mistake. Is it officially documented anywhere? I don’t see it in the link you provide, though it says to see remarks (which I’m not sure what that is referencing on this page).

    1. 640k says:

      Yet again, please replace msdn with raymond’s blog.

      msdn is more like “yeah… this is what a 5 year old could guess reading the .h file for the api… We leave it as an exercise for the reader to find out if and how it works in practice”.

    2. Matteo Italia says:

      It’s worth noting that you should paint pretty much only in WM_PAINT using BeginPaint/EndPaint anyway, anything else is suspect by default.

    3. mikebru says:

      I suspect the extended window styles used to be in the CreateWindowEx() documentation. Then the styles got moved but without the remarks. The timeout doesn’t seem to be mentioned there either.

  3. Danny says:

    This sounds like an incomplete article. Raymond, please, finish the article properly with “…and we never heard from the customer to know if this was what they wanted or nor”

  4. Is the existence of the fail-safe timeout and its duration part of the contract or is it an implementation detail?

    1. cheong00 says:

      Possibly should count as implementation detail because I cannot find this be mentioned elsewhere.

      If it’s not part of any official documentation, it’s “implementation detail”.

      1. Richard says:

        Soubds like an implementation detail to me – and one that might be better not to exist. I wonder what the story is behind it?

        To be honest, if I never let go or end painting I’d expect nothing to appear at all when double-buffered.
        Other double-buffering schemes I know of have an explicit “swap buffers” call.
        How else can the system know I’m done with the surface and it’s safe to present?

        And how do you even manage to forget to do that?

        1. middings says:

          All good questions. My guess is that this behavior covers for a bug in somebody’s application.

        2. Erik F says:

          Probably someone heard about WS_EX_COMPOSITED and thought “This will fix all my application’s display issues with no extra coding!” They probably never heard about the important engineering principle TANSTAAFL, unfortunately.

          1. xcomcmdr says:

            Or more simply, they never bothered to a) read the documentation and/or b) test the results.

  5. Drak says:

    Is this also the reason that when I drag an Excel sheet around, it seems to lag behind my mouse? I’ve been wondering why not all programs behave in this sluggish way.

    1. Jan Ringoš says:

      When you let the system (user32) do the dragging, i.e. returning HTCAPTION on WM_NCHITTEST, then the system masks this lag by hiding the real (HW) mouse cursor and painting one at the point where the window was grabbed. The other way, i.e. computing mouse cursor position difference and calling MoveWindow (or similar), does not do that, and the windows position lags behind.

  6. Neil says:

    Presumably this heuristic doesn’t work very well for windows with the CS_OWNDC class style, since there’s no onus to release those DCs…

  7. florian says:

    I have a few resizable dialog boxes, and despite using (Begin-/End-)DeferWindowPos to change the size and positions of the child controls simultaneously, there was still considerable flickering on resizing (at least, on systems running Windows XP, and on older machines running Windows 7). Single-column List Views in report-view mode to have their column auto-resized with LVM_SETCOLUMNWIDTH(0,LVSCW_AUTOSIZE_USEHEADER) were the worst (despite using LVS_EX_DOUBLEBUFFER on Vista and above), but other controls also showed flickering.

    Adding WS_EX_COMPOSITED to the dialog boxes (can even be done by adding EXSTYLE WS_EX_COMPOSITED to the dialog template resource scripts) significantly reduces or even eliminates the flickering!

    Thanks (once again) for a wonderful tip!

    1. Jan Ringoš says:

      I’ve found that thorough use of WS_CLIPxxx styles also helps. In the years long past, when off-screen double-buffering bitmap was considered excessive waste of memory, I’ve often subclassed LISTBOXes and other controls to suppress WM_ERASEBKGND (the cause of most flickering) and then painted areas that the default WM_PAINT handler didn’t touch with background color myself.

      1. florian says:

        Thanks. With all my reading here, in Raymond’s book, on MSDN and elsewhere, this seems obvious to me, but I will double-check.

Comments are closed.

Skip to main content