diff --git a/panda/src/wgldisplay/wglGraphicsBuffer.cxx b/panda/src/wgldisplay/wglGraphicsBuffer.cxx index dfa4279b18..593f04d755 100644 --- a/panda/src/wgldisplay/wglGraphicsBuffer.cxx +++ b/panda/src/wgldisplay/wglGraphicsBuffer.cxx @@ -17,6 +17,7 @@ //////////////////////////////////////////////////////////////////// #include "wglGraphicsBuffer.h" +#include "wglGraphicsPipe.h" #include "config_wgldisplay.h" #include "glgsg.h" #include "pStatTimer.h" @@ -24,8 +25,6 @@ #include TypeHandle wglGraphicsBuffer::_type_handle; -const char * const wglGraphicsBuffer::_window_class_name = "wglGraphicsBuffer"; -bool wglGraphicsBuffer::_window_class_registered = false; //////////////////////////////////////////////////////////////////// // Function: wglGraphicsBuffer::Constructor @@ -38,8 +37,6 @@ wglGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, int x_size, int y_size, bool want_texture) : GraphicsBuffer(pipe, gsg, name, x_size, y_size, want_texture) { - _window = (HWND)0; - _window_dc = (HDC)0; _pbuffer = (HPBUFFERARB)0; _pbuffer_dc = (HDC)0; @@ -196,15 +193,6 @@ process_events() { //////////////////////////////////////////////////////////////////// void wglGraphicsBuffer:: close_buffer() { - if (_window_dc) { - ReleaseDC(_window, _window_dc); - _window_dc = 0; - } - if (_window) { - DestroyWindow(_window); - _window = 0; - } - if (_gsg != (GraphicsStateGuardian *)NULL) { wglGraphicsStateGuardian *wglgsg; DCAST_INTO_V(wglgsg, _gsg); @@ -231,15 +219,16 @@ close_buffer() { //////////////////////////////////////////////////////////////////// bool wglGraphicsBuffer:: 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. 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(); _needs_context = false; @@ -247,88 +236,25 @@ open_buffer() { // create a rendering context, we can attempt to create a pbuffer. // This might fail if the pbuffer extensions are not supported. - if (!make_pbuffer()) { + if (!make_pbuffer(twindow_dc)) { + wglMakeCurrent(0, 0); return false; } _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)); 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; 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 // Access: Private @@ -338,7 +264,7 @@ make_window() { // failure. //////////////////////////////////////////////////////////////////// bool wglGraphicsBuffer:: -make_pbuffer() { +make_pbuffer(HDC twindow_dc) { wglGraphicsStateGuardian *wglgsg; DCAST_INTO_R(wglgsg, _gsg, false); @@ -353,18 +279,47 @@ make_pbuffer() { if (wglgsg->_supports_pixel_format) { // Select a suitable pixel format that matches the GSG's existing // 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; int iattrib_list[max_attrib_list]; - float fattrib_list[max_attrib_list]; + int ivalue_list[max_attrib_list]; 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; // Since we are trying to create a pbuffer, the pixel format we @@ -376,25 +331,39 @@ make_pbuffer() { // Match up the framebuffer bits. 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++] = pfd.cGreenBits; + iattrib_list[ni++] = ivalue_list[green_bits_i]; 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++] = 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++] = pfd.cDepthBits; + iattrib_list[ni++] = ivalue_list[depth_bits_i]; 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. 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++] = ((pfd.dwFlags & PFD_STEREO) != 0); + iattrib_list[ni++] = ivalue_list[stereo_i]; // Terminate the lists. 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 // requirements. - static const int max_pformats = 32; + 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, + if (!wglgsg->_wglChoosePixelFormatARB(twindow_dc, iattrib_list, fattrib_list, max_pformats, pformat, &nformats)) { wgldisplay_cat.info() << "Couldn't find a suitable pixel format for creating a pbuffer.\n"; return false; } + nformats = min(nformats, max_pformats); + if (wgldisplay_cat.is_debug()) { wgldisplay_cat.debug() << "Found " << nformats << " pbuffer formats: ["; @@ -425,16 +396,32 @@ make_pbuffer() { << " ]\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[] = { 0, }; - _pbuffer = wglgsg->_wglCreatePbufferARB(_window_dc, pbformat, + _pbuffer = wglgsg->_wglCreatePbufferARB(twindow_dc, pbformat, _x_size, _y_size, attrib_list); - + if (_pbuffer == 0) { wgldisplay_cat.info() << "Attempt to create pbuffer failed.\n"; @@ -464,48 +451,5 @@ process_1_event() { // Call window_proc 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); -} diff --git a/panda/src/wgldisplay/wglGraphicsBuffer.h b/panda/src/wgldisplay/wglGraphicsBuffer.h index 0b0af8132d..e839b3d248 100644 --- a/panda/src/wgldisplay/wglGraphicsBuffer.h +++ b/panda/src/wgldisplay/wglGraphicsBuffer.h @@ -59,22 +59,13 @@ protected: virtual bool open_buffer(); private: - bool make_window(); - bool make_pbuffer(); + bool make_pbuffer(HDC window_dc); 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; HDC _pbuffer_dc; - static const char * const _window_class_name; - static bool _window_class_registered; - public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/wgldisplay/wglGraphicsPipe.I b/panda/src/wgldisplay/wglGraphicsPipe.I index 7f901d908e..6c23260f14 100644 --- a/panda/src/wgldisplay/wglGraphicsPipe.I +++ b/panda/src/wgldisplay/wglGraphicsPipe.I @@ -15,3 +15,4 @@ // panda3d-general@lists.sourceforge.net . // //////////////////////////////////////////////////////////////////// + diff --git a/panda/src/wgldisplay/wglGraphicsPipe.cxx b/panda/src/wgldisplay/wglGraphicsPipe.cxx index 9a2773a880..046eae0bc9 100644 --- a/panda/src/wgldisplay/wglGraphicsPipe.cxx +++ b/panda/src/wgldisplay/wglGraphicsPipe.cxx @@ -23,7 +23,6 @@ #include "wglGraphicsBuffer.h" typedef enum {Software, MCD, ICD} OGLDriverType; -static const char * const OGLDrvStrings[] = { "Software", "MCD", "ICD" }; TypeHandle wglGraphicsPipe::_type_handle; @@ -100,30 +99,83 @@ make_gsg(const FrameBufferProperties &properties, 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 // the screen DC. HDC hdc = GetDC(NULL); - int pfnum = choose_pfnum(properties, hdc); + int temp_pfnum; - if (gl_force_pixfmt != 0) { + if (!gl_force_pixfmt.has_value()) { + temp_pfnum = choose_pfnum(properties, hdc); + + } else { 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); + 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()) { wgldisplay_cat.debug() << "Picking pixfmt #" << pfnum << " = " << 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 // 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; } +//////////////////////////////////////////////////////////////////// +// 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 // Access: Private, Static @@ -448,6 +628,93 @@ get_properties(FrameBufferProperties &properties, HDC hdc, 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 // Access: Private, Static diff --git a/panda/src/wgldisplay/wglGraphicsPipe.h b/panda/src/wgldisplay/wglGraphicsPipe.h index 95e66964d6..802c586c65 100644 --- a/panda/src/wgldisplay/wglGraphicsPipe.h +++ b/panda/src/wgldisplay/wglGraphicsPipe.h @@ -22,6 +22,8 @@ #include "pandabase.h" #include "winGraphicsPipe.h" +class wglGraphicsStateGuardian; + //////////////////////////////////////////////////////////////////// // Class : wglGraphicsPipe // Description : This graphics pipe represents the interface for @@ -46,10 +48,16 @@ protected: int x_size, int y_size, bool want_texture); private: 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, bool bLookforHW); static void get_properties(FrameBufferProperties &properties, HDC hdc, int pfnum); + static bool get_properties_advanced(FrameBufferProperties &properties, + wglGraphicsStateGuardian *wglgsg, + HDC window_dc, int pfnum); static string format_pfd_flags(DWORD pfd_flags); public: diff --git a/panda/src/wgldisplay/wglGraphicsStateGuardian.I b/panda/src/wgldisplay/wglGraphicsStateGuardian.I index 3fcce67e36..363473b0d5 100755 --- a/panda/src/wgldisplay/wglGraphicsStateGuardian.I +++ b/panda/src/wgldisplay/wglGraphicsStateGuardian.I @@ -61,3 +61,19 @@ get_context(HDC hdc) { } 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; +} + diff --git a/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx b/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx index 03d79a2a61..b93783d32a 100755 --- a/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx +++ b/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx @@ -21,6 +21,9 @@ TypeHandle wglGraphicsStateGuardian::_type_handle; +const char * const wglGraphicsStateGuardian::_twindow_class_name = "wglGraphicsStateGuardian"; +bool wglGraphicsStateGuardian::_twindow_class_registered = false; + //////////////////////////////////////////////////////////////////// // Function: wglGraphicsStateGuardian::Constructor // Access: Public @@ -37,8 +40,12 @@ wglGraphicsStateGuardian(const FrameBufferProperties &properties, _made_context = false; _context = (HGLRC)NULL; + _twindow = (HWND)0; + _twindow_dc = (HDC)0; + _supports_pbuffer = false; _supports_pixel_format = false; + _supports_wgl_multisample = false; } //////////////////////////////////////////////////////////////////// @@ -48,6 +55,7 @@ wglGraphicsStateGuardian(const FrameBufferProperties &properties, //////////////////////////////////////////////////////////////////// wglGraphicsStateGuardian:: ~wglGraphicsStateGuardian() { + release_twindow(); if (_context != (HGLRC)NULL) { wglDeleteContext(_context); _context = (HGLRC)NULL; @@ -66,6 +74,7 @@ reset() { _supports_pbuffer = has_extension("WGL_ARB_pbuffer"); _supports_pixel_format = has_extension("WGL_ARB_pixel_format"); + _supports_wgl_multisample = has_extension("WGL_ARB_multisample"); _wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB"); @@ -250,3 +259,96 @@ redirect_share_pool(wglGraphicsStateGuardian *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; +} diff --git a/panda/src/wgldisplay/wglGraphicsStateGuardian.h b/panda/src/wgldisplay/wglGraphicsStateGuardian.h index 6835ecd083..9f0e73fe62 100755 --- a/panda/src/wgldisplay/wglGraphicsStateGuardian.h +++ b/panda/src/wgldisplay/wglGraphicsStateGuardian.h @@ -45,6 +45,8 @@ public: virtual void reset(); + INLINE HDC get_twindow_dc(); + protected: virtual void get_extra_extensions(); virtual void *get_extension_func(const char *prefix, const char *name); @@ -54,6 +56,11 @@ private: HGLRC get_share_context() const; 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 // context with, since we don't create our own context in the // constructor. @@ -67,6 +74,12 @@ private: bool _made_context; HGLRC _context; + HWND _twindow; + HDC _twindow_dc; + + static const char * const _twindow_class_name; + static bool _twindow_class_registered; + public: bool _supports_pbuffer; @@ -82,6 +95,8 @@ public: PFNWGLGETPIXELFORMATATTRIBFVARBPROC _wglGetPixelFormatAttribfvARB; PFNWGLCHOOSEPIXELFORMATARBPROC _wglChoosePixelFormatARB; + bool _supports_wgl_multisample; + public: static TypeHandle get_class_type() { return _type_handle;