osmesa_context.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. //========================================================================
  2. // GLFW 3.4 OSMesa - www.glfw.org
  3. //------------------------------------------------------------------------
  4. // Copyright (c) 2016 Google Inc.
  5. // Copyright (c) 2016-2017 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 <stdlib.h>
  30. #include <string.h>
  31. #include <assert.h>
  32. #include "internal.h"
  33. static void makeContextCurrentOSMesa(_GLFWwindow* window)
  34. {
  35. if (window)
  36. {
  37. int width, height;
  38. _glfwPlatformGetFramebufferSize(window, &width, &height);
  39. // Check to see if we need to allocate a new buffer
  40. if ((window->context.osmesa.buffer == NULL) ||
  41. (width != window->context.osmesa.width) ||
  42. (height != window->context.osmesa.height))
  43. {
  44. free(window->context.osmesa.buffer);
  45. // Allocate the new buffer (width * height * 8-bit RGBA)
  46. window->context.osmesa.buffer = calloc(4, (size_t) width * height);
  47. window->context.osmesa.width = width;
  48. window->context.osmesa.height = height;
  49. }
  50. if (!OSMesaMakeCurrent(window->context.osmesa.handle,
  51. window->context.osmesa.buffer,
  52. GL_UNSIGNED_BYTE,
  53. width, height))
  54. {
  55. _glfwInputError(GLFW_PLATFORM_ERROR,
  56. "OSMesa: Failed to make context current");
  57. return;
  58. }
  59. }
  60. _glfwPlatformSetTls(&_glfw.contextSlot, window);
  61. }
  62. static GLFWglproc getProcAddressOSMesa(const char* procname)
  63. {
  64. return (GLFWglproc) OSMesaGetProcAddress(procname);
  65. }
  66. static void destroyContextOSMesa(_GLFWwindow* window)
  67. {
  68. if (window->context.osmesa.handle)
  69. {
  70. OSMesaDestroyContext(window->context.osmesa.handle);
  71. window->context.osmesa.handle = NULL;
  72. }
  73. if (window->context.osmesa.buffer)
  74. {
  75. free(window->context.osmesa.buffer);
  76. window->context.osmesa.width = 0;
  77. window->context.osmesa.height = 0;
  78. }
  79. }
  80. static void swapBuffersOSMesa(_GLFWwindow* window UNUSED)
  81. {
  82. // No double buffering on OSMesa
  83. }
  84. static void swapIntervalOSMesa(int interval UNUSED)
  85. {
  86. // No swap interval on OSMesa
  87. }
  88. static int extensionSupportedOSMesa(const char* extension UNUSED)
  89. {
  90. // OSMesa does not have extensions
  91. return false;
  92. }
  93. //////////////////////////////////////////////////////////////////////////
  94. ////// GLFW internal API //////
  95. //////////////////////////////////////////////////////////////////////////
  96. bool _glfwInitOSMesa(void)
  97. {
  98. int i;
  99. const char* sonames[] =
  100. {
  101. #if defined(_GLFW_OSMESA_LIBRARY)
  102. _GLFW_OSMESA_LIBRARY,
  103. #elif defined(_WIN32)
  104. "libOSMesa.dll",
  105. "OSMesa.dll",
  106. #elif defined(__APPLE__)
  107. "libOSMesa.8.dylib",
  108. #elif defined(__CYGWIN__)
  109. "libOSMesa-8.so",
  110. #else
  111. "libOSMesa.so.8",
  112. "libOSMesa.so.6",
  113. #endif
  114. NULL
  115. };
  116. if (_glfw.osmesa.handle)
  117. return true;
  118. for (i = 0; sonames[i]; i++)
  119. {
  120. _glfw.osmesa.handle = _glfw_dlopen(sonames[i]);
  121. if (_glfw.osmesa.handle)
  122. break;
  123. }
  124. if (!_glfw.osmesa.handle)
  125. {
  126. _glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found");
  127. return false;
  128. }
  129. glfw_dlsym(_glfw.osmesa.CreateContextExt, _glfw.osmesa.handle, "OSMesaCreateContextExt");
  130. glfw_dlsym(_glfw.osmesa.CreateContextAttribs, _glfw.osmesa.handle, "OSMesaCreateContextAttribs");
  131. glfw_dlsym(_glfw.osmesa.DestroyContext, _glfw.osmesa.handle, "OSMesaDestroyContext");
  132. glfw_dlsym(_glfw.osmesa.MakeCurrent, _glfw.osmesa.handle, "OSMesaMakeCurrent");
  133. glfw_dlsym(_glfw.osmesa.GetColorBuffer, _glfw.osmesa.handle, "OSMesaGetColorBuffer");
  134. glfw_dlsym(_glfw.osmesa.GetDepthBuffer, _glfw.osmesa.handle, "OSMesaGetDepthBuffer");
  135. glfw_dlsym(_glfw.osmesa.GetProcAddress, _glfw.osmesa.handle, "OSMesaGetProcAddress");
  136. if (!_glfw.osmesa.CreateContextExt ||
  137. !_glfw.osmesa.DestroyContext ||
  138. !_glfw.osmesa.MakeCurrent ||
  139. !_glfw.osmesa.GetColorBuffer ||
  140. !_glfw.osmesa.GetDepthBuffer ||
  141. !_glfw.osmesa.GetProcAddress)
  142. {
  143. _glfwInputError(GLFW_PLATFORM_ERROR,
  144. "OSMesa: Failed to load required entry points");
  145. _glfwTerminateOSMesa();
  146. return false;
  147. }
  148. return true;
  149. }
  150. void _glfwTerminateOSMesa(void)
  151. {
  152. if (_glfw.osmesa.handle)
  153. {
  154. _glfw_dlclose(_glfw.osmesa.handle);
  155. _glfw.osmesa.handle = NULL;
  156. }
  157. }
  158. #define setAttrib(a, v) \
  159. { \
  160. assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
  161. attribs[index++] = a; \
  162. attribs[index++] = v; \
  163. }
  164. bool _glfwCreateContextOSMesa(_GLFWwindow* window,
  165. const _GLFWctxconfig* ctxconfig,
  166. const _GLFWfbconfig* fbconfig)
  167. {
  168. OSMesaContext share = NULL;
  169. const int accumBits = fbconfig->accumRedBits +
  170. fbconfig->accumGreenBits +
  171. fbconfig->accumBlueBits +
  172. fbconfig->accumAlphaBits;
  173. if (ctxconfig->client == GLFW_OPENGL_ES_API)
  174. {
  175. _glfwInputError(GLFW_API_UNAVAILABLE,
  176. "OSMesa: OpenGL ES is not available on OSMesa");
  177. return false;
  178. }
  179. if (ctxconfig->share)
  180. share = ctxconfig->share->context.osmesa.handle;
  181. if (OSMesaCreateContextAttribs)
  182. {
  183. int index = 0, attribs[40];
  184. setAttrib(OSMESA_FORMAT, OSMESA_RGBA);
  185. setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits);
  186. setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
  187. setAttrib(OSMESA_ACCUM_BITS, accumBits);
  188. if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
  189. {
  190. setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
  191. }
  192. else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
  193. {
  194. setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
  195. }
  196. if (ctxconfig->major != 1 || ctxconfig->minor != 0)
  197. {
  198. setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
  199. setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
  200. }
  201. if (ctxconfig->forward)
  202. {
  203. _glfwInputError(GLFW_VERSION_UNAVAILABLE,
  204. "OSMesa: Forward-compatible contexts not supported");
  205. return false;
  206. }
  207. setAttrib(0, 0);
  208. window->context.osmesa.handle =
  209. OSMesaCreateContextAttribs(attribs, share);
  210. }
  211. else
  212. {
  213. if (ctxconfig->profile)
  214. {
  215. _glfwInputError(GLFW_VERSION_UNAVAILABLE,
  216. "OSMesa: OpenGL profiles unavailable");
  217. return false;
  218. }
  219. window->context.osmesa.handle =
  220. OSMesaCreateContextExt(OSMESA_RGBA,
  221. fbconfig->depthBits,
  222. fbconfig->stencilBits,
  223. accumBits,
  224. share);
  225. }
  226. if (window->context.osmesa.handle == NULL)
  227. {
  228. _glfwInputError(GLFW_VERSION_UNAVAILABLE,
  229. "OSMesa: Failed to create context");
  230. return false;
  231. }
  232. window->context.makeCurrent = makeContextCurrentOSMesa;
  233. window->context.swapBuffers = swapBuffersOSMesa;
  234. window->context.swapInterval = swapIntervalOSMesa;
  235. window->context.extensionSupported = extensionSupportedOSMesa;
  236. window->context.getProcAddress = getProcAddressOSMesa;
  237. window->context.destroy = destroyContextOSMesa;
  238. return true;
  239. }
  240. #undef setAttrib
  241. //////////////////////////////////////////////////////////////////////////
  242. ////// GLFW native API //////
  243. //////////////////////////////////////////////////////////////////////////
  244. GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width,
  245. int* height, int* format, void** buffer)
  246. {
  247. void* mesaBuffer;
  248. GLint mesaWidth, mesaHeight, mesaFormat;
  249. _GLFWwindow* window = (_GLFWwindow*) handle;
  250. assert(window != NULL);
  251. _GLFW_REQUIRE_INIT_OR_RETURN(false);
  252. if (!OSMesaGetColorBuffer(window->context.osmesa.handle,
  253. &mesaWidth, &mesaHeight,
  254. &mesaFormat, &mesaBuffer))
  255. {
  256. _glfwInputError(GLFW_PLATFORM_ERROR,
  257. "OSMesa: Failed to retrieve color buffer");
  258. return false;
  259. }
  260. if (width)
  261. *width = mesaWidth;
  262. if (height)
  263. *height = mesaHeight;
  264. if (format)
  265. *format = mesaFormat;
  266. if (buffer)
  267. *buffer = mesaBuffer;
  268. return true;
  269. }
  270. GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle,
  271. int* width, int* height,
  272. int* bytesPerValue,
  273. void** buffer)
  274. {
  275. void* mesaBuffer;
  276. GLint mesaWidth, mesaHeight, mesaBytes;
  277. _GLFWwindow* window = (_GLFWwindow*) handle;
  278. assert(window != NULL);
  279. _GLFW_REQUIRE_INIT_OR_RETURN(false);
  280. if (!OSMesaGetDepthBuffer(window->context.osmesa.handle,
  281. &mesaWidth, &mesaHeight,
  282. &mesaBytes, &mesaBuffer))
  283. {
  284. _glfwInputError(GLFW_PLATFORM_ERROR,
  285. "OSMesa: Failed to retrieve depth buffer");
  286. return false;
  287. }
  288. if (width)
  289. *width = mesaWidth;
  290. if (height)
  291. *height = mesaHeight;
  292. if (bytesPerValue)
  293. *bytesPerValue = mesaBytes;
  294. if (buffer)
  295. *buffer = mesaBuffer;
  296. return true;
  297. }
  298. GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
  299. {
  300. _GLFWwindow* window = (_GLFWwindow*) handle;
  301. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  302. if (window->context.client == GLFW_NO_API)
  303. {
  304. _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
  305. return NULL;
  306. }
  307. return window->context.osmesa.handle;
  308. }