1 module ws.gl.context; 2 3 4 import 5 std.conv, 6 std.algorithm, 7 std.string, 8 std.traits, 9 ws.wm, 10 ws.exception, 11 ws.gl.gl; 12 13 14 version(Windows){ 15 16 17 string getLastError(){ 18 DWORD errcode = GetLastError(); 19 if(!errcode) 20 return "No error"; 21 LPCSTR msgBuf; 22 DWORD i = FormatMessageA( 23 cast(uint)( 24 FORMAT_MESSAGE_ALLOCATE_BUFFER | 25 FORMAT_MESSAGE_FROM_SYSTEM | 26 FORMAT_MESSAGE_IGNORE_INSERTS), 27 null, 28 errcode, 29 cast(uint)MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 30 cast(LPSTR)&msgBuf, 31 0, 32 null 33 ); 34 string text = to!string(msgBuf); 35 LocalFree(cast(HLOCAL)msgBuf); 36 return text; 37 } 38 39 40 import ws.wm.win32.api; 41 42 private static GraphicsContext current; 43 44 auto chooseBestPixelFormat(){ 45 46 } 47 48 __gshared class GlContext { 49 50 GraphicsContext handle; 51 __gshared GraphicsContext sharedHandle; 52 WindowHandle window; 53 HDC deviceContext; 54 55 private GraphicsContext spawn(){ 56 auto c = wm.wglCreateContextAttribsARB(GetDC(window), sharedHandle, null); 57 if(!c) 58 throw new Exception("Failed to create shared context"); 59 return c; 60 } 61 62 this(WindowHandle window, GraphicsContext context){ 63 this.window = window; 64 this.handle = context; 65 this.sharedHandle = context; 66 } 67 68 this(WindowHandle window){ 69 enum antiAliasing = 0; 70 this.window = window; 71 deviceContext = GetDC(window); 72 try { 73 if(!deviceContext) 74 throw new Exception("window.Show failed: GetDC"); 75 uint formatCount = 0; 76 int pixelFormat; 77 int[] iAttribList = [ 78 0x2001, true, 79 0x2010, true, 80 0x2011, true, 81 0x2003, 0x2027, 82 0x2014, 0x202B, 83 0x2014, 24, 84 0x201B, 8, 85 0x2022, 16, 86 0x2023, 8, 87 0x2011, true, 88 0x2041, antiAliasing > 1 ? true : false, 89 0x2042, antiAliasing, 90 0 91 ]; 92 wm.wglChoosePixelFormatARB(deviceContext, iAttribList.ptr, null, 1, &pixelFormat, &formatCount); 93 if(!formatCount) 94 throw new Exception("wglChoosePixelFormatARB failed: %s".format(getLastError())); 95 SetPixelFormat(deviceContext, pixelFormat, null); 96 }catch(Exception e){ 97 ubyte depth = 32; 98 ubyte color = 24; 99 ubyte stencil = 8; 100 PIXELFORMATDESCRIPTOR descriptor; 101 descriptor.nSize = descriptor.sizeof; 102 descriptor.nVersion = 1; 103 descriptor.iLayerType = PFD_MAIN_PLANE; 104 descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; 105 descriptor.iPixelType = PFD_TYPE_RGBA; 106 descriptor.cColorBits = depth; 107 descriptor.cDepthBits = color; 108 descriptor.cStencilBits = stencil; 109 descriptor.cAlphaBits = depth == 32 ? 8 : 0; 110 auto pixelFormat = ChoosePixelFormat(deviceContext, &descriptor); 111 SetPixelFormat(deviceContext, pixelFormat, &descriptor); 112 } 113 114 try { 115 enum WGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091; 116 enum WGL_CONTEXT_MINOR_VERSION_ARB = 0x2092; 117 enum WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002; 118 int[] attribs = [ 119 WGL_CONTEXT_MAJOR_VERSION_ARB, 3, 120 WGL_CONTEXT_MINOR_VERSION_ARB, 3, 121 //WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 1, 122 0, 0 123 ]; 124 handle = wm.wglCreateContextAttribsARB(deviceContext, null, attribs.ptr); 125 if(!handle) 126 throw new Exception("wglCreateContextAttribsARB() failed: %s".format(getLastError())); 127 }catch(Exception e){ 128 import std.stdio; writeln(e); 129 handle = core.sys.windows.wingdi.wglCreateContext(deviceContext); 130 } 131 this.sharedHandle = handle; 132 wglMakeCurrent(deviceContext, handle); 133 DerelictGL3.reload(); 134 } 135 136 void swapBuffers(){ 137 assert(handle == sharedHandle, "Can only swap from main"); 138 SwapBuffers(deviceContext); 139 } 140 141 template opDispatch(string s){ 142 auto opDispatch(Args...)(Args args){ 143 if(!handle && sharedHandle){ 144 synchronized(this){ 145 handle = spawn; 146 } 147 } 148 if(current != handle){ 149 wglMakeCurrent(window, handle); 150 current = handle; 151 } 152 assert(wglGetCurrentContext() == handle); 153 debug { gl.check("?"); } 154 enum s = s[0..1].capitalize ~ s[1..$]; 155 mixin("alias returns = ReturnType!(gl" ~ s ~ ");"); 156 static if(!is(returns == void)){ 157 mixin("auto result = gl" ~ s ~ "(args);"); 158 debug { gl.check("gl" ~ s); } 159 return result; 160 }else{ 161 mixin("gl" ~ s ~ "(args);"); 162 debug { gl.check("gl" ~ s); } 163 } 164 } 165 } 166 167 } 168 169 170 } 171 172 173 version(Posix){ 174 175 import ws.wm.x11.api; 176 import derelictX = derelict.util.xtypes; 177 178 import derelict.opengl3.glx; 179 180 private static GraphicsContext current; 181 182 T_glXCreateContextAttribsARB glXCreateContextAttribsARB; 183 184 class GlContext { 185 186 GraphicsContext handle; 187 WindowHandle window; 188 Display* display; 189 190 this(WindowHandle window){ 191 this(wm.displayHandle, window); 192 } 193 194 this(Display* display, WindowHandle window){ 195 this.window = window; 196 this.display = display; 197 XVisualInfo* graphicsInfo; 198 try { 199 200 wm.glCore = true; 201 glXCreateContextAttribsARB = cast(T_glXCreateContextAttribsARB) 202 glXGetProcAddress("glXCreateContextAttribsARB"); 203 if(!glXCreateContextAttribsARB) 204 wm.glCore = false; 205 206 if(!wm.glCore) 207 throw new Exception("disabled"); 208 209 XWindowAttributes wa; 210 assert(XGetWindowAttributes(display, window, &wa)); 211 212 XVisualInfo visual; 213 visual.screen = DefaultScreen(display); 214 visual.visualid = XVisualIDFromVisual(wa.visual); 215 int visualCount = 0; 216 graphicsInfo = XGetVisualInfo(display, VisualIDMask | VisualScreenMask, &visual, &visualCount); 217 218 size_t config = size_t.max; 219 220 int nbConfigs = 0; 221 GLXFBConfig* configs = glXChooseFBConfig(display, DefaultScreen(display), null, &nbConfigs); 222 223 foreach(i, fbc; configs[0..nbConfigs]){ 224 auto vis = cast(XVisualInfo*)glXGetVisualFromFBConfig(display, fbc); 225 if(!vis) 226 continue; 227 scope(exit) 228 XFree(vis); 229 if(vis.visualid == visual.visualid){ 230 config = i; 231 break; 232 } 233 } 234 235 import std.stdio; 236 writeln(*graphicsInfo); 237 238 if(config == size_t.max) 239 throw new Exception("Failed to get FB config"); 240 241 int[] attribs = [ 242 GLX_CONTEXT_MAJOR_VERSION_ARB, 3, 243 GLX_CONTEXT_MINOR_VERSION_ARB, 3, 244 0 245 ]; 246 247 handle = glXCreateContextAttribsARB( 248 display, configs[config], null, cast(int)True, attribs.ptr 249 ); 250 if(!handle) 251 throw new Exception("glXCreateContextAttribsARB failed"); 252 253 debug(glContextInfo){ 254 import std.stdio; 255 writeln(graphicsInfo.depth); 256 } 257 258 }catch(Exception e){ 259 import std.stdio; 260 writeln(e); 261 GLint[] att = [GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_ALPHA_SIZE, 8, GLX_DOUBLEBUFFER, 0]; 262 graphicsInfo = cast(XVisualInfo*)glXChooseVisual(display, 0, att.ptr); 263 handle = glXCreateContext(display, cast(derelictX.XVisualInfo*)graphicsInfo, null, True); 264 if(!handle) 265 throw new Exception("glXCreateContext failed"); 266 } 267 glXMakeCurrent(display, cast(uint)window, cast(__GLXcontextRec*)handle); 268 current = handle; 269 DerelictGL3.reload(); 270 271 } 272 273 void swapBuffers(){ 274 glXSwapBuffers(display, cast(uint)window); 275 } 276 277 template opDispatch(string s){ 278 auto opDispatch(Args...)(Args args){ 279 if(current != handle){ 280 debug(glContextSwitch){ 281 import std.stdio; 282 writeln("CONTEXT SWITCH %s -> %s".format(current, handle)); 283 } 284 glXMakeCurrent(display, cast(uint)window, cast(__GLXcontextRec*)handle); 285 current = handle; 286 } 287 assert(glXGetCurrentContext() == cast(__GLXcontextRec*)handle); 288 debug { gl.check("?"); } 289 enum s = s[0..1].capitalize ~ s[1..$]; 290 mixin("alias returns = ReturnType!(gl" ~ s ~ ");"); 291 static if(!is(returns == void)){ 292 mixin("auto result = gl" ~ s ~ "(args);"); 293 debug { gl.check("gl" ~ s); } 294 return result; 295 }else{ 296 mixin("gl" ~ s ~ "(args);"); 297 debug { gl.check("gl" ~ s); } 298 } 299 } 300 } 301 302 } 303 304 }