1b8e80941Smrg/* 2b8e80941Smrg * Copyright © 2014 Jon Turney 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21b8e80941Smrg * IN THE SOFTWARE. 22b8e80941Smrg */ 23b8e80941Smrg 24b8e80941Smrg#include "windowsgl.h" 25b8e80941Smrg#include "windowsgl_internal.h" 26b8e80941Smrg 27b8e80941Smrg#include "glapi.h" 28b8e80941Smrg#include "wgl.h" 29b8e80941Smrg 30b8e80941Smrg#include <dlfcn.h> 31b8e80941Smrg#include <assert.h> 32b8e80941Smrg#include <stdio.h> 33b8e80941Smrg#include <strings.h> 34b8e80941Smrg 35b8e80941Smrgstatic struct _glapi_table *windows_api = NULL; 36b8e80941Smrg 37b8e80941Smrgstatic void * 38b8e80941Smrgwindows_get_dl_handle(void) 39b8e80941Smrg{ 40b8e80941Smrg static void *dl_handle = NULL; 41b8e80941Smrg 42b8e80941Smrg if (!dl_handle) 43b8e80941Smrg dl_handle = dlopen("cygnativeGLthunk.dll", RTLD_NOW); 44b8e80941Smrg 45b8e80941Smrg return dl_handle; 46b8e80941Smrg} 47b8e80941Smrg 48b8e80941Smrgstatic void 49b8e80941Smrgwindows_glapi_create_table(void) 50b8e80941Smrg{ 51b8e80941Smrg if (windows_api) 52b8e80941Smrg return; 53b8e80941Smrg 54b8e80941Smrg windows_api = _glapi_create_table_from_handle(windows_get_dl_handle(), "gl"); 55b8e80941Smrg assert(windows_api); 56b8e80941Smrg} 57b8e80941Smrg 58b8e80941Smrgstatic void windows_glapi_set_dispatch(void) 59b8e80941Smrg{ 60b8e80941Smrg windows_glapi_create_table(); 61b8e80941Smrg _glapi_set_dispatch(windows_api); 62b8e80941Smrg} 63b8e80941Smrg 64b8e80941SmrgwindowsContext * 65b8e80941Smrgwindows_create_context(int pxfi, windowsContext *shared) 66b8e80941Smrg{ 67b8e80941Smrg windowsContext *gc; 68b8e80941Smrg 69b8e80941Smrg gc = calloc(1, sizeof *gc); 70b8e80941Smrg if (gc == NULL) 71b8e80941Smrg return NULL; 72b8e80941Smrg 73b8e80941Smrg // create a temporary, invisible window 74b8e80941Smrg#define GL_TEMP_WINDOW_CLASS "glTempWndClass" 75b8e80941Smrg { 76b8e80941Smrg static wATOM glTempWndClass = 0; 77b8e80941Smrg 78b8e80941Smrg if (glTempWndClass == 0) { 79b8e80941Smrg WNDCLASSEX wc; 80b8e80941Smrg wc.cbSize = sizeof(WNDCLASSEX); 81b8e80941Smrg wc.style = CS_HREDRAW | CS_VREDRAW; 82b8e80941Smrg wc.lpfnWndProc = DefWindowProc; 83b8e80941Smrg wc.cbClsExtra = 0; 84b8e80941Smrg wc.cbWndExtra = 0; 85b8e80941Smrg wc.hInstance = GetModuleHandle(NULL); 86b8e80941Smrg wc.hIcon = 0; 87b8e80941Smrg wc.hCursor = 0; 88b8e80941Smrg wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); 89b8e80941Smrg wc.lpszMenuName = NULL; 90b8e80941Smrg wc.lpszClassName = GL_TEMP_WINDOW_CLASS; 91b8e80941Smrg wc.hIconSm = 0; 92b8e80941Smrg RegisterClassEx(&wc); 93b8e80941Smrg } 94b8e80941Smrg } 95b8e80941Smrg 96b8e80941Smrg HWND hwnd = CreateWindowExA(0, 97b8e80941Smrg GL_TEMP_WINDOW_CLASS, 98b8e80941Smrg "glWindow", 99b8e80941Smrg 0, 100b8e80941Smrg 0, 0, 0, 0, 101b8e80941Smrg NULL, NULL, GetModuleHandle(NULL), NULL); 102b8e80941Smrg HDC hdc = GetDC(hwnd); 103b8e80941Smrg 104b8e80941Smrg // We must set the windows pixel format before we can create a WGL context 105b8e80941Smrg gc->pxfi = pxfi; 106b8e80941Smrg SetPixelFormat(hdc, gc->pxfi, NULL); 107b8e80941Smrg 108b8e80941Smrg gc->ctx = wglCreateContext(hdc); 109b8e80941Smrg 110b8e80941Smrg if (shared && gc->ctx) 111b8e80941Smrg wglShareLists(shared->ctx, gc->ctx); 112b8e80941Smrg 113b8e80941Smrg ReleaseDC(hwnd, hdc); 114b8e80941Smrg DestroyWindow(hwnd); 115b8e80941Smrg 116b8e80941Smrg if (!gc->ctx) 117b8e80941Smrg { 118b8e80941Smrg free(gc); 119b8e80941Smrg return NULL; 120b8e80941Smrg } 121b8e80941Smrg 122b8e80941Smrg return gc; 123b8e80941Smrg} 124b8e80941Smrg 125b8e80941SmrgwindowsContext * 126b8e80941Smrgwindows_create_context_attribs(int pxfi, windowsContext *shared, const int *attribList) 127b8e80941Smrg{ 128b8e80941Smrg windowsContext *gc; 129b8e80941Smrg 130b8e80941Smrg gc = calloc(1, sizeof *gc); 131b8e80941Smrg if (gc == NULL) 132b8e80941Smrg return NULL; 133b8e80941Smrg 134b8e80941Smrg // create a temporary, invisible window 135b8e80941Smrg#define GL_TEMP_WINDOW_CLASS "glTempWndClass" 136b8e80941Smrg { 137b8e80941Smrg static wATOM glTempWndClass = 0; 138b8e80941Smrg 139b8e80941Smrg if (glTempWndClass == 0) { 140b8e80941Smrg WNDCLASSEX wc; 141b8e80941Smrg wc.cbSize = sizeof(WNDCLASSEX); 142b8e80941Smrg wc.style = CS_HREDRAW | CS_VREDRAW; 143b8e80941Smrg wc.lpfnWndProc = DefWindowProc; 144b8e80941Smrg wc.cbClsExtra = 0; 145b8e80941Smrg wc.cbWndExtra = 0; 146b8e80941Smrg wc.hInstance = GetModuleHandle(NULL); 147b8e80941Smrg wc.hIcon = 0; 148b8e80941Smrg wc.hCursor = 0; 149b8e80941Smrg wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); 150b8e80941Smrg wc.lpszMenuName = NULL; 151b8e80941Smrg wc.lpszClassName = GL_TEMP_WINDOW_CLASS; 152b8e80941Smrg wc.hIconSm = 0; 153b8e80941Smrg RegisterClassEx(&wc); 154b8e80941Smrg } 155b8e80941Smrg } 156b8e80941Smrg 157b8e80941Smrg HWND hwnd = CreateWindowExA(0, 158b8e80941Smrg GL_TEMP_WINDOW_CLASS, 159b8e80941Smrg "glWindow", 160b8e80941Smrg 0, 161b8e80941Smrg 0, 0, 0, 0, 162b8e80941Smrg NULL, NULL, GetModuleHandle(NULL), NULL); 163b8e80941Smrg HDC hdc = GetDC(hwnd); 164b8e80941Smrg HGLRC shareContext = NULL; 165b8e80941Smrg if (shared) 166b8e80941Smrg shareContext = shared->ctx; 167b8e80941Smrg 168b8e80941Smrg // We must set the windows pixel format before we can create a WGL context 169b8e80941Smrg gc->pxfi = pxfi; 170b8e80941Smrg SetPixelFormat(hdc, gc->pxfi, NULL); 171b8e80941Smrg 172b8e80941Smrg gc->ctx = wglCreateContextAttribsARB(hdc, shareContext, attribList); 173b8e80941Smrg 174b8e80941Smrg ReleaseDC(hwnd, hdc); 175b8e80941Smrg DestroyWindow(hwnd); 176b8e80941Smrg 177b8e80941Smrg if (!gc->ctx) 178b8e80941Smrg { 179b8e80941Smrg free(gc); 180b8e80941Smrg return NULL; 181b8e80941Smrg } 182b8e80941Smrg 183b8e80941Smrg return gc; 184b8e80941Smrg} 185b8e80941Smrg 186b8e80941Smrgvoid 187b8e80941Smrgwindows_destroy_context(windowsContext *context) 188b8e80941Smrg{ 189b8e80941Smrg wglDeleteContext(context->ctx); 190b8e80941Smrg context->ctx = NULL; 191b8e80941Smrg free(context); 192b8e80941Smrg} 193b8e80941Smrg 194b8e80941Smrgint windows_bind_context(windowsContext *context, windowsDrawable *draw, windowsDrawable *read) 195b8e80941Smrg{ 196b8e80941Smrg HDC drawDc = draw->callbacks->getdc(draw); 197b8e80941Smrg 198b8e80941Smrg if (!draw->pxfi) 199b8e80941Smrg { 200b8e80941Smrg SetPixelFormat(drawDc, context->pxfi, NULL); 201b8e80941Smrg draw->pxfi = context->pxfi; 202b8e80941Smrg } 203b8e80941Smrg 204b8e80941Smrg if ((read != NULL) && (read != draw)) 205b8e80941Smrg { 206b8e80941Smrg /* 207b8e80941Smrg If there is a separate read drawable, create a separate read DC, and 208b8e80941Smrg use the wglMakeContextCurrent extension to make the context current 209b8e80941Smrg drawing to one DC and reading from the other 210b8e80941Smrg 211b8e80941Smrg Should only occur when WGL_ARB_make_current_read extension is present 212b8e80941Smrg */ 213b8e80941Smrg HDC readDc = read->callbacks->getdc(read); 214b8e80941Smrg 215b8e80941Smrg BOOL ret = wglMakeContextCurrentARB(drawDc, readDc, context->ctx); 216b8e80941Smrg 217b8e80941Smrg read->callbacks->releasedc(read, readDc); 218b8e80941Smrg 219b8e80941Smrg if (!ret) { 220b8e80941Smrg printf("wglMakeContextCurrentARB error: %08x\n", GetLastError()); 221b8e80941Smrg return FALSE; 222b8e80941Smrg } 223b8e80941Smrg } 224b8e80941Smrg else 225b8e80941Smrg { 226b8e80941Smrg /* Otherwise, just use wglMakeCurrent */ 227b8e80941Smrg BOOL ret = wglMakeCurrent(drawDc, context->ctx); 228b8e80941Smrg if (!ret) { 229b8e80941Smrg printf("wglMakeCurrent error: %08x\n", GetLastError()); 230b8e80941Smrg return FALSE; 231b8e80941Smrg } 232b8e80941Smrg } 233b8e80941Smrg 234b8e80941Smrg draw->callbacks->releasedc(draw, drawDc); 235b8e80941Smrg 236b8e80941Smrg windows_glapi_set_dispatch(); 237b8e80941Smrg 238b8e80941Smrg return TRUE; 239b8e80941Smrg} 240b8e80941Smrg 241b8e80941Smrgvoid windows_unbind_context(windowsContext * context) 242b8e80941Smrg{ 243b8e80941Smrg wglMakeCurrent(NULL, NULL); 244b8e80941Smrg} 245b8e80941Smrg 246b8e80941Smrg/* 247b8e80941Smrg * 248b8e80941Smrg */ 249b8e80941Smrg 250b8e80941Smrgvoid 251b8e80941Smrgwindows_swap_buffers(windowsDrawable *draw) 252b8e80941Smrg{ 253b8e80941Smrg HDC drawDc = GetDC(draw->hWnd); 254b8e80941Smrg SwapBuffers(drawDc); 255b8e80941Smrg ReleaseDC(draw->hWnd, drawDc); 256b8e80941Smrg} 257b8e80941Smrg 258b8e80941Smrg 259b8e80941Smrgtypedef void (__stdcall * PFNGLADDSWAPHINTRECTWIN) (GLint x, GLint y, 260b8e80941Smrg GLsizei width, 261b8e80941Smrg GLsizei height); 262b8e80941Smrg 263b8e80941Smrgstatic void 264b8e80941SmrgglAddSwapHintRectWIN(GLint x, GLint y, GLsizei width, 265b8e80941Smrg GLsizei height) 266b8e80941Smrg{ 267b8e80941Smrg PFNGLADDSWAPHINTRECTWIN proc = (PFNGLADDSWAPHINTRECTWIN)wglGetProcAddress("glAddSwapHintRectWIN"); 268b8e80941Smrg if (proc) 269b8e80941Smrg proc(x, y, width, height); 270b8e80941Smrg} 271b8e80941Smrg 272b8e80941Smrgvoid 273b8e80941Smrgwindows_copy_subbuffer(windowsDrawable *draw, 274b8e80941Smrg int x, int y, int width, int height) 275b8e80941Smrg{ 276b8e80941Smrg glAddSwapHintRectWIN(x, y, width, height); 277b8e80941Smrg windows_swap_buffers(draw); 278b8e80941Smrg} 279b8e80941Smrg 280b8e80941Smrg/* 281b8e80941Smrg * Helper function for calling a test function on an initial context 282b8e80941Smrg */ 283b8e80941Smrgstatic void 284b8e80941Smrgwindows_call_with_context(void (*proc)(HDC, void *), void *args) 285b8e80941Smrg{ 286b8e80941Smrg // create window class 287b8e80941Smrg#define WIN_GL_TEST_WINDOW_CLASS "GLTest" 288b8e80941Smrg { 289b8e80941Smrg static wATOM glTestWndClass = 0; 290b8e80941Smrg 291b8e80941Smrg if (glTestWndClass == 0) { 292b8e80941Smrg WNDCLASSEX wc; 293b8e80941Smrg 294b8e80941Smrg wc.cbSize = sizeof(WNDCLASSEX); 295b8e80941Smrg wc.style = CS_HREDRAW | CS_VREDRAW; 296b8e80941Smrg wc.lpfnWndProc = DefWindowProc; 297b8e80941Smrg wc.cbClsExtra = 0; 298b8e80941Smrg wc.cbWndExtra = 0; 299b8e80941Smrg wc.hInstance = GetModuleHandle(NULL); 300b8e80941Smrg wc.hIcon = 0; 301b8e80941Smrg wc.hCursor = 0; 302b8e80941Smrg wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); 303b8e80941Smrg wc.lpszMenuName = NULL; 304b8e80941Smrg wc.lpszClassName = WIN_GL_TEST_WINDOW_CLASS; 305b8e80941Smrg wc.hIconSm = 0; 306b8e80941Smrg glTestWndClass = RegisterClassEx(&wc); 307b8e80941Smrg } 308b8e80941Smrg } 309b8e80941Smrg 310b8e80941Smrg // create an invisible window for a scratch DC 311b8e80941Smrg HWND hwnd = CreateWindowExA(0, 312b8e80941Smrg WIN_GL_TEST_WINDOW_CLASS, 313b8e80941Smrg "GL Renderer Capabilities Test Window", 314b8e80941Smrg 0, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), 315b8e80941Smrg NULL); 316b8e80941Smrg if (hwnd) { 317b8e80941Smrg HDC hdc = GetDC(hwnd); 318b8e80941Smrg 319b8e80941Smrg // we must set a pixel format before we can create a context, just use the first one... 320b8e80941Smrg SetPixelFormat(hdc, 1, NULL); 321b8e80941Smrg HGLRC hglrc = wglCreateContext(hdc); 322b8e80941Smrg wglMakeCurrent(hdc, hglrc); 323b8e80941Smrg 324b8e80941Smrg // call the test function 325b8e80941Smrg proc(hdc, args); 326b8e80941Smrg 327b8e80941Smrg // clean up 328b8e80941Smrg wglMakeCurrent(NULL, NULL); 329b8e80941Smrg wglDeleteContext(hglrc); 330b8e80941Smrg ReleaseDC(hwnd, hdc); 331b8e80941Smrg DestroyWindow(hwnd); 332b8e80941Smrg } 333b8e80941Smrg} 334b8e80941Smrg 335b8e80941Smrgstatic void 336b8e80941Smrgwindows_check_render_test(HDC hdc, void *args) 337b8e80941Smrg{ 338b8e80941Smrg int *result = (int *)args; 339b8e80941Smrg 340b8e80941Smrg /* Rather than play linkage games using stdcall to ensure we get 341b8e80941Smrg glGetString from opengl32.dll here, use dlsym */ 342b8e80941Smrg void *dlhandle = windows_get_dl_handle(); 343b8e80941Smrg const char *(*proc)(int) = dlsym(dlhandle, "glGetString"); 344b8e80941Smrg const char *gl_renderer = (const char *)proc(GL_RENDERER); 345b8e80941Smrg 346b8e80941Smrg if ((!gl_renderer) || (strcasecmp(gl_renderer, "GDI Generic") == 0)) 347b8e80941Smrg *result = FALSE; 348b8e80941Smrg else 349b8e80941Smrg *result = TRUE; 350b8e80941Smrg} 351b8e80941Smrg 352b8e80941Smrgint 353b8e80941Smrgwindows_check_renderer(void) 354b8e80941Smrg{ 355b8e80941Smrg int result; 356b8e80941Smrg windows_call_with_context(windows_check_render_test, &result); 357b8e80941Smrg return result; 358b8e80941Smrg} 359b8e80941Smrg 360b8e80941Smrgtypedef struct { 361b8e80941Smrg char *gl_extensions; 362b8e80941Smrg char *wgl_extensions; 363b8e80941Smrg} windows_extensions_result; 364b8e80941Smrg 365b8e80941Smrgstatic void 366b8e80941Smrgwindows_extensions_test(HDC hdc, void *args) 367b8e80941Smrg{ 368b8e80941Smrg windows_extensions_result *r = (windows_extensions_result *)args; 369b8e80941Smrg 370b8e80941Smrg void *dlhandle = windows_get_dl_handle(); 371b8e80941Smrg const char *(*proc)(int) = dlsym(dlhandle, "glGetString"); 372b8e80941Smrg 373b8e80941Smrg r->gl_extensions = strdup(proc(GL_EXTENSIONS)); 374b8e80941Smrg 375b8e80941Smrg wglResolveExtensionProcs(); 376b8e80941Smrg r->wgl_extensions = strdup(wglGetExtensionsStringARB(hdc)); 377b8e80941Smrg} 378b8e80941Smrg 379b8e80941Smrgvoid 380b8e80941Smrgwindows_extensions(char **gl_extensions, char **wgl_extensions) 381b8e80941Smrg{ 382b8e80941Smrg windows_extensions_result result; 383b8e80941Smrg 384b8e80941Smrg *gl_extensions = ""; 385b8e80941Smrg *wgl_extensions = ""; 386b8e80941Smrg 387b8e80941Smrg windows_call_with_context(windows_extensions_test, &result); 388b8e80941Smrg 389b8e80941Smrg *gl_extensions = result.gl_extensions; 390b8e80941Smrg *wgl_extensions = result.wgl_extensions; 391b8e80941Smrg} 392b8e80941Smrg 393b8e80941Smrgvoid windows_setTexBuffer(windowsContext *context, int textureTarget, 394b8e80941Smrg int textureFormat, windowsDrawable *drawable) 395b8e80941Smrg{ 396b8e80941Smrg // not yet implemented 397b8e80941Smrg} 398b8e80941Smrg 399b8e80941Smrgvoid windows_releaseTexBuffer(windowsContext *context, int textureTarget, 400b8e80941Smrg windowsDrawable *drawable) 401b8e80941Smrg{ 402b8e80941Smrg // not yet implemented 403b8e80941Smrg} 404