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

WGLPBufferStreams.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 <iostream>
00028 #include <sstream>
00029 
00030 #include "ShError.hpp"
00031 #include "ShEnvironment.hpp"
00032 #include "WGLPBufferStreams.hpp"
00033 
00034 namespace shgl {
00035 
00036   using namespace SH;
00037 
00038   class WGLPBufferStreamException: public ShException
00039     {
00040     public:
00041       WGLPBufferStreamException(const std::string& message) :
00042         ShException("WGL PBuffer Stream Execution: " + message)
00043         {
00044         }
00045     };
00046 
00047   WGLPBufferStreams::WGLPBufferStreams(void) :
00048     m_orig_hdc(NULL),
00049     m_orig_hglrc(NULL)
00050     {
00051     }
00052 
00053   WGLPBufferStreams::~WGLPBufferStreams()
00054     {
00055     }
00056 
00057   StreamStrategy* WGLPBufferStreams::create(void)
00058     {
00059     return new WGLPBufferStreams;
00060     }
00061 
00062   FloatExtension WGLPBufferStreams::setupContext(int width, int height)
00063     {
00064     // Grab the current DC and context, this will need to be
00065     // restored after the pbuffer work has been completed. If
00066     // there is no DC then we need to create one, the subsequent
00067     // WGL calls need a suitable DC to bootstrap the pbuffer
00068     // creation. 
00069     // TODO: cleanup this hackery. I assume the a that "DISPLAY"
00070     // DC is suitable enough for the subsequent WGL stuffs, but
00071     // the Win32 documentation doesn't say one way or another if
00072     // this is the "right" thing. Should the HWND/HDC/HGLRC that
00073     // is being used in GlBackend::GlBackend be kept around so
00074     // this code doesn't need any special cases (see comments
00075     // in GlBackend.cpp)?
00076     bool delete_dc = false;
00077     m_orig_hdc = wglGetCurrentDC();
00078     if (m_orig_hdc == NULL)
00079       {
00080       delete_dc = true;
00081       m_orig_hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
00082       if (m_orig_hdc == NULL)
00083         {
00084         std::stringstream msg;
00085         msg << "CreateDC failed (" << GetLastError() << ")";
00086         shError(WGLPBufferStreamException(msg.str()));
00087         }
00088       }
00089     else
00090       {
00091       m_orig_hglrc = wglGetCurrentContext();
00092       }
00093 
00094     // search the crrent list of pbuffers for an applicable one
00095     ShWGLPBufferInfo match;
00096     for(std::list<ShWGLPBufferInfo>::iterator itr = m_infos.begin();
00097               itr != m_infos.end();
00098               itr++)
00099       {
00100       if ((*itr).valid() && (*itr).width == width && (*itr).height == height)
00101               {
00102               match = (*itr);
00103               break;
00104               }
00105       }
00106 
00107     // if a valid match wasn't found then create a new
00108     // context and add it to the list of infos
00109     if (!match.valid())
00110       {
00111       match = createContext(width, height);
00112       m_infos.push_back(match);
00113       }
00114 
00115     // Activate the pbuffer/context 
00116     if (!wglMakeCurrent(match.pbuffer_hdc, match.pbuffer_hglrc))
00117       {
00118       wglReleasePbufferDCARB(match.pbuffer, match.pbuffer_hdc);
00119       wglDestroyPbufferARB(match.pbuffer);
00120       wglDeleteContext(match.pbuffer_hglrc);
00121 
00122       match.pbuffer = NULL;
00123       match.pbuffer_hdc = NULL;
00124       match.pbuffer_hglrc = NULL;
00125 
00126       std::stringstream msg;
00127       msg << "wglMakeCurrent failed (" << GetLastError() << ")";
00128       shError(WGLPBufferStreamException(msg.str()));
00129       }
00130 
00131     // If we had to create the DC (see above) then delete it.
00132     // TODO: cleanup this hackery (see above)
00133     if (delete_dc)
00134       {
00135       DeleteDC(m_orig_hdc);
00136       m_orig_hdc = NULL;
00137       }
00138 
00139     return match.extension;
00140     }
00141 
00142   void WGLPBufferStreams::restoreContext(void)
00143     {
00144     if (m_orig_hdc != NULL && m_orig_hglrc != NULL)
00145       {
00146       if (!wglMakeCurrent(m_orig_hdc, m_orig_hglrc))
00147         {
00148         std::stringstream msg;
00149         msg << "wglMakeCurrent failed (" << GetLastError() << ")";
00150         shError(WGLPBufferStreamException(msg.str()));
00151         }
00152       else
00153         {
00154         m_orig_hdc = NULL;
00155         m_orig_hglrc = NULL;
00156         }
00157       }
00158     }
00159 
00160   ShWGLPBufferInfo WGLPBufferStreams::createContext(int width, int height)
00161     {
00162     ShWGLPBufferInfo ret;
00163     ret.width = width;
00164     ret.height = height;
00165 
00166     int nfattribs = 0;
00167     int niattribs = 0;
00168 
00169     std::vector<int> fb_base_attribs;
00170     fb_base_attribs.push_back(WGL_DOUBLE_BUFFER_ARB); fb_base_attribs.push_back(false);
00171     fb_base_attribs.push_back(WGL_RED_BITS_ARB); fb_base_attribs.push_back(32);
00172     fb_base_attribs.push_back(WGL_GREEN_BITS_ARB); fb_base_attribs.push_back(32);
00173     fb_base_attribs.push_back(WGL_BLUE_BITS_ARB); fb_base_attribs.push_back(32);
00174     fb_base_attribs.push_back(WGL_DRAW_TO_PBUFFER_ARB); fb_base_attribs.push_back(true);
00175     fb_base_attribs.push_back(WGL_SUPPORT_OPENGL_ARB); fb_base_attribs.push_back(true);
00176   
00177     bool found_pixelformat = false;
00178     int format = 0;
00179 
00180     // Try NVIDIA
00181     if (!found_pixelformat)
00182       {
00183       std::vector<int> fb_attribs(fb_base_attribs);
00184 
00185       fb_attribs.push_back(WGL_PIXEL_TYPE_ARB); fb_attribs.push_back(WGL_TYPE_RGBA_ARB);
00186       fb_attribs.push_back(WGL_FLOAT_COMPONENTS_NV); fb_attribs.push_back(true);
00187       fb_attribs.push_back(0);
00188     
00189       unsigned int nformats = 0;
00190       if (!wglChoosePixelFormatARB(m_orig_hdc, &fb_attribs[0], NULL, 1, &format, &nformats))
00191         {
00192         SH_DEBUG_WARN("wglChoosePixelFormatARB failed (" << GetLastError() << ")");
00193         }
00194 
00195       if (nformats > 0)
00196         {
00197         found_pixelformat = true;
00198         ret.extension = SH_ARB_NV_FLOAT_BUFFER;
00199         }
00200       }
00201 
00202     // Try ATI
00203     if (!found_pixelformat)
00204       {
00205       std::vector<int> fb_attribs(fb_base_attribs);
00206 
00207       fb_attribs.push_back(WGL_PIXEL_TYPE_ARB); fb_attribs.push_back(WGL_TYPE_RGBA_FLOAT_ATI);
00208       fb_attribs.push_back(0);
00209     
00210       unsigned int nformats = 0;
00211       if (!wglChoosePixelFormatARB(m_orig_hdc, &fb_attribs[0], NULL, 1, &format, &nformats))
00212         {
00213         SH_DEBUG_WARN("wglChoosePixelFormatARB failed (" << GetLastError() << ")");
00214         }
00215 
00216       if (nformats > 0)
00217         {
00218         found_pixelformat = true;
00219         ret.extension = SH_ARB_ATI_PIXEL_FORMAT_FLOAT;
00220         }
00221       }
00222 
00223     if (!found_pixelformat)
00224       {
00225       shError(WGLPBufferStreamException("Could not find appropriate pixel format!"));
00226       }
00227 
00228     if (ret.extension == SH_ARB_NO_FLOAT_EXT)
00229       {
00230       shError(WGLPBufferStreamException("Could not choose a floating-point extension!"));
00231       }
00232 
00233     // Set up the pbuffer
00234     int pbuffer_attribs[] = {
00235       WGL_PBUFFER_LARGEST_ARB, false,
00236       0
00237     };
00238 
00239     // TODO: It seems that on windows with ATI cards small pbuffers produce
00240     // bad results in the first few pixels of the image. I've found that making
00241     // atleast an 8x8 pbuffer alleviates this. Some further testing is needed
00242     // and possible a better work around. -Kevin
00243     int temp_width = std::max(ret.width, 8);
00244     int temp_height = std::max(ret.height, 8);
00245 
00246     ret.pbuffer = wglCreatePbufferARB(m_orig_hdc, format, temp_width, temp_height, pbuffer_attribs);
00247     if (ret.pbuffer == NULL)
00248       {
00249       std::stringstream msg;
00250       msg << "wglCreatePbufferARB failed (" << GetLastError() << ")";
00251       shError(WGLPBufferStreamException(msg.str()));
00252       }
00253 
00254     ret.pbuffer_hdc = wglGetPbufferDCARB(ret.pbuffer);
00255     if (ret.pbuffer_hdc == NULL)
00256       {
00257       wglDestroyPbufferARB(ret.pbuffer);
00258 
00259       ret.pbuffer = NULL;
00260 
00261       std::stringstream msg;
00262       msg << "wglGetPbufferDCARB failed (" << GetLastError() << ")";
00263       shError(WGLPBufferStreamException(msg.str()));
00264       }
00265 
00266     // Create a new gl context for the p-buffer.
00267     ret.pbuffer_hglrc = wglCreateContext(ret.pbuffer_hdc);
00268     if (ret.pbuffer_hglrc == NULL)
00269       {
00270       wglReleasePbufferDCARB(ret.pbuffer, ret.pbuffer_hdc);
00271       wglDestroyPbufferARB(ret.pbuffer);
00272 
00273       ret.pbuffer = NULL;
00274       ret.pbuffer_hdc = NULL;
00275 
00276       std::stringstream msg;
00277       msg << "wglCreateContext failed (" << GetLastError() << ")";
00278       shError(WGLPBufferStreamException(msg.str()));
00279       }
00280 
00281     return ret;
00282     }
00283 
00284 }

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