• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
71 static boolean use_llvmpipe = FALSE;
72 #endif
73 #ifdef GALLIUM_SWR
74 static boolean use_swr = FALSE;
75 #endif
76 #ifdef GALLIUM_D3D12
77 static boolean use_d3d12 = FALSE;
78 #endif
79 #ifdef GALLIUM_ZINK
80 static boolean use_zink = FALSE;
81 #endif
82 
83 static const char *created_driver_name = NULL;
84 
85 static struct pipe_screen *
wgl_screen_create_by_name(HDC hDC,const char * driver,struct sw_winsys * winsys)86 wgl_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 
127 static struct pipe_screen *
wgl_screen_create(HDC hDC)128 wgl_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 
171 static void
wgl_present(struct pipe_screen * screen,struct pipe_context * ctx,struct pipe_resource * res,HDC hDC)172 wgl_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
229 static boolean
wgl_get_adapter_luid(struct pipe_screen * screen,HDC hDC,LUID * adapter_luid)230 wgl_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 
243 static unsigned
wgl_get_pfd_flags(struct pipe_screen * screen)244 wgl_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 
254 static struct stw_winsys_framebuffer *
wgl_create_framebuffer(struct pipe_screen * screen,HWND hWnd,int iPixelFormat)255 wgl_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 
266 static const char *
wgl_get_name(void)267 wgl_get_name(void)
268 {
269    return created_driver_name;
270 }
271 
272 
273 static 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 
290 EXTERN_C BOOL WINAPI
291 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
292 
293 
294 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)295 DllMain(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