osmesa_context.c (11935B)
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 28 #include "internal.h" 29 30 #include <stdlib.h> 31 #include <string.h> 32 #include <assert.h> 33 34 static void makeContextCurrentOSMesa(_GLFWwindow* window) 35 { 36 if (window) 37 { 38 int width, height; 39 _glfw.platform.getFramebufferSize(window, &width, &height); 40 41 // Check to see if we need to allocate a new buffer 42 if ((window->context.osmesa.buffer == NULL) || 43 (width != window->context.osmesa.width) || 44 (height != window->context.osmesa.height)) 45 { 46 _glfw_free(window->context.osmesa.buffer); 47 48 // Allocate the new buffer (width * height * 8-bit RGBA) 49 window->context.osmesa.buffer = _glfw_calloc(4, (size_t) width * height); 50 window->context.osmesa.width = width; 51 window->context.osmesa.height = height; 52 } 53 54 if (!OSMesaMakeCurrent(window->context.osmesa.handle, 55 window->context.osmesa.buffer, 56 GL_UNSIGNED_BYTE, 57 width, height)) 58 { 59 _glfwInputError(GLFW_PLATFORM_ERROR, 60 "OSMesa: Failed to make context current"); 61 return; 62 } 63 } 64 65 _glfwPlatformSetTls(&_glfw.contextSlot, window); 66 } 67 68 static GLFWglproc getProcAddressOSMesa(const char* procname) 69 { 70 return (GLFWglproc) OSMesaGetProcAddress(procname); 71 } 72 73 static void destroyContextOSMesa(_GLFWwindow* window) 74 { 75 if (window->context.osmesa.handle) 76 { 77 OSMesaDestroyContext(window->context.osmesa.handle); 78 window->context.osmesa.handle = NULL; 79 } 80 81 if (window->context.osmesa.buffer) 82 { 83 _glfw_free(window->context.osmesa.buffer); 84 window->context.osmesa.width = 0; 85 window->context.osmesa.height = 0; 86 } 87 } 88 89 static void swapBuffersOSMesa(_GLFWwindow* window) 90 { 91 // No double buffering on OSMesa 92 } 93 94 static void swapIntervalOSMesa(int interval) 95 { 96 // No swap interval on OSMesa 97 } 98 99 static int extensionSupportedOSMesa(const char* extension) 100 { 101 // OSMesa does not have extensions 102 return GLFW_FALSE; 103 } 104 105 106 ////////////////////////////////////////////////////////////////////////// 107 ////// GLFW internal API ////// 108 ////////////////////////////////////////////////////////////////////////// 109 110 GLFWbool _glfwInitOSMesa(void) 111 { 112 int i; 113 const char* sonames[] = 114 { 115 #if defined(_GLFW_OSMESA_LIBRARY) 116 _GLFW_OSMESA_LIBRARY, 117 #elif defined(_WIN32) 118 "libOSMesa.dll", 119 "OSMesa.dll", 120 #elif defined(__APPLE__) 121 "libOSMesa.8.dylib", 122 #elif defined(__CYGWIN__) 123 "libOSMesa-8.so", 124 #elif defined(__OpenBSD__) || defined(__NetBSD__) 125 "libOSMesa.so", 126 #else 127 "libOSMesa.so.8", 128 "libOSMesa.so.6", 129 #endif 130 NULL 131 }; 132 133 if (_glfw.osmesa.handle) 134 return GLFW_TRUE; 135 136 for (i = 0; sonames[i]; i++) 137 { 138 _glfw.osmesa.handle = _glfwPlatformLoadModule(sonames[i]); 139 if (_glfw.osmesa.handle) 140 break; 141 } 142 143 if (!_glfw.osmesa.handle) 144 { 145 _glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found"); 146 return GLFW_FALSE; 147 } 148 149 _glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt) 150 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaCreateContextExt"); 151 _glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs) 152 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaCreateContextAttribs"); 153 _glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext) 154 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaDestroyContext"); 155 _glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent) 156 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaMakeCurrent"); 157 _glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer) 158 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetColorBuffer"); 159 _glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer) 160 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetDepthBuffer"); 161 _glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress) 162 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetProcAddress"); 163 164 if (!_glfw.osmesa.CreateContextExt || 165 !_glfw.osmesa.DestroyContext || 166 !_glfw.osmesa.MakeCurrent || 167 !_glfw.osmesa.GetColorBuffer || 168 !_glfw.osmesa.GetDepthBuffer || 169 !_glfw.osmesa.GetProcAddress) 170 { 171 _glfwInputError(GLFW_PLATFORM_ERROR, 172 "OSMesa: Failed to load required entry points"); 173 174 _glfwTerminateOSMesa(); 175 return GLFW_FALSE; 176 } 177 178 return GLFW_TRUE; 179 } 180 181 void _glfwTerminateOSMesa(void) 182 { 183 if (_glfw.osmesa.handle) 184 { 185 _glfwPlatformFreeModule(_glfw.osmesa.handle); 186 _glfw.osmesa.handle = NULL; 187 } 188 } 189 190 #define SET_ATTRIB(a, v) \ 191 { \ 192 assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ 193 attribs[index++] = a; \ 194 attribs[index++] = v; \ 195 } 196 197 GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, 198 const _GLFWctxconfig* ctxconfig, 199 const _GLFWfbconfig* fbconfig) 200 { 201 OSMesaContext share = NULL; 202 const int accumBits = fbconfig->accumRedBits + 203 fbconfig->accumGreenBits + 204 fbconfig->accumBlueBits + 205 fbconfig->accumAlphaBits; 206 207 if (ctxconfig->client == GLFW_OPENGL_ES_API) 208 { 209 _glfwInputError(GLFW_API_UNAVAILABLE, 210 "OSMesa: OpenGL ES is not available on OSMesa"); 211 return GLFW_FALSE; 212 } 213 214 if (ctxconfig->share) 215 share = ctxconfig->share->context.osmesa.handle; 216 217 if (OSMesaCreateContextAttribs) 218 { 219 int index = 0, attribs[40]; 220 221 SET_ATTRIB(OSMESA_FORMAT, OSMESA_RGBA); 222 SET_ATTRIB(OSMESA_DEPTH_BITS, fbconfig->depthBits); 223 SET_ATTRIB(OSMESA_STENCIL_BITS, fbconfig->stencilBits); 224 SET_ATTRIB(OSMESA_ACCUM_BITS, accumBits); 225 226 if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) 227 { 228 SET_ATTRIB(OSMESA_PROFILE, OSMESA_CORE_PROFILE); 229 } 230 else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) 231 { 232 SET_ATTRIB(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE); 233 } 234 235 if (ctxconfig->major != 1 || ctxconfig->minor != 0) 236 { 237 SET_ATTRIB(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major); 238 SET_ATTRIB(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor); 239 } 240 241 if (ctxconfig->forward) 242 { 243 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 244 "OSMesa: Forward-compatible contexts not supported"); 245 return GLFW_FALSE; 246 } 247 248 SET_ATTRIB(0, 0); 249 250 window->context.osmesa.handle = 251 OSMesaCreateContextAttribs(attribs, share); 252 } 253 else 254 { 255 if (ctxconfig->profile) 256 { 257 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 258 "OSMesa: OpenGL profiles unavailable"); 259 return GLFW_FALSE; 260 } 261 262 window->context.osmesa.handle = 263 OSMesaCreateContextExt(OSMESA_RGBA, 264 fbconfig->depthBits, 265 fbconfig->stencilBits, 266 accumBits, 267 share); 268 } 269 270 if (window->context.osmesa.handle == NULL) 271 { 272 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 273 "OSMesa: Failed to create context"); 274 return GLFW_FALSE; 275 } 276 277 window->context.makeCurrent = makeContextCurrentOSMesa; 278 window->context.swapBuffers = swapBuffersOSMesa; 279 window->context.swapInterval = swapIntervalOSMesa; 280 window->context.extensionSupported = extensionSupportedOSMesa; 281 window->context.getProcAddress = getProcAddressOSMesa; 282 window->context.destroy = destroyContextOSMesa; 283 284 return GLFW_TRUE; 285 } 286 287 #undef SET_ATTRIB 288 289 290 ////////////////////////////////////////////////////////////////////////// 291 ////// GLFW native API ////// 292 ////////////////////////////////////////////////////////////////////////// 293 294 GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width, 295 int* height, int* format, void** buffer) 296 { 297 void* mesaBuffer; 298 GLint mesaWidth, mesaHeight, mesaFormat; 299 _GLFWwindow* window = (_GLFWwindow*) handle; 300 assert(window != NULL); 301 302 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 303 304 if (window->context.source != GLFW_OSMESA_CONTEXT_API) 305 { 306 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); 307 return GLFW_FALSE; 308 } 309 310 if (!OSMesaGetColorBuffer(window->context.osmesa.handle, 311 &mesaWidth, &mesaHeight, 312 &mesaFormat, &mesaBuffer)) 313 { 314 _glfwInputError(GLFW_PLATFORM_ERROR, 315 "OSMesa: Failed to retrieve color buffer"); 316 return GLFW_FALSE; 317 } 318 319 if (width) 320 *width = mesaWidth; 321 if (height) 322 *height = mesaHeight; 323 if (format) 324 *format = mesaFormat; 325 if (buffer) 326 *buffer = mesaBuffer; 327 328 return GLFW_TRUE; 329 } 330 331 GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle, 332 int* width, int* height, 333 int* bytesPerValue, 334 void** buffer) 335 { 336 void* mesaBuffer; 337 GLint mesaWidth, mesaHeight, mesaBytes; 338 _GLFWwindow* window = (_GLFWwindow*) handle; 339 assert(window != NULL); 340 341 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 342 343 if (window->context.source != GLFW_OSMESA_CONTEXT_API) 344 { 345 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); 346 return GLFW_FALSE; 347 } 348 349 if (!OSMesaGetDepthBuffer(window->context.osmesa.handle, 350 &mesaWidth, &mesaHeight, 351 &mesaBytes, &mesaBuffer)) 352 { 353 _glfwInputError(GLFW_PLATFORM_ERROR, 354 "OSMesa: Failed to retrieve depth buffer"); 355 return GLFW_FALSE; 356 } 357 358 if (width) 359 *width = mesaWidth; 360 if (height) 361 *height = mesaHeight; 362 if (bytesPerValue) 363 *bytesPerValue = mesaBytes; 364 if (buffer) 365 *buffer = mesaBuffer; 366 367 return GLFW_TRUE; 368 } 369 370 GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle) 371 { 372 _GLFWwindow* window = (_GLFWwindow*) handle; 373 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 374 375 if (window->context.source != GLFW_OSMESA_CONTEXT_API) 376 { 377 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); 378 return NULL; 379 } 380 381 return window->context.osmesa.handle; 382 } 383