context.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. //========================================================================
  2. // GLFW 3.4 - www.glfw.org
  3. //------------------------------------------------------------------------
  4. // Copyright (c) 2002-2006 Marcus Geelnard
  5. // Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
  6. //
  7. // This software is provided 'as-is', without any express or implied
  8. // warranty. In no event will the authors be held liable for any damages
  9. // arising from the use of this software.
  10. //
  11. // Permission is granted to anyone to use this software for any purpose,
  12. // including commercial applications, and to alter it and redistribute it
  13. // freely, subject to the following restrictions:
  14. //
  15. // 1. The origin of this software must not be misrepresented; you must not
  16. // claim that you wrote the original software. If you use this software
  17. // in a product, an acknowledgment in the product documentation would
  18. // be appreciated but is not required.
  19. //
  20. // 2. Altered source versions must be plainly marked as such, and must not
  21. // be misrepresented as being the original software.
  22. //
  23. // 3. This notice may not be removed or altered from any source
  24. // distribution.
  25. //
  26. //========================================================================
  27. // Please use C89 style variable declarations in this file because VS 2010
  28. //========================================================================
  29. #include "internal.h"
  30. #include <assert.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <stdio.h>
  34. //////////////////////////////////////////////////////////////////////////
  35. ////// GLFW internal API //////
  36. //////////////////////////////////////////////////////////////////////////
  37. // Checks whether the desired context attributes are valid
  38. //
  39. // This function checks things like whether the specified client API version
  40. // exists and whether all relevant options have supported and non-conflicting
  41. // values
  42. //
  43. bool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
  44. {
  45. if (ctxconfig->share)
  46. {
  47. if (ctxconfig->client == GLFW_NO_API ||
  48. ctxconfig->share->context.client == GLFW_NO_API)
  49. {
  50. _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
  51. return false;
  52. }
  53. }
  54. if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API &&
  55. ctxconfig->source != GLFW_EGL_CONTEXT_API &&
  56. ctxconfig->source != GLFW_OSMESA_CONTEXT_API)
  57. {
  58. _glfwInputError(GLFW_INVALID_ENUM,
  59. "Invalid context creation API 0x%08X",
  60. ctxconfig->source);
  61. return false;
  62. }
  63. if (ctxconfig->client != GLFW_NO_API &&
  64. ctxconfig->client != GLFW_OPENGL_API &&
  65. ctxconfig->client != GLFW_OPENGL_ES_API)
  66. {
  67. _glfwInputError(GLFW_INVALID_ENUM,
  68. "Invalid client API 0x%08X",
  69. ctxconfig->client);
  70. return false;
  71. }
  72. if (ctxconfig->client == GLFW_OPENGL_API)
  73. {
  74. if ((ctxconfig->major < 1 || ctxconfig->minor < 0) ||
  75. (ctxconfig->major == 1 && ctxconfig->minor > 5) ||
  76. (ctxconfig->major == 2 && ctxconfig->minor > 1) ||
  77. (ctxconfig->major == 3 && ctxconfig->minor > 3))
  78. {
  79. // OpenGL 1.0 is the smallest valid version
  80. // OpenGL 1.x series ended with version 1.5
  81. // OpenGL 2.x series ended with version 2.1
  82. // OpenGL 3.x series ended with version 3.3
  83. // For now, let everything else through
  84. _glfwInputError(GLFW_INVALID_VALUE,
  85. "Invalid OpenGL version %i.%i",
  86. ctxconfig->major, ctxconfig->minor);
  87. return false;
  88. }
  89. if (ctxconfig->profile)
  90. {
  91. if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE &&
  92. ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE)
  93. {
  94. _glfwInputError(GLFW_INVALID_ENUM,
  95. "Invalid OpenGL profile 0x%08X",
  96. ctxconfig->profile);
  97. return false;
  98. }
  99. if (ctxconfig->major <= 2 ||
  100. (ctxconfig->major == 3 && ctxconfig->minor < 2))
  101. {
  102. // Desktop OpenGL context profiles are only defined for version 3.2
  103. // and above
  104. _glfwInputError(GLFW_INVALID_VALUE,
  105. "Context profiles are only defined for OpenGL version 3.2 and above");
  106. return false;
  107. }
  108. }
  109. if (ctxconfig->forward && ctxconfig->major <= 2)
  110. {
  111. // Forward-compatible contexts are only defined for OpenGL version 3.0 and above
  112. _glfwInputError(GLFW_INVALID_VALUE,
  113. "Forward-compatibility is only defined for OpenGL version 3.0 and above");
  114. return false;
  115. }
  116. }
  117. else if (ctxconfig->client == GLFW_OPENGL_ES_API)
  118. {
  119. if (ctxconfig->major < 1 || ctxconfig->minor < 0 ||
  120. (ctxconfig->major == 1 && ctxconfig->minor > 1) ||
  121. (ctxconfig->major == 2 && ctxconfig->minor > 0))
  122. {
  123. // OpenGL ES 1.0 is the smallest valid version
  124. // OpenGL ES 1.x series ended with version 1.1
  125. // OpenGL ES 2.x series ended with version 2.0
  126. // For now, let everything else through
  127. _glfwInputError(GLFW_INVALID_VALUE,
  128. "Invalid OpenGL ES version %i.%i",
  129. ctxconfig->major, ctxconfig->minor);
  130. return false;
  131. }
  132. }
  133. if (ctxconfig->robustness)
  134. {
  135. if (ctxconfig->robustness != GLFW_NO_RESET_NOTIFICATION &&
  136. ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET)
  137. {
  138. _glfwInputError(GLFW_INVALID_ENUM,
  139. "Invalid context robustness mode 0x%08X",
  140. ctxconfig->robustness);
  141. return false;
  142. }
  143. }
  144. if (ctxconfig->release)
  145. {
  146. if (ctxconfig->release != GLFW_RELEASE_BEHAVIOR_NONE &&
  147. ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH)
  148. {
  149. _glfwInputError(GLFW_INVALID_ENUM,
  150. "Invalid context release behavior 0x%08X",
  151. ctxconfig->release);
  152. return false;
  153. }
  154. }
  155. return true;
  156. }
  157. // Retrieves the attributes of the current context
  158. //
  159. bool _glfwRefreshContextAttribs(_GLFWwindow* window,
  160. const _GLFWctxconfig* ctxconfig)
  161. {
  162. int i;
  163. _GLFWwindow* previous;
  164. const char* version;
  165. const char* prefixes[] =
  166. {
  167. "OpenGL ES-CM ",
  168. "OpenGL ES-CL ",
  169. "OpenGL ES ",
  170. NULL
  171. };
  172. window->context.source = ctxconfig->source;
  173. window->context.client = GLFW_OPENGL_API;
  174. previous = _glfwPlatformGetTls(&_glfw.contextSlot);
  175. glfwMakeContextCurrent((GLFWwindow*) window);
  176. window->context.GetIntegerv = (PFNGLGETINTEGERVPROC)
  177. window->context.getProcAddress("glGetIntegerv");
  178. window->context.GetString = (PFNGLGETSTRINGPROC)
  179. window->context.getProcAddress("glGetString");
  180. if (!window->context.GetIntegerv || !window->context.GetString)
  181. {
  182. _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
  183. glfwMakeContextCurrent((GLFWwindow*) previous);
  184. return false;
  185. }
  186. version = (const char*) window->context.GetString(GL_VERSION);
  187. if (!version)
  188. {
  189. if (ctxconfig->client == GLFW_OPENGL_API)
  190. {
  191. _glfwInputError(GLFW_PLATFORM_ERROR,
  192. "OpenGL version string retrieval is broken");
  193. }
  194. else
  195. {
  196. _glfwInputError(GLFW_PLATFORM_ERROR,
  197. "OpenGL ES version string retrieval is broken");
  198. }
  199. glfwMakeContextCurrent((GLFWwindow*) previous);
  200. return false;
  201. }
  202. for (i = 0; prefixes[i]; i++)
  203. {
  204. const size_t length = strlen(prefixes[i]);
  205. if (strncmp(version, prefixes[i], length) == 0)
  206. {
  207. version += length;
  208. window->context.client = GLFW_OPENGL_ES_API;
  209. break;
  210. }
  211. }
  212. if (sscanf(version, "%d.%d.%d",
  213. &window->context.major,
  214. &window->context.minor,
  215. &window->context.revision) < 1)
  216. {
  217. if (window->context.client == GLFW_OPENGL_API)
  218. {
  219. _glfwInputError(GLFW_PLATFORM_ERROR,
  220. "No version found in OpenGL version string");
  221. }
  222. else
  223. {
  224. _glfwInputError(GLFW_PLATFORM_ERROR,
  225. "No version found in OpenGL ES version string");
  226. }
  227. glfwMakeContextCurrent((GLFWwindow*) previous);
  228. return false;
  229. }
  230. if (window->context.major < ctxconfig->major ||
  231. (window->context.major == ctxconfig->major &&
  232. window->context.minor < ctxconfig->minor))
  233. {
  234. // The desired OpenGL version is greater than the actual version
  235. // This only happens if the machine lacks {GLX|WGL}_ARB_create_context
  236. // /and/ the user has requested an OpenGL version greater than 1.0
  237. // For API consistency, we emulate the behavior of the
  238. // {GLX|WGL}_ARB_create_context extension and fail here
  239. if (window->context.client == GLFW_OPENGL_API)
  240. {
  241. _glfwInputError(GLFW_VERSION_UNAVAILABLE,
  242. "Requested OpenGL version %i.%i, got version %i.%i",
  243. ctxconfig->major, ctxconfig->minor,
  244. window->context.major, window->context.minor);
  245. }
  246. else
  247. {
  248. _glfwInputError(GLFW_VERSION_UNAVAILABLE,
  249. "Requested OpenGL ES version %i.%i, got version %i.%i",
  250. ctxconfig->major, ctxconfig->minor,
  251. window->context.major, window->context.minor);
  252. }
  253. glfwMakeContextCurrent((GLFWwindow*) previous);
  254. return false;
  255. }
  256. if (window->context.major >= 3)
  257. {
  258. // OpenGL 3.0+ uses a different function for extension string retrieval
  259. // We cache it here instead of in glfwExtensionSupported mostly to alert
  260. // users as early as possible that their build may be broken
  261. window->context.GetStringi = (PFNGLGETSTRINGIPROC)
  262. window->context.getProcAddress("glGetStringi");
  263. if (!window->context.GetStringi)
  264. {
  265. _glfwInputError(GLFW_PLATFORM_ERROR,
  266. "Entry point retrieval is broken");
  267. glfwMakeContextCurrent((GLFWwindow*) previous);
  268. return false;
  269. }
  270. }
  271. if (window->context.client == GLFW_OPENGL_API)
  272. {
  273. // Read back context flags (OpenGL 3.0 and above)
  274. if (window->context.major >= 3)
  275. {
  276. GLint flags;
  277. window->context.GetIntegerv(GL_CONTEXT_FLAGS, &flags);
  278. if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
  279. window->context.forward = true;
  280. if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
  281. window->context.debug = true;
  282. else if (glfwExtensionSupported("GL_ARB_debug_output") &&
  283. ctxconfig->debug)
  284. {
  285. // HACK: This is a workaround for older drivers (pre KHR_debug)
  286. // not setting the debug bit in the context flags for
  287. // debug contexts
  288. window->context.debug = true;
  289. }
  290. if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR)
  291. window->context.noerror = true;
  292. }
  293. // Read back OpenGL context profile (OpenGL 3.2 and above)
  294. if (window->context.major >= 4 ||
  295. (window->context.major == 3 && window->context.minor >= 2))
  296. {
  297. GLint mask;
  298. window->context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
  299. if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
  300. window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
  301. else if (mask & GL_CONTEXT_CORE_PROFILE_BIT)
  302. window->context.profile = GLFW_OPENGL_CORE_PROFILE;
  303. else if (glfwExtensionSupported("GL_ARB_compatibility"))
  304. {
  305. // HACK: This is a workaround for the compatibility profile bit
  306. // not being set in the context flags if an OpenGL 3.2+
  307. // context was created without having requested a specific
  308. // version
  309. window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
  310. }
  311. }
  312. // Read back robustness strategy
  313. if (glfwExtensionSupported("GL_ARB_robustness"))
  314. {
  315. // NOTE: We avoid using the context flags for detection, as they are
  316. // only present from 3.0 while the extension applies from 1.1
  317. GLint strategy;
  318. window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
  319. &strategy);
  320. if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
  321. window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
  322. else if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
  323. window->context.robustness = GLFW_NO_RESET_NOTIFICATION;
  324. }
  325. }
  326. else
  327. {
  328. // Read back robustness strategy
  329. if (glfwExtensionSupported("GL_EXT_robustness"))
  330. {
  331. // NOTE: The values of these constants match those of the OpenGL ARB
  332. // one, so we can reuse them here
  333. GLint strategy;
  334. window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
  335. &strategy);
  336. if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
  337. window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
  338. else if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
  339. window->context.robustness = GLFW_NO_RESET_NOTIFICATION;
  340. }
  341. }
  342. if (glfwExtensionSupported("GL_KHR_context_flush_control"))
  343. {
  344. GLint behavior;
  345. window->context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior);
  346. if (behavior == GL_NONE)
  347. window->context.release = GLFW_RELEASE_BEHAVIOR_NONE;
  348. else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH)
  349. window->context.release = GLFW_RELEASE_BEHAVIOR_FLUSH;
  350. }
  351. glfwMakeContextCurrent((GLFWwindow*) previous);
  352. return true;
  353. }
  354. // Searches an extension string for the specified extension
  355. //
  356. bool _glfwStringInExtensionString(const char* string, const char* extensions)
  357. {
  358. const char* start = extensions;
  359. for (;;)
  360. {
  361. const char* where;
  362. const char* terminator;
  363. where = strstr(start, string);
  364. if (!where)
  365. return false;
  366. terminator = where + strlen(string);
  367. if (where == start || *(where - 1) == ' ')
  368. {
  369. if (*terminator == ' ' || *terminator == '\0')
  370. break;
  371. }
  372. start = terminator;
  373. }
  374. return true;
  375. }
  376. //////////////////////////////////////////////////////////////////////////
  377. ////// GLFW public API //////
  378. //////////////////////////////////////////////////////////////////////////
  379. GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
  380. {
  381. _GLFW_REQUIRE_INIT();
  382. _GLFWwindow* window = (_GLFWwindow*) handle;
  383. _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot);
  384. if (window && window->context.client == GLFW_NO_API)
  385. {
  386. _glfwInputError(GLFW_NO_WINDOW_CONTEXT,
  387. "Cannot make current with a window that has no OpenGL or OpenGL ES context");
  388. return;
  389. }
  390. if (previous)
  391. {
  392. if (!window || window->context.source != previous->context.source)
  393. previous->context.makeCurrent(NULL);
  394. }
  395. if (window)
  396. window->context.makeCurrent(window);
  397. }
  398. GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
  399. {
  400. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  401. return _glfwPlatformGetTls(&_glfw.contextSlot);
  402. }
  403. GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
  404. {
  405. _GLFWwindow* window = (_GLFWwindow*) handle;
  406. assert(window != NULL);
  407. _GLFW_REQUIRE_INIT();
  408. if (window->context.client == GLFW_NO_API)
  409. {
  410. _glfwInputError(GLFW_NO_WINDOW_CONTEXT,
  411. "Cannot swap buffers of a window that has no OpenGL or OpenGL ES context");
  412. return;
  413. }
  414. window->context.swapBuffers(window);
  415. #ifdef _GLFW_WAYLAND
  416. _glfwWaylandAfterBufferSwap(window);
  417. #endif
  418. }
  419. GLFWAPI void glfwSwapInterval(int interval)
  420. {
  421. _GLFWwindow* window;
  422. _GLFW_REQUIRE_INIT();
  423. window = _glfwPlatformGetTls(&_glfw.contextSlot);
  424. if (!window)
  425. {
  426. _glfwInputError(GLFW_NO_CURRENT_CONTEXT,
  427. "Cannot set swap interval without a current OpenGL or OpenGL ES context");
  428. return;
  429. }
  430. window->context.swapInterval(interval);
  431. }
  432. GLFWAPI int glfwExtensionSupported(const char* extension)
  433. {
  434. _GLFWwindow* window;
  435. assert(extension != NULL);
  436. _GLFW_REQUIRE_INIT_OR_RETURN(false);
  437. window = _glfwPlatformGetTls(&_glfw.contextSlot);
  438. if (!window)
  439. {
  440. _glfwInputError(GLFW_NO_CURRENT_CONTEXT,
  441. "Cannot query extension without a current OpenGL or OpenGL ES context");
  442. return false;
  443. }
  444. if (*extension == '\0')
  445. {
  446. _glfwInputError(GLFW_INVALID_VALUE, "Extension name cannot be an empty string");
  447. return false;
  448. }
  449. if (window->context.major >= 3)
  450. {
  451. int i;
  452. GLint count;
  453. // Check if extension is in the modern OpenGL extensions string list
  454. window->context.GetIntegerv(GL_NUM_EXTENSIONS, &count);
  455. for (i = 0; i < count; i++)
  456. {
  457. const char* en = (const char*)
  458. window->context.GetStringi(GL_EXTENSIONS, i);
  459. if (!en)
  460. {
  461. _glfwInputError(GLFW_PLATFORM_ERROR,
  462. "Extension string retrieval is broken");
  463. return false;
  464. }
  465. if (strcmp(en, extension) == 0)
  466. return true;
  467. }
  468. }
  469. else
  470. {
  471. // Check if extension is in the old style OpenGL extensions string
  472. const char* extensions = (const char*)
  473. window->context.GetString(GL_EXTENSIONS);
  474. if (!extensions)
  475. {
  476. _glfwInputError(GLFW_PLATFORM_ERROR,
  477. "Extension string retrieval is broken");
  478. return false;
  479. }
  480. if (_glfwStringInExtensionString(extension, extensions))
  481. return true;
  482. }
  483. // Check if extension is in the platform-specific string
  484. return window->context.extensionSupported(extension);
  485. }
  486. GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname)
  487. {
  488. _GLFWwindow* window;
  489. assert(procname != NULL);
  490. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  491. window = _glfwPlatformGetTls(&_glfw.contextSlot);
  492. if (!window)
  493. {
  494. _glfwInputError(GLFW_NO_CURRENT_CONTEXT,
  495. "Cannot query entry point without a current OpenGL or OpenGL ES context");
  496. return NULL;
  497. }
  498. return window->context.getProcAddress(procname);
  499. }