wgl.c revision 7ec681f3
1/**************************************************************************
2 *
3 * Copyright 2009-2010 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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 *
27 **************************************************************************/
28
29/**
30 * @file
31 * Softpipe/LLVMpipe support.
32 *
33 * @author Jose Fonseca <jfonseca@vmware.com>
34 */
35
36
37#include <windows.h>
38
39#include "util/u_debug.h"
40#include "util/debug.h"
41#include "stw_winsys.h"
42#include "stw_device.h"
43#include "gdi/gdi_sw_winsys.h"
44#include "pipe/p_screen.h"
45#include "pipe/p_context.h"
46
47#ifdef GALLIUM_SOFTPIPE
48#include "softpipe/sp_texture.h"
49#include "softpipe/sp_screen.h"
50#include "softpipe/sp_public.h"
51#endif
52
53#ifdef GALLIUM_LLVMPIPE
54#include "llvmpipe/lp_texture.h"
55#include "llvmpipe/lp_screen.h"
56#include "llvmpipe/lp_public.h"
57#endif
58
59#ifdef GALLIUM_SWR
60#include "swr/swr_public.h"
61#endif
62#ifdef GALLIUM_D3D12
63#include "d3d12/wgl/d3d12_wgl_public.h"
64#endif
65
66#ifdef GALLIUM_ZINK
67#include "zink/zink_public.h"
68#endif
69
70#ifdef GALLIUM_LLVMPIPE
71static boolean use_llvmpipe = FALSE;
72#endif
73#ifdef GALLIUM_SWR
74static boolean use_swr = FALSE;
75#endif
76#ifdef GALLIUM_D3D12
77static boolean use_d3d12 = FALSE;
78#endif
79#ifdef GALLIUM_ZINK
80static boolean use_zink = FALSE;
81#endif
82
83static const char *created_driver_name = NULL;
84
85static struct pipe_screen *
86wgl_screen_create_by_name(HDC hDC, const char* driver, struct sw_winsys *winsys)
87{
88   struct pipe_screen* screen = NULL;
89
90#ifdef GALLIUM_LLVMPIPE
91   if (strcmp(driver, "llvmpipe") == 0) {
92      screen = llvmpipe_create_screen(winsys);
93      if (screen)
94         use_llvmpipe = TRUE;
95   }
96#endif
97#ifdef GALLIUM_SWR
98   if (strcmp(driver, "swr") == 0) {
99      screen = swr_create_screen(winsys);
100      if (screen)
101         use_swr = TRUE;
102   }
103#endif
104#ifdef GALLIUM_D3D12
105   if (strcmp(driver, "d3d12") == 0) {
106      screen = d3d12_wgl_create_screen(winsys, hDC);
107      if (screen)
108         use_d3d12 = TRUE;
109   }
110#endif
111#ifdef GALLIUM_ZINK
112   if (strcmp(driver, "zink") == 0) {
113      screen = zink_create_screen(winsys);
114      if (screen)
115         use_zink = TRUE;
116   }
117#endif
118#ifdef GALLIUM_SOFTPIPE
119   if (strcmp(driver, "softpipe") == 0) {
120      screen = softpipe_create_screen(winsys);
121   }
122#endif
123
124   return screen;
125}
126
127static struct pipe_screen *
128wgl_screen_create(HDC hDC)
129{
130   struct sw_winsys *winsys;
131   UNUSED bool sw_only = env_var_as_boolean("LIBGL_ALWAYS_SOFTWARE", false);
132
133   winsys = gdi_create_sw_winsys();
134   if (!winsys)
135      return NULL;
136
137   const char *const drivers[] = {
138      debug_get_option("GALLIUM_DRIVER", ""),
139#ifdef GALLIUM_D3D12
140      sw_only ? "" : "d3d12",
141#endif
142#if defined(GALLIUM_LLVMPIPE)
143      "llvmpipe",
144#endif
145#if GALLIUM_SWR
146      "swr",
147#endif
148#if defined(GALLIUM_SOFTPIPE)
149      "softpipe",
150#endif
151   };
152
153   /* If the default driver screen creation fails, fall back to the next option in the
154    * sorted list. Don't do this if GALLIUM_DRIVER is specified.
155    */
156   for (unsigned i = 0; i < ARRAY_SIZE(drivers); ++i) {
157      struct pipe_screen* screen = wgl_screen_create_by_name(hDC, drivers[i], winsys);
158      if (screen) {
159         created_driver_name = drivers[i];
160         return screen;
161      }
162      if (i == 0 && drivers[i][0] != '\0')
163         break;
164   }
165
166   winsys->destroy(winsys);
167   return NULL;
168}
169
170
171static void
172wgl_present(struct pipe_screen *screen,
173            struct pipe_context *ctx,
174            struct pipe_resource *res,
175            HDC hDC)
176{
177   /* This will fail if any interposing layer (trace, debug, etc) has
178    * been introduced between the gallium frontends and the pipe driver.
179    *
180    * Ideally this would get replaced with a call to
181    * pipe_screen::flush_frontbuffer().
182    *
183    * Failing that, it may be necessary for intervening layers to wrap
184    * other structs such as this stw_winsys as well...
185    */
186
187   struct sw_winsys *winsys = NULL;
188   struct sw_displaytarget *dt = NULL;
189
190#ifdef GALLIUM_LLVMPIPE
191   if (use_llvmpipe) {
192      winsys = llvmpipe_screen(screen)->winsys;
193      dt = llvmpipe_resource(res)->dt;
194      gdi_sw_display(winsys, dt, hDC);
195      return;
196   }
197#endif
198
199#ifdef GALLIUM_SWR
200   if (use_swr) {
201      swr_gdi_swap(screen, ctx, res, hDC);
202      return;
203   }
204#endif
205
206#ifdef GALLIUM_D3D12
207   if (use_d3d12) {
208      d3d12_wgl_present(screen, ctx, res, hDC);
209      return;
210   }
211#endif
212
213#ifdef GALLIUM_ZINK
214   if (use_zink) {
215      screen->flush_frontbuffer(screen, ctx, res, 0, 0, hDC, NULL);
216      return;
217   }
218#endif
219
220#ifdef GALLIUM_SOFTPIPE
221   winsys = softpipe_screen(screen)->winsys,
222   dt = softpipe_resource(res)->dt,
223   gdi_sw_display(winsys, dt, hDC);
224#endif
225}
226
227
228#if WINVER >= 0xA00
229static boolean
230wgl_get_adapter_luid(struct pipe_screen* screen,
231   HDC hDC,
232   LUID* adapter_luid)
233{
234   if (!stw_dev || !stw_dev->callbacks.pfnGetAdapterLuid)
235      return false;
236
237   stw_dev->callbacks.pfnGetAdapterLuid(hDC, adapter_luid);
238   return true;
239}
240#endif
241
242
243static unsigned
244wgl_get_pfd_flags(struct pipe_screen *screen)
245{
246#ifdef GALLIUM_D3D12
247   if (use_d3d12)
248      return d3d12_wgl_get_pfd_flags(screen);
249#endif
250   return stw_pfd_gdi_support;
251}
252
253
254static struct stw_winsys_framebuffer *
255wgl_create_framebuffer(struct pipe_screen *screen,
256                       HWND hWnd,
257                       int iPixelFormat)
258{
259#ifdef GALLIUM_D3D12
260   if (use_d3d12)
261      return d3d12_wgl_create_framebuffer(screen, hWnd, iPixelFormat);
262#endif
263   return NULL;
264}
265
266static const char *
267wgl_get_name(void)
268{
269   return created_driver_name;
270}
271
272
273static const struct stw_winsys stw_winsys = {
274   &wgl_screen_create,
275   &wgl_present,
276#if WINVER >= 0xA00
277   &wgl_get_adapter_luid,
278#else
279   NULL, /* get_adapter_luid */
280#endif
281   NULL, /* shared_surface_open */
282   NULL, /* shared_surface_close */
283   NULL, /* compose */
284   &wgl_get_pfd_flags,
285   &wgl_create_framebuffer,
286   &wgl_get_name,
287};
288
289
290EXTERN_C BOOL WINAPI
291DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
292
293
294BOOL WINAPI
295DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
296{
297   switch (fdwReason) {
298   case DLL_PROCESS_ATTACH:
299      stw_init(&stw_winsys);
300      stw_init_thread();
301      break;
302
303   case DLL_THREAD_ATTACH:
304      stw_init_thread();
305      break;
306
307   case DLL_THREAD_DETACH:
308      stw_cleanup_thread();
309      break;
310
311   case DLL_PROCESS_DETACH:
312      if (lpvReserved == NULL) {
313         // We're being unloaded from the process.
314         stw_cleanup_thread();
315         stw_cleanup();
316      } else {
317         // Process itself is terminating, and all threads and modules are
318         // being detached.
319         //
320         // The order threads (including llvmpipe rasterizer threads) are
321         // destroyed can not be relied up, so it's not safe to cleanup.
322         //
323         // However global destructors (e.g., LLVM's) will still be called, and
324         // if Microsoft OPENGL32.DLL's DllMain is called after us, it will
325         // still try to invoke DrvDeleteContext to destroys all outstanding,
326         // so set stw_dev to NULL to return immediately if that happens.
327         stw_dev = NULL;
328      }
329      break;
330   }
331   return TRUE;
332}
333