pbuffers are finally working

This commit is contained in:
David Rose 2004-02-18 00:42:14 +00:00
parent f0288e05c9
commit dffa847486
2 changed files with 188 additions and 94 deletions

View File

@ -40,6 +40,8 @@ wglGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
{
_window = (HWND)0;
_window_dc = (HDC)0;
_pbuffer = (HPBUFFERARB)0;
_pbuffer_dc = (HDC)0;
}
////////////////////////////////////////////////////////////////////
@ -62,13 +64,14 @@ void wglGraphicsBuffer::
make_current() {
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_V(wglgsg, _gsg);
wglMakeCurrent(_window_dc, wglgsg->get_context(_window_dc));
// Now that we have made the context current to a window, we can
// reset the GSG state if this is the first time it has been used.
// (We can't just call reset() when we construct the GSG, because
// reset() requires having a current context.)
wglgsg->reset_if_new();
// Use the pbuffer if we got it, otherwise fall back to the window.
if (_pbuffer_dc) {
wglMakeCurrent(_pbuffer_dc, wglgsg->get_context(_pbuffer_dc));
} else {
wglMakeCurrent(_window_dc, wglgsg->get_context(_window_dc));
}
}
////////////////////////////////////////////////////////////////////
@ -114,7 +117,11 @@ begin_flip() {
get_texture()->copy(_gsg, dr, _gsg->get_render_buffer(RenderBuffer::T_back));
}
SwapBuffers(_window_dc);
if (_pbuffer_dc) {
SwapBuffers(_pbuffer_dc);
} else {
SwapBuffers(_window_dc);
}
}
}
@ -159,6 +166,20 @@ close_buffer() {
_window = 0;
}
if (_gsg != (GraphicsStateGuardian *)NULL) {
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_V(wglgsg, _gsg);
if (_pbuffer_dc) {
wglgsg->_wglReleasePbufferDCARB(_pbuffer, _pbuffer_dc);
}
if (_pbuffer) {
wglgsg->_wglDestroyPbufferARB(_pbuffer);
}
}
_pbuffer_dc = 0;
_pbuffer = 0;
_is_valid = false;
}
@ -171,17 +192,60 @@ close_buffer() {
////////////////////////////////////////////////////////////////////
bool wglGraphicsBuffer::
open_buffer() {
// I made a good solid effort to use the wglPbuffer extension. Not
// only are wgl extensions incredibly convoluted to get to, but the
// pbuffer extension turned out not be supported on the Intel card I
// tried it on, and crashed the driver for the nVidia card I tried
// it on. And it's not even supported on the Microsoft software
// reference implementation. Not a good record.
if (!make_window()) {
// If we couldn't make a window, we can't get a GL context.
return false;
}
// In lieu of the pbuffer extension, it appears that rendering to a
// window that is hidden works fine on some drivers (although it
// doesn't work on other drivers).
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_R(wglgsg, _gsg, false);
wglMakeCurrent(_window_dc, wglgsg->get_context(_window_dc));
wglgsg->reset_if_new();
// Now that we have fully made a window and used that window to
// create a rendering context, we can attempt to create a pbuffer.
// This might fail if the pbuffer extensions are not supported; in
// that case, we'll just keep the window and hope it works even if
// it is not shown.
if (make_pbuffer()) {
_pbuffer_dc = wglgsg->_wglGetPbufferDCARB(_pbuffer);
wgldisplay_cat.info()
<< "Created PBuffer " << _pbuffer << ", DC " << _pbuffer_dc << "\n";
wglMakeCurrent(_pbuffer_dc, wglgsg->get_context(_pbuffer_dc));
wglgsg->report_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;
@ -225,7 +289,110 @@ open_buffer() {
return false;
}
_is_valid = true;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsBuffer::make_pbuffer
// Access: Private
// Description: Once the GL context has been fully realized, attempts
// to create an offscreen pbuffer if the graphics API
// supports it. Returns true if successful, false on
// failure.
////////////////////////////////////////////////////////////////////
bool wglGraphicsBuffer::
make_pbuffer() {
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_R(wglgsg, _gsg, false);
if (!wglgsg->_supports_pbuffer) {
return false;
}
int pbformat = wglgsg->get_pfnum();
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 ni = 0;
int nf = 0;
// Since we are trying to create a pbuffer, the pixel format we
// request (and subsequently use) must be "pbuffer capable".
iattrib_list[ni++] = WGL_DRAW_TO_PBUFFER_ARB;
iattrib_list[ni++] = true;
// Match up the framebuffer bits.
iattrib_list[ni++] = WGL_RED_BITS_ARB;
iattrib_list[ni++] = pfd.cRedBits;
iattrib_list[ni++] = WGL_GREEN_BITS_ARB;
iattrib_list[ni++] = pfd.cGreenBits;
iattrib_list[ni++] = WGL_BLUE_BITS_ARB;
iattrib_list[ni++] = pfd.cBlueBits;
iattrib_list[ni++] = WGL_ALPHA_BITS_ARB;
iattrib_list[ni++] = pfd.cAlphaBits;
iattrib_list[ni++] = WGL_DEPTH_BITS_ARB;
iattrib_list[ni++] = pfd.cDepthBits;
iattrib_list[ni++] = WGL_STENCIL_BITS_ARB;
iattrib_list[ni++] = pfd.cStencilBits;
// 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 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 pixel format for creating a pbuffer.\n";
return false;
}
if (wgldisplay_cat.is_debug()) {
wgldisplay_cat.debug()
<< "Found " << nformats << " pbuffer formats: [";
for (unsigned int i = 0; i < nformats; i++) {
wgldisplay_cat.debug(false)
<< " " << pformat[i];
}
wgldisplay_cat.debug(false)
<< " ]\n";
}
pbformat = pformat[0];
}
int attrib_list[] = {
0,
};
_pbuffer = wglgsg->_wglCreatePbufferARB(_window_dc, pbformat,
_x_size, _y_size, attrib_list);
if (_pbuffer == 0) {
wgldisplay_cat.info()
<< "Attempt to create pbuffer failed.\n";
return false;
}
return true;
}
@ -295,80 +462,3 @@ static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
}
/*
if (wglgsg->_supports_pixel_format) {
// Get ready to query for a suitable pixel format that meets our
// minimum requirements.
static const int MAX_ATTRIBS = 128;
static const int MAX_PFORMATS = 128;
int iattributes[2*MAX_ATTRIBS];
float fattributes[2*MAX_ATTRIBS];
int nfattribs = 0;
int niattribs = 0;
// Attribute arrays must be "0" terminated--for simplicity, first
// just zero-out the array then fill from left to right.
for ( int a = 0; a < 2*MAX_ATTRIBS; a++ )
{
iattributes[a] = 0;
fattributes[a] = 0;
}
// Since we are trying to create a pbuffer, the pixel format we
// request (and subsequently use) must be "pbuffer capable".
iattributes[2*niattribs ] = WGL_DRAW_TO_PBUFFER_ARB;
iattributes[2*niattribs+1] = true;
niattribs++;
// We require a minimum of 24-bit depth.
iattributes[2*niattribs ] = WGL_DEPTH_BITS_ARB;
iattributes[2*niattribs+1] = 24;
niattribs++;
// We require a minimum of 8-bits for each R, G, B, and A.
iattributes[2*niattribs ] = WGL_RED_BITS_ARB;
iattributes[2*niattribs+1] = 8;
niattribs++;
iattributes[2*niattribs ] = WGL_GREEN_BITS_ARB;
iattributes[2*niattribs+1] = 8;
niattribs++;
iattributes[2*niattribs ] = WGL_BLUE_BITS_ARB;
iattributes[2*niattribs+1] = 8;
niattribs++;
iattributes[2*niattribs ] = WGL_ALPHA_BITS_ARB;
iattributes[2*niattribs+1] = 8;
niattribs++;
// Now obtain a list of pixel formats that meet these minimum
// requirements.
int pformat[MAX_PFORMATS];
memset(pformat, 0, sizeof(pformat));
unsigned int nformats = 0;
if (!wglgsg->_wglChoosePixelFormatARB(_window_dc, iattributes, fattributes,
MAX_PFORMATS, pformat, &nformats)) {
cerr << "pbuffer creation error: Couldn't find a suitable pixel format.\n";
} else {
cerr << "Found " << nformats << " formats, selecting " << pformat[0] << "\n";
pbformat = pformat[0];
}
}
HPBUFFERARB _pbuffer;
wglMakeCurrent(_window_dc, wglgsg->get_context(_window_dc));
wglgsg->reset_if_new();
cerr << "Creating pbuffer(" << _window_dc << ", " << wglgsg->get_pfnum()
<< ", " << _x_size << ", " << _y_size << ", ...)\n";
int attrib_list[] = {
0,
};
HDC hdc = wglGetCurrentDC();
cerr << "current dc = " << hdc << " window dc = " << _window_dc << "\n";
_pbuffer = wglgsg->_wglCreatePbufferARB(hdc, pbformat,
_x_size, _y_size, attrib_list);
cerr << "pbuffer = " << (void *)_pbuffer << "\n";
if (_pbuffer == NULL) {
wgldisplay_cat.error()
<< "Attempt to create pbuffer failed.\n";
}
*/

View File

@ -57,6 +57,8 @@ protected:
private:
bool make_window();
bool make_pbuffer();
static void process_1_event();
static void register_window_class();
@ -64,6 +66,8 @@ private:
HWND _window;
HDC _window_dc;
HPBUFFERARB _pbuffer;
HDC _pbuffer_dc;
static const char * const _window_class_name;
static bool _window_class_registered;