diff --git a/source/renderer/PBuffer.cpp b/source/renderer/PBuffer.cpp new file mode 100755 index 0000000000..e07847327b --- /dev/null +++ b/source/renderer/PBuffer.cpp @@ -0,0 +1,385 @@ +#include "pbuffer.h" + +#ifdef _WIN32 +#include +#include +#include +#include + +static HDC lastDC; +static HGLRC lastGLRC; + +static bool GotExts=false; +static PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB=0; +static PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB=0; +static PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB=0; +static PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB=0; +static PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB=0; +static PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB=0; +static PFNWGLGETPIXELFORMATATTRIBFVARBPROC wglGetPixelFormatAttribfvARB=0; +static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB=0; + +class PBuffer +{ +public: + enum { MAX_ATTRIBS = 32 }; + enum { MAX_PFORMATS = 256 }; + + PBuffer(); + ~PBuffer(); + + void makeCurrent(); + + bool init(int width,int height,int doublebuffer,int colorbits,int depthbits,int stencilbits, + int rendertextureformat=0,int rendertexturetarget=0,int havemipmaps=0); + void close(); + + // return width,height of this pbuffer + int GetWidth() const { return _width; } + int GetHeight() const { return _height; } + +private: + HDC _hDC; + HGLRC _hGLRC; + HPBUFFERARB _hBuffer; + int _width; + int _height; + int _doublebuffer; + int _colorbits; + int _depthbits; + int _stencilbits; + int _rendertextureformat; + int _rendertexturetarget; + int _havemipmaps; +}; + +static PBuffer g_PBuffer; + +PBuffer::PBuffer() + : _width(0), _height(0), _hDC(0), _hGLRC(0), _hBuffer(0) +{ +} + +PBuffer::~PBuffer() +{ + close(); +} + +void PBuffer::close() +{ + if (_hBuffer) { + wglDeleteContext(_hGLRC); + wglReleasePbufferDCARB(_hBuffer,_hDC); + wglDestroyPbufferARB(_hBuffer); + _hBuffer=0; + } +} + +static void GetExts() +{ + wglCreatePbufferARB=(PFNWGLCREATEPBUFFERARBPROC) wglGetProcAddress("wglCreatePbufferARB"); + wglGetPbufferDCARB=(PFNWGLGETPBUFFERDCARBPROC) wglGetProcAddress("wglGetPbufferDCARB"); + wglReleasePbufferDCARB=(PFNWGLRELEASEPBUFFERDCARBPROC) wglGetProcAddress("wglReleasePbufferDCARB"); + wglDestroyPbufferARB=(PFNWGLDESTROYPBUFFERARBPROC) wglGetProcAddress("wglDestroyPbufferARB"); + wglQueryPbufferARB=(PFNWGLQUERYPBUFFERARBPROC) wglGetProcAddress("wglQueryPbufferARB"); + wglGetPixelFormatAttribivARB=(PFNWGLGETPIXELFORMATATTRIBIVARBPROC) wglGetProcAddress("wglGetPixelFormatAttribivARB"); + wglGetPixelFormatAttribfvARB=(PFNWGLGETPIXELFORMATATTRIBFVARBPROC) wglGetProcAddress("wglGetPixelFormatAttribfvARB"); + wglChoosePixelFormatARB=(PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB"); + GotExts=true; +} + +// This function actually does the creation of the p-buffer. +// It can only be called once a window has already been created. +bool PBuffer::init(int width,int height,int doublebuffer,int colorbits,int depthbits,int stencilbits, + int rendertextureformat,int rendertexturetarget,int havemipmaps) +{ + if (!GotExts) { + GetExts(); + } + + // store requested parameters + _width=width; + _height=height; + _doublebuffer=doublebuffer; + _colorbits=colorbits; + _depthbits=depthbits; + _stencilbits=stencilbits; + _rendertextureformat=rendertextureformat; + _rendertexturetarget=rendertexturetarget; + _havemipmaps=havemipmaps; + + HDC hdc = wglGetCurrentDC(); + HGLRC hglrc = wglGetCurrentContext(); + + // build attributes + int iattributes[2*PBuffer::MAX_ATTRIBS]; + memset(iattributes,0,sizeof(int)*2*MAX_ATTRIBS); + float fattributes[2*PBuffer::MAX_ATTRIBS]; + memset(fattributes,0,sizeof(float)*2*MAX_ATTRIBS); + + int niattribs=0; + + // pixel format must be "p-buffer capable" .. + iattributes[2*niattribs] = WGL_DRAW_TO_PBUFFER_ARB; + iattributes[2*niattribs+1] = 1; + niattribs++; + + // .. use RGBA rather than index mode .. + iattributes[2*niattribs] = WGL_PIXEL_TYPE_ARB; + iattributes[2*niattribs+1] = WGL_TYPE_RGBA_ARB; + niattribs++; + + // .. setup double buffer .. + iattributes[2*niattribs] = WGL_DOUBLE_BUFFER_ARB; + iattributes[2*niattribs+1] = doublebuffer; + niattribs++; + + // .. setup color and alpha bits .. + iattributes[2*niattribs] = WGL_COLOR_BITS_ARB; + iattributes[2*niattribs+1] = colorbits; + niattribs++; + iattributes[2*niattribs] = WGL_ALPHA_BITS_ARB; + iattributes[2*niattribs+1] = (colorbits==32) ? 8 : 0; + niattribs++; + + // .. setup depth/stencil buffer .. + iattributes[2*niattribs] = WGL_DEPTH_BITS_ARB; + iattributes[2*niattribs+1] = depthbits; + niattribs++; + iattributes[2*niattribs] = WGL_STENCIL_BITS_ARB; + iattributes[2*niattribs+1] = stencilbits; + niattribs++; + + + // .. must support opengl (doh ..) + iattributes[2*niattribs] = WGL_SUPPORT_OPENGL_ARB; + iattributes[2*niattribs+1] = 1; + niattribs++; + + if (rendertextureformat!=0) { + // pbuffer meant to be bound as an RGBA texture, so need a color plane + iattributes[2*niattribs] = WGL_BIND_TO_TEXTURE_RGBA_ARB; + iattributes[2*niattribs+1] = 1; + niattribs++; + } + + int pformat[MAX_PFORMATS]; + unsigned int nformats; + if (!wglChoosePixelFormatARB(hdc,iattributes,fattributes,MAX_PFORMATS,pformat,&nformats)) { + // LOG << "PBuffer creation failed: wglChoosePixelFormatARB() returned 0\n"; + return false; + } + if (nformats<=0) { + // LOG << "PBuffer creation failed: couldn't find a suitable pixel format\n"; + return false; + } + + // Create the p-buffer. + niattribs=0; + memset(iattributes,0,sizeof(int)*2*MAX_ATTRIBS); + if (rendertextureformat!=0) { + + // set format + iattributes[2*niattribs]=WGL_TEXTURE_FORMAT_ARB; + iattributes[2*niattribs+1]=rendertextureformat; + niattribs++; + + // set target + iattributes[2*niattribs]=WGL_TEXTURE_TARGET_ARB; + iattributes[2*niattribs+1]=rendertexturetarget; + niattribs++; + + // mipmaps .. + iattributes[2*niattribs] = WGL_MIPMAP_TEXTURE_ARB; + iattributes[2*niattribs+1] = havemipmaps; + niattribs++; + + // ask to allocate the largest pbuffer it can, if it is + // unable to allocate for the width and height + iattributes[2*niattribs]=WGL_PBUFFER_LARGEST_ARB; + iattributes[2*niattribs+1]=0; + niattribs++; + + } + + _hBuffer=wglCreatePbufferARB(hdc,pformat[0],_width,_height,iattributes ); + if (!_hBuffer) { + // LOG << "PBuffer creation failed: wglCreatePbufferARB returned 0\n"; + return false; + } + + // Get the device context. + _hDC=wglGetPbufferDCARB(_hBuffer); + if (!_hDC) { + // LOG << "PBuffer creation failed: wglGetPbufferDCARB returned 0\n"; + return false; + } + + // Create a gl context for the p-buffer. + _hGLRC=wglCreateContext(_hDC); + if (!_hGLRC) { + // LOG << "PBuffer creation failed: wglCreateContext returned 0\n"; + return false; + } + + if(!wglShareLists(hglrc,_hGLRC)) { + // LOG << "PBuffer creation failed: wglShareLists returned 0\n"; + return false; + } + + // Determine the actual width and height we were able to create. + wglQueryPbufferARB(_hBuffer,WGL_PBUFFER_WIDTH_ARB,&_width); + wglQueryPbufferARB(_hBuffer,WGL_PBUFFER_HEIGHT_ARB,&_height); + + // success .. + // LOG << "PBuffer created: " << _width << " x " << _height << "\n"; + + // log out attributes of pbuffer's pixel format + int values[MAX_ATTRIBS]; + int iatr[MAX_ATTRIBS] = { WGL_PIXEL_TYPE_ARB, WGL_COLOR_BITS_ARB, + WGL_RED_BITS_ARB, WGL_GREEN_BITS_ARB, WGL_BLUE_BITS_ARB, + WGL_ALPHA_BITS_ARB, WGL_DEPTH_BITS_ARB, WGL_STENCIL_BITS_ARB, WGL_ACCUM_BITS_ARB, + WGL_DOUBLE_BUFFER_ARB, WGL_SUPPORT_OPENGL_ARB, WGL_ACCELERATION_ARB, + WGL_BIND_TO_TEXTURE_RGBA_ARB, WGL_SAMPLE_BUFFERS_ARB, WGL_SAMPLES_ARB + }; + + if (wglGetPixelFormatAttribivARB(hdc,pformat[0],0,15,iatr,values)) { + // LOG << "\nPBuffer pixelformat (" << pformat[0] << "):\n"; + + if (values[0]==WGL_TYPE_COLORINDEX_ARB) { + // LOG << " pixel type = WGL_TYPE_COLORINDEX_ARB\n"; + } else if (values[0]==WGL_TYPE_RGBA_ARB) { + // LOG << " pixel type = WGL_TYPE_RGBA_ARB\n"; + } else { + // LOG << " pixel type = UNKNOWN\n"; + } + + // LOG << " color bits = " << values[1] << "\n"; + // LOG << " red = " << values[2] << "\n"; + // LOG << " green = " << values[3] << "\n"; + // LOG << " blue = " << values[4] << "\n"; + // LOG << " alpha = " << values[5] << "\n"; + // LOG << " depth bits = " << values[6] << "\n"; + // LOG << " stencil bits = " << values[7] << "\n"; + // LOG << " accum bits = " << values[8] << "\n"; + // LOG << " doublebuffer = " << values[9] << "\n"; + // LOG << " support opengl = " << values[10] << "\n"; + + if (values[11]==WGL_FULL_ACCELERATION_ARB) { + // LOG << " acceleration = WGL_FULL_ACCELERATION_ARB\n"; + } else if (values[11]== WGL_GENERIC_ACCELERATION_ARB) { + // LOG << " acceleration = WGL_GENERIC_ACCELERATION_ARB\n"; + } else { + // LOG << " acceleration = UNKNOWN\n"; + } + + // LOG << " bind to texture = " << values[12] << "\n\n"; + // LOG << " multisample = " << values[13] << "\n"; + if (values[13]) { + // LOG << " sample buffers = " << values[14] << "\n\n"; + } + } + + return true; +} + +void PBuffer::makeCurrent() +{ + lastGLRC=wglGetCurrentContext(); + lastDC=wglGetCurrentDC(); + + // check first for lost pbuffer + int lost; + wglQueryPbufferARB(_hBuffer,WGL_PBUFFER_LOST_ARB,&lost); + + if (lost) { + // ack .. have to recreate it .. + close(); + if (!init(_width,_height,_doublebuffer,_colorbits,_depthbits,_stencilbits, + _rendertextureformat,_rendertexturetarget,_havemipmaps)) { + // oops .. couldn't rebuild it .. + // LOG << "PBuffer lost; couldn't rebuild"; + return; + } + } + + if (!wglMakeCurrent(_hDC,_hGLRC)) { + // LOG << "PBuffer::makeCurrent - failed to make pbuffer current"; + } +} + +void PBufferMakeCurrent() +{ + g_PBuffer.makeCurrent(); +} + + +bool isWGLExtensionSupported(const char *extension) +{ + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB=(PFNWGLGETEXTENSIONSSTRINGARBPROC) wglGetProcAddress("wglGetExtensionsStringARB"); + if (!wglGetExtensionsStringARB) { + // no function to retrieve WGL extension : maybe worth looking in the regular extensions .. + return false; + } + + static const char *extensions = NULL; + const char *start; + char *where, *terminator; + + where = (char *) strchr(extension, ' '); + if ((where) || (*extension == '\0')) + return false; + + if (!extensions) + extensions = (const char *) wglGetExtensionsStringARB(wglGetCurrentDC()); + + start = extensions; + for (;;) { + where = (char *) strstr((const char *) start, extension); + if (!where) + break; + + terminator = where + strlen(extension); + if (where == start || *(where - 1) == ' ') { + if (*terminator == ' ' || *terminator == '\0') { + return true; + } + } + + start = terminator; + } + + return false; +} + +void PBufferInit(int width,int height,int doublebuffer,int colorbits,int depthbits,int stencilbits, + int rendertextureformat,int rendertexturetarget,int havemipmaps) +{ + g_PBuffer.init(width,height,doublebuffer,colorbits,depthbits,stencilbits, + rendertextureformat,rendertexturetarget,havemipmaps); +} + +void PBufferClose() +{ + g_PBuffer.close(); + +} + +void PBufferMakeUncurrent() +{ + wglMakeCurrent(lastDC,lastGLRC); +} + +int PBufferWidth() +{ + return g_PBuffer.GetWidth(); +} + +#endif + +bool PBufferQuery() +{ + if (!isWGLExtensionSupported("WGL_ARB_pbuffer")) return false; + if (!isWGLExtensionSupported("WGL_ARB_pixel_format")) return false; + return true; +} diff --git a/source/renderer/PBuffer.h b/source/renderer/PBuffer.h new file mode 100755 index 0000000000..d70021f07e --- /dev/null +++ b/source/renderer/PBuffer.h @@ -0,0 +1,12 @@ +#ifndef _PBUFFER_H +#define _PBUFFER_H + + +extern void PBufferMakeCurrent(); +extern void PBufferInit(int width,int height,int doublebuffer,int colorbits,int depthbits,int stencilbits, + int rendertextureformat=0,int rendertexturetarget=0,int havemipmaps=0); +extern void PBufferClose(); +extern void PBufferMakeUncurrent(); +extern int PBufferWidth(); + +#endif