tags:

views:

29

answers:

1

Hi to all.

Developing an OpenGL application, I create a window, get the associated device context using GetDC, and create an OpenGL context on the device context handle returned by GetDC. It all ok. Before creating the OpenGL context, I shall call SetPixelFormat. Documentation says that SetPixelFormat shall be called only once (I think once per device context handle).

Well. For systems having only one device it's very simple, but what about systems having two or more devices? how this could work?

First, I don't know how created windows are associated with device contexts. I thought to enumerated every available devices on system, query every pixel format for each device, and then create windows after having setup every device context. In this case I don't have to worry about device pixel format, and I can setup multiple devices for having compatible pixel formats (usefull for sharing objects between OpenGL contexts).

Is it possible to enumerated available video devices? I haven't found any Windows API for enumerating graphical devices to obtain the same handle returned by GetDC... It is possible to associate a window to a specific video device context?

Thanks for your time!

A: 

Device Contexts are rather dynamic objects and are created and disposed of over the course of an applications life. DC's can be display DCs (created using the monitor APIs or CreateDC), window DCs (retrieved from the Window managers DC cache usign the GetDC api) and memory DCs (created using CreateCompatibleDC).

SetPixelFormat wants a window DC. Namely, it wants the window DC of the window you are going to be doing OpenGL rendering on. You MUST call it once, and only once, for every window you create.

Either in your frameworks Window::OnCreate method, or in your WM_CREATE handler, or when CreateWindow returns, you would have code like this:

HGLRC InitWindowForOpenGL(HWND hwnd)
{
  HGLRC glctx;
  PIXELFORMATDESCRIPTOR pfd = { /*initialization data*/ };
  HDC hdc = GetDC(hwnd); // get a DC to use with OpenGL
  int pf = ChoosePixelFormat(hdc,&pfd);
  SetPixelFormat(hdc,pf,&pfd); //sets the pixel format of the associated window
  glctx = wglCreateContext(hdc)
  ReleaseDC(hdc,hwnd);
  return glctx;
}

OpenGL maintains a seperate context for every window in your application. This means you need to store the HGLRC with each window object (As a member of your CWnd (or equivalent) derived class), as well as ensuring that the appropriate context is made current before calling any OpenGL functions.

A lot of OpenGL sample code on the net simply stores the gl context in a global variable, which is very limiting if you ever want to expand to using OpenGL in more than one window. If you are using only one window however, it is acceptable to simple call wglMakeCurrent once on app startup and forget about it.

If you want to support more than one OpenGL window you need to set the context before calling any OpenGL code for a window:

HDC SetGLContext(HWND hwnd, HGLRC hglrc, HDC hdc=NULL)
{
  if(!hdc)
    hdc = GetDC(hwnd);
  wglMakeCurrent(hdc,hglrc);
  return hdc;
}


void ResetGLContext(HWND hwnd, HDC hdc)
{
  wglMakeCurrent(hdc,NULL);
  if(hdc)
    ReleaseDC(hwnd,hdc);
}

Your WindoProc might have entries like this:

  HDC hdc;
case WM_PAINT:
  hdc = BeginPaint(m_hwnd,&ps);
  SetGLContext(m_hwnd,m_hglctx,hdc);
  PaintOpenGLScene();
  ResetGLContext(m_hwnd,NULL); // dont pass the DC as its owned by EndPaint
  EndPaint(m_hwnd,&ps);
  return 0;
case WM_TIMER:
  hdc = SetGLContext(m_hwnd,m_hglctx,NULL);
  DoOnIdleRendering();
  ResetGLContext(m_hwnd,hdc);
  return 0;
Chris Becke
That's ok. I can't create OpenGL contexts using handle returned by CreateDC, but only whose returned by GetDC. So, how I can determine whether two or more window device contexts belong to the same "phisical" device, in the case of multiple display devices?The question about how device contexts are assigned to windows is not yet resolved.
Luca
SetPixelFormat is called once _per_window_. The window device contexts ultimately will represent what is called a mirror device - a virtual device driver that reflects (mirrors) calls down to the underlaying physical display drivers. This is how a windows app can paint onto one DC in its WM_PAINT and all overlapped displays will be updated. Anyhow, for the purpose of this API, a "device" is a window. Theres no way to (reliably) reverse a (window) dc back to its window. Its up to you, the app programmer, to know for each dc, which window they got it from.
Chris Becke
i.e. a window device context is assigned to a window when you call GetDC, passing it a window handle.
Chris Becke