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