Or to ask it another way, how OnEraseBkgnd() works?
I'm building a custom control and I hit on this problem. Childs are rectangles, as usual. I had to disable OnEraseBkgnd() and I use only the OnPaint(). What I need is to efficiently clear the area behind the childs and without flickering. Techniques like using back buffers are not an option.
Edit: I am very interested in the algorithm that's under the hood of OnEraseBkgnd(). But any helpful answer will also be accepted.
Usually in Windows, the easiest (but not most effective) means of reducing flicker, is to turn off the WM_ERASEBKGND notification handling. This is because if you erase the background in the notification handler, then paint the window in the WM_PAINT handler, there is a short delay between the two - this delay is seen as a flicker.
Instead, if you do all of the erasing and drawing in the WM_PAINT handler, you will tend to see a lot less flicker. This is because the delay between the two is reduced. You will still see some flicker, especially when resizing because there is still a small delay between the two actions, and you cannot always get in all of the drawing before the next occurance of the vertical blanking interrupt for the monitor. If you cannot use double buffering, then this is probably the most effective method you will be able to use.
You can get better drawing performance by following most of the usual recommendations around client area invalidation - do not invalidate the whole window unless you really need to. Try to invalidate only the areas that have changed. Also, you should use the BeginDeferWindowPos functions if you are updating the positions of a collection of child windows at the same time.
Related
I'm trying to implement a cross-platform UI library that takes as little system resource as possible. I'm considering to either use my own software renderer or opengl.
For stationary controls everything's fine, I can repaint only when it's needed. However, when it comes to implementing animations, especially animated blinking carets like the 'phase' caret in sublime text, I don't see a easy way to balance resource usage and performance.
For a blinking caret, it's required that the caret be redrawn very frequently(15-20 times per sec at least, I guess). On one hand, the software renderer supports partial redraw but is far too slow to be practical(3-4 fps for large redraw regions, say, 1000x800, which makes it impossible to implement animations). On the other hand, opengl doesn't support partial redraw very well as far as I know, which means the whole screen needs to be rendered at 15-20 fps constantly.
So my question is:
How are carets usually implemented in various UI systems?
Is there any way to have opengl to render to only a proportion of the screen?
I know that glViewport enables rendering to part of the screen, but due to double buffering or other stuff the rest of the screen is not kept as it was. In this way I still need to render the whole screen again.
First you need to ask yourself.
Do I really need to partially redraw the screen?
OpenGL or better said the GPU can draw thousands of triangles at ease. So before you start fiddling with partial redrawing of the screen, then you should instead benchmark and see whether it's worth looking into at all.
This doesn't however imply that you have to redraw the screen endlessly. You can still just redraw it when changes happen.
Thus if you have a cursor blinking every 500 ms, then you redraw once every 500 ms. If you have an animation running, then you continuously redraw while that animation is playing (or every time the animation does a change that requires redrawing).
This is what Chrome, Firefox, etc does. You can see this if you open the Developer Tools (F12) and go to the Timeline tab.
Take a look at the following screenshot. The first row of the timeline shows how often Chrome redraws the windows.
The first section shows a lot continuously redrawing. Which was because I was scrolling around on the page.
The last section shows a single redraw every few 500 ms. Which was the cursor blinking in a textbox.
Open the image in a new tab, to see better what's going on.
Note that it doesn't tell whether Chrome is fully redrawing the window or only that parts of it. It is just showing the frequency of the redrawing. (If you want to see the redrawn regions, then both Firefox and Chrome has "Show Paint Rectangles".)
To circumvent the problem with double buffering and partially redrawing. Then you could instead draw to a framebuffer object. Now you can utilize glScissor() as much as you want. If you have various things that are static and only a few dynamic things. Then you could have multiple framebuffer objects and only draw the static contents once and continuously update the framebuffer containing the dynamic content.
However (and I can't emphasize this enough) benchmark and check if this is even needed. Having two framebuffer objects could be more expensive than just always redrawing everything. The same goes for say having a buffer for each rectangle, in contrast to packing all rectangles in a single buffer.
Lastly to give an example let's take NanoGUI (a minimalistic GUI library for OpenGL). NanoGUI continuously redraws the screen.
The problem with not just continuously redrawing the screen is that now you need a system for issuing a redraw. Now calling setText() on a label needs to callback and tell the window to redraw. Now what if the parent panel the label is added to isn't visible? Then setText() just issued a redundant redrawing of the screen.
The point I'm trying to make is that if you have a system for issuing redrawing of the screen. Then that might be more prone to errors. Thus unless continuously redrawing is an issue, then that is definitely a more optimal starting point.
If the content of the last frame isn't changed on receiving WM_PAINT, is it possible to simply direct the operating system to redraw the window using the old back buffer instead of redrawing the whole scene again to the new back buffer and swapping it?
No. There is no such "backbuffer". And when drawing occurs you don't know what areas may be covered by other windows. The clipping area isn't a real good indicator.
The only thing you know is that such areas need to be redrawn. Each window cares about its own client area. If you want to buffer something, you have to do it on your own.
The reason is simple: Imagine you have hundreds of windows. To hold a buffer for each window is inefficient, when just a view on the top are visible. So the Windows makers decide not to store any windows content and just notify windows on the top to redraw themselves.
OK. Since we have a DWM (Dynamic Window Manager) things changed a lot. But the principle is still: You are responsible to draw. If you want to buffer something, you have to do it on your own.
I am drawing an animation using double-buffered GDI on a window, on a system where DWM composition is enabled, and seeing clearly visible tearing onscreen. Is there a way to prevent this?
Details
The animation takes the same image, and moves it right to left over the screen; the number of pixels across is determined by the difference between the current time and the time the animation started and the time to end, to get a fraction complete which is applied to the whole window width, using timeGetTime with a 1ms resolution. The animation draws in a loop without processing application messages; it calls the (VCL library) method Repaint which internally invalidates and then calls UpdateWindow for the window in question, directly calling into the message procedure with WM_PAINT. The VCL implementation of the paint handler uses BeginBufferedPaint. Painting is itself double-buffered.
The aim of this is to have as high a frame-rate as possible to get a smooth animation across the screen. (The drawing uses double-buffering to remove flickering and to ensure a whole image or frame is onscreen at any one time. It invalidates and updates directly by calling into the message procedure, without doing other message processing. Painting is implemented using modern techniques (eg BeginBufferedPaint) for Aero composition.) Within this, painting is done in a couple of BitBlt calls (one for the left side of the animation, ie what's moving offscreen, and one for the right side of the animation, ie what's moving onscreen.)
When watching the animation, there is clearly visible tearing. This occurs on Windows Vista, 7 and 8.1 on multiple systems with different graphics cards.
My approach to handle this has been to reduce the rate at which it is drawing, or to try to wait for VSync before painting again. This might be the wrong approach, so the answer to this question might be "Do something else completely: X". If so, great :)
(What I'd really like is a way to ask the DWM to compose / use only fully-painted frames for this specific window.)
I've tried the following approaches, none of which remove all visible tearing. Therefore the question is, Is it possible to avoid tearing when using DWM composition, and if so how?
Approaches tried:
Getting the monitor refresh rate via GetDeviceCaps(Application.MainForm.Handle, VREFRESH); sleeping for 1 / refresh rate milliseconds. Slightly improved over painting as fast as possible, but may be wishful thinking. Perceptually slightly less smooth animation rate. (Tweaks: normal Sleep and a high-resolution spin-wait using timeGetTime.)
Using DwmSetPresentParameters to try to limit updating to the same rate at which the code draws. (Variations: lots of buffers (cBuffer = 8) (no visible effect); specifying a source rate of monitor refresh rate / 1 and sleeping using the above code (the same as just trying the sleeping approach); specifying a refresh per frame of 1, 10, etc (no visible effect); changing the source frame coverage (no visible effect.)
Using DwmGetCompositionTimingInfo in a variety of ways:
While cFramesPending > 0, spin;
Get cFrame (frame composed) and spin while this number doesn't change;
Get cFrameDisplayed and spin while this doesn't change;
Calculating a time to sleep to by adding qpcVBlank + qpcRefreshPeriod, and then while QueryPerformanceCounter returns a time less than this, spin
All these approaches have also been varied by painting, then spinning/sleeping before painting again; or the reverse: sleeping and then painting.
Few seem to have any visible effect and what effect there is is hard to qualify and may just be a result of a lower frame rate. None prevent tearing, ie none make the DWM compose the window with a "whole" copy of the contents of the window's DC.
Advice appreciated :)
Since you're using BitBlt, make sure your DIBs are 4-bytes / pixel. With 3 bytes / pixel, GDI is horribly slow while DWM is running, that could be the source of your tearing. Another BitBlt issue I've run into, if your DIB is somewhat larger, than the BitBlt call make take an unexpectedly long time. If you split up one call into smaller calls than only draw a portion of the data, it might help. Both of these items helped me for my case, only because BitBlt itself was running too slow, thus leading to video artifacts.
I've seen cases where people use DrawFrameControl along with PtInRect (where the mouse position is tested to the rectangle of the frame control), to simulate the effect of having a control (like a button). Why would you want to do this, rather than using child windows?
An example where this technique is used is this docking framework, where the docking window's close button isn't a physical window.
For an application I'm writing, I'm using a list view control which will hold up to 1000 items. Each item will hold, let's say, 10 buttons. All buttons are custom drawn.
Would it be considered a more efficient (and faster) approach to use the PtInRect mechanism for this?
Each process has a limit of about 10,000 window handles. Not only would it be inefficient to create windows for 10 buttons on each of 1,000 items, it wouldn't necessarily be possible.
To answer your question: yes, creating "virtual" buttons by painting and hit-testing yourself is a much better solution.
Having separate child windows brings certain overhead with them. Each child has its own attributes: window class, styles, window procedure, position, owning thread, etc. If you need to manage large array of such children many of their attributes will most probably be the same, wasting system resources. It may also become harder to manage them as separate windows:
You may notice painting glitches. Each window paints somewhat independently from the others, so when someone moves another window on top of your multi-children window and then moves that away, depending on how you organize things you may see unpleasant intermediate states like the background being redrawn with holes visible at the location of each child moments before children repaint. CS_PARENTDC might help with that.
Whenever you need to reposition these children, you need use the DeferWindowPos family of functions or else suffer similar repainting issues.
All these children need separate messages to manipulate.
After all it may be even simpler to simulate these children. My feeling is that attempting to put 10000 buttons on top of a list view will be much harder to implement and will suffer from the above visual problems. Using DrawFrameControl with owner-draw List View items would most probably give you simpler implementation with better visual result.
Besides there is a limit on the number of windows you can create, as #arx noted.
I've never quite understood why erasing the background has a separate windows message. I looks a bit redundant to me. When I've created owner-drawn buttons, I've always ended up erasing the background from inside WM_PAINT. I have sometimes even done all the painting from inside WM_ERASEBKGND and left WM_PAINT empty. Both seem to work fine. Is there any advantage to separating the painting into 2 operations?
This is entirely guesses:
Back in the olden days, filling a rectangle with colour was a relatively slow operation. But filling one big rectangle was still a lot quicker than filling lots of little rectangles.
I guess that if you had a window with a child window, and both had the same registered background brush, then Windows was smart enough to realise it didn't need to send a WM_ERASEBKGND to the child when it had already cleared the parent. With a moderately complex dialog box on a very slow PC, this might be a significant improvement.