osmesa_context.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. //========================================================================
  2. // GLFW 3.4 OSMesa - www.glfw.org
  3. //------------------------------------------------------------------------
  4. // Copyright (c) 2016 Google Inc.
  5. // Copyright (c) 2016-2017 Camilla Löwy <[email protected]>
  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)
  81. {
  82. // No double buffering on OSMesa
  83. }
  84. static void swapIntervalOSMesa(int interval)
  85. {
  86. // No swap interval on OSMesa
  87. }
  88. static int extensionSupportedOSMesa(const char* extension)
  89. {
  90. // OSMesa does not have extensions
  91. return GLFW_FALSE;
  92. }
  93. //////////////////////////////////////////////////////////////////////////
  94. ////// GLFW internal API //////
  95. //////////////////////////////////////////////////////////////////////////
  96. GLFWbool _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 GLFW_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 GLFW_FALSE;
  128. }
  129. _glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt)
  130. _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt");
  131. _glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs)
  132. _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs");
  133. _glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext)
  134. _glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext");
  135. _glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent)
  136. _glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent");
  137. _glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer)
  138. _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer");
  139. _glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer)
  140. _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer");
  141. _glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress)
  142. _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress");
  143. if (!_glfw.osmesa.CreateContextExt ||
  144. !_glfw.osmesa.DestroyContext ||
  145. !_glfw.osmesa.MakeCurrent ||
  146. !_glfw.osmesa.GetColorBuffer ||
  147. !_glfw.osmesa.GetDepthBuffer ||
  148. !_glfw.osmesa.GetProcAddress)
  149. {
  150. _glfwInputError(GLFW_PLATFORM_ERROR,
  151. "OSMesa: Failed to load required entry points");
  152. _glfwTerminateOSMesa();
  153. return GLFW_FALSE;
  154. }
  155. return GLFW_TRUE;
  156. }
  157. void _glfwTerminateOSMesa(void)
  158. {
  159. if (_glfw.osmesa.handle)
  160. {
  161. _glfw_dlclose(_glfw.osmesa.handle);
  162. _glfw.osmesa.handle = NULL;
  163. }
  164. }
  165. #define setAttrib(a, v) \
  166. { \
  167. assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
  168. attribs[index++] = a; \
  169. attribs[index++] = v; \
  170. }
  171. GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
  172. const _GLFWctxconfig* ctxconfig,
  173. const _GLFWfbconfig* fbconfig)
  174. {
  175. OSMesaContext share = NULL;
  176. const int accumBits = fbconfig->accumRedBits +
  177. fbconfig->accumGreenBits +
  178. fbconfig->accumBlueBits +
  179. fbconfig->accumAlphaBits;
  180. if (ctxconfig->client == GLFW_OPENGL_ES_API)
  181. {
  182. _glfwInputError(GLFW_API_UNAVAILABLE,
  183. "OSMesa: OpenGL ES is not available on OSMesa");
  184. return GLFW_FALSE;
  185. }
  186. if (ctxconfig->share)
  187. share = ctxconfig->share->context.osmesa.handle;
  188. if (OSMesaCreateContextAttribs)
  189. {
  190. int index = 0, attribs[40];
  191. setAttrib(OSMESA_FORMAT, OSMESA_RGBA);
  192. setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits);
  193. setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
  194. setAttrib(OSMESA_ACCUM_BITS, accumBits);
  195. if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
  196. {
  197. setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
  198. }
  199. else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
  200. {
  201. setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
  202. }
  203. if (ctxconfig->major != 1 || ctxconfig->minor != 0)
  204. {
  205. setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
  206. setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
  207. }
  208. if (ctxconfig->forward)
  209. {
  210. _glfwInputError(GLFW_VERSION_UNAVAILABLE,
  211. "OSMesa: Forward-compatible contexts not supported");
  212. return GLFW_FALSE;
  213. }
  214. setAttrib(0, 0);
  215. window->context.osmesa.handle =
  216. OSMesaCreateContextAttribs(attribs, share);
  217. }
  218. else
  219. {
  220. if (ctxconfig->profile)
  221. {
  222. _glfwInputError(GLFW_VERSION_UNAVAILABLE,
  223. "OSMesa: OpenGL profiles unavailable");
  224. return GLFW_FALSE;
  225. }
  226. window->context.osmesa.handle =
  227. OSMesaCreateContextExt(OSMESA_RGBA,
  228. fbconfig->depthBits,
  229. fbconfig->stencilBits,
  230. accumBits,
  231. share);
  232. }
  233. if (window->context.osmesa.handle == NULL)
  234. {
  235. _glfwInputError(GLFW_VERSION_UNAVAILABLE,
  236. "OSMesa: Failed to create context");
  237. return GLFW_FALSE;
  238. }
  239. window->context.makeCurrent = makeContextCurrentOSMesa;
  240. window->context.swapBuffers = swapBuffersOSMesa;
  241. window->context.swapInterval = swapIntervalOSMesa;
  242. window->context.extensionSupported = extensionSupportedOSMesa;
  243. window->context.getProcAddress = getProcAddressOSMesa;
  244. window->context.destroy = destroyContextOSMesa;
  245. return GLFW_TRUE;
  246. }
  247. #undef setAttrib
  248. //////////////////////////////////////////////////////////////////////////
  249. ////// GLFW native API //////
  250. //////////////////////////////////////////////////////////////////////////
  251. GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width,
  252. int* height, int* format, void** buffer)
  253. {
  254. void* mesaBuffer;
  255. GLint mesaWidth, mesaHeight, mesaFormat;
  256. _GLFWwindow* window = (_GLFWwindow*) handle;
  257. assert(window != NULL);
  258. _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
  259. if (!OSMesaGetColorBuffer(window->context.osmesa.handle,
  260. &mesaWidth, &mesaHeight,
  261. &mesaFormat, &mesaBuffer))
  262. {
  263. _glfwInputError(GLFW_PLATFORM_ERROR,
  264. "OSMesa: Failed to retrieve color buffer");
  265. return GLFW_FALSE;
  266. }
  267. if (width)
  268. *width = mesaWidth;
  269. if (height)
  270. *height = mesaHeight;
  271. if (format)
  272. *format = mesaFormat;
  273. if (buffer)
  274. *buffer = mesaBuffer;
  275. return GLFW_TRUE;
  276. }
  277. GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle,
  278. int* width, int* height,
  279. int* bytesPerValue,
  280. void** buffer)
  281. {
  282. void* mesaBuffer;
  283. GLint mesaWidth, mesaHeight, mesaBytes;
  284. _GLFWwindow* window = (_GLFWwindow*) handle;
  285. assert(window != NULL);
  286. _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
  287. if (!OSMesaGetDepthBuffer(window->context.osmesa.handle,
  288. &mesaWidth, &mesaHeight,
  289. &mesaBytes, &mesaBuffer))
  290. {
  291. _glfwInputError(GLFW_PLATFORM_ERROR,
  292. "OSMesa: Failed to retrieve depth buffer");
  293. return GLFW_FALSE;
  294. }
  295. if (width)
  296. *width = mesaWidth;
  297. if (height)
  298. *height = mesaHeight;
  299. if (bytesPerValue)
  300. *bytesPerValue = mesaBytes;
  301. if (buffer)
  302. *buffer = mesaBuffer;
  303. return GLFW_TRUE;
  304. }
  305. GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
  306. {
  307. _GLFWwindow* window = (_GLFWwindow*) handle;
  308. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  309. if (window->context.client == GLFW_NO_API)
  310. {
  311. _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
  312. return NULL;
  313. }
  314. return window->context.osmesa.handle;
  315. }