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