2
votes

Reading about GetDC/ReleaseDC I should it appears always do the latter, and that CS_OWNDC on a window is considered evil:

 https://blogs.msdn.microsoft.com/oldnewthing/20060601-06/?p=31003

Looking through my code I see I'm holding onto a DC retrieved from GetDC, which I've sent into wglCreateContextAttribARB. I'm presuming the context is created on that DC so it would be bad manners to subsequently release it from under the driver. Is my assumption correct? At the moment I'm calling ReleaseDC when I destroy my other OpenGL resources.

Additionally, elsewhere in my libraries I'm calling GetDC to instantiate a GDI+ Graphics object, then releasing it again when I've finished drawing. I'm thinking it would be nice to persist the DC and Graphics object between draw calls for performance reasons, only recreating it on WM_DISPLAYCHANGE etc.

So, is there a definitive guide to best practice in this area? The way I diligently release the GDI+ DC but persist the OpenGL DC seems somewhat inconsistent.

1

1 Answers

2
votes

OpenGL and GDI+ behave differently.

In OpenGL you need a context, which is attached with a DC. This means that the DC must exist while the context exists. Thus, you do need CS_OWNDC style for the window where OpenGL draws.
Call ReleaseDC after you have deleted the context.

GDI+ is used in MS Windows like any common DC: retrieve a DC, draw to it, release that DC. In this scenary the use of CS_OWNDC can be evil, as pointed out in the link you posted.
The way MS GDI+ uses the graphics hardware (i.e. creating a context or whatever) is irrelevant for you.


EDIT due to Chris Becke's comment:

The CS_OWNDC usage is not required

Quoting https://msdn.microsoft.com/es-es/library/windows/desktop/dd374387(v=vs.85).aspx:

The hdc parameter must refer to a drawing surface supported by OpenGL. It need not be the same hdc that was passed to wglCreateContext when hglrc was created, but it must be on the same device and have the same pixel format.

The CS_OWNDC usage is recommended.

In the old days of Windows 9x acquiring and releasing a device context was expensive and slow. Having a fixed dc was much more efficent. Using the CS_OWNDC flag at window registration was the way to have a fixed dc.

The CS_OWNDC usage provides a private device context (see https://msdn.microsoft.com/en-us/library/windows/desktop/ms633574(v=vs.85).aspx#class_styles).
Quoting from MS docs (https://msdn.microsoft.com/en-us/library/windows/desktop/dd162872(v=vs.85).aspx):

Although a private device context is convenient to use, it is memory-intensive in terms of system resources, requiring 800 or more bytes to store. Private device contexts are recommended when performance considerations outweigh storage costs.

You must be aware that you must avoid ReleaseDC with a private device context:

An application can retrieve a handle to the private device context by using the GetDC function any time after the window is created. The application must retrieve the handle only once. Thereafter, it can keep and use the handle any number of times. Because a private device context is not part of the display device context cache, an application need never release the device context by using the ReleaseDC function.

In the common scenary where you draw to an unique window by retriving a DC, setting the curent context, drawing, swapping buffers and releasing the DC the usage of CS_OWNDC instead of GetDC&ReleaseDC is natural.

It can be also the case where wglGetCurrentDC() is used (e.g. by an extern library) regarless of your GetDC/ReleaseDC code. Normally no issues will happen. But if the current gl-context is NULL (as you would do right after ReleaseDC) then wglGetCurrentDC() will fail.

Code without CS_OWNDC
used in two windows with the same pixel format would look like this:

myGLContext = wglCreateContext(...)

//Draw to window A
HDC hdcA = GetDC(hWndA)
wglMakeCurrent(hdcA, myGLContext)
... render...
SwapBuffers(hdcA)
ReleaseDC(hWndA, hdcA)

//Draw to window B
HDC hdcB = GetDC(hWndB)
wglMakeCurrent(hdcB, myGLContext)
... render...
SwapBuffers(hdcB)
ReleaseDC(hWndA, hdcA)

wglMakeCurrent(hdcB, NULL)