1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2008 VMware, Inc.
4bf215546Sopenharmony_ci * All Rights Reserved.
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
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16bf215546Sopenharmony_ci * of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci **************************************************************************/
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include <windows.h>
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include "glapi/glapi.h"
31bf215546Sopenharmony_ci#include "util/debug.h"
32bf215546Sopenharmony_ci#include "util/u_debug.h"
33bf215546Sopenharmony_ci#include "util/u_math.h"
34bf215546Sopenharmony_ci#include "util/u_memory.h"
35bf215546Sopenharmony_ci#include "util/u_driconf.h"
36bf215546Sopenharmony_ci#include "util/driconf.h"
37bf215546Sopenharmony_ci#include "pipe/p_screen.h"
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci#include "stw_device.h"
40bf215546Sopenharmony_ci#include "stw_winsys.h"
41bf215546Sopenharmony_ci#include "stw_pixelformat.h"
42bf215546Sopenharmony_ci#include "gldrv.h"
43bf215546Sopenharmony_ci#include "stw_tls.h"
44bf215546Sopenharmony_ci#include "stw_framebuffer.h"
45bf215546Sopenharmony_ci#include "stw_st.h"
46bf215546Sopenharmony_ci
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_cistruct stw_device *stw_dev = NULL;
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_cistatic int
51bf215546Sopenharmony_cistw_get_param(struct st_manager *smapi,
52bf215546Sopenharmony_ci              enum st_manager_param param)
53bf215546Sopenharmony_ci{
54bf215546Sopenharmony_ci   switch (param) {
55bf215546Sopenharmony_ci   case ST_MANAGER_BROKEN_INVALIDATE:
56bf215546Sopenharmony_ci      /*
57bf215546Sopenharmony_ci       * Force framebuffer validation on glViewport.
58bf215546Sopenharmony_ci       *
59bf215546Sopenharmony_ci       * Certain applications, like Rhinoceros 4, uses glReadPixels
60bf215546Sopenharmony_ci       * exclusively (never uses SwapBuffers), so framebuffers never get
61bf215546Sopenharmony_ci       * resized unless we check on glViewport.
62bf215546Sopenharmony_ci       */
63bf215546Sopenharmony_ci      return 1;
64bf215546Sopenharmony_ci   default:
65bf215546Sopenharmony_ci      return 0;
66bf215546Sopenharmony_ci   }
67bf215546Sopenharmony_ci}
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci/** Get the refresh rate for the monitor, in Hz */
71bf215546Sopenharmony_cistatic int
72bf215546Sopenharmony_ciget_refresh_rate(void)
73bf215546Sopenharmony_ci{
74bf215546Sopenharmony_ci   DEVMODE devModes;
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devModes)) {
77bf215546Sopenharmony_ci      /* clamp the value, just in case we get garbage */
78bf215546Sopenharmony_ci      return CLAMP(devModes.dmDisplayFrequency, 30, 120);
79bf215546Sopenharmony_ci   }
80bf215546Sopenharmony_ci   else {
81bf215546Sopenharmony_ci      /* reasonable default */
82bf215546Sopenharmony_ci      return 60;
83bf215546Sopenharmony_ci   }
84bf215546Sopenharmony_ci}
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_cistatic bool
87bf215546Sopenharmony_ciinit_screen(const struct stw_winsys *stw_winsys, HDC hdc)
88bf215546Sopenharmony_ci{
89bf215546Sopenharmony_ci   struct pipe_screen *screen = stw_winsys->create_screen(hdc);
90bf215546Sopenharmony_ci   if (!screen)
91bf215546Sopenharmony_ci      return false;
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci   if (stw_winsys->get_adapter_luid)
94bf215546Sopenharmony_ci      stw_winsys->get_adapter_luid(screen, hdc, &stw_dev->AdapterLuid);
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci   stw_dev->smapi->screen = screen;
97bf215546Sopenharmony_ci   stw_dev->screen = screen;
98bf215546Sopenharmony_ci   stw_dev->zink = !memcmp(screen->get_name(screen), "zink", 4);
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci   stw_dev->max_2d_length = screen->get_param(screen,
101bf215546Sopenharmony_ci                                              PIPE_CAP_MAX_TEXTURE_2D_SIZE);
102bf215546Sopenharmony_ci   return true;
103bf215546Sopenharmony_ci}
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_cistatic void
106bf215546Sopenharmony_ciinit_options()
107bf215546Sopenharmony_ci{
108bf215546Sopenharmony_ci   const driOptionDescription gallium_driconf[] = {
109bf215546Sopenharmony_ci      #include "pipe-loader/driinfo_gallium.h"
110bf215546Sopenharmony_ci   };
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci   const char *driver_name = stw_dev->stw_winsys->get_name ? stw_dev->stw_winsys->get_name() : NULL;
113bf215546Sopenharmony_ci   driParseOptionInfo(&stw_dev->option_info, gallium_driconf, ARRAY_SIZE(gallium_driconf));
114bf215546Sopenharmony_ci   driParseConfigFiles(&stw_dev->option_cache, &stw_dev->option_info, 0,
115bf215546Sopenharmony_ci      driver_name ? driver_name : "", NULL, NULL, NULL, 0, NULL, 0);
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci   u_driconf_fill_st_options(&stw_dev->st_options, &stw_dev->option_cache);
118bf215546Sopenharmony_ci}
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ciboolean
121bf215546Sopenharmony_cistw_init(const struct stw_winsys *stw_winsys)
122bf215546Sopenharmony_ci{
123bf215546Sopenharmony_ci   static struct stw_device stw_dev_storage;
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci   if (env_var_as_boolean("WGL_DISABLE_ERROR_DIALOGS", false))
126bf215546Sopenharmony_ci      debug_disable_win32_error_dialogs();
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   assert(!stw_dev);
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   stw_tls_init();
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci   stw_dev = &stw_dev_storage;
133bf215546Sopenharmony_ci   memset(stw_dev, 0, sizeof(*stw_dev));
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   stw_dev->stw_winsys = stw_winsys;
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   stw_dev->stapi = stw_st_create_api();
138bf215546Sopenharmony_ci   stw_dev->smapi = CALLOC_STRUCT(st_manager);
139bf215546Sopenharmony_ci   if (!stw_dev->stapi || !stw_dev->smapi)
140bf215546Sopenharmony_ci      goto error1;
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   stw_dev->smapi->get_param = stw_get_param;
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci   InitializeCriticalSection(&stw_dev->screen_mutex);
145bf215546Sopenharmony_ci   InitializeCriticalSection(&stw_dev->ctx_mutex);
146bf215546Sopenharmony_ci   InitializeCriticalSection(&stw_dev->fb_mutex);
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci   stw_dev->ctx_table = handle_table_create();
149bf215546Sopenharmony_ci   if (!stw_dev->ctx_table) {
150bf215546Sopenharmony_ci      goto error1;
151bf215546Sopenharmony_ci   }
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci   /* env var override for WGL_EXT_swap_control, useful for testing/debugging */
154bf215546Sopenharmony_ci   const char *s = os_get_option("WGL_SWAP_INTERVAL");
155bf215546Sopenharmony_ci   if (s) {
156bf215546Sopenharmony_ci      stw_dev->swap_interval = atoi(s);
157bf215546Sopenharmony_ci   }
158bf215546Sopenharmony_ci   stw_dev->refresh_rate = get_refresh_rate();
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   stw_dev->initialized = true;
161bf215546Sopenharmony_ci
162bf215546Sopenharmony_ci   return TRUE;
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_cierror1:
165bf215546Sopenharmony_ci   FREE(stw_dev->smapi);
166bf215546Sopenharmony_ci   if (stw_dev->stapi)
167bf215546Sopenharmony_ci      stw_dev->stapi->destroy(stw_dev->stapi);
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ci   stw_dev = NULL;
170bf215546Sopenharmony_ci   return FALSE;
171bf215546Sopenharmony_ci}
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ciboolean
174bf215546Sopenharmony_cistw_init_screen(HDC hdc)
175bf215546Sopenharmony_ci{
176bf215546Sopenharmony_ci   EnterCriticalSection(&stw_dev->screen_mutex);
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ci   if (!stw_dev->screen_initialized) {
179bf215546Sopenharmony_ci      stw_dev->screen_initialized = true;
180bf215546Sopenharmony_ci      if (!init_screen(stw_dev->stw_winsys, hdc)) {
181bf215546Sopenharmony_ci         LeaveCriticalSection(&stw_dev->screen_mutex);
182bf215546Sopenharmony_ci         return false;
183bf215546Sopenharmony_ci      }
184bf215546Sopenharmony_ci      init_options();
185bf215546Sopenharmony_ci      stw_pixelformat_init();
186bf215546Sopenharmony_ci   }
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_ci   LeaveCriticalSection(&stw_dev->screen_mutex);
189bf215546Sopenharmony_ci   return stw_dev->screen != NULL;
190bf215546Sopenharmony_ci}
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_cistruct stw_device *
193bf215546Sopenharmony_cistw_get_device(void)
194bf215546Sopenharmony_ci{
195bf215546Sopenharmony_ci   return stw_dev;
196bf215546Sopenharmony_ci}
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ciboolean
199bf215546Sopenharmony_cistw_init_thread(void)
200bf215546Sopenharmony_ci{
201bf215546Sopenharmony_ci   return stw_tls_init_thread();
202bf215546Sopenharmony_ci}
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_civoid
206bf215546Sopenharmony_cistw_cleanup_thread(void)
207bf215546Sopenharmony_ci{
208bf215546Sopenharmony_ci   stw_tls_cleanup_thread();
209bf215546Sopenharmony_ci}
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_civoid
213bf215546Sopenharmony_cistw_cleanup(void)
214bf215546Sopenharmony_ci{
215bf215546Sopenharmony_ci   DHGLRC dhglrc;
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci   debug_printf("%s\n", __FUNCTION__);
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci   if (!stw_dev)
220bf215546Sopenharmony_ci      return;
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_ci   /*
223bf215546Sopenharmony_ci    * Abort cleanup if there are still active contexts. In some situations
224bf215546Sopenharmony_ci    * this DLL may be unloaded before the DLL that is using GL contexts is.
225bf215546Sopenharmony_ci    */
226bf215546Sopenharmony_ci   stw_lock_contexts(stw_dev);
227bf215546Sopenharmony_ci   dhglrc = handle_table_get_first_handle(stw_dev->ctx_table);
228bf215546Sopenharmony_ci   stw_unlock_contexts(stw_dev);
229bf215546Sopenharmony_ci   if (dhglrc) {
230bf215546Sopenharmony_ci      debug_printf("%s: contexts still active -- cleanup aborted\n", __FUNCTION__);
231bf215546Sopenharmony_ci      stw_dev = NULL;
232bf215546Sopenharmony_ci      return;
233bf215546Sopenharmony_ci   }
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci   free(stw_dev->st_options.force_gl_vendor);
236bf215546Sopenharmony_ci   free(stw_dev->st_options.force_gl_renderer);
237bf215546Sopenharmony_ci   free(stw_dev->st_options.mesa_extension_override);
238bf215546Sopenharmony_ci   driDestroyOptionCache(&stw_dev->option_cache);
239bf215546Sopenharmony_ci   driDestroyOptionInfo(&stw_dev->option_info);
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_ci   handle_table_destroy(stw_dev->ctx_table);
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   stw_framebuffer_cleanup();
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci   DeleteCriticalSection(&stw_dev->fb_mutex);
246bf215546Sopenharmony_ci   DeleteCriticalSection(&stw_dev->ctx_mutex);
247bf215546Sopenharmony_ci   DeleteCriticalSection(&stw_dev->screen_mutex);
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_ci   if (stw_dev->smapi->destroy)
250bf215546Sopenharmony_ci      stw_dev->smapi->destroy(stw_dev->smapi);
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci   FREE(stw_dev->smapi);
253bf215546Sopenharmony_ci   stw_dev->stapi->destroy(stw_dev->stapi);
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ci   stw_dev->screen->destroy(stw_dev->screen);
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   /* glapi is statically linked: we can call the local destroy function. */
258bf215546Sopenharmony_ci#ifdef _GLAPI_NO_EXPORTS
259bf215546Sopenharmony_ci   _glapi_destroy_multithread();
260bf215546Sopenharmony_ci#endif
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_ci   stw_tls_cleanup();
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci   util_dynarray_fini(&stw_dev->pixelformats);
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_ci   stw_dev = NULL;
267bf215546Sopenharmony_ci}
268bf215546Sopenharmony_ci
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_civoid APIENTRY
271bf215546Sopenharmony_ciDrvSetCallbackProcs(INT nProcs, PROC *pProcs)
272bf215546Sopenharmony_ci{
273bf215546Sopenharmony_ci   size_t size;
274bf215546Sopenharmony_ci
275bf215546Sopenharmony_ci   if (stw_dev == NULL)
276bf215546Sopenharmony_ci      return;
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci   size = MIN2(nProcs * sizeof *pProcs, sizeof stw_dev->callbacks);
279bf215546Sopenharmony_ci   memcpy(&stw_dev->callbacks, pProcs, size);
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci   return;
282bf215546Sopenharmony_ci}
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ciBOOL APIENTRY
286bf215546Sopenharmony_ciDrvValidateVersion(ULONG ulVersion)
287bf215546Sopenharmony_ci{
288bf215546Sopenharmony_ci   /* ulVersion is the version reported by the KMD:
289bf215546Sopenharmony_ci    * - via D3DKMTQueryAdapterInfo(KMTQAITYPE_UMOPENGLINFO) on WDDM,
290bf215546Sopenharmony_ci    * - or ExtEscape on XPDM and can be used to ensure the KMD and OpenGL ICD
291bf215546Sopenharmony_ci    *   versions match.
292bf215546Sopenharmony_ci    *
293bf215546Sopenharmony_ci    * We should get the expected version number from the winsys, but for now
294bf215546Sopenharmony_ci    * ignore it.
295bf215546Sopenharmony_ci    */
296bf215546Sopenharmony_ci   (void)ulVersion;
297bf215546Sopenharmony_ci   return TRUE;
298bf215546Sopenharmony_ci}
299