Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing to window from child thread

My app has been drawing its graphics from a worker thread for over 10 years now and I've never had any problems with it. The worker thread draws to my HWND (created by the main thread) like this:

hdc = GetDC(hwnd);
SetDIBitsToDevice() ... or StretchDIBits()
ReleaseDC(hwnd, hdc);

After having ported my app to other platforms, I began to realize that drawing from any other thread than the main thread is usually a no-go on many platforms (e.g. macOS). My research has shown that this might be true for Win32 as well but I'm still lacking a definite answer.

Thus, my question:

Is it allowed to draw to my window like shown above from a worker thread that did not create the window it is drawing to? Note that the worker thread is really the only thread that draws to the window. The main thread doesn't do any drawing. Not even in WM_PAINT. Drawing in WM_PAINT is unnecessary in my case because the worker thread draws at 50fps.

If it isn't allowed, what's the best way to delegate drawing from the worker thread to the main thread?

like image 981
Andreas Avatar asked Aug 31 '25 06:08

Andreas


1 Answers

Is it allowed to draw to my window like shown above from a worker thread that did not create the window it is drawing to?

It may not be the best solution to your problem, but it's safe, as long as you respect the documented rules for GetDC:

  • Note that the handle to the DC can only be used by a single thread at any one time.
  • ReleaseDC must be called from the same thread that called GetDC.

If you do render to the same device context from multiple threads, you are responsible for synchronizing accesses to it.*

As explained in the comments, a better solution would be to generate the DIB from the worker thread, and have this thread update the window by calling RedrawWindow. The main thread can then StretchBlt in its WM_PAINT handler. Calling RedrawWindow across threads implements a synchronization barrier. When the call returns, rendering on the target thread has run to completion, and it's safe to re-use the DIB.


* See Thread affinity of user interface objects, part 2: Device contexts.

like image 123
IInspectable Avatar answered Sep 04 '25 03:09

IInspectable