1 /// Translated from C to D 2 module glfw3.osmesa_context; 3 4 extern(C): @nogc: nothrow: __gshared: 5 //======================================================================== 6 // GLFW 3.3 OSMesa - www.glfw.org 7 //------------------------------------------------------------------------ 8 // Copyright (c) 2016 Google Inc. 9 // Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org> 10 // 11 // This software is provided 'as-is', without any express or implied 12 // warranty. In no event will the authors be held liable for any damages 13 // arising from the use of this software. 14 // 15 // Permission is granted to anyone to use this software for any purpose, 16 // including commercial applications, and to alter it and redistribute it 17 // freely, subject to the following restrictions: 18 // 19 // 1. The origin of this software must not be misrepresented; you must not 20 // claim that you wrote the original software. If you use this software 21 // in a product, an acknowledgment in the product documentation would 22 // be appreciated but is not required. 23 // 24 // 2. Altered source versions must be plainly marked as such, and must not 25 // be misrepresented as being the original software. 26 // 27 // 3. This notice may not be removed or altered from any source 28 // distribution. 29 // 30 //======================================================================== 31 // Please use C89 style variable declarations in this file because VS 2010 32 //======================================================================== 33 34 import core.stdc.stdlib; 35 import core.stdc.string; 36 import core.stdc.assert_; 37 38 import glfw3.internal; 39 40 enum OSMESA_RGBA = 0x1908; 41 enum OSMESA_FORMAT = 0x22; 42 enum OSMESA_DEPTH_BITS = 0x30; 43 enum OSMESA_STENCIL_BITS = 0x31; 44 enum OSMESA_ACCUM_BITS = 0x32; 45 enum OSMESA_PROFILE = 0x33; 46 enum OSMESA_CORE_PROFILE = 0x34; 47 enum OSMESA_COMPAT_PROFILE = 0x35; 48 enum OSMESA_CONTEXT_MAJOR_VERSION = 0x36; 49 enum OSMESA_CONTEXT_MINOR_VERSION = 0x37; 50 51 alias void* OSMesaContext; 52 alias void function() OSMESAproc; 53 54 alias OSMesaContext function(GLenum, GLint, GLint, GLint, OSMesaContext) PFN_OSMesaCreateContextExt; 55 alias OSMesaContext function(const(int)*, OSMesaContext) PFN_OSMesaCreateContextAttribs; 56 alias void function(OSMesaContext) PFN_OSMesaDestroyContext; 57 alias int function(OSMesaContext, void*, int, int, int) PFN_OSMesaMakeCurrent; 58 alias int function(OSMesaContext, int*, int*, int*, void**) PFN_OSMesaGetColorBuffer; 59 alias int function(OSMesaContext, int*, int*, int*, void**) PFN_OSMesaGetDepthBuffer; 60 alias GLFWglproc function(const(char)*) PFN_OSMesaGetProcAddress; 61 alias OSMesaCreateContextExt = _glfw.osmesa.CreateContextExt; 62 alias OSMesaCreateContextAttribs = _glfw.osmesa.CreateContextAttribs; 63 alias OSMesaDestroyContext = _glfw.osmesa.DestroyContext; 64 alias OSMesaMakeCurrent = _glfw.osmesa.MakeCurrent; 65 alias OSMesaGetColorBuffer = _glfw.osmesa.GetColorBuffer; 66 alias OSMesaGetDepthBuffer = _glfw.osmesa.GetDepthBuffer; 67 alias OSMesaGetProcAddress = _glfw.osmesa.GetProcAddress; 68 69 mixin template _GLFW_OSMESA_CONTEXT_STATE() { _GLFWcontextOSMesa osmesa;} 70 mixin template _GLFW_OSMESA_LIBRARY_CONTEXT_STATE() { _GLFWlibraryOSMesa osmesa;} 71 72 // OSMesa-specific per-context data 73 // 74 struct _GLFWcontextOSMesa { 75 OSMesaContext handle; 76 int width; 77 int height; 78 void* buffer; 79 80 }/+alias _GLFWcontextOSMesa _GLFWcontextOSMesa;+/ 81 82 // OSMesa-specific global data 83 // 84 struct _GLFWlibraryOSMesa { 85 void* handle; 86 87 PFN_OSMesaCreateContextExt CreateContextExt; 88 PFN_OSMesaCreateContextAttribs CreateContextAttribs; 89 PFN_OSMesaDestroyContext DestroyContext; 90 PFN_OSMesaMakeCurrent MakeCurrent; 91 PFN_OSMesaGetColorBuffer GetColorBuffer; 92 PFN_OSMesaGetDepthBuffer GetDepthBuffer; 93 PFN_OSMesaGetProcAddress GetProcAddress; 94 95 }/+alias _GLFWlibraryOSMesa _GLFWlibraryOSMesa;+/ 96 97 GLFWbool _glfwInitOSMesa(); 98 void _glfwTerminateOSMesa(); 99 GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig); 100 101 private void makeContextCurrentOSMesa(_GLFWwindow* window) { 102 if (window) 103 { 104 int width;int height; 105 _glfwPlatformGetFramebufferSize(window, &width, &height); 106 107 // Check to see if we need to allocate a new buffer 108 if ((window.context.osmesa.buffer == null) || 109 (width != window.context.osmesa.width) || 110 (height != window.context.osmesa.height)) 111 { 112 free(window.context.osmesa.buffer); 113 114 // Allocate the new buffer (width * height * 8-bit RGBA) 115 window.context.osmesa.buffer = calloc(4, cast(size_t) width * height); 116 window.context.osmesa.width = width; 117 window.context.osmesa.height = height; 118 } 119 120 if (!_glfw.osmesa.MakeCurrent(window.context.osmesa.handle, 121 window.context.osmesa.buffer, 122 GL_UNSIGNED_BYTE, 123 width, height)) 124 { 125 _glfwInputError(GLFW_PLATFORM_ERROR, 126 "OSMesa: Failed to make context current"); 127 return; 128 } 129 } 130 131 _glfwPlatformSetTls(&_glfw.contextSlot, window); 132 } 133 134 private GLFWglproc getProcAddressOSMesa(const(char)* procname) { 135 return cast(GLFWglproc) _glfw.osmesa.GetProcAddress(procname); 136 } 137 138 private void destroyContextOSMesa(_GLFWwindow* window) { 139 if (window.context.osmesa.handle) 140 { 141 _glfw.osmesa.DestroyContext(window.context.osmesa.handle); 142 window.context.osmesa.handle = null; 143 } 144 145 if (window.context.osmesa.buffer) 146 { 147 free(window.context.osmesa.buffer); 148 window.context.osmesa.width = 0; 149 window.context.osmesa.height = 0; 150 } 151 } 152 153 static void swapBuffersOSMesa(_GLFWwindow* window) { 154 // No double buffering on OSMesa 155 } 156 157 static void swapIntervalOSMesa(int interval) { 158 // No swap interval on OSMesa 159 } 160 161 static int extensionSupportedOSMesa(const(char)* extension) { 162 // OSMesa does not have extensions 163 return GLFW_FALSE; 164 } 165 166 167 ////////////////////////////////////////////////////////////////////////// 168 ////// GLFW internal API ////// 169 ////////////////////////////////////////////////////////////////////////// 170 171 GLFWbool _glfwInitOSMesa() { 172 int i; 173 174 version(Windows) { 175 static immutable char*[3] sonames = ["libOSMesa.dll", "OSMesa.dll", null]; 176 } else version(Cygwin) { 177 static immutable char*[2] sonames = ["libOSMesa.8.dylib", null]; 178 } else { 179 static immutable char*[3] sonames = ["libOSMesa.so.8", "libOSMesa.so.6", null]; 180 } 181 182 if (_glfw.osmesa.handle) 183 return GLFW_TRUE; 184 185 for (i = 0; sonames[i]; i++) 186 { 187 _glfw.osmesa.handle = _glfw_dlopen(sonames[i]); 188 if (_glfw.osmesa.handle) 189 break; 190 } 191 192 if (!_glfw.osmesa.handle) 193 { 194 _glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found"); 195 return GLFW_FALSE; 196 } 197 198 _glfw.osmesa.CreateContextExt = cast(PFN_OSMesaCreateContextExt) 199 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt"); 200 _glfw.osmesa.CreateContextAttribs = cast(PFN_OSMesaCreateContextAttribs) 201 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs"); 202 _glfw.osmesa.DestroyContext = cast(PFN_OSMesaDestroyContext) 203 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext"); 204 _glfw.osmesa.MakeCurrent = cast(PFN_OSMesaMakeCurrent) 205 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent"); 206 _glfw.osmesa.GetColorBuffer = cast(PFN_OSMesaGetColorBuffer) 207 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer"); 208 _glfw.osmesa.GetDepthBuffer = cast(PFN_OSMesaGetDepthBuffer) 209 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer"); 210 _glfw.osmesa.GetProcAddress = cast(PFN_OSMesaGetProcAddress) 211 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress"); 212 213 if (!_glfw.osmesa.CreateContextExt || 214 !_glfw.osmesa.DestroyContext || 215 !_glfw.osmesa.MakeCurrent || 216 !_glfw.osmesa.GetColorBuffer || 217 !_glfw.osmesa.GetDepthBuffer || 218 !_glfw.osmesa.GetProcAddress) 219 { 220 _glfwInputError(GLFW_PLATFORM_ERROR, 221 "OSMesa: Failed to load required entry points"); 222 223 _glfwTerminateOSMesa(); 224 return GLFW_FALSE; 225 } 226 227 return GLFW_TRUE; 228 } 229 230 void _glfwTerminateOSMesa() { 231 if (_glfw.osmesa.handle) 232 { 233 _glfw_dlclose(_glfw.osmesa.handle); 234 _glfw.osmesa.handle = null; 235 } 236 } 237 238 GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, const(_GLFWctxconfig)* ctxconfig, const(_GLFWfbconfig)* fbconfig) { 239 OSMesaContext share = null; 240 const(int) accumBits = fbconfig.accumRedBits + 241 fbconfig.accumGreenBits + 242 fbconfig.accumBlueBits + 243 fbconfig.accumAlphaBits; 244 245 if (ctxconfig.client == GLFW_OPENGL_ES_API) 246 { 247 _glfwInputError(GLFW_API_UNAVAILABLE, 248 "OSMesa: OpenGL ES is not available on OSMesa"); 249 return GLFW_FALSE; 250 } 251 252 if (ctxconfig.share) 253 share = cast(void*) ctxconfig.share.context.osmesa.handle; 254 255 //if (OSMesaCreateContextAttribs) 256 if (_glfw.osmesa.CreateContextAttribs) 257 { 258 int index = 0;int[40] attribs; 259 void setAttrib(int a, int v) { 260 assert((cast(size_t) index + 1) < attribs.length); 261 attribs[index++] = a; 262 attribs[index++] = v; 263 } 264 265 setAttrib(OSMESA_FORMAT, OSMESA_RGBA); 266 setAttrib(OSMESA_DEPTH_BITS, fbconfig.depthBits); 267 setAttrib(OSMESA_STENCIL_BITS, fbconfig.stencilBits); 268 setAttrib(OSMESA_ACCUM_BITS, accumBits); 269 270 if (ctxconfig.profile == GLFW_OPENGL_CORE_PROFILE) 271 { 272 setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE); 273 } 274 else if (ctxconfig.profile == GLFW_OPENGL_COMPAT_PROFILE) 275 { 276 setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE); 277 } 278 279 if (ctxconfig.major != 1 || ctxconfig.minor != 0) 280 { 281 setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig.major); 282 setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig.minor); 283 } 284 285 if (ctxconfig.forward) 286 { 287 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 288 "OSMesa: Forward-compatible contexts not supported"); 289 return GLFW_FALSE; 290 } 291 292 setAttrib(0, 0); 293 294 window.context.osmesa.handle = 295 _glfw.osmesa.CreateContextAttribs(attribs.ptr, share); 296 } 297 else 298 { 299 if (ctxconfig.profile) 300 { 301 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 302 "OSMesa: OpenGL profiles unavailable"); 303 return GLFW_FALSE; 304 } 305 306 window.context.osmesa.handle = 307 _glfw.osmesa.CreateContextExt(OSMESA_RGBA, 308 fbconfig.depthBits, 309 fbconfig.stencilBits, 310 accumBits, 311 share); 312 } 313 314 if (window.context.osmesa.handle == null) 315 { 316 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 317 "OSMesa: Failed to create context"); 318 return GLFW_FALSE; 319 } 320 321 window.context.makeCurrent = &makeContextCurrentOSMesa; 322 window.context.swapBuffers = &swapBuffersOSMesa; 323 window.context.swapInterval = &swapIntervalOSMesa; 324 window.context.extensionSupported = &extensionSupportedOSMesa; 325 window.context.getProcAddress = &getProcAddressOSMesa; 326 window.context.destroy = &destroyContextOSMesa; 327 328 return GLFW_TRUE; 329 } 330 331 ////////////////////////////////////////////////////////////////////////// 332 ////// GLFW native API ////// 333 ////////////////////////////////////////////////////////////////////////// 334 335 int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width, int* height, int* format, void** buffer) { 336 void* mesaBuffer; 337 GLint mesaWidth;GLint mesaHeight;GLint mesaFormat; 338 _GLFWwindow* window = cast(_GLFWwindow*) handle; 339 assert(window != null); 340 341 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!("GLFW_FALSE")); 342 343 if (!_glfw.osmesa.GetColorBuffer(window.context.osmesa.handle, 344 &mesaWidth, &mesaHeight, 345 &mesaFormat, &mesaBuffer)) 346 { 347 _glfwInputError(GLFW_PLATFORM_ERROR, 348 "OSMesa: Failed to retrieve color buffer"); 349 return GLFW_FALSE; 350 } 351 352 if (width) 353 *width = mesaWidth; 354 if (height) 355 *height = mesaHeight; 356 if (format) 357 *format = mesaFormat; 358 if (buffer) 359 *buffer = mesaBuffer; 360 361 return GLFW_TRUE; 362 } 363 364 int glfwGetOSMesaDepthBuffer(GLFWwindow* handle, int* width, int* height, int* bytesPerValue, void** buffer) { 365 void* mesaBuffer; 366 GLint mesaWidth;GLint mesaHeight;GLint mesaBytes; 367 _GLFWwindow* window = cast(_GLFWwindow*) handle; 368 assert(window != null); 369 370 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!("GLFW_FALSE")); 371 372 if (!_glfw.osmesa.GetDepthBuffer(window.context.osmesa.handle, 373 &mesaWidth, &mesaHeight, 374 &mesaBytes, &mesaBuffer)) 375 { 376 _glfwInputError(GLFW_PLATFORM_ERROR, 377 "OSMesa: Failed to retrieve depth buffer"); 378 return GLFW_FALSE; 379 } 380 381 if (width) 382 *width = mesaWidth; 383 if (height) 384 *height = mesaHeight; 385 if (bytesPerValue) 386 *bytesPerValue = mesaBytes; 387 if (buffer) 388 *buffer = mesaBuffer; 389 390 return GLFW_TRUE; 391 } 392 393 OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle) { 394 _GLFWwindow* window = cast(_GLFWwindow*) handle; 395 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!("null")); 396 397 if (window.context.client == GLFW_NO_API) 398 { 399 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, null); 400 return null; 401 } 402 403 return window.context.osmesa.handle; 404 }