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