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