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 
41 wglCreateContext_t wglCreateContext_func = 0;
42 wglDeleteContext_t wglDeleteContext_func = 0;
43 
44 
45 /**
46  * The implementation of this function is tricky.  The OPENGL32.DLL library
47  * remaps the context IDs returned by our stw_create_context_attribs()
48  * function to different values returned to the caller of wglCreateContext().
49  * That is, DHGLRC (driver) handles are not equivalent to HGLRC (public)
50  * handles.
51  *
52  * So we need to generate a new HGLRC ID here.  We do that by calling
53  * the regular wglCreateContext() function.  Then, we replace the newly-
54  * created stw_context with a new stw_context that reflects the arguments
55  * to this function.
56  */
57 HGLRC WINAPI
wglCreateContextAttribsARB(HDC hDC,HGLRC hShareContext,const int * attribList)58 wglCreateContextAttribsARB(HDC hDC, HGLRC hShareContext, const int *attribList)
59 {
60    HGLRC context;
61 
62    int majorVersion = 1, minorVersion = 0, layerPlane = 0;
63    int contextFlags = 0x0;
64    int profileMask = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
65    int i;
66    BOOL done = FALSE;
67    const int contextFlagsAll = (WGL_CONTEXT_DEBUG_BIT_ARB |
68                                 WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB);
69 
70    /* parse attrib_list */
71    if (attribList) {
72       for (i = 0; !done && attribList[i]; i++) {
73          switch (attribList[i]) {
74          case WGL_CONTEXT_MAJOR_VERSION_ARB:
75             majorVersion = attribList[++i];
76             break;
77          case WGL_CONTEXT_MINOR_VERSION_ARB:
78             minorVersion = attribList[++i];
79             break;
80          case WGL_CONTEXT_LAYER_PLANE_ARB:
81             layerPlane = attribList[++i];
82             break;
83          case WGL_CONTEXT_FLAGS_ARB:
84             contextFlags = attribList[++i];
85             break;
86          case WGL_CONTEXT_PROFILE_MASK_ARB:
87             profileMask = attribList[++i];
88             break;
89          case 0:
90             /* end of list */
91             done = TRUE;
92             break;
93          default:
94             /* bad attribute */
95             SetLastError(ERROR_INVALID_PARAMETER);
96             return 0;
97          }
98       }
99    }
100 
101    /* check contextFlags */
102    if (contextFlags & ~contextFlagsAll) {
103       SetLastError(ERROR_INVALID_PARAMETER);
104       return NULL;
105    }
106 
107    /* check profileMask */
108    if (profileMask != WGL_CONTEXT_CORE_PROFILE_BIT_ARB &&
109        profileMask != WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB &&
110        profileMask != WGL_CONTEXT_ES_PROFILE_BIT_EXT) {
111       SetLastError(ERROR_INVALID_PROFILE_ARB);
112       return NULL;
113    }
114 
115    /* check version (generate ERROR_INVALID_VERSION_ARB if bad) */
116    if (majorVersion <= 0 ||
117        minorVersion < 0 ||
118        (profileMask != WGL_CONTEXT_ES_PROFILE_BIT_EXT &&
119         ((majorVersion == 1 && minorVersion > 5) ||
120          (majorVersion == 2 && minorVersion > 1) ||
121          (majorVersion == 3 && minorVersion > 3) ||
122          (majorVersion == 4 && minorVersion > 5) ||
123          majorVersion > 4)) ||
124        (profileMask == WGL_CONTEXT_ES_PROFILE_BIT_EXT &&
125         ((majorVersion == 1 && minorVersion > 1) ||
126          (majorVersion == 2 && minorVersion > 0) ||
127          (majorVersion == 3 && minorVersion > 1) ||
128          majorVersion > 3))) {
129       SetLastError(ERROR_INVALID_VERSION_ARB);
130       return NULL;
131    }
132 
133    if ((contextFlags & WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB) &&
134        majorVersion < 3) {
135       SetLastError(ERROR_INVALID_VERSION_ARB);
136       return 0;
137    }
138 
139    /* Get pointer to OPENGL32.DLL's wglCreate/DeleteContext() functions */
140    if (!wglCreateContext_func || !wglDeleteContext_func) {
141       /* Get the OPENGL32.DLL library */
142       HMODULE opengl_lib = GetModuleHandleA("opengl32.dll");
143       if (!opengl_lib) {
144          _debug_printf("wgl: GetModuleHandleA(\"opengl32.dll\") failed\n");
145          return 0;
146       }
147 
148       /* Get pointer to wglCreateContext() function */
149       wglCreateContext_func = (wglCreateContext_t)
150          GetProcAddress(opengl_lib, "wglCreateContext");
151       if (!wglCreateContext_func) {
152          _debug_printf("wgl: failed to get wglCreateContext()\n");
153          return 0;
154       }
155 
156       /* Get pointer to wglDeleteContext() function */
157       wglDeleteContext_func = (wglDeleteContext_t)
158          GetProcAddress(opengl_lib, "wglDeleteContext");
159       if (!wglDeleteContext_func) {
160          _debug_printf("wgl: failed to get wglDeleteContext()\n");
161          return 0;
162       }
163    }
164 
165    /* Call wglCreateContext to get a valid context ID */
166    context = wglCreateContext_func(hDC);
167 
168    if (context) {
169       /* Now replace the context we just created with a new one that reflects
170        * the attributes passed to this function.
171        */
172       DHGLRC dhglrc, c, share_dhglrc = 0;
173 
174       /* Convert public HGLRC to driver DHGLRC */
175       if (stw_dev && stw_dev->callbacks.pfnGetDhglrc) {
176          dhglrc = stw_dev->callbacks.pfnGetDhglrc(context);
177          if (hShareContext)
178             share_dhglrc = stw_dev->callbacks.pfnGetDhglrc(hShareContext);
179       }
180       else {
181          /* not using ICD */
182          dhglrc = (DHGLRC)(INT_PTR)context;
183          share_dhglrc = (DHGLRC)(INT_PTR)hShareContext;
184       }
185 
186       c = stw_create_context_attribs(hDC, layerPlane, share_dhglrc,
187                                      majorVersion, minorVersion,
188                                      contextFlags, profileMask,
189                                      dhglrc);
190       if (!c) {
191          wglDeleteContext_func(context);
192          context = 0;
193       }
194    }
195 
196    return context;
197 }
198 
199 
200 /** Defined by WGL_ARB_make_current_read */
201 BOOL APIENTRY
wglMakeContextCurrentARB(HDC hDrawDC,HDC hReadDC,HGLRC hglrc)202 wglMakeContextCurrentARB(HDC hDrawDC, HDC hReadDC, HGLRC hglrc)
203 {
204    DHGLRC dhglrc = 0;
205 
206    if (stw_dev && stw_dev->callbacks.pfnGetDhglrc) {
207       /* Convert HGLRC to DHGLRC */
208       dhglrc = stw_dev->callbacks.pfnGetDhglrc(hglrc);
209    }
210 
211    return stw_make_current(hDrawDC, hReadDC, dhglrc);
212 }
213