Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

GlBackend.cpp

00001 // Sh: A GPU metaprogramming language.
00002 //
00003 // Copyright (c) 2003 University of Waterloo Computer Graphics Laboratory
00004 // Project administrator: Michael D. McCool
00005 // Authors: Zheng Qin, Stefanus Du Toit, Kevin Moule, Tiberiu S. Popa,
00006 //          Michael D. McCool
00007 // 
00008 // This software is provided 'as-is', without any express or implied
00009 // warranty. In no event will the authors be held liable for any damages
00010 // arising from the use of this software.
00011 // 
00012 // Permission is granted to anyone to use this software for any purpose,
00013 // including commercial applications, and to alter it and redistribute it
00014 // freely, subject to the following restrictions:
00015 // 
00016 // 1. The origin of this software must not be misrepresented; you must
00017 // not claim that you wrote the original software. If you use this
00018 // software in a product, an acknowledgment in the product documentation
00019 // would be appreciated but is not required.
00020 // 
00021 // 2. Altered source versions must be plainly marked as such, and must
00022 // not be misrepresented as being the original software.
00023 // 
00024 // 3. This notice may not be removed or altered from any source
00025 // distribution.
00027 #include "GlBackend.hpp"
00028 #include "ShDebug.hpp"
00029 #include "ShError.hpp"
00030 
00031 #include <sstream>
00032 
00033 #ifdef WIN32
00034 
00035 PFNGLPROGRAMSTRINGARBPROC glProgramStringARB = 0;
00036 PFNGLBINDPROGRAMARBPROC glBindProgramARB = 0;
00037 PFNGLGENPROGRAMSARBPROC glGenProgramsARB = 0;
00038 PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = 0;
00039 PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB = 0;
00040 PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB = 0;
00041 PFNGLGETPROGRAMIVARBPROC glGetProgramivARB = 0;
00042 
00043 PFNGLTEXIMAGE3DPROC glTexImage3D = 0;
00044 PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D = 0;
00045 
00046 // WGL_ARB_pixel_format
00047 PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB = 0;
00048 PFNWGLGETPIXELFORMATATTRIBFVARBPROC wglGetPixelFormatAttribfvARB = 0;
00049 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = 0;
00050 
00051 // WGL_ARB_pbuffer
00052 PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB = 0;
00053 PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB = 0;
00054 PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB = 0;
00055 PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB = 0;
00056 PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB = 0;
00057 
00058 #endif /* WIN32 */
00059 
00060 namespace shgl {
00061 
00062 using namespace SH;
00063 
00064 #ifdef WIN32
00065 LRESULT CALLBACK shGlWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00066   {
00067   // An empty WindowProc, we need one to create a window. For now
00068   // just pass everything through DefWindowProc.
00069   // TODO: Should we actually process any messages? There will
00070   // definitely be atleast a WM_CREATE coming through here and
00071   // maybe some others.
00072   return DefWindowProc(hWnd, uMsg, wParam, lParam);
00073   }
00074 #endif /* WIN32 */
00075 
00076 void shGlCheckError(const char* desc, const char* file, int line)
00077 {
00078   GLenum errnum = glGetError();
00079   char* error = 0;
00080   switch (errnum) {
00081   case GL_NO_ERROR:
00082     return;
00083   case GL_INVALID_ENUM:
00084     error = "GL_INVALID_ENUM";
00085     break;
00086   case GL_INVALID_VALUE:
00087     error = "GL_INVALID_VALUE";
00088     break;
00089   case GL_INVALID_OPERATION:
00090     error = "GL_INVALID_OPERATION";
00091     break;
00092   case GL_STACK_OVERFLOW:
00093     error = "GL_STACK_OVERFLOW";
00094     break;
00095   case GL_STACK_UNDERFLOW:
00096     error = "GL_STACK_UNDERFLOW";
00097     break;
00098   case GL_OUT_OF_MEMORY:
00099     error = "GL_OUT_OF_MEMORY";
00100     break;
00101   case GL_TABLE_TOO_LARGE:
00102     error = "GL_TABLE_TOO_LARGE";
00103     break;
00104   default:
00105     error = "Unknown error!";
00106     break;
00107   }
00108   SH_DEBUG_PRINT("GL ERROR on " << file << ": " <<line<<": "<< error);
00109   SH_DEBUG_PRINT("GL ERROR call: " << desc);
00110 }
00111 
00112 #ifdef WIN32
00113 #define GET_WGL_PROCEDURE(x, T) \
00114 if ((x = reinterpret_cast<PFN ## T ## PROC>(wglGetProcAddress(#x))) == NULL) \
00115   { \
00116   std::stringstream msg; \
00117   msg << "wglGetProcAddress failed (" << GetLastError() << ")"; \
00118   shError(ShException(msg.str())); \
00119   }
00120 #endif /* WIN32 */
00121 
00122 GlBackend::GlBackend(CodeStrategy* code, TextureStrategy* texture, StreamStrategy* stream) :
00123   m_code(code),
00124   m_texture(texture),
00125   m_stream(stream)
00126   {
00127 
00128 #ifdef WIN32
00129   // wglGetProcessAddress will fail outright if there isn't a current
00130   // context. So, If there isn't a current context we need to create one.
00131   // To create a context we need just one thing, an HDC. But not just
00132   // any HDC, an HDC that can be assigned an accelerated pixel format and
00133   // subsequently bound to an OpenGL context. Creating a "DISPLAY" DC
00134   // (via CreateDC) can have its pixel format set, but is incapable of
00135   // being assigned to an HGLRC. A memory DC (via CreateCompatibleDC) is
00136   // only good for PFD_DRAW_TO_BITMAP pixel formats which are inherently
00137   // not accelerated (and then all the wglGetProcAddress fail because
00138   // its not the ICD driver). The only solution seems to be creating an
00139   // actual window which gets us a real HDC. The window is temporary and
00140   // only exist long enough to fetch the functions needed. 
00141   // TODO: cleanup this hackery. I try to create a simple a window as 
00142   // possible to just get an HDC, the Win32 documentation is a little
00143   // sparse on what the requirements are (i.e settings for dwStyle,
00144   // WNDCLASSEX, PIXELFORMATDESCRIPTOR, etc). Should this window perhaps
00145   // be kept around for the lifetime of the GlBackend? It would simplify
00146   // the pbuffer code. What are the implications of having a hidden window
00147   // lying around, what about the event loop and shGlWindowProc. How does
00148   // this interact with a UI toolkit. If someone loads the backend before
00149   // initializing glut does this stuff conflict with the WGL stuff done 
00150   // by GLUT. The documentation explicit states that "extension function
00151   // addresses are unique for each pixel format", a little troubling, although
00152   // I'm not sure I believe it.
00153   HWND hWnd = NULL;
00154   HDC hdc = wglGetCurrentDC();
00155   HGLRC hglrc = wglGetCurrentContext();
00156   if (hdc == NULL && hglrc == NULL)
00157     {
00158     WNDCLASSEX wc;
00159     ZeroMemory(&wc, sizeof (WNDCLASSEX));
00160     wc.cbSize = sizeof(WNDCLASSEX);
00161     wc.style = 0;
00162     wc.lpfnWndProc = shGlWindowProc;
00163     wc.cbClsExtra = 0;
00164     wc.cbWndExtra = 0;
00165     wc.hInstance = NULL;
00166     wc.hIcon = NULL;
00167     wc.hCursor = NULL;
00168     wc.hbrBackground = NULL;
00169     wc.lpszMenuName = NULL;
00170     wc.lpszClassName = "shGlWindow";
00171     wc.hIconSm = NULL;
00172 
00173     if (!RegisterClassEx(&wc))
00174       {
00175       std::stringstream msg;
00176       msg << "RegisterClassEx failed (" << GetLastError() << ")";
00177       shError(ShException(msg.str()));
00178       }
00179 
00180     hWnd = CreateWindowEx(0, "shGlWindow", "shGlWindow", WS_POPUP,
00181                           CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
00182                           NULL, NULL, NULL, NULL);
00183 
00184     if (hWnd == NULL)
00185       {
00186       std::stringstream msg;
00187       msg << "CreateWindowEx failed (" << GetLastError() << ")";
00188       shError(ShException(msg.str()));
00189       }
00190 
00191     hdc = GetDC(hWnd);
00192     if (hdc == NULL)
00193       {
00194       DestroyWindow(hWnd);
00195 
00196       std::stringstream msg;
00197       msg << "GetDC failed (" << GetLastError() << ")";
00198       shError(ShException(msg.str()));
00199       }
00200 
00201           PIXELFORMATDESCRIPTOR pfd;
00202           ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
00203           pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
00204           pfd.nVersion = 1;
00205           pfd.dwFlags = PFD_SUPPORT_OPENGL;
00206           pfd.iPixelType = PFD_TYPE_RGBA;
00207     pfd.iLayerType = PFD_MAIN_PLANE;
00208 
00209           int pf = ChoosePixelFormat(hdc, &pfd);
00210     if (pf == 0)
00211       {
00212       std::stringstream msg;
00213       msg << "ChoosePixelFormat failed (" << GetLastError() << ")";
00214       shError(ShException(msg.str()));
00215       }
00216 
00217           if (!SetPixelFormat(hdc, pf, &pfd))
00218       {
00219       std::stringstream msg;
00220       msg << "SetPixelFormat failed (" << GetLastError() << ")";
00221       shError(ShException(msg.str()));
00222       }
00223 
00224     hglrc = wglCreateContext(hdc);
00225     if (hglrc == NULL)
00226       {
00227       ReleaseDC(hWnd, hdc);
00228       DestroyWindow(hWnd);
00229 
00230       std::stringstream msg;
00231       msg << "wglCreateContext failed (" << GetLastError() << ")";
00232       shError(ShException(msg.str()));
00233       }
00234 
00235     if (!wglMakeCurrent(hdc, hglrc))
00236       {
00237       wglDeleteContext(hglrc);
00238       ReleaseDC(hWnd, hdc);
00239       DestroyWindow(hWnd);
00240 
00241       std::stringstream msg;
00242       msg << "wglMakeCurrent failed (" << GetLastError() << ")";
00243       shError(ShException(msg.str()));
00244       }
00245     }
00246   else
00247     {
00248     hdc = NULL;
00249     hglrc = NULL;
00250     }
00251 
00252   GET_WGL_PROCEDURE(glProgramStringARB, GLPROGRAMSTRINGARB);
00253   GET_WGL_PROCEDURE(glBindProgramARB, GLBINDPROGRAMARB);
00254   GET_WGL_PROCEDURE(glGenProgramsARB, GLGENPROGRAMSARB);
00255   GET_WGL_PROCEDURE(glActiveTextureARB, GLACTIVETEXTUREARB);
00256   GET_WGL_PROCEDURE(glProgramEnvParameter4fvARB, GLPROGRAMENVPARAMETER4FVARB);
00257   GET_WGL_PROCEDURE(glProgramLocalParameter4fvARB, GLPROGRAMLOCALPARAMETER4FVARB);
00258   GET_WGL_PROCEDURE(glGetProgramivARB, GLGETPROGRAMIVARB);
00259 
00260   GET_WGL_PROCEDURE(glTexImage3D, GLTEXIMAGE3D);
00261   GET_WGL_PROCEDURE(glTexSubImage3D, GLTEXSUBIMAGE3D);
00262 
00263   // WGL_ARB_pixel_format
00264   GET_WGL_PROCEDURE(wglGetPixelFormatAttribivARB, WGLGETPIXELFORMATATTRIBIVARB);
00265   GET_WGL_PROCEDURE(wglGetPixelFormatAttribfvARB, WGLGETPIXELFORMATATTRIBFVARB);
00266   GET_WGL_PROCEDURE(wglChoosePixelFormatARB, WGLCHOOSEPIXELFORMATARB);
00267 
00268   // WGL_ARB_pbuffer
00269   GET_WGL_PROCEDURE(wglCreatePbufferARB, WGLCREATEPBUFFERARB);
00270   GET_WGL_PROCEDURE(wglGetPbufferDCARB, WGLGETPBUFFERDCARB);
00271   GET_WGL_PROCEDURE(wglReleasePbufferDCARB, WGLRELEASEPBUFFERDCARB);
00272   GET_WGL_PROCEDURE(wglDestroyPbufferARB, WGLDESTROYPBUFFERARB);
00273   GET_WGL_PROCEDURE(wglQueryPbufferARB, WGLQUERYPBUFFERARB);
00274 
00275   if (hWnd)
00276     {
00277     wglMakeCurrent(NULL, NULL);
00278     ReleaseDC(hWnd, hdc);
00279     wglDeleteContext(hglrc);
00280     DestroyWindow(hWnd);
00281     }
00282   
00283 #endif /* WIN32 */
00284   }
00285 
00286 SH::ShBackendCodePtr
00287 GlBackend::generateCode(const std::string& target,
00288                         const SH::ShProgramNodeCPtr& shader)
00289 {
00290   return m_code->generate(target, shader, m_texture);
00291 }
00292 
00293 void
00294 GlBackend::execute(const SH::ShProgramNodeCPtr& program,
00295                    SH::ShStream& dest)
00296 {
00297  m_stream->execute(program, dest);
00298 }
00299 
00300 }

Generated on Mon Jan 24 18:36:29 2005 for Sh by  doxygen 1.4.1