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