CmWin32GLSupport.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. #include "CmWin32GLSupport.h"
  2. #include "CmGLTexture.h"
  3. #include "CmWin32Window.h"
  4. #include "CmGLRenderSystem.h"
  5. #include "CmWin32Context.h"
  6. #include "CmException.h"
  7. #include "GL/wglew.h"
  8. #include <algorithm>
  9. GLenum __stdcall wglewContextInit (BansheeEngine::GLSupport *glSupport);
  10. namespace BansheeEngine
  11. {
  12. template<class C> void remove_duplicates(C& c)
  13. {
  14. std::sort(c.begin(), c.end());
  15. typename C::iterator p = std::unique(c.begin(), c.end());
  16. c.erase(p, c.end());
  17. }
  18. Win32GLSupport::Win32GLSupport()
  19. : mInitialWindow(0), mHasPixelFormatARB(false), mHasMultisample(false),
  20. mHasHardwareGamma(false), mHasAdvancedContext(false)
  21. {
  22. initialiseWGL();
  23. }
  24. RenderWindowPtr Win32GLSupport::newWindow(RENDER_WINDOW_DESC& desc, RenderWindowPtr parentWindow)
  25. {
  26. if(parentWindow != nullptr)
  27. {
  28. HWND hWnd;
  29. parentWindow->getCustomAttribute("WINDOW", &hWnd);
  30. desc.platformSpecific["parentWindowHandle"] = toString((UINT64)hWnd);
  31. }
  32. Win32Window* window = new (cm_alloc<Win32Window, PoolAlloc>()) Win32Window(desc, *this);
  33. if(!mInitialWindow)
  34. mInitialWindow = window;
  35. return RenderWindowPtr(window, &CoreObject::_deleteDelayed<Win32Window, PoolAlloc>);
  36. }
  37. void Win32GLSupport::start()
  38. {
  39. }
  40. void Win32GLSupport::stop()
  41. {
  42. mInitialWindow = nullptr;
  43. }
  44. void Win32GLSupport::initialiseExtensions()
  45. {
  46. assert(mInitialWindow != nullptr);
  47. GLSupport::initialiseExtensions();
  48. wglewContextInit(this);
  49. // Check for W32 specific extensions probe function
  50. PFNWGLGETEXTENSIONSSTRINGARBPROC _wglGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsString");
  51. if(_wglGetExtensionsString == nullptr)
  52. return;
  53. const char *wgl_extensions = _wglGetExtensionsString(mInitialWindow->_getHDC());
  54. // Parse them, and add them to the main list
  55. StringStream ext;
  56. String instr;
  57. ext << wgl_extensions;
  58. while(ext >> instr)
  59. {
  60. extensionList.insert(instr);
  61. }
  62. }
  63. Win32Context* Win32GLSupport::createContext(HDC hdc, HGLRC externalGlrc)
  64. {
  65. GLRenderSystem* rs = static_cast<GLRenderSystem*>(RenderSystem::instancePtr());
  66. // If RenderSystem has initialized a context use that, otherwise we create our own
  67. HGLRC glrc = externalGlrc;
  68. bool createdNew = false;
  69. if (!rs->isContextInitialized())
  70. {
  71. if (externalGlrc == 0)
  72. {
  73. if (mHasAdvancedContext)
  74. {
  75. int attribs[40];
  76. int i = 0;
  77. attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
  78. attribs[i++] = 4;
  79. attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB;
  80. attribs[i++] = 3;
  81. attribs[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
  82. attribs[i++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
  83. #if CM_DEBUG_MODE
  84. attribs[i++] = WGL_CONTEXT_FLAGS_ARB;
  85. attribs[i++] = WGL_CONTEXT_DEBUG_BIT_ARB;
  86. #endif
  87. attribs[i++] = 0;
  88. glrc = wglCreateContextAttribsARB(hdc, 0, attribs);
  89. }
  90. else
  91. glrc = wglCreateContext(hdc);
  92. if (glrc == 0)
  93. CM_EXCEPT(RenderingAPIException, "wglCreateContext failed: " + translateWGLError());
  94. createdNew = true;
  95. }
  96. }
  97. else
  98. {
  99. rs->getMainContext()->setCurrent();
  100. glrc = wglGetCurrentContext();
  101. }
  102. return cm_new<Win32Context>(hdc, glrc, createdNew);
  103. }
  104. void* Win32GLSupport::getProcAddress(const String& procname)
  105. {
  106. return (void*)wglGetProcAddress(procname.c_str());
  107. }
  108. void Win32GLSupport::initialiseWGL()
  109. {
  110. // We need to create a dummy context in order to get functions
  111. // that allow us to create a more advanced context. It seems
  112. // hacky but that's the only way to do it.
  113. LPCSTR dummyText = "Dummy";
  114. #ifdef CM_STATIC_LIB
  115. HINSTANCE hinst = GetModuleHandle(NULL);
  116. #else
  117. HINSTANCE hinst = GetModuleHandle(MODULE_NAME.c_str());
  118. #endif
  119. WNDCLASS dummyClass;
  120. memset(&dummyClass, 0, sizeof(WNDCLASS));
  121. dummyClass.style = CS_OWNDC;
  122. dummyClass.hInstance = hinst;
  123. dummyClass.lpfnWndProc = dummyWndProc;
  124. dummyClass.lpszClassName = dummyText;
  125. RegisterClass(&dummyClass);
  126. HWND hwnd = CreateWindow(dummyText, dummyText, WS_POPUP | WS_CLIPCHILDREN,
  127. 0, 0, 32, 32, 0, 0, hinst, 0);
  128. if (hwnd == nullptr)
  129. CM_EXCEPT(RenderingAPIException, "CreateWindow() failed");
  130. HDC hdc = GetDC(hwnd);
  131. PIXELFORMATDESCRIPTOR pfd;
  132. memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
  133. pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
  134. pfd.nVersion = 1;
  135. pfd.cColorBits = 16;
  136. pfd.cDepthBits = 15;
  137. pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
  138. pfd.iPixelType = PFD_TYPE_RGBA;
  139. int format;
  140. if ((format = ChoosePixelFormat(hdc, &pfd)) != 0)
  141. SetPixelFormat(hdc, format, &pfd);
  142. HGLRC hrc = wglCreateContext(hdc);
  143. if (hrc)
  144. {
  145. HGLRC oldrc = wglGetCurrentContext();
  146. HDC oldhdc = wglGetCurrentDC();
  147. // if wglMakeCurrent fails, wglGetProcAddress will return null
  148. wglMakeCurrent(hdc, hrc);
  149. PFNWGLGETEXTENSIONSSTRINGARBPROC _wglGetExtensionsStringARB =
  150. (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
  151. PFNWGLCREATECONTEXTATTRIBSARBPROC _wglCreateContextAttribsARB =
  152. (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
  153. if (_wglCreateContextAttribsARB != nullptr)
  154. {
  155. WGLEW_GET_FUN(__wglewCreateContextAttribsARB) = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
  156. mHasAdvancedContext = true;
  157. }
  158. // Check for pixel format and multisampling support
  159. if (_wglGetExtensionsStringARB != nullptr)
  160. {
  161. std::istringstream wglexts(_wglGetExtensionsStringARB(hdc));
  162. String ext;
  163. while (wglexts >> ext)
  164. {
  165. if (ext == "WGL_ARB_pixel_format")
  166. mHasPixelFormatARB = true;
  167. else if (ext == "WGL_ARB_multisample")
  168. mHasMultisample = true;
  169. else if (ext == "WGL_EXT_framebuffer_sRGB")
  170. mHasHardwareGamma = true;
  171. }
  172. }
  173. if (mHasPixelFormatARB && mHasMultisample)
  174. {
  175. // Enumerate all formats w/ multisampling
  176. static const int iattr[] = {
  177. WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
  178. WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
  179. WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
  180. WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
  181. WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
  182. WGL_SAMPLES_ARB, 2,
  183. 0
  184. };
  185. int formats[256];
  186. unsigned int count;
  187. WGLEW_GET_FUN(__wglewChoosePixelFormatARB) = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
  188. if (WGLEW_GET_FUN(__wglewChoosePixelFormatARB)(hdc, iattr, 0, 256, formats, &count))
  189. {
  190. // determine what multisampling levels are offered
  191. int query = WGL_SAMPLES_ARB, samples;
  192. for (unsigned int i = 0; i < count; ++i)
  193. {
  194. PFNWGLGETPIXELFORMATATTRIBIVARBPROC _wglGetPixelFormatAttribivARB =
  195. (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
  196. wglGetProcAddress("wglGetPixelFormatAttribivARB");
  197. if (_wglGetPixelFormatAttribivARB(hdc, formats[i], 0, 1, &query, &samples))
  198. {
  199. mFSAALevels.push_back(samples);
  200. }
  201. }
  202. remove_duplicates(mFSAALevels);
  203. }
  204. }
  205. wglMakeCurrent(oldhdc, oldrc);
  206. wglDeleteContext(hrc);
  207. }
  208. // clean up our dummy window and class
  209. DestroyWindow(hwnd);
  210. UnregisterClass(dummyText, hinst);
  211. }
  212. LRESULT Win32GLSupport::dummyWndProc(HWND hwnd, UINT umsg, WPARAM wp, LPARAM lp)
  213. {
  214. return DefWindowProc(hwnd, umsg, wp, lp);
  215. }
  216. bool Win32GLSupport::selectPixelFormat(HDC hdc, int colourDepth, int multisample, bool hwGamma)
  217. {
  218. PIXELFORMATDESCRIPTOR pfd;
  219. memset(&pfd, 0, sizeof(pfd));
  220. pfd.nSize = sizeof(pfd);
  221. pfd.nVersion = 1;
  222. pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
  223. pfd.iPixelType = PFD_TYPE_RGBA;
  224. pfd.cColorBits = (colourDepth > 16)? 24 : colourDepth;
  225. pfd.cAlphaBits = (colourDepth > 16)? 8 : 0;
  226. pfd.cDepthBits = 24;
  227. pfd.cStencilBits = 8;
  228. int format = 0;
  229. int useHwGamma = hwGamma? GL_TRUE : GL_FALSE;
  230. if (multisample && (!mHasMultisample || !mHasPixelFormatARB))
  231. return false;
  232. if (hwGamma && !mHasHardwareGamma)
  233. return false;
  234. if ((multisample || hwGamma) && WGLEW_GET_FUN(__wglewChoosePixelFormatARB))
  235. {
  236. // Use WGL to test extended caps (multisample, sRGB)
  237. Vector<int> attribList;
  238. attribList.push_back(WGL_DRAW_TO_WINDOW_ARB); attribList.push_back(GL_TRUE);
  239. attribList.push_back(WGL_SUPPORT_OPENGL_ARB); attribList.push_back(GL_TRUE);
  240. attribList.push_back(WGL_DOUBLE_BUFFER_ARB); attribList.push_back(GL_TRUE);
  241. attribList.push_back(WGL_SAMPLE_BUFFERS_ARB); attribList.push_back(GL_TRUE);
  242. attribList.push_back(WGL_ACCELERATION_ARB); attribList.push_back(WGL_FULL_ACCELERATION_ARB);
  243. attribList.push_back(WGL_COLOR_BITS_ARB); attribList.push_back(pfd.cColorBits);
  244. attribList.push_back(WGL_ALPHA_BITS_ARB); attribList.push_back(pfd.cAlphaBits);
  245. attribList.push_back(WGL_DEPTH_BITS_ARB); attribList.push_back(24);
  246. attribList.push_back(WGL_STENCIL_BITS_ARB); attribList.push_back(8);
  247. attribList.push_back(WGL_SAMPLES_ARB); attribList.push_back(multisample);
  248. if (useHwGamma && checkExtension("WGL_EXT_framebuffer_sRGB"))
  249. {
  250. attribList.push_back(WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT); attribList.push_back(GL_TRUE);
  251. }
  252. // terminator
  253. attribList.push_back(0);
  254. UINT nformats;
  255. if (!WGLEW_GET_FUN(__wglewChoosePixelFormatARB)(hdc, &(attribList[0]), NULL, 1, &format, &nformats) || nformats <= 0)
  256. return false;
  257. }
  258. else
  259. {
  260. format = ChoosePixelFormat(hdc, &pfd);
  261. }
  262. return (format && SetPixelFormat(hdc, format, &pfd));
  263. }
  264. String translateWGLError()
  265. {
  266. int winError = GetLastError();
  267. char errDesc[255];
  268. int i;
  269. // Try windows errors first
  270. i = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  271. NULL, winError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  272. (LPTSTR) errDesc, 255, NULL);
  273. return String(errDesc);
  274. }
  275. }