• 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_D3D12
60 #include "d3d12/wgl/d3d12_wgl_public.h"
61 #endif
62 
63 #ifdef GALLIUM_ZINK
64 #include "zink/zink_public.h"
65 #endif
66 
67 #ifdef GALLIUM_LLVMPIPE
68 static boolean use_llvmpipe = FALSE;
69 #endif
70 #ifdef GALLIUM_D3D12
71 static boolean use_d3d12 = FALSE;
72 #endif
73 #ifdef GALLIUM_ZINK
74 static boolean use_zink = FALSE;
75 #endif
76 
77 static const char *created_driver_name = NULL;
78 
79 static struct pipe_screen *
wgl_screen_create_by_name(HDC hDC,const char * driver,struct sw_winsys * winsys)80 wgl_screen_create_by_name(HDC hDC, const char* driver, struct sw_winsys *winsys)
81 {
82    struct pipe_screen* screen = NULL;
83 
84 #ifdef GALLIUM_LLVMPIPE
85    if (strcmp(driver, "llvmpipe") == 0) {
86       screen = llvmpipe_create_screen(winsys);
87       if (screen)
88          use_llvmpipe = TRUE;
89    }
90 #endif
91 #ifdef GALLIUM_D3D12
92    if (strcmp(driver, "d3d12") == 0) {
93       screen = d3d12_wgl_create_screen(winsys, hDC);
94       if (screen)
95          use_d3d12 = TRUE;
96    }
97 #endif
98 #ifdef GALLIUM_ZINK
99    if (strcmp(driver, "zink") == 0) {
100       screen = zink_create_screen(winsys, NULL);
101       if (screen)
102          use_zink = TRUE;
103    }
104 #endif
105 #ifdef GALLIUM_SOFTPIPE
106    if (strcmp(driver, "softpipe") == 0) {
107       screen = softpipe_create_screen(winsys);
108    }
109 #endif
110 
111    return screen;
112 }
113 
114 static struct pipe_screen *
wgl_screen_create(HDC hDC)115 wgl_screen_create(HDC hDC)
116 {
117    struct sw_winsys *winsys;
118    UNUSED bool sw_only = env_var_as_boolean("LIBGL_ALWAYS_SOFTWARE", false);
119 
120    winsys = gdi_create_sw_winsys();
121    if (!winsys)
122       return NULL;
123 
124    const char *const drivers[] = {
125       debug_get_option("GALLIUM_DRIVER", ""),
126 #ifdef GALLIUM_D3D12
127       sw_only ? "" : "d3d12",
128 #endif
129 #ifdef GALLIUM_ZINK
130       sw_only ? "" : "zink",
131 #endif
132 #if defined(GALLIUM_LLVMPIPE)
133       "llvmpipe",
134 #endif
135 #if defined(GALLIUM_SOFTPIPE)
136       "softpipe",
137 #endif
138    };
139 
140    /* If the default driver screen creation fails, fall back to the next option in the
141     * sorted list. Don't do this if GALLIUM_DRIVER is specified.
142     */
143    for (unsigned i = 0; i < ARRAY_SIZE(drivers); ++i) {
144       struct pipe_screen* screen = wgl_screen_create_by_name(hDC, drivers[i], winsys);
145       if (screen) {
146          created_driver_name = drivers[i];
147          return screen;
148       }
149       if (i == 0 && drivers[i][0] != '\0')
150          break;
151    }
152 
153    winsys->destroy(winsys);
154    return NULL;
155 }
156 
157 
158 static void
wgl_present(struct pipe_screen * screen,struct pipe_context * ctx,struct pipe_resource * res,HDC hDC)159 wgl_present(struct pipe_screen *screen,
160             struct pipe_context *ctx,
161             struct pipe_resource *res,
162             HDC hDC)
163 {
164    /* This will fail if any interposing layer (trace, debug, etc) has
165     * been introduced between the gallium frontends and the pipe driver.
166     *
167     * Ideally this would get replaced with a call to
168     * pipe_screen::flush_frontbuffer().
169     *
170     * Failing that, it may be necessary for intervening layers to wrap
171     * other structs such as this stw_winsys as well...
172     */
173 
174    struct sw_winsys *winsys = NULL;
175    struct sw_displaytarget *dt = NULL;
176 
177 #ifdef GALLIUM_LLVMPIPE
178    if (use_llvmpipe) {
179       winsys = llvmpipe_screen(screen)->winsys;
180       dt = llvmpipe_resource(res)->dt;
181       gdi_sw_display(winsys, dt, hDC);
182       return;
183    }
184 #endif
185 
186 #ifdef GALLIUM_D3D12
187    if (use_d3d12) {
188       d3d12_wgl_present(screen, ctx, res, hDC);
189       return;
190    }
191 #endif
192 
193 #ifdef GALLIUM_ZINK
194    if (use_zink) {
195       screen->flush_frontbuffer(screen, ctx, res, 0, 0, hDC, NULL);
196       return;
197    }
198 #endif
199 
200 #ifdef GALLIUM_SOFTPIPE
201    winsys = softpipe_screen(screen)->winsys,
202    dt = softpipe_resource(res)->dt,
203    gdi_sw_display(winsys, dt, hDC);
204 #endif
205 }
206 
207 
208 #if WINVER >= 0xA00
209 static boolean
wgl_get_adapter_luid(struct pipe_screen * screen,HDC hDC,LUID * adapter_luid)210 wgl_get_adapter_luid(struct pipe_screen* screen,
211    HDC hDC,
212    LUID* adapter_luid)
213 {
214    if (!stw_dev || !stw_dev->callbacks.pfnGetAdapterLuid)
215       return false;
216 
217    stw_dev->callbacks.pfnGetAdapterLuid(hDC, adapter_luid);
218    return true;
219 }
220 #endif
221 
222 
223 static unsigned
wgl_get_pfd_flags(struct pipe_screen * screen)224 wgl_get_pfd_flags(struct pipe_screen *screen)
225 {
226 #ifdef GALLIUM_D3D12
227    if (use_d3d12)
228       return d3d12_wgl_get_pfd_flags(screen);
229 #endif
230    return stw_pfd_gdi_support;
231 }
232 
233 
234 static struct stw_winsys_framebuffer *
wgl_create_framebuffer(struct pipe_screen * screen,HWND hWnd,int iPixelFormat)235 wgl_create_framebuffer(struct pipe_screen *screen,
236                        HWND hWnd,
237                        int iPixelFormat)
238 {
239 #ifdef GALLIUM_D3D12
240    if (use_d3d12)
241       return d3d12_wgl_create_framebuffer(screen, hWnd, iPixelFormat);
242 #endif
243    return NULL;
244 }
245 
246 static const char *
wgl_get_name(void)247 wgl_get_name(void)
248 {
249    return created_driver_name;
250 }
251 
252 
253 static const struct stw_winsys stw_winsys = {
254    &wgl_screen_create,
255    &wgl_present,
256 #if WINVER >= 0xA00
257    &wgl_get_adapter_luid,
258 #else
259    NULL, /* get_adapter_luid */
260 #endif
261    NULL, /* shared_surface_open */
262    NULL, /* shared_surface_close */
263    NULL, /* compose */
264    &wgl_get_pfd_flags,
265    &wgl_create_framebuffer,
266    &wgl_get_name,
267 };
268 
269 
270 EXTERN_C BOOL WINAPI
271 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
272 
273 
274 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)275 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
276 {
277    switch (fdwReason) {
278    case DLL_PROCESS_ATTACH:
279       stw_init(&stw_winsys);
280       stw_init_thread();
281       break;
282 
283    case DLL_THREAD_ATTACH:
284       stw_init_thread();
285       break;
286 
287    case DLL_THREAD_DETACH:
288       stw_cleanup_thread();
289       break;
290 
291    case DLL_PROCESS_DETACH:
292       if (lpvReserved == NULL) {
293          // We're being unloaded from the process.
294          stw_cleanup_thread();
295          stw_cleanup();
296       } else {
297          // Process itself is terminating, and all threads and modules are
298          // being detached.
299          //
300          // The order threads (including llvmpipe rasterizer threads) are
301          // destroyed can not be relied up, so it's not safe to cleanup.
302          //
303          // However global destructors (e.g., LLVM's) will still be called, and
304          // if Microsoft OPENGL32.DLL's DllMain is called after us, it will
305          // still try to invoke DrvDeleteContext to destroys all outstanding,
306          // so set stw_dev to NULL to return immediately if that happens.
307          stw_dev = NULL;
308       }
309       break;
310    }
311    return TRUE;
312 }
313