1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 2011 Morgan Armand <morgan.devel@gmail.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25#include <stdio.h> 26#include <windows.h> 27 28#define WGL_WGLEXT_PROTOTYPES 29 30#include <GL/gl.h> 31#include <GL/wglext.h> 32 33#include "gldrv.h" 34#include "stw_context.h" 35#include "stw_device.h" 36#include "stw_ext_context.h" 37 38#include "util/u_debug.h" 39 40 41static wglCreateContext_t wglCreateContext_func = 0; 42static wglDeleteContext_t wglDeleteContext_func = 0; 43 44/* When this library is used as a opengl32.dll drop-in replacement, ensure we 45 * use the wglCreate/Destroy entrypoints above, and not the true opengl32.dll, 46 * which could happen if this library's name is not opengl32.dll exactly. 47 * 48 * For example, Qt 5.4 bundles this as opengl32sw.dll: 49 * https://blog.qt.io/blog/2014/11/27/qt-weekly-21-dynamic-opengl-implementation-loading-in-qt-5-4/ 50 */ 51void 52stw_override_opengl32_entry_points(wglCreateContext_t create, wglDeleteContext_t delete) 53{ 54 wglCreateContext_func = create; 55 wglDeleteContext_func = delete; 56} 57 58 59/** 60 * The implementation of this function is tricky. The OPENGL32.DLL library 61 * remaps the context IDs returned by our stw_create_context_attribs() 62 * function to different values returned to the caller of wglCreateContext(). 63 * That is, DHGLRC (driver) handles are not equivalent to HGLRC (public) 64 * handles. 65 * 66 * So we need to generate a new HGLRC ID here. We do that by calling 67 * the regular wglCreateContext() function. Then, we replace the newly- 68 * created stw_context with a new stw_context that reflects the arguments 69 * to this function. 70 */ 71HGLRC WINAPI 72wglCreateContextAttribsARB(HDC hDC, HGLRC hShareContext, const int *attribList) 73{ 74 HGLRC context; 75 76 int majorVersion = 1, minorVersion = 0, layerPlane = 0; 77 int contextFlags = 0x0; 78 int profileMask = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; 79 int resetStrategy = WGL_NO_RESET_NOTIFICATION_ARB; 80 int i; 81 BOOL done = FALSE; 82 const int contextFlagsAll = (WGL_CONTEXT_DEBUG_BIT_ARB | 83 WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | 84 WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB); 85 86 /* parse attrib_list */ 87 if (attribList) { 88 for (i = 0; !done && attribList[i]; i++) { 89 switch (attribList[i]) { 90 case WGL_CONTEXT_MAJOR_VERSION_ARB: 91 majorVersion = attribList[++i]; 92 break; 93 case WGL_CONTEXT_MINOR_VERSION_ARB: 94 minorVersion = attribList[++i]; 95 break; 96 case WGL_CONTEXT_LAYER_PLANE_ARB: 97 layerPlane = attribList[++i]; 98 break; 99 case WGL_CONTEXT_FLAGS_ARB: 100 contextFlags = attribList[++i]; 101 break; 102 case WGL_CONTEXT_PROFILE_MASK_ARB: 103 profileMask = attribList[++i]; 104 break; 105 case WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB: 106 resetStrategy = attribList[++i]; 107 break; 108 case 0: 109 /* end of list */ 110 done = TRUE; 111 break; 112 default: 113 /* bad attribute */ 114 SetLastError(ERROR_INVALID_PARAMETER); 115 return 0; 116 } 117 } 118 } 119 120 /* check contextFlags */ 121 if (contextFlags & ~contextFlagsAll) { 122 SetLastError(ERROR_INVALID_PARAMETER); 123 return NULL; 124 } 125 126 /* check profileMask */ 127 if (profileMask != WGL_CONTEXT_CORE_PROFILE_BIT_ARB && 128 profileMask != WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB && 129 profileMask != WGL_CONTEXT_ES_PROFILE_BIT_EXT) { 130 SetLastError(ERROR_INVALID_PROFILE_ARB); 131 return NULL; 132 } 133 134 /* check version (generate ERROR_INVALID_VERSION_ARB if bad) */ 135 if (majorVersion <= 0 || 136 minorVersion < 0 || 137 (profileMask != WGL_CONTEXT_ES_PROFILE_BIT_EXT && 138 ((majorVersion == 1 && minorVersion > 5) || 139 (majorVersion == 2 && minorVersion > 1) || 140 (majorVersion == 3 && minorVersion > 3) || 141 (majorVersion == 4 && minorVersion > 6) || 142 majorVersion > 4)) || 143 (profileMask == WGL_CONTEXT_ES_PROFILE_BIT_EXT && 144 ((majorVersion == 1 && minorVersion > 1) || 145 (majorVersion == 2 && minorVersion > 0) || 146 (majorVersion == 3 && minorVersion > 1) || 147 majorVersion > 3))) { 148 SetLastError(ERROR_INVALID_VERSION_ARB); 149 return NULL; 150 } 151 152 if ((contextFlags & WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB) && 153 majorVersion < 3) { 154 SetLastError(ERROR_INVALID_VERSION_ARB); 155 return 0; 156 } 157 158 if (resetStrategy != WGL_NO_RESET_NOTIFICATION_ARB && 159 resetStrategy != WGL_LOSE_CONTEXT_ON_RESET_ARB) { 160 SetLastError(ERROR_INVALID_PARAMETER); 161 return NULL; 162 } 163 164 /* Get pointer to OPENGL32.DLL's wglCreate/DeleteContext() functions */ 165 if (!wglCreateContext_func || !wglDeleteContext_func) { 166 /* Get the OPENGL32.DLL library */ 167 HMODULE opengl_lib = GetModuleHandleA("opengl32.dll"); 168 if (!opengl_lib) { 169 _debug_printf("wgl: GetModuleHandleA(\"opengl32.dll\") failed\n"); 170 return 0; 171 } 172 173 /* Get pointer to wglCreateContext() function */ 174 wglCreateContext_func = (wglCreateContext_t) 175 GetProcAddress(opengl_lib, "wglCreateContext"); 176 if (!wglCreateContext_func) { 177 _debug_printf("wgl: failed to get wglCreateContext()\n"); 178 return 0; 179 } 180 181 /* Get pointer to wglDeleteContext() function */ 182 wglDeleteContext_func = (wglDeleteContext_t) 183 GetProcAddress(opengl_lib, "wglDeleteContext"); 184 if (!wglDeleteContext_func) { 185 _debug_printf("wgl: failed to get wglDeleteContext()\n"); 186 return 0; 187 } 188 } 189 190 /* Call wglCreateContext to get a valid context ID */ 191 context = wglCreateContext_func(hDC); 192 193 if (context) { 194 /* Now replace the context we just created with a new one that reflects 195 * the attributes passed to this function. 196 */ 197 DHGLRC dhglrc, c, share_dhglrc = 0; 198 199 /* Convert public HGLRC to driver DHGLRC */ 200 if (stw_dev && stw_dev->callbacks.pfnGetDhglrc) { 201 dhglrc = stw_dev->callbacks.pfnGetDhglrc(context); 202 if (hShareContext) 203 share_dhglrc = stw_dev->callbacks.pfnGetDhglrc(hShareContext); 204 } 205 else { 206 /* not using ICD */ 207 dhglrc = (DHGLRC)(INT_PTR)context; 208 share_dhglrc = (DHGLRC)(INT_PTR)hShareContext; 209 } 210 211 struct stw_context *share_stw = stw_lookup_context(share_dhglrc); 212 213 struct stw_context *stw_ctx = stw_create_context_attribs(hDC, layerPlane, share_stw, 214 majorVersion, minorVersion, 215 contextFlags, profileMask, 0, 216 resetStrategy); 217 218 if (!stw_ctx) { 219 wglDeleteContext_func(context); 220 return 0; 221 } 222 223 c = stw_create_context_handle(stw_ctx, dhglrc); 224 if (!c) { 225 stw_destroy_context(stw_ctx); 226 wglDeleteContext_func(context); 227 context = 0; 228 } 229 } 230 231 return context; 232} 233 234 235/** Defined by WGL_ARB_make_current_read */ 236BOOL APIENTRY 237wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc) 238{ 239 DHGLRC dhglrc = 0; 240 241 if (stw_dev && stw_dev->callbacks.pfnGetDhglrc) { 242 /* Convert HGLRC to DHGLRC */ 243 dhglrc = stw_dev->callbacks.pfnGetDhglrc(hglrc); 244 } 245 246 return stw_make_current_by_handles(hDrawDC, hReadDC, dhglrc); 247} 248 249HDC APIENTRY 250wglGetCurrentReadDCARB(VOID) 251{ 252 return stw_get_current_read_dc(); 253} 254