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