Browse Source

support multisample on windows

David Rose 21 years ago
parent
commit
415c129bb6

+ 96 - 152
panda/src/wgldisplay/wglGraphicsBuffer.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "wglGraphicsBuffer.h"
 #include "wglGraphicsBuffer.h"
+#include "wglGraphicsPipe.h"
 #include "config_wgldisplay.h"
 #include "config_wgldisplay.h"
 #include "glgsg.h"
 #include "glgsg.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
@@ -24,8 +25,6 @@
 #include <wingdi.h>
 #include <wingdi.h>
 
 
 TypeHandle wglGraphicsBuffer::_type_handle;
 TypeHandle wglGraphicsBuffer::_type_handle;
-const char * const wglGraphicsBuffer::_window_class_name = "wglGraphicsBuffer";
-bool wglGraphicsBuffer::_window_class_registered = false;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsBuffer::Constructor
 //     Function: wglGraphicsBuffer::Constructor
@@ -38,8 +37,6 @@ wglGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
                   int x_size, int y_size, bool want_texture) :
                   int x_size, int y_size, bool want_texture) :
   GraphicsBuffer(pipe, gsg, name, x_size, y_size, want_texture) 
   GraphicsBuffer(pipe, gsg, name, x_size, y_size, want_texture) 
 {
 {
-  _window = (HWND)0;
-  _window_dc = (HDC)0;
   _pbuffer = (HPBUFFERARB)0;
   _pbuffer = (HPBUFFERARB)0;
   _pbuffer_dc = (HDC)0;
   _pbuffer_dc = (HDC)0;
 
 
@@ -196,15 +193,6 @@ process_events() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void wglGraphicsBuffer::
 void wglGraphicsBuffer::
 close_buffer() {
 close_buffer() {
-  if (_window_dc) {
-    ReleaseDC(_window, _window_dc);
-    _window_dc = 0;
-  }
-  if (_window) {
-    DestroyWindow(_window);
-    _window = 0;
-  }
-
   if (_gsg != (GraphicsStateGuardian *)NULL) {
   if (_gsg != (GraphicsStateGuardian *)NULL) {
     wglGraphicsStateGuardian *wglgsg;
     wglGraphicsStateGuardian *wglgsg;
     DCAST_INTO_V(wglgsg, _gsg);
     DCAST_INTO_V(wglgsg, _gsg);
@@ -231,15 +219,16 @@ close_buffer() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool wglGraphicsBuffer::
 bool wglGraphicsBuffer::
 open_buffer() {
 open_buffer() {
-  if (!make_window()) {
+  wglGraphicsStateGuardian *wglgsg;
+  DCAST_INTO_R(wglgsg, _gsg, false);
+
+  HDC twindow_dc = wglgsg->get_twindow_dc();
+  if (twindow_dc == 0) {
     // If we couldn't make a window, we can't get a GL context.
     // If we couldn't make a window, we can't get a GL context.
     return false;
     return false;
   }
   }
 
 
-  wglGraphicsStateGuardian *wglgsg;
-  DCAST_INTO_R(wglgsg, _gsg, false);
-
-  wglMakeCurrent(_window_dc, wglgsg->get_context(_window_dc));
+  wglMakeCurrent(twindow_dc, wglgsg->get_context(twindow_dc));
   wglgsg->reset_if_new();
   wglgsg->reset_if_new();
   _needs_context = false;
   _needs_context = false;
 
 
@@ -247,88 +236,25 @@ open_buffer() {
   // create a rendering context, we can attempt to create a pbuffer.
   // create a rendering context, we can attempt to create a pbuffer.
   // This might fail if the pbuffer extensions are not supported.
   // This might fail if the pbuffer extensions are not supported.
 
 
-  if (!make_pbuffer()) {
+  if (!make_pbuffer(twindow_dc)) {
+    wglMakeCurrent(0, 0);
     return false;
     return false;
   }
   }
 
 
   _pbuffer_dc = wglgsg->_wglGetPbufferDCARB(_pbuffer);
   _pbuffer_dc = wglgsg->_wglGetPbufferDCARB(_pbuffer);
-  wgldisplay_cat.info()
-    << "Created PBuffer " << _pbuffer << ", DC " << _pbuffer_dc << "\n";
+  if (wgldisplay_cat.is_debug()) {
+    wgldisplay_cat.debug()
+      << "Created PBuffer " << _pbuffer << ", DC " << _pbuffer_dc << "\n";
+  }
   
   
   wglMakeCurrent(_pbuffer_dc, wglgsg->get_context(_pbuffer_dc));
   wglMakeCurrent(_pbuffer_dc, wglgsg->get_context(_pbuffer_dc));
   wglgsg->report_my_gl_errors();
   wglgsg->report_my_gl_errors();
   
   
-  // Now that the pbuffer is created, we don't need the window any
-  // more.
-  if (_window_dc) {
-    ReleaseDC(_window, _window_dc);
-    _window_dc = 0;
-  }
-  if (_window) {
-    DestroyWindow(_window);
-    _window = 0;
-  }
-  
   _is_valid = true;
   _is_valid = true;
 
 
   return true;
   return true;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: wglGraphicsBuffer::make_window
-//       Access: Private
-//  Description: Creates an invisible window to associate with the GL
-//               context, even if we are not going to use it.  This is
-//               necessary because in the Windows OpenGL API, we have
-//               to create window before we can create a GL
-//               context--even before we can ask about what GL
-//               extensions are available!
-////////////////////////////////////////////////////////////////////
-bool wglGraphicsBuffer::
-make_window() {
-  DWORD window_style = WS_POPUP | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW;
-
-  RECT win_rect;
-  SetRect(&win_rect, 0, 0, _x_size, _y_size);
-  
-  // compute window size based on desired client area size
-  if (!AdjustWindowRect(&win_rect, window_style, FALSE)) {
-    wgldisplay_cat.error()
-      << "AdjustWindowRect failed!" << endl;
-    return false;
-  }
-
-  register_window_class();
-  HINSTANCE hinstance = GetModuleHandle(NULL);
-  _window = CreateWindow(_window_class_name, "buffer", window_style, 
-                         win_rect.left, win_rect.top,
-                         win_rect.right - win_rect.left,
-                         win_rect.bottom - win_rect.top,
-                         NULL, NULL, hinstance, 0);
-  
-  if (!_window) {
-    wgldisplay_cat.error()
-      << "CreateWindow() failed!" << endl;
-    return false;
-  }
-
-  ShowWindow(_window, SW_HIDE);
-
-  _window_dc = GetDC(_window);
-
-  wglGraphicsStateGuardian *wglgsg;
-  DCAST_INTO_R(wglgsg, _gsg, false);
-  int pfnum = wglgsg->get_pfnum();
-  PIXELFORMATDESCRIPTOR pixelformat;
-  if (!SetPixelFormat(_window_dc, pfnum, &pixelformat)) {
-    wgldisplay_cat.error()
-      << "SetPixelFormat(" << pfnum << ") failed after window create\n";
-    return false;
-  }
-
-  return true;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsBuffer::make_pbuffer
 //     Function: wglGraphicsBuffer::make_pbuffer
 //       Access: Private
 //       Access: Private
@@ -338,7 +264,7 @@ make_window() {
 //               failure.
 //               failure.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool wglGraphicsBuffer::
 bool wglGraphicsBuffer::
-make_pbuffer() {
+make_pbuffer(HDC twindow_dc) {
   wglGraphicsStateGuardian *wglgsg;
   wglGraphicsStateGuardian *wglgsg;
   DCAST_INTO_R(wglgsg, _gsg, false);
   DCAST_INTO_R(wglgsg, _gsg, false);
 
 
@@ -353,18 +279,47 @@ make_pbuffer() {
   if (wglgsg->_supports_pixel_format) {
   if (wglgsg->_supports_pixel_format) {
     // Select a suitable pixel format that matches the GSG's existing
     // Select a suitable pixel format that matches the GSG's existing
     // format, and also is appropriate for a pixel buffer.
     // format, and also is appropriate for a pixel buffer.
-    PIXELFORMATDESCRIPTOR pfd;
-    ZeroMemory(&pfd,sizeof(PIXELFORMATDESCRIPTOR));
-    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
-    pfd.nVersion = 1;
-
-    DescribePixelFormat(_window_dc, wglgsg->get_pfnum(), 
-                        sizeof(PIXELFORMATDESCRIPTOR), &pfd);
 
 
     static const int max_attrib_list = 32;
     static const int max_attrib_list = 32;
     int iattrib_list[max_attrib_list];
     int iattrib_list[max_attrib_list];
-    float fattrib_list[max_attrib_list];
+    int ivalue_list[max_attrib_list];
     int ni = 0;
     int ni = 0;
+
+    int acceleration_i, pixel_type_i, double_buffer_i, stereo_i,
+      red_bits_i, green_bits_i, blue_bits_i, alpha_bits_i, 
+      accum_red_bits_i, accum_green_bits_i, accum_blue_bits_i,
+      accum_alpha_bits_i, depth_bits_i, 
+      stencil_bits_i, multisample_bits_i;
+
+    iattrib_list[acceleration_i = ni++] = WGL_ACCELERATION_ARB;
+    iattrib_list[pixel_type_i = ni++] = WGL_PIXEL_TYPE_ARB;
+    iattrib_list[double_buffer_i = ni++] = WGL_DOUBLE_BUFFER_ARB;
+    iattrib_list[stereo_i = ni++] = WGL_STEREO_ARB;
+    iattrib_list[red_bits_i = ni++] = WGL_RED_BITS_ARB;
+    iattrib_list[green_bits_i = ni++] = WGL_GREEN_BITS_ARB;
+    iattrib_list[blue_bits_i = ni++] = WGL_BLUE_BITS_ARB;
+    iattrib_list[alpha_bits_i = ni++] = WGL_ALPHA_BITS_ARB;
+    iattrib_list[accum_red_bits_i = ni++] = WGL_ACCUM_RED_BITS_ARB;
+    iattrib_list[accum_green_bits_i = ni++] = WGL_ACCUM_GREEN_BITS_ARB;
+    iattrib_list[accum_blue_bits_i = ni++] = WGL_ACCUM_BLUE_BITS_ARB;
+    iattrib_list[accum_alpha_bits_i = ni++] = WGL_ACCUM_ALPHA_BITS_ARB;
+    iattrib_list[depth_bits_i = ni++] = WGL_DEPTH_BITS_ARB;
+    iattrib_list[stencil_bits_i = ni++] = WGL_STENCIL_BITS_ARB;
+
+    if (wglgsg->_supports_wgl_multisample) {
+      iattrib_list[multisample_bits_i = ni++] = WGL_SAMPLES_ARB;
+    }
+
+    // Terminate the list.
+    nassertr(ni <= max_attrib_list, false);
+
+    if (!wglgsg->_wglGetPixelFormatAttribivARB(twindow_dc, pbformat, 0,
+                                               ni, iattrib_list, ivalue_list)) {
+      return false;
+    }
+
+    ni = 0;
+    float fattrib_list[max_attrib_list];
     int nf = 0;
     int nf = 0;
 
 
     // Since we are trying to create a pbuffer, the pixel format we
     // Since we are trying to create a pbuffer, the pixel format we
@@ -376,25 +331,39 @@ make_pbuffer() {
 
 
     // Match up the framebuffer bits.
     // Match up the framebuffer bits.
     iattrib_list[ni++] = WGL_RED_BITS_ARB;
     iattrib_list[ni++] = WGL_RED_BITS_ARB;
-    iattrib_list[ni++] = pfd.cRedBits;
+    iattrib_list[ni++] = ivalue_list[red_bits_i];
     iattrib_list[ni++] = WGL_GREEN_BITS_ARB;
     iattrib_list[ni++] = WGL_GREEN_BITS_ARB;
-    iattrib_list[ni++] = pfd.cGreenBits;
+    iattrib_list[ni++] = ivalue_list[green_bits_i];
     iattrib_list[ni++] = WGL_BLUE_BITS_ARB;
     iattrib_list[ni++] = WGL_BLUE_BITS_ARB;
-    iattrib_list[ni++] = pfd.cBlueBits;
+    iattrib_list[ni++] = ivalue_list[blue_bits_i];
     iattrib_list[ni++] = WGL_ALPHA_BITS_ARB;
     iattrib_list[ni++] = WGL_ALPHA_BITS_ARB;
-    iattrib_list[ni++] = pfd.cAlphaBits;
+    iattrib_list[ni++] = ivalue_list[alpha_bits_i];
+
+    iattrib_list[ni++] = WGL_ACCUM_RED_BITS_ARB;
+    iattrib_list[ni++] = ivalue_list[accum_red_bits_i];
+    iattrib_list[ni++] = WGL_ACCUM_GREEN_BITS_ARB;
+    iattrib_list[ni++] = ivalue_list[accum_green_bits_i];
+    iattrib_list[ni++] = WGL_ACCUM_BLUE_BITS_ARB;
+    iattrib_list[ni++] = ivalue_list[accum_blue_bits_i];
+    iattrib_list[ni++] = WGL_ACCUM_ALPHA_BITS_ARB;
+    iattrib_list[ni++] = ivalue_list[accum_alpha_bits_i];
 
 
     iattrib_list[ni++] = WGL_DEPTH_BITS_ARB;
     iattrib_list[ni++] = WGL_DEPTH_BITS_ARB;
-    iattrib_list[ni++] = pfd.cDepthBits;
+    iattrib_list[ni++] = ivalue_list[depth_bits_i];
 
 
     iattrib_list[ni++] = WGL_STENCIL_BITS_ARB;
     iattrib_list[ni++] = WGL_STENCIL_BITS_ARB;
-    iattrib_list[ni++] = pfd.cStencilBits;
+    iattrib_list[ni++] = ivalue_list[stencil_bits_i];
+
+    if (wglgsg->_supports_wgl_multisample) {
+      iattrib_list[ni++] = WGL_SAMPLES_ARB;
+      iattrib_list[ni++] = ivalue_list[multisample_bits_i];
+    }
 
 
     // Match up properties.
     // Match up properties.
     iattrib_list[ni++] = WGL_DOUBLE_BUFFER_ARB;
     iattrib_list[ni++] = WGL_DOUBLE_BUFFER_ARB;
-    iattrib_list[ni++] = ((pfd.dwFlags & PFD_DOUBLEBUFFER) != 0);
+    iattrib_list[ni++] = ivalue_list[double_buffer_i];
     iattrib_list[ni++] = WGL_STEREO_ARB;
     iattrib_list[ni++] = WGL_STEREO_ARB;
-    iattrib_list[ni++] = ((pfd.dwFlags & PFD_STEREO) != 0);
+    iattrib_list[ni++] = ivalue_list[stereo_i];
 
 
     // Terminate the lists.
     // Terminate the lists.
     nassertr(ni < max_attrib_list && nf < max_attrib_list, NULL);
     nassertr(ni < max_attrib_list && nf < max_attrib_list, NULL);
@@ -403,17 +372,19 @@ make_pbuffer() {
 
 
     // Now obtain a list of pixel formats that meet these minimum
     // Now obtain a list of pixel formats that meet these minimum
     // requirements.
     // requirements.
-    static const int max_pformats = 32;
+    static const unsigned int max_pformats = 32;
     int pformat[max_pformats];
     int pformat[max_pformats];
     memset(pformat, 0, sizeof(pformat));
     memset(pformat, 0, sizeof(pformat));
     unsigned int nformats = 0;
     unsigned int nformats = 0;
-    if (!wglgsg->_wglChoosePixelFormatARB(_window_dc, iattrib_list, fattrib_list,
+    if (!wglgsg->_wglChoosePixelFormatARB(twindow_dc, iattrib_list, fattrib_list,
                                           max_pformats, pformat, &nformats)) {
                                           max_pformats, pformat, &nformats)) {
       wgldisplay_cat.info()
       wgldisplay_cat.info()
         << "Couldn't find a suitable pixel format for creating a pbuffer.\n";
         << "Couldn't find a suitable pixel format for creating a pbuffer.\n";
       return false;
       return false;
     }
     }
 
 
+    nformats = min(nformats, max_pformats);
+
     if (wgldisplay_cat.is_debug()) {
     if (wgldisplay_cat.is_debug()) {
       wgldisplay_cat.debug()
       wgldisplay_cat.debug()
         << "Found " << nformats << " pbuffer formats: [";
         << "Found " << nformats << " pbuffer formats: [";
@@ -425,16 +396,32 @@ make_pbuffer() {
         << " ]\n";
         << " ]\n";
     }
     }
 
 
-    pbformat = pformat[0];
+    // If one of the options is the original pixfmt, keep it.
+    bool found_pbformat = false;
+    for (unsigned int i = 0; i < nformats && !found_pbformat; i++) {
+      if (pformat[i] == pbformat) {
+        found_pbformat = true;
+      }
+    }
+
+    if (!found_pbformat) {
+      // Otherwise, pick any of them.
+      pbformat = pformat[0];
+    }
+  }
+
+  if (wgldisplay_cat.is_debug()) {
+    wgldisplay_cat.debug()
+      << "Chose pixfmt #" << pbformat << " for pbuffer\n";
   }
   }
   
   
   int attrib_list[] = {
   int attrib_list[] = {
     0,
     0,
   };
   };
   
   
-  _pbuffer = wglgsg->_wglCreatePbufferARB(_window_dc, pbformat, 
+  _pbuffer = wglgsg->_wglCreatePbufferARB(twindow_dc, pbformat, 
                                           _x_size, _y_size, attrib_list);
                                           _x_size, _y_size, attrib_list);
-  
+
   if (_pbuffer == 0) {
   if (_pbuffer == 0) {
     wgldisplay_cat.info()
     wgldisplay_cat.info()
       << "Attempt to create pbuffer failed.\n";
       << "Attempt to create pbuffer failed.\n";
@@ -464,48 +451,5 @@ process_1_event() {
   // Call window_proc
   // Call window_proc
   DispatchMessage(&msg);
   DispatchMessage(&msg);
 }
 }
-  
-////////////////////////////////////////////////////////////////////
-//     Function: wglGraphicsBuffer::register_window_class
-//       Access: Private, Static
-//  Description: Registers a Window class for all wglGraphicsBuffers.
-//               This only needs to be done once per session.
-////////////////////////////////////////////////////////////////////
-void wglGraphicsBuffer::
-register_window_class() {
-  if (_window_class_registered) {
-    return;
-  }
-
-  WNDCLASS wc;
-
-  HINSTANCE instance = GetModuleHandle(NULL);
-
-  // Clear before filling in window structure!
-  ZeroMemory(&wc, sizeof(WNDCLASS));
-  wc.style = CS_OWNDC;
-  wc.lpfnWndProc = static_window_proc;
-  wc.hInstance = instance;
-  wc.lpszClassName = _window_class_name;
-  
-  if (!RegisterClass(&wc)) {
-    wgldisplay_cat.error()
-      << "could not register window class!" << endl;
-    return;
-  }
-  _window_class_registered = true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: wglGraphicsBuffer::static_window_proc
-//       Access: Private, Static
-//  Description: This is attached to the window class for all
-//               wglGraphicsBuffer windows; it is called to handle
-//               window events.
-////////////////////////////////////////////////////////////////////
-LONG WINAPI wglGraphicsBuffer::
-static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
-  return DefWindowProc(hwnd, msg, wparam, lparam);
-}
 
 
 
 

+ 1 - 10
panda/src/wgldisplay/wglGraphicsBuffer.h

@@ -59,22 +59,13 @@ protected:
   virtual bool open_buffer();
   virtual bool open_buffer();
 
 
 private:
 private:
-  bool make_window();
-  bool make_pbuffer();
+  bool make_pbuffer(HDC window_dc);
 
 
   static void process_1_event();
   static void process_1_event();
 
 
-  static void register_window_class();
-  static LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
-
-  HWND _window;
-  HDC _window_dc;
   HPBUFFERARB _pbuffer;
   HPBUFFERARB _pbuffer;
   HDC _pbuffer_dc;
   HDC _pbuffer_dc;
 
 
-  static const char * const _window_class_name;
-  static bool _window_class_registered;
-
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

+ 1 - 0
panda/src/wgldisplay/wglGraphicsPipe.I

@@ -15,3 +15,4 @@
 // [email protected] .
 // [email protected] .
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
+

+ 277 - 10
panda/src/wgldisplay/wglGraphicsPipe.cxx

@@ -23,7 +23,6 @@
 #include "wglGraphicsBuffer.h"
 #include "wglGraphicsBuffer.h"
 
 
 typedef enum {Software, MCD, ICD} OGLDriverType;
 typedef enum {Software, MCD, ICD} OGLDriverType;
-static const char * const OGLDrvStrings[] = { "Software", "MCD", "ICD" };
 
 
 TypeHandle wglGraphicsPipe::_type_handle;
 TypeHandle wglGraphicsPipe::_type_handle;
   
   
@@ -100,30 +99,83 @@ make_gsg(const FrameBufferProperties &properties,
     DCAST_INTO_R(share_gsg, share_with, NULL);
     DCAST_INTO_R(share_gsg, share_with, NULL);
   }
   }
 
 
+  int frame_buffer_mode = 0;
+  if (properties.has_frame_buffer_mode()) {
+    frame_buffer_mode = properties.get_frame_buffer_mode();
+  }
+
   // We need a DC to examine the available pixel formats.  We'll use
   // We need a DC to examine the available pixel formats.  We'll use
   // the screen DC.
   // the screen DC.
   HDC hdc = GetDC(NULL);
   HDC hdc = GetDC(NULL);
-  int pfnum = choose_pfnum(properties, hdc);
+  int temp_pfnum;
+
+  if (!gl_force_pixfmt.has_value()) {
+    temp_pfnum = choose_pfnum(properties, hdc);
 
 
-  if (gl_force_pixfmt != 0) {
+  } else {
     wgldisplay_cat.info()
     wgldisplay_cat.info()
-      << "overriding pixfmt choice algorithm (" << pfnum 
-      << ") with gl-force-pixfmt(" << gl_force_pixfmt << ")\n";
-    pfnum = gl_force_pixfmt;
+      << "overriding pixfmt choice with gl-force-pixfmt(" 
+      << gl_force_pixfmt << ")\n";
+    temp_pfnum = gl_force_pixfmt;
   }
   }
 
 
-  FrameBufferProperties new_properties;
-  get_properties(new_properties, hdc, pfnum);
+  FrameBufferProperties temp_properties;
+  get_properties(temp_properties, hdc, temp_pfnum);
+
+  // We're done with hdc now.
   ReleaseDC(NULL, hdc);
   ReleaseDC(NULL, hdc);
 
 
+  if (wgldisplay_cat.is_debug()) {
+    wgldisplay_cat.debug()
+      << "Preliminary pixfmt #" << temp_pfnum << " = " 
+      << temp_properties << "\n";
+  }
+
+  // Now we need to create a temporary GSG to query the WGL
+  // extensions, so we can look for more advanced properties like
+  // multisampling.
+  PT(wglGraphicsStateGuardian) temp_gsg = 
+    new wglGraphicsStateGuardian(temp_properties, share_gsg, temp_pfnum);
+
+  int pfnum = temp_pfnum;
+  FrameBufferProperties new_properties = temp_properties;
+
+  // Actually, don't bother with the advanced stuff unless the
+  // requested frame buffer requires multisample, since at the moment
+  // that's the only reason we'd need to use the advanced query.
+  if (frame_buffer_mode & FrameBufferProperties::FM_multisample) {
+    HDC twindow_dc = temp_gsg->get_twindow_dc();
+    if (twindow_dc != 0) {
+      wglMakeCurrent(twindow_dc, temp_gsg->get_context(twindow_dc));
+      temp_gsg->reset_if_new();
+      
+      if (temp_gsg->_supports_pixel_format) {
+        pfnum = choose_pfnum_advanced(properties, temp_gsg, twindow_dc, 
+                                      temp_pfnum);
+        if (!get_properties_advanced(new_properties, temp_gsg, twindow_dc, 
+                                     pfnum)) {
+          wgldisplay_cat.debug()
+            << "Unable to query properties using extension interface.\n";
+          
+          get_properties(new_properties, twindow_dc, pfnum);
+        }
+      }
+    }
+  }
+
   if (wgldisplay_cat.is_debug()) {
   if (wgldisplay_cat.is_debug()) {
     wgldisplay_cat.debug()
     wgldisplay_cat.debug()
       << "Picking pixfmt #" << pfnum << " = " 
       << "Picking pixfmt #" << pfnum << " = " 
       << new_properties << "\n";
       << new_properties << "\n";
   }
   }
 
 
-  PT(wglGraphicsStateGuardian) gsg = 
-    new wglGraphicsStateGuardian(new_properties, share_gsg, pfnum);
+  // Now create the actual GSG.  If we happen to have ended up with
+  // the same pfnum that we had the first time around, we can just
+  // keep our initial, temporary GSG.
+  PT(wglGraphicsStateGuardian) gsg = temp_gsg;
+  if (pfnum != temp_pfnum) {
+    gsg = new wglGraphicsStateGuardian(new_properties, share_gsg, pfnum);
+  }
 
 
   // Ideally, we should be able to detect whether the share_gsg will
   // Ideally, we should be able to detect whether the share_gsg will
   // be successful, and return NULL if it won't work.  But we can't do
   // be successful, and return NULL if it won't work.  But we can't do
@@ -220,6 +272,134 @@ choose_pfnum(const FrameBufferProperties &properties, HDC hdc) {
   return pfnum;
   return pfnum;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: wglGraphicsPipe::choose_pfnum_advanced
+//       Access: Private, Static
+//  Description: Uses the WGL extensions, if available, to find a
+//               suitable pfnum.  This requires having created a
+//               temporary context first.
+////////////////////////////////////////////////////////////////////
+int wglGraphicsPipe::
+choose_pfnum_advanced(const FrameBufferProperties &properties, 
+                      const wglGraphicsStateGuardian *wglgsg,
+                      HDC window_dc, int orig_pfnum) {
+  int frame_buffer_mode = 0;
+
+  if (properties.has_frame_buffer_mode()) {
+    frame_buffer_mode = properties.get_frame_buffer_mode();
+  }
+
+  int want_depth_bits = properties.get_depth_bits();
+  int want_color_bits = properties.get_color_bits();
+  int want_alpha_bits = properties.get_alpha_bits();
+  int want_stencil_bits = properties.get_stencil_bits();
+  int want_multisample_bits = properties.get_multisample_bits();
+
+  static const int max_attrib_list = 32;
+  int iattrib_list[max_attrib_list];
+  float fattrib_list[max_attrib_list];
+  int ni = 0;
+  int nf = 0;
+
+  iattrib_list[ni++] = WGL_SUPPORT_OPENGL_ARB;
+  iattrib_list[ni++] = true;
+  iattrib_list[ni++] = WGL_PIXEL_TYPE_ARB;
+  iattrib_list[ni++] = WGL_TYPE_RGBA_ARB;
+  iattrib_list[ni++] = WGL_COLOR_BITS_ARB;
+  iattrib_list[ni++] = want_color_bits;
+
+  if (frame_buffer_mode & FrameBufferProperties::FM_alpha) {
+    iattrib_list[ni++] = WGL_ALPHA_BITS_ARB;
+    iattrib_list[ni++] = want_alpha_bits;
+  }
+
+  switch (frame_buffer_mode & FrameBufferProperties::FM_buffer) {
+  case FrameBufferProperties::FM_single_buffer:
+    iattrib_list[ni++] = WGL_DOUBLE_BUFFER_ARB;
+    iattrib_list[ni++] = false;
+    break;
+
+  case FrameBufferProperties::FM_double_buffer:
+  case FrameBufferProperties::FM_triple_buffer:
+    iattrib_list[ni++] = WGL_DOUBLE_BUFFER_ARB;
+    iattrib_list[ni++] = true;
+    break;
+  }
+
+  if (frame_buffer_mode & FrameBufferProperties::FM_stereo) {
+    iattrib_list[ni++] = WGL_STEREO_ARB;
+    iattrib_list[ni++] = true;
+  } else {
+    iattrib_list[ni++] = WGL_STEREO_ARB;
+    iattrib_list[ni++] = false;
+  }
+
+  if (frame_buffer_mode & FrameBufferProperties::FM_depth) {
+    iattrib_list[ni++] = WGL_DEPTH_BITS_ARB;
+    iattrib_list[ni++] = want_depth_bits;
+  }
+
+  if (frame_buffer_mode & FrameBufferProperties::FM_stencil) {
+    iattrib_list[ni++] = WGL_STENCIL_BITS_ARB;
+    iattrib_list[ni++] = want_stencil_bits;
+  }
+
+  if (frame_buffer_mode & FrameBufferProperties::FM_accum) {
+    iattrib_list[ni++] = WGL_ACCUM_BITS_ARB;
+    iattrib_list[ni++] = want_color_bits;
+    if (frame_buffer_mode & FrameBufferProperties::FM_alpha) {
+      iattrib_list[ni++] = WGL_ACCUM_ALPHA_BITS_ARB;
+      iattrib_list[ni++] = want_alpha_bits;
+    }
+  }
+
+  if (frame_buffer_mode & FrameBufferProperties::FM_multisample) {
+    iattrib_list[ni++] = WGL_SAMPLES_ARB;
+    iattrib_list[ni++] = want_multisample_bits;
+  }
+
+  // Terminate the lists.
+  nassertr(ni < max_attrib_list && nf < max_attrib_list, NULL);
+  iattrib_list[ni] = 0;
+  fattrib_list[nf] = 0;
+
+  // Now obtain a list of pixel formats that meet these minimum
+  // requirements.
+  static const unsigned int max_pformats = 32;
+  int pformat[max_pformats];
+  memset(pformat, 0, sizeof(pformat));
+  unsigned int nformats = 0;
+  if (!wglgsg->_wglChoosePixelFormatARB(window_dc, iattrib_list, fattrib_list,
+                                        max_pformats, pformat, &nformats)) {
+    wgldisplay_cat.info()
+      << "Couldn't find a suitable advanced pixel format.\n";
+    return orig_pfnum;
+  }
+  
+  nformats = min(nformats, max_pformats);
+
+  if (wgldisplay_cat.is_debug()) {
+    wgldisplay_cat.debug()
+      << "Found " << nformats << " advanced formats: [";
+    for (unsigned int i = 0; i < nformats; i++) {
+      wgldisplay_cat.debug(false)
+        << " " << pformat[i];
+    }
+    wgldisplay_cat.debug(false)
+      << " ]\n";
+  }
+  
+  // If our original pfnum is on the list, take it.
+  for (unsigned int i = 0; i < nformats; i++) {
+    if (pformat[i] == orig_pfnum) {
+      return orig_pfnum;
+    }
+  }
+
+  // Otherwise, return the first available.
+  return pformat[0];
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsPipe::find_pixfmtnum
 //     Function: wglGraphicsPipe::find_pixfmtnum
 //       Access: Private, Static
 //       Access: Private, Static
@@ -448,6 +628,93 @@ get_properties(FrameBufferProperties &properties, HDC hdc,
   properties.set_frame_buffer_mode(mode);
   properties.set_frame_buffer_mode(mode);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: wglGraphicsPipe::get_properties_advanced
+//       Access: Private, Static
+//  Description: Gets the FrameBufferProperties to match the
+//               indicated pixel format descriptor, using the WGL
+//               extensions.
+////////////////////////////////////////////////////////////////////
+bool wglGraphicsPipe::
+get_properties_advanced(FrameBufferProperties &properties, 
+                        wglGraphicsStateGuardian *wglgsg, 
+                        HDC window_dc, int pfnum) {
+
+  static const int max_attrib_list = 32;
+  int iattrib_list[max_attrib_list];
+  int ivalue_list[max_attrib_list];
+  int ni = 0;
+
+  int acceleration_i, pixel_type_i, double_buffer_i, stereo_i,
+    color_bits_i, alpha_bits_i, accum_bits_i, depth_bits_i, 
+    stencil_bits_i, multisample_bits_i;
+
+  iattrib_list[acceleration_i = ni++] = WGL_ACCELERATION_ARB;
+  iattrib_list[pixel_type_i = ni++] = WGL_PIXEL_TYPE_ARB;
+  iattrib_list[double_buffer_i = ni++] = WGL_DOUBLE_BUFFER_ARB;
+  iattrib_list[stereo_i = ni++] = WGL_STEREO_ARB;
+  iattrib_list[color_bits_i = ni++] = WGL_COLOR_BITS_ARB;
+  iattrib_list[alpha_bits_i = ni++] = WGL_ALPHA_BITS_ARB;
+  iattrib_list[accum_bits_i = ni++] = WGL_ACCUM_BITS_ARB;
+  iattrib_list[depth_bits_i = ni++] = WGL_DEPTH_BITS_ARB;
+  iattrib_list[stencil_bits_i = ni++] = WGL_STENCIL_BITS_ARB;
+
+  if (wglgsg->_supports_wgl_multisample) {
+    iattrib_list[multisample_bits_i = ni++] = WGL_SAMPLES_ARB;
+  }
+
+  // Terminate the list.
+  nassertr(ni <= max_attrib_list, false);
+
+  if (!wglgsg->_wglGetPixelFormatAttribivARB(window_dc, pfnum, 0,
+                                             ni, iattrib_list, ivalue_list)) {
+    return false;
+  }
+
+  int frame_buffer_mode = 0;
+  if (ivalue_list[acceleration_i] == WGL_NO_ACCELERATION_ARB) {
+    frame_buffer_mode |= FrameBufferProperties::FM_software;
+  } else {
+    frame_buffer_mode |= FrameBufferProperties::FM_hardware;
+  }
+
+  if (ivalue_list[pixel_type_i] == WGL_TYPE_COLORINDEX_ARB) {
+    frame_buffer_mode |= FrameBufferProperties::FM_index;
+  }
+  if (ivalue_list[double_buffer_i]) {
+    frame_buffer_mode |= FrameBufferProperties::FM_double_buffer;
+  }
+  if (ivalue_list[stereo_i]) {
+    frame_buffer_mode |= FrameBufferProperties::FM_stereo;
+  }
+  if (ivalue_list[alpha_bits_i] != 0) {
+    frame_buffer_mode |= FrameBufferProperties::FM_alpha;
+    properties.set_alpha_bits(ivalue_list[alpha_bits_i]);
+  }
+  if (ivalue_list[accum_bits_i] != 0) {
+    frame_buffer_mode |= FrameBufferProperties::FM_accum;
+  }
+  if (ivalue_list[depth_bits_i] != 0) {
+    frame_buffer_mode |= FrameBufferProperties::FM_depth;
+    properties.set_depth_bits(ivalue_list[depth_bits_i]);
+  }
+  if (ivalue_list[stencil_bits_i] != 0) {
+    frame_buffer_mode |= FrameBufferProperties::FM_stencil;
+    properties.set_stencil_bits(ivalue_list[stencil_bits_i]);
+  }
+  if (wglgsg->_supports_wgl_multisample) {
+    if (ivalue_list[multisample_bits_i] != 0) {
+      frame_buffer_mode |= FrameBufferProperties::FM_multisample;
+      properties.set_multisample_bits(ivalue_list[multisample_bits_i]);
+    }
+  }
+
+  properties.set_frame_buffer_mode(frame_buffer_mode);
+  properties.set_color_bits(ivalue_list[color_bits_i]);
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsPipe::format_pfd_flags
 //     Function: wglGraphicsPipe::format_pfd_flags
 //       Access: Private, Static
 //       Access: Private, Static

+ 8 - 0
panda/src/wgldisplay/wglGraphicsPipe.h

@@ -22,6 +22,8 @@
 #include "pandabase.h"
 #include "pandabase.h"
 #include "winGraphicsPipe.h"
 #include "winGraphicsPipe.h"
 
 
+class wglGraphicsStateGuardian;
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : wglGraphicsPipe
 //       Class : wglGraphicsPipe
 // Description : This graphics pipe represents the interface for
 // Description : This graphics pipe represents the interface for
@@ -46,10 +48,16 @@ protected:
                                          int x_size, int y_size, bool want_texture);
                                          int x_size, int y_size, bool want_texture);
 private:
 private:
   static int choose_pfnum(const FrameBufferProperties &properties, HDC hdc);
   static int choose_pfnum(const FrameBufferProperties &properties, HDC hdc);
+  static int choose_pfnum_advanced(const FrameBufferProperties &properties, 
+                                   const wglGraphicsStateGuardian *wglgsg,
+                                   HDC window_dc, int orig_pfnum);
   static int find_pixfmtnum(const FrameBufferProperties &properties, HDC hdc,
   static int find_pixfmtnum(const FrameBufferProperties &properties, HDC hdc,
                             bool bLookforHW);
                             bool bLookforHW);
   static void get_properties(FrameBufferProperties &properties, HDC hdc,
   static void get_properties(FrameBufferProperties &properties, HDC hdc,
                              int pfnum);
                              int pfnum);
+  static bool get_properties_advanced(FrameBufferProperties &properties, 
+                                      wglGraphicsStateGuardian *wglgsg, 
+                                      HDC window_dc, int pfnum);
   static string format_pfd_flags(DWORD pfd_flags);
   static string format_pfd_flags(DWORD pfd_flags);
 
 
 public:
 public:

+ 16 - 0
panda/src/wgldisplay/wglGraphicsStateGuardian.I

@@ -61,3 +61,19 @@ get_context(HDC hdc) {
   }
   }
   return _context;
   return _context;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: wglGraphicsStateGuardian::get_twindow_dc
+//       Access: Public
+//  Description: Returns the DC associated with the temporary,
+//               invisible window that was created with the gsg to
+//               query WGL extensions.
+////////////////////////////////////////////////////////////////////
+INLINE HDC wglGraphicsStateGuardian::
+get_twindow_dc() {
+  if (_twindow_dc == 0) {
+    make_twindow();
+  }
+  return _twindow_dc;
+}
+

+ 102 - 0
panda/src/wgldisplay/wglGraphicsStateGuardian.cxx

@@ -21,6 +21,9 @@
 
 
 TypeHandle wglGraphicsStateGuardian::_type_handle;
 TypeHandle wglGraphicsStateGuardian::_type_handle;
 
 
+const char * const wglGraphicsStateGuardian::_twindow_class_name = "wglGraphicsStateGuardian";
+bool wglGraphicsStateGuardian::_twindow_class_registered = false;
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsStateGuardian::Constructor
 //     Function: wglGraphicsStateGuardian::Constructor
 //       Access: Public
 //       Access: Public
@@ -37,8 +40,12 @@ wglGraphicsStateGuardian(const FrameBufferProperties &properties,
   _made_context = false;
   _made_context = false;
   _context = (HGLRC)NULL;
   _context = (HGLRC)NULL;
 
 
+  _twindow = (HWND)0;
+  _twindow_dc = (HDC)0;
+
   _supports_pbuffer = false;
   _supports_pbuffer = false;
   _supports_pixel_format = false;
   _supports_pixel_format = false;
+  _supports_wgl_multisample = false;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -48,6 +55,7 @@ wglGraphicsStateGuardian(const FrameBufferProperties &properties,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 wglGraphicsStateGuardian::
 wglGraphicsStateGuardian::
 ~wglGraphicsStateGuardian() {
 ~wglGraphicsStateGuardian() {
+  release_twindow();
   if (_context != (HGLRC)NULL) {
   if (_context != (HGLRC)NULL) {
     wglDeleteContext(_context);
     wglDeleteContext(_context);
     _context = (HGLRC)NULL;
     _context = (HGLRC)NULL;
@@ -66,6 +74,7 @@ reset() {
 
 
   _supports_pbuffer = has_extension("WGL_ARB_pbuffer");
   _supports_pbuffer = has_extension("WGL_ARB_pbuffer");
   _supports_pixel_format = has_extension("WGL_ARB_pixel_format");
   _supports_pixel_format = has_extension("WGL_ARB_pixel_format");
+  _supports_wgl_multisample = has_extension("WGL_ARB_multisample");
 
 
   _wglCreatePbufferARB = 
   _wglCreatePbufferARB = 
     (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
     (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
@@ -250,3 +259,96 @@ redirect_share_pool(wglGraphicsStateGuardian *share_with) {
     _share_with = share_with;
     _share_with = share_with;
   }
   }
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: wglGraphicsStateGuardian::make_twindow
+//       Access: Private
+//  Description: Creates an invisible window to associate with the GL
+//               context, even if we are not going to use it.  This is
+//               necessary because in the Windows OpenGL API, we have
+//               to create window before we can create a GL
+//               context--even before we can ask about what GL
+//               extensions are available!
+////////////////////////////////////////////////////////////////////
+bool wglGraphicsStateGuardian::
+make_twindow() {
+  release_twindow();
+
+  DWORD window_style = 0;
+
+  register_twindow_class();
+  HINSTANCE hinstance = GetModuleHandle(NULL);
+  _twindow = CreateWindow(_twindow_class_name, "twindow", window_style, 
+                          0, 0, 1, 1, NULL, NULL, hinstance, 0);
+  
+  if (!_twindow) {
+    wgldisplay_cat.error()
+      << "CreateWindow() failed!" << endl;
+    return false;
+  }
+
+  ShowWindow(_twindow, SW_HIDE);
+
+  _twindow_dc = GetDC(_twindow);
+
+  PIXELFORMATDESCRIPTOR pixelformat;
+  if (!SetPixelFormat(_twindow_dc, _pfnum, &pixelformat)) {
+    wgldisplay_cat.error()
+      << "SetPixelFormat(" << _pfnum << ") failed after window create\n";
+    release_twindow();
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: wglGraphicsStateGuardian::release_twindow
+//       Access: Private
+//  Description: Closes and frees the resources associated with the
+//               temporary window created by a previous call to
+//               make_twindow().
+////////////////////////////////////////////////////////////////////
+void wglGraphicsStateGuardian::
+release_twindow() {
+  if (_twindow_dc) {
+    ReleaseDC(_twindow, _twindow_dc);
+    _twindow_dc = 0;
+  }
+  if (_twindow) {
+    DestroyWindow(_twindow);
+    _twindow = 0;
+  }
+}
+  
+////////////////////////////////////////////////////////////////////
+//     Function: wglGraphicsStateGuardian::register_twindow_class
+//       Access: Private, Static
+//  Description: Registers a Window class for the twindow created by
+//               all wglGraphicsPipes.  This only needs to be done
+//               once per session.
+////////////////////////////////////////////////////////////////////
+void wglGraphicsStateGuardian::
+register_twindow_class() {
+  if (_twindow_class_registered) {
+    return;
+  }
+
+  WNDCLASS wc;
+
+  HINSTANCE instance = GetModuleHandle(NULL);
+
+  // Clear before filling in window structure!
+  ZeroMemory(&wc, sizeof(WNDCLASS));
+  wc.style = CS_OWNDC;
+  wc.lpfnWndProc = DefWindowProc;
+  wc.hInstance = instance;
+  wc.lpszClassName = _twindow_class_name;
+  
+  if (!RegisterClass(&wc)) {
+    wgldisplay_cat.error()
+      << "could not register window class!" << endl;
+    return;
+  }
+  _twindow_class_registered = true;
+}

+ 15 - 0
panda/src/wgldisplay/wglGraphicsStateGuardian.h

@@ -45,6 +45,8 @@ public:
 
 
   virtual void reset();
   virtual void reset();
 
 
+  INLINE HDC get_twindow_dc();
+
 protected:
 protected:
   virtual void get_extra_extensions();
   virtual void get_extra_extensions();
   virtual void *get_extension_func(const char *prefix, const char *name);
   virtual void *get_extension_func(const char *prefix, const char *name);
@@ -54,6 +56,11 @@ private:
   HGLRC get_share_context() const;
   HGLRC get_share_context() const;
   void redirect_share_pool(wglGraphicsStateGuardian *share_with);
   void redirect_share_pool(wglGraphicsStateGuardian *share_with);
 
 
+  bool make_twindow();
+  void release_twindow();
+
+  static void register_twindow_class();
+
   // We have to save a pointer to the GSG we intend to share texture
   // We have to save a pointer to the GSG we intend to share texture
   // context with, since we don't create our own context in the
   // context with, since we don't create our own context in the
   // constructor.
   // constructor.
@@ -67,6 +74,12 @@ private:
   bool _made_context;
   bool _made_context;
   HGLRC _context;
   HGLRC _context;
 
 
+  HWND _twindow;
+  HDC _twindow_dc;
+
+  static const char * const _twindow_class_name;
+  static bool _twindow_class_registered;
+
 public:
 public:
   bool _supports_pbuffer;
   bool _supports_pbuffer;
 
 
@@ -82,6 +95,8 @@ public:
   PFNWGLGETPIXELFORMATATTRIBFVARBPROC _wglGetPixelFormatAttribfvARB;
   PFNWGLGETPIXELFORMATATTRIBFVARBPROC _wglGetPixelFormatAttribfvARB;
   PFNWGLCHOOSEPIXELFORMATARBPROC _wglChoosePixelFormatARB;
   PFNWGLCHOOSEPIXELFORMATARBPROC _wglChoosePixelFormatARB;
 
 
+  bool _supports_wgl_multisample;
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;