gl-windows.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. /******************************************************************************
  2. Copyright (C) 2013 by Hugh Bailey <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #define WIN32_LEAN_AND_MEAN
  15. #include <windows.h>
  16. #include <util/darray.h>
  17. #include "gl-subsystem.h"
  18. #include <glad/glad_wgl.h>
  19. /* Basically swapchain-specific information. Fortunately for windows this is
  20. * super basic stuff */
  21. struct gl_windowinfo {
  22. HWND hwnd;
  23. HDC hdc;
  24. };
  25. /* Like the other subsystems, the GL subsystem has one swap chain created by
  26. * default. */
  27. struct gl_platform {
  28. HGLRC hrc;
  29. struct gl_windowinfo window;
  30. };
  31. /* For now, only support basic 32bit formats for graphics output. */
  32. static inline int get_color_format_bits(enum gs_color_format format)
  33. {
  34. switch ((uint32_t)format) {
  35. case GS_RGBA:
  36. case GS_BGRA:
  37. return 32;
  38. default:
  39. return 0;
  40. }
  41. }
  42. static inline int get_depth_format_bits(enum gs_zstencil_format zsformat)
  43. {
  44. switch ((uint32_t)zsformat) {
  45. case GS_Z16:
  46. return 16;
  47. case GS_Z24_S8:
  48. return 24;
  49. default:
  50. return 0;
  51. }
  52. }
  53. static inline int get_stencil_format_bits(enum gs_zstencil_format zsformat)
  54. {
  55. switch ((uint32_t)zsformat) {
  56. case GS_Z24_S8:
  57. return 8;
  58. default:
  59. return 0;
  60. }
  61. }
  62. /* would use designated initializers but Microsoft sort of sucks */
  63. static inline void init_dummy_pixel_format(PIXELFORMATDESCRIPTOR *pfd)
  64. {
  65. memset(pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
  66. pfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
  67. pfd->nVersion = 1;
  68. pfd->iPixelType = PFD_TYPE_RGBA;
  69. pfd->cColorBits = 32;
  70. pfd->cDepthBits = 24;
  71. pfd->cStencilBits = 8;
  72. pfd->iLayerType = PFD_MAIN_PLANE;
  73. pfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
  74. PFD_DOUBLEBUFFER;
  75. }
  76. static const char *dummy_window_class = "GLDummyWindow";
  77. static bool registered_dummy_window_class = false;
  78. struct dummy_context {
  79. HWND hwnd;
  80. HGLRC hrc;
  81. HDC hdc;
  82. };
  83. /* Need a dummy window for the dummy context */
  84. static bool gl_register_dummy_window_class(void)
  85. {
  86. WNDCLASSA wc;
  87. if (registered_dummy_window_class)
  88. return true;
  89. memset(&wc, 0, sizeof(wc));
  90. wc.style = CS_OWNDC;
  91. wc.hInstance = GetModuleHandle(NULL);
  92. wc.lpfnWndProc = DefWindowProc;
  93. wc.lpszClassName = dummy_window_class;
  94. if (!RegisterClassA(&wc)) {
  95. blog(LOG_ERROR, "Could not create dummy window class");
  96. return false;
  97. }
  98. registered_dummy_window_class = true;
  99. return true;
  100. }
  101. static inline HWND gl_create_dummy_window(void)
  102. {
  103. HWND hwnd = CreateWindowExA(0, dummy_window_class, "Dummy GL Window",
  104. WS_POPUP, 0, 0, 2, 2, NULL, NULL,
  105. GetModuleHandle(NULL), NULL);
  106. if (!hwnd)
  107. blog(LOG_ERROR, "Could not create dummy context window");
  108. return hwnd;
  109. }
  110. static inline bool wgl_make_current(HDC hdc, HGLRC hglrc)
  111. {
  112. bool success = wglMakeCurrent(hdc, hglrc);
  113. if (!success)
  114. blog(LOG_ERROR,
  115. "wglMakeCurrent failed, GetLastError "
  116. "returned %lu",
  117. GetLastError());
  118. return success;
  119. }
  120. static inline HGLRC gl_init_basic_context(HDC hdc)
  121. {
  122. HGLRC hglrc = wglCreateContext(hdc);
  123. if (!hglrc) {
  124. blog(LOG_ERROR, "wglCreateContext failed, %lu", GetLastError());
  125. return NULL;
  126. }
  127. if (!wgl_make_current(hdc, hglrc)) {
  128. wglDeleteContext(hglrc);
  129. return NULL;
  130. }
  131. return hglrc;
  132. }
  133. static inline HGLRC gl_init_context(HDC hdc)
  134. {
  135. static const int attribs[] = {
  136. #ifdef _DEBUG
  137. WGL_CONTEXT_FLAGS_ARB,
  138. WGL_CONTEXT_DEBUG_BIT_ARB,
  139. #endif
  140. WGL_CONTEXT_PROFILE_MASK_ARB,
  141. WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
  142. WGL_CONTEXT_MAJOR_VERSION_ARB,
  143. 3,
  144. WGL_CONTEXT_MINOR_VERSION_ARB,
  145. 3,
  146. 0,
  147. 0};
  148. HGLRC hglrc = wglCreateContextAttribsARB(hdc, 0, attribs);
  149. if (!hglrc) {
  150. blog(LOG_ERROR,
  151. "wglCreateContextAttribsARB failed, "
  152. "%lu",
  153. GetLastError());
  154. return NULL;
  155. }
  156. if (!wgl_make_current(hdc, hglrc)) {
  157. wglDeleteContext(hglrc);
  158. return NULL;
  159. }
  160. return hglrc;
  161. }
  162. static bool gl_dummy_context_init(struct dummy_context *dummy)
  163. {
  164. PIXELFORMATDESCRIPTOR pfd;
  165. int format_index;
  166. if (!gl_register_dummy_window_class())
  167. return false;
  168. dummy->hwnd = gl_create_dummy_window();
  169. if (!dummy->hwnd)
  170. return false;
  171. dummy->hdc = GetDC(dummy->hwnd);
  172. init_dummy_pixel_format(&pfd);
  173. format_index = ChoosePixelFormat(dummy->hdc, &pfd);
  174. if (!format_index) {
  175. blog(LOG_ERROR, "Dummy ChoosePixelFormat failed, %lu",
  176. GetLastError());
  177. return false;
  178. }
  179. if (!SetPixelFormat(dummy->hdc, format_index, &pfd)) {
  180. blog(LOG_ERROR, "Dummy SetPixelFormat failed, %lu",
  181. GetLastError());
  182. return false;
  183. }
  184. dummy->hrc = gl_init_basic_context(dummy->hdc);
  185. if (!dummy->hrc) {
  186. blog(LOG_ERROR, "Failed to initialize dummy context");
  187. return false;
  188. }
  189. return true;
  190. }
  191. static inline void gl_dummy_context_free(struct dummy_context *dummy)
  192. {
  193. wglMakeCurrent(NULL, NULL);
  194. wglDeleteContext(dummy->hrc);
  195. DestroyWindow(dummy->hwnd);
  196. memset(dummy, 0, sizeof(struct dummy_context));
  197. }
  198. static inline void required_extension_error(const char *extension)
  199. {
  200. blog(LOG_ERROR, "OpenGL extension %s is required", extension);
  201. }
  202. static bool gl_init_extensions(HDC hdc)
  203. {
  204. if (!gladLoadWGL(hdc)) {
  205. blog(LOG_ERROR, "Failed to load WGL entry functions.");
  206. return false;
  207. }
  208. if (!GLAD_WGL_ARB_pixel_format) {
  209. required_extension_error("ARB_pixel_format");
  210. return false;
  211. }
  212. if (!GLAD_WGL_ARB_create_context) {
  213. required_extension_error("ARB_create_context");
  214. return false;
  215. }
  216. if (!GLAD_WGL_ARB_create_context_profile) {
  217. required_extension_error("ARB_create_context_profile");
  218. return false;
  219. }
  220. return true;
  221. }
  222. static inline void add_attrib(struct darray *list, int attrib, int val)
  223. {
  224. darray_push_back(sizeof(int), list, &attrib);
  225. darray_push_back(sizeof(int), list, &val);
  226. }
  227. /* Creates the real pixel format for the target window */
  228. static int gl_choose_pixel_format(HDC hdc, const struct gs_init_data *info)
  229. {
  230. struct darray attribs;
  231. int color_bits = get_color_format_bits(info->format);
  232. int depth_bits = get_depth_format_bits(info->zsformat);
  233. int stencil_bits = get_stencil_format_bits(info->zsformat);
  234. UINT num_formats;
  235. BOOL success;
  236. int format;
  237. if (!color_bits) {
  238. blog(LOG_ERROR, "gl_init_pixel_format: color format not "
  239. "supported");
  240. return false;
  241. }
  242. darray_init(&attribs);
  243. add_attrib(&attribs, WGL_DRAW_TO_WINDOW_ARB, GL_TRUE);
  244. add_attrib(&attribs, WGL_SUPPORT_OPENGL_ARB, GL_TRUE);
  245. add_attrib(&attribs, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
  246. add_attrib(&attribs, WGL_DOUBLE_BUFFER_ARB, GL_TRUE);
  247. add_attrib(&attribs, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
  248. add_attrib(&attribs, WGL_COLOR_BITS_ARB, color_bits);
  249. add_attrib(&attribs, WGL_DEPTH_BITS_ARB, depth_bits);
  250. add_attrib(&attribs, WGL_STENCIL_BITS_ARB, stencil_bits);
  251. add_attrib(&attribs, 0, 0);
  252. success = wglChoosePixelFormatARB(hdc, attribs.array, NULL, 1, &format,
  253. &num_formats);
  254. if (!success || !num_formats) {
  255. blog(LOG_ERROR, "wglChoosePixelFormatARB failed, %lu",
  256. GetLastError());
  257. format = 0;
  258. }
  259. darray_free(&attribs);
  260. return format;
  261. }
  262. static inline bool gl_getpixelformat(HDC hdc, const struct gs_init_data *info,
  263. int *format, PIXELFORMATDESCRIPTOR *pfd)
  264. {
  265. if (!format)
  266. return false;
  267. *format = gl_choose_pixel_format(hdc, info);
  268. if (!DescribePixelFormat(hdc, *format, sizeof(*pfd), pfd)) {
  269. blog(LOG_ERROR, "DescribePixelFormat failed, %lu",
  270. GetLastError());
  271. return false;
  272. }
  273. return true;
  274. }
  275. static inline bool gl_setpixelformat(HDC hdc, int format,
  276. PIXELFORMATDESCRIPTOR *pfd)
  277. {
  278. if (!SetPixelFormat(hdc, format, pfd)) {
  279. blog(LOG_ERROR, "SetPixelFormat failed, %lu", GetLastError());
  280. return false;
  281. }
  282. return true;
  283. }
  284. static struct gl_windowinfo *gl_windowinfo_bare(const struct gs_init_data *info)
  285. {
  286. struct gl_windowinfo *wi = bzalloc(sizeof(struct gl_windowinfo));
  287. wi->hwnd = info->window.hwnd;
  288. wi->hdc = GetDC(wi->hwnd);
  289. if (!wi->hdc) {
  290. blog(LOG_ERROR, "Unable to get device context from window");
  291. bfree(wi);
  292. return NULL;
  293. }
  294. return wi;
  295. }
  296. #define DUMMY_WNDCLASS "Dummy GL Window Class"
  297. static bool register_dummy_class(void)
  298. {
  299. static bool created = false;
  300. WNDCLASSA wc = {0};
  301. wc.style = CS_OWNDC;
  302. wc.hInstance = GetModuleHandleW(NULL);
  303. wc.lpfnWndProc = (WNDPROC)DefWindowProcA;
  304. wc.lpszClassName = DUMMY_WNDCLASS;
  305. if (created)
  306. return true;
  307. if (!RegisterClassA(&wc)) {
  308. blog(LOG_ERROR, "Failed to register dummy GL window class, %lu",
  309. GetLastError());
  310. return false;
  311. }
  312. created = true;
  313. return true;
  314. }
  315. static bool create_dummy_window(struct gl_platform *plat)
  316. {
  317. plat->window.hwnd = CreateWindowExA(0, DUMMY_WNDCLASS,
  318. "OpenGL Dummy Window", WS_POPUP, 0,
  319. 0, 1, 1, NULL, NULL,
  320. GetModuleHandleW(NULL), NULL);
  321. if (!plat->window.hwnd) {
  322. blog(LOG_ERROR, "Failed to create dummy GL window, %lu",
  323. GetLastError());
  324. return false;
  325. }
  326. plat->window.hdc = GetDC(plat->window.hwnd);
  327. if (!plat->window.hdc) {
  328. blog(LOG_ERROR, "Failed to get dummy GL window DC (%lu)",
  329. GetLastError());
  330. return false;
  331. }
  332. return true;
  333. }
  334. static bool init_default_swap(struct gl_platform *plat, gs_device_t *device,
  335. int pixel_format, PIXELFORMATDESCRIPTOR *pfd)
  336. {
  337. if (!gl_setpixelformat(plat->window.hdc, pixel_format, pfd))
  338. return false;
  339. return true;
  340. }
  341. void gl_update(gs_device_t *device)
  342. {
  343. /* does nothing on windows */
  344. UNUSED_PARAMETER(device);
  345. }
  346. void gl_clear_context(gs_device_t *device)
  347. {
  348. UNUSED_PARAMETER(device);
  349. wglMakeCurrent(NULL, NULL);
  350. }
  351. static void init_dummy_swap_info(struct gs_init_data *info)
  352. {
  353. info->format = GS_RGBA;
  354. info->zsformat = GS_ZS_NONE;
  355. }
  356. struct gl_platform *gl_platform_create(gs_device_t *device, uint32_t adapter)
  357. {
  358. struct gl_platform *plat = bzalloc(sizeof(struct gl_platform));
  359. struct dummy_context dummy;
  360. struct gs_init_data info = {0};
  361. int pixel_format;
  362. PIXELFORMATDESCRIPTOR pfd;
  363. memset(&dummy, 0, sizeof(struct dummy_context));
  364. init_dummy_swap_info(&info);
  365. if (!gl_dummy_context_init(&dummy))
  366. goto fail;
  367. if (!gl_init_extensions(dummy.hdc))
  368. goto fail;
  369. if (!register_dummy_class())
  370. return false;
  371. if (!create_dummy_window(plat))
  372. return false;
  373. /* you have to have a dummy context open before you can actually
  374. * use wglChoosePixelFormatARB */
  375. if (!gl_getpixelformat(dummy.hdc, &info, &pixel_format, &pfd))
  376. goto fail;
  377. gl_dummy_context_free(&dummy);
  378. if (!init_default_swap(plat, device, pixel_format, &pfd))
  379. goto fail;
  380. plat->hrc = gl_init_context(plat->window.hdc);
  381. if (!plat->hrc)
  382. goto fail;
  383. if (!gladLoadGL()) {
  384. blog(LOG_ERROR, "Failed to initialize OpenGL entry functions.");
  385. goto fail;
  386. }
  387. UNUSED_PARAMETER(adapter);
  388. return plat;
  389. fail:
  390. blog(LOG_ERROR, "gl_platform_create failed");
  391. gl_platform_destroy(plat);
  392. gl_dummy_context_free(&dummy);
  393. return NULL;
  394. }
  395. void gl_platform_destroy(struct gl_platform *plat)
  396. {
  397. if (plat) {
  398. if (plat->hrc) {
  399. wglMakeCurrent(NULL, NULL);
  400. wglDeleteContext(plat->hrc);
  401. }
  402. if (plat->window.hdc)
  403. ReleaseDC(plat->window.hwnd, plat->window.hdc);
  404. if (plat->window.hwnd)
  405. DestroyWindow(plat->window.hwnd);
  406. bfree(plat);
  407. }
  408. }
  409. bool gl_platform_init_swapchain(struct gs_swap_chain *swap)
  410. {
  411. UNUSED_PARAMETER(swap);
  412. return true;
  413. }
  414. void gl_platform_cleanup_swapchain(struct gs_swap_chain *swap)
  415. {
  416. UNUSED_PARAMETER(swap);
  417. }
  418. struct gl_windowinfo *gl_windowinfo_create(const struct gs_init_data *info)
  419. {
  420. struct gl_windowinfo *wi = gl_windowinfo_bare(info);
  421. PIXELFORMATDESCRIPTOR pfd;
  422. int pixel_format;
  423. if (!wi)
  424. return NULL;
  425. if (!gl_getpixelformat(wi->hdc, info, &pixel_format, &pfd))
  426. goto fail;
  427. if (!gl_setpixelformat(wi->hdc, pixel_format, &pfd))
  428. goto fail;
  429. return wi;
  430. fail:
  431. blog(LOG_ERROR, "gl_windowinfo_create failed");
  432. gl_windowinfo_destroy(wi);
  433. return NULL;
  434. }
  435. void gl_windowinfo_destroy(struct gl_windowinfo *wi)
  436. {
  437. if (wi) {
  438. if (wi->hdc)
  439. ReleaseDC(wi->hwnd, wi->hdc);
  440. bfree(wi);
  441. }
  442. }
  443. void device_enter_context(gs_device_t *device)
  444. {
  445. HDC hdc = device->plat->window.hdc;
  446. if (device->cur_swap)
  447. hdc = device->cur_swap->wi->hdc;
  448. if (!wgl_make_current(hdc, device->plat->hrc))
  449. blog(LOG_ERROR, "device_enter_context (GL) failed");
  450. }
  451. void device_leave_context(gs_device_t *device)
  452. {
  453. UNUSED_PARAMETER(device);
  454. wglMakeCurrent(NULL, NULL);
  455. }
  456. void *device_get_device_obj(gs_device_t *device)
  457. {
  458. return device->plat->hrc;
  459. }
  460. void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swap)
  461. {
  462. HDC hdc = device->plat->window.hdc;
  463. if (device->cur_swap == swap)
  464. return;
  465. device->cur_swap = swap;
  466. if (swap)
  467. hdc = swap->wi->hdc;
  468. if (hdc) {
  469. if (!wgl_make_current(hdc, device->plat->hrc))
  470. blog(LOG_ERROR, "device_load_swapchain (GL) failed");
  471. }
  472. }
  473. bool device_is_present_ready(gs_device_t *device)
  474. {
  475. UNUSED_PARAMETER(device);
  476. return true;
  477. }
  478. void device_present(gs_device_t *device)
  479. {
  480. if (!SwapBuffers(device->cur_swap->wi->hdc)) {
  481. blog(LOG_ERROR,
  482. "SwapBuffers failed, GetLastError "
  483. "returned %lu",
  484. GetLastError());
  485. blog(LOG_ERROR, "device_present (GL) failed");
  486. }
  487. }
  488. extern void gl_getclientsize(const struct gs_swap_chain *swap, uint32_t *width,
  489. uint32_t *height)
  490. {
  491. RECT rc;
  492. if (swap) {
  493. GetClientRect(swap->wi->hwnd, &rc);
  494. *width = rc.right;
  495. *height = rc.bottom;
  496. } else {
  497. *width = 0;
  498. *height = 0;
  499. }
  500. }
  501. EXPORT bool device_is_monitor_hdr(gs_device_t *device, void *monitor)
  502. {
  503. return false;
  504. }
  505. EXPORT bool device_gdi_texture_available(void)
  506. {
  507. return false;
  508. }
  509. EXPORT bool device_shared_texture_available(void)
  510. {
  511. return false;
  512. }