17ec681f3Smrg/************************************************************************** 27ec681f3Smrg * 37ec681f3Smrg * Copyright 2009-2010 VMware, Inc. 47ec681f3Smrg * All Rights Reserved. 57ec681f3Smrg * 67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77ec681f3Smrg * copy of this software and associated documentation files (the 87ec681f3Smrg * "Software"), to deal in the Software without restriction, including 97ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish, 107ec681f3Smrg * distribute, sub license, and/or sell copies of the Software, and to 117ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to 127ec681f3Smrg * the following conditions: 137ec681f3Smrg * 147ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 157ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 167ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 177ec681f3Smrg * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 187ec681f3Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 197ec681f3Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 207ec681f3Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. 217ec681f3Smrg * 227ec681f3Smrg * The above copyright notice and this permission notice (including the 237ec681f3Smrg * next paragraph) shall be included in all copies or substantial portions 247ec681f3Smrg * of the Software. 257ec681f3Smrg * 267ec681f3Smrg * 277ec681f3Smrg **************************************************************************/ 287ec681f3Smrg 297ec681f3Smrg/** 307ec681f3Smrg * @file 317ec681f3Smrg * Softpipe/LLVMpipe support. 327ec681f3Smrg * 337ec681f3Smrg * @author Jose Fonseca <jfonseca@vmware.com> 347ec681f3Smrg */ 357ec681f3Smrg 367ec681f3Smrg 377ec681f3Smrg#include <windows.h> 387ec681f3Smrg 397ec681f3Smrg#include "util/u_debug.h" 407ec681f3Smrg#include "util/debug.h" 417ec681f3Smrg#include "stw_winsys.h" 427ec681f3Smrg#include "stw_device.h" 437ec681f3Smrg#include "gdi/gdi_sw_winsys.h" 447ec681f3Smrg#include "pipe/p_screen.h" 457ec681f3Smrg#include "pipe/p_context.h" 467ec681f3Smrg 477ec681f3Smrg#ifdef GALLIUM_SOFTPIPE 487ec681f3Smrg#include "softpipe/sp_texture.h" 497ec681f3Smrg#include "softpipe/sp_screen.h" 507ec681f3Smrg#include "softpipe/sp_public.h" 517ec681f3Smrg#endif 527ec681f3Smrg 537ec681f3Smrg#ifdef GALLIUM_LLVMPIPE 547ec681f3Smrg#include "llvmpipe/lp_texture.h" 557ec681f3Smrg#include "llvmpipe/lp_screen.h" 567ec681f3Smrg#include "llvmpipe/lp_public.h" 577ec681f3Smrg#endif 587ec681f3Smrg 597ec681f3Smrg#ifdef GALLIUM_SWR 607ec681f3Smrg#include "swr/swr_public.h" 617ec681f3Smrg#endif 627ec681f3Smrg#ifdef GALLIUM_D3D12 637ec681f3Smrg#include "d3d12/wgl/d3d12_wgl_public.h" 647ec681f3Smrg#endif 657ec681f3Smrg 667ec681f3Smrg#ifdef GALLIUM_ZINK 677ec681f3Smrg#include "zink/zink_public.h" 687ec681f3Smrg#endif 697ec681f3Smrg 707ec681f3Smrg#ifdef GALLIUM_LLVMPIPE 717ec681f3Smrgstatic boolean use_llvmpipe = FALSE; 727ec681f3Smrg#endif 737ec681f3Smrg#ifdef GALLIUM_SWR 747ec681f3Smrgstatic boolean use_swr = FALSE; 757ec681f3Smrg#endif 767ec681f3Smrg#ifdef GALLIUM_D3D12 777ec681f3Smrgstatic boolean use_d3d12 = FALSE; 787ec681f3Smrg#endif 797ec681f3Smrg#ifdef GALLIUM_ZINK 807ec681f3Smrgstatic boolean use_zink = FALSE; 817ec681f3Smrg#endif 827ec681f3Smrg 837ec681f3Smrgstatic const char *created_driver_name = NULL; 847ec681f3Smrg 857ec681f3Smrgstatic struct pipe_screen * 867ec681f3Smrgwgl_screen_create_by_name(HDC hDC, const char* driver, struct sw_winsys *winsys) 877ec681f3Smrg{ 887ec681f3Smrg struct pipe_screen* screen = NULL; 897ec681f3Smrg 907ec681f3Smrg#ifdef GALLIUM_LLVMPIPE 917ec681f3Smrg if (strcmp(driver, "llvmpipe") == 0) { 927ec681f3Smrg screen = llvmpipe_create_screen(winsys); 937ec681f3Smrg if (screen) 947ec681f3Smrg use_llvmpipe = TRUE; 957ec681f3Smrg } 967ec681f3Smrg#endif 977ec681f3Smrg#ifdef GALLIUM_SWR 987ec681f3Smrg if (strcmp(driver, "swr") == 0) { 997ec681f3Smrg screen = swr_create_screen(winsys); 1007ec681f3Smrg if (screen) 1017ec681f3Smrg use_swr = TRUE; 1027ec681f3Smrg } 1037ec681f3Smrg#endif 1047ec681f3Smrg#ifdef GALLIUM_D3D12 1057ec681f3Smrg if (strcmp(driver, "d3d12") == 0) { 1067ec681f3Smrg screen = d3d12_wgl_create_screen(winsys, hDC); 1077ec681f3Smrg if (screen) 1087ec681f3Smrg use_d3d12 = TRUE; 1097ec681f3Smrg } 1107ec681f3Smrg#endif 1117ec681f3Smrg#ifdef GALLIUM_ZINK 1127ec681f3Smrg if (strcmp(driver, "zink") == 0) { 1137ec681f3Smrg screen = zink_create_screen(winsys); 1147ec681f3Smrg if (screen) 1157ec681f3Smrg use_zink = TRUE; 1167ec681f3Smrg } 1177ec681f3Smrg#endif 1187ec681f3Smrg#ifdef GALLIUM_SOFTPIPE 1197ec681f3Smrg if (strcmp(driver, "softpipe") == 0) { 1207ec681f3Smrg screen = softpipe_create_screen(winsys); 1217ec681f3Smrg } 1227ec681f3Smrg#endif 1237ec681f3Smrg 1247ec681f3Smrg return screen; 1257ec681f3Smrg} 1267ec681f3Smrg 1277ec681f3Smrgstatic struct pipe_screen * 1287ec681f3Smrgwgl_screen_create(HDC hDC) 1297ec681f3Smrg{ 1307ec681f3Smrg struct sw_winsys *winsys; 1317ec681f3Smrg UNUSED bool sw_only = env_var_as_boolean("LIBGL_ALWAYS_SOFTWARE", false); 1327ec681f3Smrg 1337ec681f3Smrg winsys = gdi_create_sw_winsys(); 1347ec681f3Smrg if (!winsys) 1357ec681f3Smrg return NULL; 1367ec681f3Smrg 1377ec681f3Smrg const char *const drivers[] = { 1387ec681f3Smrg debug_get_option("GALLIUM_DRIVER", ""), 1397ec681f3Smrg#ifdef GALLIUM_D3D12 1407ec681f3Smrg sw_only ? "" : "d3d12", 1417ec681f3Smrg#endif 1427ec681f3Smrg#if defined(GALLIUM_LLVMPIPE) 1437ec681f3Smrg "llvmpipe", 1447ec681f3Smrg#endif 1457ec681f3Smrg#if GALLIUM_SWR 1467ec681f3Smrg "swr", 1477ec681f3Smrg#endif 1487ec681f3Smrg#if defined(GALLIUM_SOFTPIPE) 1497ec681f3Smrg "softpipe", 1507ec681f3Smrg#endif 1517ec681f3Smrg }; 1527ec681f3Smrg 1537ec681f3Smrg /* If the default driver screen creation fails, fall back to the next option in the 1547ec681f3Smrg * sorted list. Don't do this if GALLIUM_DRIVER is specified. 1557ec681f3Smrg */ 1567ec681f3Smrg for (unsigned i = 0; i < ARRAY_SIZE(drivers); ++i) { 1577ec681f3Smrg struct pipe_screen* screen = wgl_screen_create_by_name(hDC, drivers[i], winsys); 1587ec681f3Smrg if (screen) { 1597ec681f3Smrg created_driver_name = drivers[i]; 1607ec681f3Smrg return screen; 1617ec681f3Smrg } 1627ec681f3Smrg if (i == 0 && drivers[i][0] != '\0') 1637ec681f3Smrg break; 1647ec681f3Smrg } 1657ec681f3Smrg 1667ec681f3Smrg winsys->destroy(winsys); 1677ec681f3Smrg return NULL; 1687ec681f3Smrg} 1697ec681f3Smrg 1707ec681f3Smrg 1717ec681f3Smrgstatic void 1727ec681f3Smrgwgl_present(struct pipe_screen *screen, 1737ec681f3Smrg struct pipe_context *ctx, 1747ec681f3Smrg struct pipe_resource *res, 1757ec681f3Smrg HDC hDC) 1767ec681f3Smrg{ 1777ec681f3Smrg /* This will fail if any interposing layer (trace, debug, etc) has 1787ec681f3Smrg * been introduced between the gallium frontends and the pipe driver. 1797ec681f3Smrg * 1807ec681f3Smrg * Ideally this would get replaced with a call to 1817ec681f3Smrg * pipe_screen::flush_frontbuffer(). 1827ec681f3Smrg * 1837ec681f3Smrg * Failing that, it may be necessary for intervening layers to wrap 1847ec681f3Smrg * other structs such as this stw_winsys as well... 1857ec681f3Smrg */ 1867ec681f3Smrg 1877ec681f3Smrg struct sw_winsys *winsys = NULL; 1887ec681f3Smrg struct sw_displaytarget *dt = NULL; 1897ec681f3Smrg 1907ec681f3Smrg#ifdef GALLIUM_LLVMPIPE 1917ec681f3Smrg if (use_llvmpipe) { 1927ec681f3Smrg winsys = llvmpipe_screen(screen)->winsys; 1937ec681f3Smrg dt = llvmpipe_resource(res)->dt; 1947ec681f3Smrg gdi_sw_display(winsys, dt, hDC); 1957ec681f3Smrg return; 1967ec681f3Smrg } 1977ec681f3Smrg#endif 1987ec681f3Smrg 1997ec681f3Smrg#ifdef GALLIUM_SWR 2007ec681f3Smrg if (use_swr) { 2017ec681f3Smrg swr_gdi_swap(screen, ctx, res, hDC); 2027ec681f3Smrg return; 2037ec681f3Smrg } 2047ec681f3Smrg#endif 2057ec681f3Smrg 2067ec681f3Smrg#ifdef GALLIUM_D3D12 2077ec681f3Smrg if (use_d3d12) { 2087ec681f3Smrg d3d12_wgl_present(screen, ctx, res, hDC); 2097ec681f3Smrg return; 2107ec681f3Smrg } 2117ec681f3Smrg#endif 2127ec681f3Smrg 2137ec681f3Smrg#ifdef GALLIUM_ZINK 2147ec681f3Smrg if (use_zink) { 2157ec681f3Smrg screen->flush_frontbuffer(screen, ctx, res, 0, 0, hDC, NULL); 2167ec681f3Smrg return; 2177ec681f3Smrg } 2187ec681f3Smrg#endif 2197ec681f3Smrg 2207ec681f3Smrg#ifdef GALLIUM_SOFTPIPE 2217ec681f3Smrg winsys = softpipe_screen(screen)->winsys, 2227ec681f3Smrg dt = softpipe_resource(res)->dt, 2237ec681f3Smrg gdi_sw_display(winsys, dt, hDC); 2247ec681f3Smrg#endif 2257ec681f3Smrg} 2267ec681f3Smrg 2277ec681f3Smrg 2287ec681f3Smrg#if WINVER >= 0xA00 2297ec681f3Smrgstatic boolean 2307ec681f3Smrgwgl_get_adapter_luid(struct pipe_screen* screen, 2317ec681f3Smrg HDC hDC, 2327ec681f3Smrg LUID* adapter_luid) 2337ec681f3Smrg{ 2347ec681f3Smrg if (!stw_dev || !stw_dev->callbacks.pfnGetAdapterLuid) 2357ec681f3Smrg return false; 2367ec681f3Smrg 2377ec681f3Smrg stw_dev->callbacks.pfnGetAdapterLuid(hDC, adapter_luid); 2387ec681f3Smrg return true; 2397ec681f3Smrg} 2407ec681f3Smrg#endif 2417ec681f3Smrg 2427ec681f3Smrg 2437ec681f3Smrgstatic unsigned 2447ec681f3Smrgwgl_get_pfd_flags(struct pipe_screen *screen) 2457ec681f3Smrg{ 2467ec681f3Smrg#ifdef GALLIUM_D3D12 2477ec681f3Smrg if (use_d3d12) 2487ec681f3Smrg return d3d12_wgl_get_pfd_flags(screen); 2497ec681f3Smrg#endif 2507ec681f3Smrg return stw_pfd_gdi_support; 2517ec681f3Smrg} 2527ec681f3Smrg 2537ec681f3Smrg 2547ec681f3Smrgstatic struct stw_winsys_framebuffer * 2557ec681f3Smrgwgl_create_framebuffer(struct pipe_screen *screen, 2567ec681f3Smrg HWND hWnd, 2577ec681f3Smrg int iPixelFormat) 2587ec681f3Smrg{ 2597ec681f3Smrg#ifdef GALLIUM_D3D12 2607ec681f3Smrg if (use_d3d12) 2617ec681f3Smrg return d3d12_wgl_create_framebuffer(screen, hWnd, iPixelFormat); 2627ec681f3Smrg#endif 2637ec681f3Smrg return NULL; 2647ec681f3Smrg} 2657ec681f3Smrg 2667ec681f3Smrgstatic const char * 2677ec681f3Smrgwgl_get_name(void) 2687ec681f3Smrg{ 2697ec681f3Smrg return created_driver_name; 2707ec681f3Smrg} 2717ec681f3Smrg 2727ec681f3Smrg 2737ec681f3Smrgstatic const struct stw_winsys stw_winsys = { 2747ec681f3Smrg &wgl_screen_create, 2757ec681f3Smrg &wgl_present, 2767ec681f3Smrg#if WINVER >= 0xA00 2777ec681f3Smrg &wgl_get_adapter_luid, 2787ec681f3Smrg#else 2797ec681f3Smrg NULL, /* get_adapter_luid */ 2807ec681f3Smrg#endif 2817ec681f3Smrg NULL, /* shared_surface_open */ 2827ec681f3Smrg NULL, /* shared_surface_close */ 2837ec681f3Smrg NULL, /* compose */ 2847ec681f3Smrg &wgl_get_pfd_flags, 2857ec681f3Smrg &wgl_create_framebuffer, 2867ec681f3Smrg &wgl_get_name, 2877ec681f3Smrg}; 2887ec681f3Smrg 2897ec681f3Smrg 2907ec681f3SmrgEXTERN_C BOOL WINAPI 2917ec681f3SmrgDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); 2927ec681f3Smrg 2937ec681f3Smrg 2947ec681f3SmrgBOOL WINAPI 2957ec681f3SmrgDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 2967ec681f3Smrg{ 2977ec681f3Smrg switch (fdwReason) { 2987ec681f3Smrg case DLL_PROCESS_ATTACH: 2997ec681f3Smrg stw_init(&stw_winsys); 3007ec681f3Smrg stw_init_thread(); 3017ec681f3Smrg break; 3027ec681f3Smrg 3037ec681f3Smrg case DLL_THREAD_ATTACH: 3047ec681f3Smrg stw_init_thread(); 3057ec681f3Smrg break; 3067ec681f3Smrg 3077ec681f3Smrg case DLL_THREAD_DETACH: 3087ec681f3Smrg stw_cleanup_thread(); 3097ec681f3Smrg break; 3107ec681f3Smrg 3117ec681f3Smrg case DLL_PROCESS_DETACH: 3127ec681f3Smrg if (lpvReserved == NULL) { 3137ec681f3Smrg // We're being unloaded from the process. 3147ec681f3Smrg stw_cleanup_thread(); 3157ec681f3Smrg stw_cleanup(); 3167ec681f3Smrg } else { 3177ec681f3Smrg // Process itself is terminating, and all threads and modules are 3187ec681f3Smrg // being detached. 3197ec681f3Smrg // 3207ec681f3Smrg // The order threads (including llvmpipe rasterizer threads) are 3217ec681f3Smrg // destroyed can not be relied up, so it's not safe to cleanup. 3227ec681f3Smrg // 3237ec681f3Smrg // However global destructors (e.g., LLVM's) will still be called, and 3247ec681f3Smrg // if Microsoft OPENGL32.DLL's DllMain is called after us, it will 3257ec681f3Smrg // still try to invoke DrvDeleteContext to destroys all outstanding, 3267ec681f3Smrg // so set stw_dev to NULL to return immediately if that happens. 3277ec681f3Smrg stw_dev = NULL; 3287ec681f3Smrg } 3297ec681f3Smrg break; 3307ec681f3Smrg } 3317ec681f3Smrg return TRUE; 3327ec681f3Smrg} 333