Question Details

No question body available.

Tags

windows performance assembly window graphical-programming

Answers (1)

April 4, 2026 Score: 2 Rep: 50,112 Quality: Medium Completeness: 70%

This is expected behavior due the how GDI was grandfathered in to the world of the Desktop Window Manager (DWM). If your ultimate goal is to paint the window with an API like OpenGL or DirectWhatever, you can ignore this and move on.

Ignoring details (most of which I don't know), the key to DWM is that composites the screen image by treating each window as a quad and a texture that contains the pixels for that window.

The Jank

When you drag the left side of a window to the left, the quad is updated immediately. So, on the next frame, the window occupies a wider area. But there is a delay between when the left side moves and when the texture gets updated. The old texture is still anchored to the left side, but it doesn't have pixel data for the newly exposed strip on the right. So it looks as though the window moved to the left. A few frames later, the texture is updated, and it appears the right side snaps back to its original position.

You have the same issue when drag-sizing the right border to the right, it's just harder to see because the anchor point of the texture doesn't change. The jank will be in how smoothly the edge you're dragging keeps up with the mouse cursor.

Causes of the Delay

If the window has GPU-native rendering, this takes rarely more than one frame. But GDI is rendered in software by the CPU, possibly directly into video memory but perhaps into system memory. Unlike a video game which constantly generates new frames, rendering (eventually) begins in reaction to the device context invalidation(s) caused by the resize event(s). I say "eventually" because the WMPAINT won't be delivered until the message queue is otherwise empty.

Because the client area is now larger, GDI first has to dump the current offscreen bitmap and create a new larger one. Then it handles the painting commands to update it (often with a little bit of batching).

Meanwhile, the DWM is effectively polling to see when the GDI rendering appears to be done, at which point it blits GDI's offscreen bitmap to its texture (which it probably also had to resize).

Reducing the Delay

Can you make a GDI-painted window not quite as janky? Maybe.

  1. Based on nothing but a gut-feel, I wonder whether CSCLASSDC hampers the synchronization between the GDI and the DWM. Given how uncommon CSCLASSDC is, I wouldn't expect it to be as optimized.

  2. CSHREDRAW and CSVREDRAW cause the entire client area to be invalidated when the window is resized. That means you have the repaint all the pixels. For a window with dynamic layout, that's usually necessary. For your blue window, that's overkill. That said, the difference in time between filling the entire client area versus just the newly-exposed area probably isn't the bottleneck when you're just filling with a solid color.

  3. Avoid WMERASEBKGND and make sure your WMPAINT handler covers everything in the update region. You're already doing that.

  4. Double-buffer the GDI rendering. This is counterintuitive and contrary to the DWM best practices, but I find this generally reduces the redraw delay. I suspect the single bitblit to the device context makes it clear to the DWM that it's time to copy the pixel data.

  5. Consider using a window frame if it makes sense (e.g., WSTHICKFRAME | WS_CAPTION). The system's non-client frame code seems to be optimized to work well with the DWM. It might take a moment for the pixels within the frame to update after a resize, but the frame will be where it should be, making the delay less visually jarring.

  6. Make your rendering DPI aware and mark the program as DPI aware, especially if you use GDI text.