Flicker when moving / resizing a window

I developed an application for displaying jpeg images. It can display 4 images, one in each quadrant of the screen. For this, 4 windows are used. Windows do not have a border (frame) and a title. When a new image is uploaded, the window size is adjusted for the new image, and then the image is displayed.

Especially when the window gets larger, it often flickers. Looking at the slots, it seems that the old content moves when you resize it until the new content is displayed.

I consulted with many resources and used all the tricks:

  • the window has only the CS_DBLCLKS style (no CS_HREDRAW or CS_VREDRAW);

  • background brush is NULL;

  • WM_ERASEBKGND returns 1;

  • WM_NCPAINT returns 0;

  • WM_NCCALCSIZE indicates to align a side that has not been moved (can you say that it drops the client area?);

  • WM_WINDOWPOSCHANGING returns 0;

  • SetWindowPos has flags SWP_NOCOPYBITS | SWP_DEFERERASE | SWP_NOREDRAW | SWP_NOSENDCHANGING.

However, flickering (or moving content) occurs when the window is resized. I want to:

  • SetWindowPos for the new size and position;

  • InvalidateRect (hWnd, NULL, FALSE);

  • UpdateWindow (HWND);

without drawing, erasing the background, or moving content to WM_PAINT. WM_PAINT uses:

hDC= BeginPaint (hWnd, &ps); hMemDC= CreateCompatibleDC (hDC); hOldBitmap = SelectObject (hMemDC, hNewBitmap); BitBlt (hDC,...,hMemDC,0,0,SRCCOPY); SelectObject (hMemDC, hOldBitmap); DeleteDC (hMemDC); EndPaint (hWnd, &ps); 

Can someone tell me if / where I am making a mistake that causes the old contents of the window to be moved?

Hardware, etc.: Windows 7 on an HP Elitebook Core7 64 bit with NVIDIA Quadro K1000m 9.18.13.3265 driver (updated to 341.44).


UPDATE (July '17)

I saw the behavior of the program on another computer running Windows (Windows 8/10). This is not like the NVIDIA display driver.

The behavior is most noticeable when you resize the window laid out in the center of the screen (bottom right = w / 2, h / 2) in the upper left or left corner (0, 0).

I may have problems computing for the WM_NCCALCSIZE message to tell Windows to do nothing. Can someone give an example of calculation for my purpose? See Also. How do I make windows NOT redraw anything in my dialog when a user resizes my dialog?

+5
source share
3 answers

You have an impressive list of anti-flickering tricks :-)

I do not know if this matters (since it depends on how your tool windows are created and espacially if they are child windows for the common parent): Try setting the WS_CLIPCHILDREN window WS_CLIPCHILDREN in the parent window of the tool window (if any).

If you do not set the parent window, this will erase its (entire) background, and then forward messages with paints to child windows, which can cause flickering. If WS_CLIPCHILDREN set, the parent window does nothing for the client area occupied by child windows. As a result, the area of ​​the child windows is not drawn twice, and there is no possibility for flickering.

0
source

This theory is more than an answer:

By default in modern Windows, your window is just a texture on the video card, and the desktop window manager maps this rectangle to the screen. It seems that you have done everything necessary to make sure that the texture is updated in one fell swoop.

But when you resize the window, it is possible that the desktop layout immediately updates its geometry, as a result of which (the new texture remains unchanged) appears in a new position on the screen. It is only later, when you paint, refresh the texture.

You can test this theory by temporarily disabling the desktop layout. In Windows 7, go to System Properties, select the "Advanced" tab, in the "Performance" section, select "Settings ..." on the "Visual Effects" tab, clear the "Enable Desktop Settings" checkbox. Then try to reproduce the problem. If this goes away, then it confirms (but does not quite prove) my theory.

(Remember to re-enable the layout, as most users will work most of the time.)

If the theory is correct, it seems that the goal is to get to the paint as soon as possible after resizing the window. If the time is small enough, then both can occur in the monitor update cycle, and there will be no flicker.

Oddly enough, your flicker elimination efforts may work against you here, as you intentionally suppressed the invalidation and redrawing that usually come from SetWindowPos until you do it manually at a later stage.

Debugging tip: try entering delays (for example, Sleep(1000); ) at key points in the process so you can see if resizing and redrawing actually appear on the screen as two different steps.

0
source

Just in addition to your list of tricks. I have the same flickering problem on my Dell XPS laptop when resizing using the left / top edge. I tried all the tricks you mentioned. As far as I understand, the window border is drawn in the GPU, and the contents of the window are prepared in the GDI subsystem and transferred to the video memory for window layout (DWM, introduced in Windows 8.1). I tried to completely remove the GDI rendering (setting the WS_EX_NOREDIRECTIONBITMAP style), which makes the window without any content, and then creates the content surface directly using the DXGI subsystem (using CreateSwapChainForComposition, there are some examples of how to do this). But the problem remains. There is still a delay between rendering the window frame and resizing / displaying the surface of the content.

However, it can solve your problem, because you have no border, and you will not notice this lag. But you will have full control over window redrawing, and it will be done on the GPU side.

0
source

Source: https://habr.com/ru/post/1206054/


All Articles