gl-windows.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #define WIN32_LEAN_AND_MEAN
  2. #include <windows.h>
  3. #include "util/darray.h"
  4. #include "gl-subsystem.h"
  5. #include "glew/include/GL/wglew.h"
  6. struct gl_windowinfo {
  7. HWND hwnd;
  8. HDC hdc;
  9. };
  10. struct gl_platform {
  11. HGLRC hrc;
  12. struct gl_windowinfo *wi;
  13. };
  14. static inline int get_color_format_bits(enum gs_color_format format)
  15. {
  16. switch (format) {
  17. case GS_RGBA:
  18. return 32;
  19. default:
  20. return 0;
  21. }
  22. }
  23. static inline int get_depth_format_bits(enum gs_zstencil_format zsformat)
  24. {
  25. switch (zsformat) {
  26. case GS_Z16:
  27. return 16;
  28. case GS_Z24_S8:
  29. return 24;
  30. default:
  31. return 0;
  32. }
  33. }
  34. static inline int get_stencil_format_bits(enum gs_zstencil_format zsformat)
  35. {
  36. switch (zsformat) {
  37. case GS_Z24_S8:
  38. return 8;
  39. default:
  40. return 0;
  41. }
  42. }
  43. /* would use designated initializers but microsoft sort of sucks */
  44. static inline void init_dummy_pixel_format(PIXELFORMATDESCRIPTOR *pfd)
  45. {
  46. memset(pfd, 0, sizeof(pfd));
  47. pfd->nSize = sizeof(pfd);
  48. pfd->nVersion = 1;
  49. pfd->iPixelType = PFD_TYPE_RGBA;
  50. pfd->cColorBits = 32;
  51. pfd->cDepthBits = 24;
  52. pfd->cStencilBits = 8;
  53. pfd->iLayerType = PFD_MAIN_PLANE;
  54. pfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
  55. PFD_DOUBLEBUFFER;
  56. }
  57. static const char *dummy_window_class = "GLDummyWindow";
  58. static bool registered_dummy_window_class = false;
  59. struct dummy_context {
  60. HWND hwnd;
  61. HGLRC hrc;
  62. HDC hdc;
  63. };
  64. static bool gl_register_dummy_window_class(void)
  65. {
  66. WNDCLASSA wc;
  67. if (registered_dummy_window_class)
  68. return true;
  69. memset(&wc, 0, sizeof(wc));
  70. wc.style = CS_OWNDC;
  71. wc.hInstance = GetModuleHandle(NULL);
  72. wc.lpfnWndProc = DefWindowProc;
  73. wc.lpszClassName = dummy_window_class;
  74. if (!RegisterClassA(&wc)) {
  75. blog(LOG_ERROR, "Could not create dummy window class");
  76. return false;
  77. }
  78. registered_dummy_window_class = true;
  79. return true;
  80. }
  81. static inline HWND gl_create_dummy_window(void)
  82. {
  83. HWND hwnd = CreateWindowExA(0, dummy_window_class, "Dummy GL Window",
  84. WS_POPUP,
  85. 0, 0, 2, 2,
  86. NULL, NULL, GetModuleHandle(NULL), NULL);
  87. if (!hwnd)
  88. blog(LOG_ERROR, "Could not create dummy context window");
  89. return hwnd;
  90. }
  91. static HGLRC gl_init_context(HDC hdc)
  92. {
  93. HGLRC hglrc = wglCreateContext(hdc);
  94. if (!hglrc) {
  95. blog(LOG_ERROR, "wglCreateContext failed, %u", GetLastError());
  96. return NULL;
  97. }
  98. if (!wglMakeCurrent(hdc, hglrc)) {
  99. blog(LOG_ERROR, "wglMakeCurrent failed, %u", GetLastError());
  100. wglDeleteContext(hglrc);
  101. return NULL;
  102. }
  103. return hglrc;
  104. }
  105. static bool gl_dummy_context_init(struct dummy_context *dummy)
  106. {
  107. PIXELFORMATDESCRIPTOR pfd;
  108. int format_index;
  109. if (!gl_register_dummy_window_class())
  110. return false;
  111. dummy->hwnd = gl_create_dummy_window();
  112. if (!dummy->hwnd)
  113. return false;
  114. dummy->hdc = GetDC(dummy->hwnd);
  115. init_dummy_pixel_format(&pfd);
  116. format_index = ChoosePixelFormat(dummy->hdc, &pfd);
  117. if (!format_index) {
  118. blog(LOG_ERROR, "Dummy ChoosePixelFormat failed, %u",
  119. GetLastError());
  120. return false;
  121. }
  122. if (!SetPixelFormat(dummy->hdc, format_index, &pfd)) {
  123. blog(LOG_ERROR, "Dummy SetPixelFormat failed, %u",
  124. GetLastError());
  125. return false;
  126. }
  127. dummy->hrc = gl_init_context(dummy->hdc);
  128. if (!dummy->hrc) {
  129. blog(LOG_ERROR, "Failed to initialize dummy context");
  130. return false;
  131. }
  132. return true;
  133. }
  134. static void gl_dummy_context_free(struct dummy_context *dummy)
  135. {
  136. wglMakeCurrent(NULL, NULL);
  137. wglDeleteContext(dummy->hrc);
  138. DestroyWindow(dummy->hwnd);
  139. memset(dummy, 0, sizeof(struct dummy_context));
  140. }
  141. static inline void required_extension_error(const char *extension)
  142. {
  143. blog(LOG_ERROR, "OpenGL extension %s is required", extension);
  144. }
  145. static bool gl_init_extensions(void)
  146. {
  147. GLenum errorcode = glewInit();
  148. if (errorcode != GLEW_OK) {
  149. blog(LOG_ERROR, "glewInit failed, %u", errorcode);
  150. return false;
  151. }
  152. if (!GLEW_VERSION_2_1) {
  153. blog(LOG_ERROR, "OpenGL 2.1 minimum required by the graphics "
  154. "adapter");
  155. return false;
  156. }
  157. if (!GLEW_ARB_framebuffer_object) {
  158. required_extension_error("GL_ARB_framebuffer_object");
  159. return false;
  160. }
  161. if (!WGLEW_ARB_pixel_format) {
  162. required_extension_error("WGL_ARB_pixel_format");
  163. return false;
  164. }
  165. return true;
  166. }
  167. static inline void add_attrib(struct darray *list, int attrib, int val)
  168. {
  169. darray_push_back(sizeof(int), list, &attrib);
  170. darray_push_back(sizeof(int), list, &val);
  171. }
  172. static int gl_choose_pixel_format(HDC hdc, struct gs_init_data *info)
  173. {
  174. struct darray attribs;
  175. int color_bits = get_color_format_bits(info->format);
  176. int depth_bits = get_depth_format_bits(info->zsformat);
  177. int stencil_bits = get_stencil_format_bits(info->zsformat);
  178. UINT num_formats;
  179. BOOL success;
  180. int format;
  181. if (!color_bits) {
  182. blog(LOG_ERROR, "gl_init_pixel_format: color format not "
  183. "supported");
  184. return false;
  185. }
  186. darray_init(&attribs);
  187. add_attrib(&attribs, WGL_DRAW_TO_WINDOW_ARB, GL_TRUE);
  188. add_attrib(&attribs, WGL_SUPPORT_OPENGL_ARB, GL_TRUE);
  189. add_attrib(&attribs, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
  190. add_attrib(&attribs, WGL_DOUBLE_BUFFER_ARB, GL_TRUE);
  191. add_attrib(&attribs, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
  192. add_attrib(&attribs, WGL_COLOR_BITS_ARB, color_bits);
  193. add_attrib(&attribs, WGL_DEPTH_BITS_ARB, depth_bits);
  194. add_attrib(&attribs, WGL_STENCIL_BITS_ARB, stencil_bits);
  195. add_attrib(&attribs, 0, 0);
  196. success = wglChoosePixelFormatARB(hdc, attribs.array, NULL, 1, &format,
  197. &num_formats);
  198. if (!success || !num_formats) {
  199. blog(LOG_ERROR, "wglChoosePixelFormatARB failed, %u",
  200. GetLastError());
  201. format = 0;
  202. }
  203. darray_free(&attribs);
  204. return format;
  205. }
  206. static inline bool gl_get_pixel_format(HDC hdc, struct gs_init_data *info,
  207. int *format, PIXELFORMATDESCRIPTOR *pfd)
  208. {
  209. *format = gl_choose_pixel_format(hdc, info);
  210. if (!format)
  211. return false;
  212. if (!DescribePixelFormat(hdc, *format, sizeof(*pfd), pfd)) {
  213. blog(LOG_ERROR, "DescribePixelFormat failed, %u",
  214. GetLastError());
  215. return false;
  216. }
  217. return true;
  218. }
  219. static inline bool gl_set_pixel_format(HDC hdc, int format,
  220. PIXELFORMATDESCRIPTOR *pfd)
  221. {
  222. if (!SetPixelFormat(hdc, format, pfd)) {
  223. blog(LOG_ERROR, "SetPixelFormat failed, %u", GetLastError());
  224. return false;
  225. }
  226. return true;
  227. }
  228. struct gl_platform *gl_platform_create(struct gs_init_data *info)
  229. {
  230. struct gl_platform *plat = bmalloc(sizeof(struct gl_platform));
  231. struct dummy_context dummy;
  232. int pixel_format;
  233. PIXELFORMATDESCRIPTOR pfd;
  234. memset(plat, 0, sizeof(struct gl_platform));
  235. memset(&dummy, 0, sizeof(struct dummy_context));
  236. if (!gl_dummy_context_init(&dummy))
  237. goto fail;
  238. if (!gl_init_extensions())
  239. goto fail;
  240. /* you have to have a dummy context open before you can actually
  241. * use wglChoosePixelFormatARB */
  242. if (!gl_get_pixel_format(dummy.hdc, info, &pixel_format, &pfd))
  243. goto fail;
  244. gl_dummy_context_free(&dummy);
  245. plat->wi = gl_windowinfo_create(info);
  246. if (!plat->wi)
  247. goto fail;
  248. if (!gl_set_pixel_format(plat->wi->hdc, pixel_format, &pfd))
  249. goto fail;
  250. plat->hrc = gl_init_context(plat->wi->hdc);
  251. if (!plat->hrc)
  252. goto fail;
  253. return plat;
  254. fail:
  255. gl_platform_destroy(plat);
  256. gl_dummy_context_free(&dummy);
  257. return NULL;
  258. }
  259. void gl_platform_destroy(struct gl_platform *plat)
  260. {
  261. if (plat) {
  262. if (plat->hrc) {
  263. wglMakeCurrent(NULL, NULL);
  264. wglDeleteContext(plat->hrc);
  265. }
  266. gl_windowinfo_destroy(plat->wi);
  267. bfree(plat);
  268. }
  269. }
  270. struct gl_windowinfo *gl_windowinfo_create(struct gs_init_data *info)
  271. {
  272. struct gl_windowinfo *wi = bmalloc(sizeof(struct gl_windowinfo));
  273. memset(wi, 0, sizeof(struct gl_windowinfo));
  274. wi->hwnd = info->hwnd;
  275. wi->hdc = GetDC(wi->hwnd);
  276. if (!wi->hdc) {
  277. blog(LOG_ERROR, "Unable to get device context from window");
  278. bfree(wi);
  279. return NULL;
  280. }
  281. return wi;
  282. }
  283. void gl_windowinfo_destroy(struct gl_windowinfo *wi)
  284. {
  285. if (wi) {
  286. if (wi->hdc)
  287. ReleaseDC(wi->hwnd, wi->hdc);
  288. bfree(wi);
  289. }
  290. }