src/video/windows/SDL_windowsvideo.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 18 May 2018 13:09:30 -0700
changeset 11983 3a50eb90e4b2
parent 11872 e917e911dab6
child 12070 1d65571b57dd
permissions -rw-r--r--
Merged latest changes from Steam Link app
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #if SDL_VIDEO_DRIVER_WINDOWS
    24 
    25 #include "SDL_main.h"
    26 #include "SDL_video.h"
    27 #include "SDL_hints.h"
    28 #include "SDL_mouse.h"
    29 #include "SDL_system.h"
    30 #include "../SDL_sysvideo.h"
    31 #include "../SDL_pixels_c.h"
    32 
    33 #include "SDL_windowsvideo.h"
    34 #include "SDL_windowsframebuffer.h"
    35 #include "SDL_windowsshape.h"
    36 #include "SDL_windowsvulkan.h"
    37 
    38 /* Initialization/Query functions */
    39 static int WIN_VideoInit(_THIS);
    40 static void WIN_VideoQuit(_THIS);
    41 
    42 /* Hints */
    43 SDL_bool g_WindowsEnableMessageLoop = SDL_TRUE;
    44 SDL_bool g_WindowFrameUsableWhileCursorHidden = SDL_TRUE;
    45 
    46 static void SDLCALL
    47 UpdateWindowsEnableMessageLoop(void *userdata, const char *name, const char *oldValue, const char *newValue)
    48 {
    49     if (newValue && *newValue == '0') {
    50         g_WindowsEnableMessageLoop = SDL_FALSE;
    51     } else {
    52         g_WindowsEnableMessageLoop = SDL_TRUE;
    53     }
    54 }
    55 
    56 static void SDLCALL
    57 UpdateWindowFrameUsableWhileCursorHidden(void *userdata, const char *name, const char *oldValue, const char *newValue)
    58 {
    59     if (newValue && *newValue == '0') {
    60         g_WindowFrameUsableWhileCursorHidden = SDL_FALSE;
    61     } else {
    62         g_WindowFrameUsableWhileCursorHidden = SDL_TRUE;
    63     }
    64 }
    65 
    66 
    67 /* Windows driver bootstrap functions */
    68 
    69 static int
    70 WIN_Available(void)
    71 {
    72     return (1);
    73 }
    74 
    75 static void
    76 WIN_DeleteDevice(SDL_VideoDevice * device)
    77 {
    78     SDL_VideoData *data = (SDL_VideoData *) device->driverdata;
    79 
    80     SDL_UnregisterApp();
    81     if (data->userDLL) {
    82         SDL_UnloadObject(data->userDLL);
    83     }
    84     if (data->shcoreDLL) {
    85         SDL_UnloadObject(data->shcoreDLL);
    86     }
    87 
    88     SDL_free(device->driverdata);
    89     SDL_free(device);
    90 }
    91 
    92 static SDL_VideoDevice *
    93 WIN_CreateDevice(int devindex)
    94 {
    95     SDL_VideoDevice *device;
    96     SDL_VideoData *data;
    97 
    98     SDL_RegisterApp(NULL, 0, NULL);
    99 
   100     /* Initialize all variables that we clean on shutdown */
   101     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
   102     if (device) {
   103         data = (struct SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
   104     } else {
   105         data = NULL;
   106     }
   107     if (!data) {
   108         SDL_free(device);
   109         SDL_OutOfMemory();
   110         return NULL;
   111     }
   112     device->driverdata = data;
   113 
   114     data->userDLL = SDL_LoadObject("USER32.DLL");
   115     if (data->userDLL) {
   116         data->CloseTouchInputHandle = (BOOL (WINAPI *)(HTOUCHINPUT)) SDL_LoadFunction(data->userDLL, "CloseTouchInputHandle");
   117         data->GetTouchInputInfo = (BOOL (WINAPI *)(HTOUCHINPUT, UINT, PTOUCHINPUT, int)) SDL_LoadFunction(data->userDLL, "GetTouchInputInfo");
   118         data->RegisterTouchWindow = (BOOL (WINAPI *)(HWND, ULONG)) SDL_LoadFunction(data->userDLL, "RegisterTouchWindow");
   119     } else {
   120         SDL_ClearError();
   121     }
   122 
   123     data->shcoreDLL = SDL_LoadObject("SHCORE.DLL");
   124     if (data->shcoreDLL) {
   125         data->GetDpiForMonitor = (HRESULT (WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *)) SDL_LoadFunction(data->shcoreDLL, "GetDpiForMonitor");
   126     } else {
   127         SDL_ClearError();
   128     }
   129 
   130     /* Set the function pointers */
   131     device->VideoInit = WIN_VideoInit;
   132     device->VideoQuit = WIN_VideoQuit;
   133     device->GetDisplayBounds = WIN_GetDisplayBounds;
   134     device->GetDisplayUsableBounds = WIN_GetDisplayUsableBounds;
   135     device->GetDisplayDPI = WIN_GetDisplayDPI;
   136     device->GetDisplayModes = WIN_GetDisplayModes;
   137     device->SetDisplayMode = WIN_SetDisplayMode;
   138     device->PumpEvents = WIN_PumpEvents;
   139 
   140     device->CreateSDLWindow = WIN_CreateWindow;
   141     device->CreateSDLWindowFrom = WIN_CreateWindowFrom;
   142     device->SetWindowTitle = WIN_SetWindowTitle;
   143     device->SetWindowIcon = WIN_SetWindowIcon;
   144     device->SetWindowPosition = WIN_SetWindowPosition;
   145     device->SetWindowSize = WIN_SetWindowSize;
   146     device->GetWindowBordersSize = WIN_GetWindowBordersSize;
   147     device->SetWindowOpacity = WIN_SetWindowOpacity;
   148     device->ShowWindow = WIN_ShowWindow;
   149     device->HideWindow = WIN_HideWindow;
   150     device->RaiseWindow = WIN_RaiseWindow;
   151     device->MaximizeWindow = WIN_MaximizeWindow;
   152     device->MinimizeWindow = WIN_MinimizeWindow;
   153     device->RestoreWindow = WIN_RestoreWindow;
   154     device->SetWindowBordered = WIN_SetWindowBordered;
   155     device->SetWindowResizable = WIN_SetWindowResizable;
   156     device->SetWindowFullscreen = WIN_SetWindowFullscreen;
   157     device->SetWindowGammaRamp = WIN_SetWindowGammaRamp;
   158     device->GetWindowGammaRamp = WIN_GetWindowGammaRamp;
   159     device->SetWindowGrab = WIN_SetWindowGrab;
   160     device->DestroyWindow = WIN_DestroyWindow;
   161     device->GetWindowWMInfo = WIN_GetWindowWMInfo;
   162     device->CreateWindowFramebuffer = WIN_CreateWindowFramebuffer;
   163     device->UpdateWindowFramebuffer = WIN_UpdateWindowFramebuffer;
   164     device->DestroyWindowFramebuffer = WIN_DestroyWindowFramebuffer;
   165     device->OnWindowEnter = WIN_OnWindowEnter;
   166     device->SetWindowHitTest = WIN_SetWindowHitTest;
   167 
   168     device->shape_driver.CreateShaper = Win32_CreateShaper;
   169     device->shape_driver.SetWindowShape = Win32_SetWindowShape;
   170     device->shape_driver.ResizeWindowShape = Win32_ResizeWindowShape;
   171 
   172 #if SDL_VIDEO_OPENGL_WGL
   173     device->GL_LoadLibrary = WIN_GL_LoadLibrary;
   174     device->GL_GetProcAddress = WIN_GL_GetProcAddress;
   175     device->GL_UnloadLibrary = WIN_GL_UnloadLibrary;
   176     device->GL_CreateContext = WIN_GL_CreateContext;
   177     device->GL_MakeCurrent = WIN_GL_MakeCurrent;
   178     device->GL_SetSwapInterval = WIN_GL_SetSwapInterval;
   179     device->GL_GetSwapInterval = WIN_GL_GetSwapInterval;
   180     device->GL_SwapWindow = WIN_GL_SwapWindow;
   181     device->GL_DeleteContext = WIN_GL_DeleteContext;
   182 #elif SDL_VIDEO_OPENGL_EGL        
   183     /* Use EGL based functions */
   184     device->GL_LoadLibrary = WIN_GLES_LoadLibrary;
   185     device->GL_GetProcAddress = WIN_GLES_GetProcAddress;
   186     device->GL_UnloadLibrary = WIN_GLES_UnloadLibrary;
   187     device->GL_CreateContext = WIN_GLES_CreateContext;
   188     device->GL_MakeCurrent = WIN_GLES_MakeCurrent;
   189     device->GL_SetSwapInterval = WIN_GLES_SetSwapInterval;
   190     device->GL_GetSwapInterval = WIN_GLES_GetSwapInterval;
   191     device->GL_SwapWindow = WIN_GLES_SwapWindow;
   192     device->GL_DeleteContext = WIN_GLES_DeleteContext;
   193 #endif
   194 #if SDL_VIDEO_VULKAN
   195     device->Vulkan_LoadLibrary = WIN_Vulkan_LoadLibrary;
   196     device->Vulkan_UnloadLibrary = WIN_Vulkan_UnloadLibrary;
   197     device->Vulkan_GetInstanceExtensions = WIN_Vulkan_GetInstanceExtensions;
   198     device->Vulkan_CreateSurface = WIN_Vulkan_CreateSurface;
   199 #endif
   200 
   201     device->StartTextInput = WIN_StartTextInput;
   202     device->StopTextInput = WIN_StopTextInput;
   203     device->SetTextInputRect = WIN_SetTextInputRect;
   204 
   205     device->SetClipboardText = WIN_SetClipboardText;
   206     device->GetClipboardText = WIN_GetClipboardText;
   207     device->HasClipboardText = WIN_HasClipboardText;
   208 
   209     device->free = WIN_DeleteDevice;
   210 
   211     return device;
   212 }
   213 
   214 
   215 VideoBootStrap WINDOWS_bootstrap = {
   216     "windows", "SDL Windows video driver", WIN_Available, WIN_CreateDevice
   217 };
   218 
   219 int
   220 WIN_VideoInit(_THIS)
   221 {
   222     if (WIN_InitModes(_this) < 0) {
   223         return -1;
   224     }
   225 
   226     WIN_InitKeyboard(_this);
   227     WIN_InitMouse(_this);
   228 
   229     SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL);
   230     SDL_AddHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL);
   231 
   232     return 0;
   233 }
   234 
   235 void
   236 WIN_VideoQuit(_THIS)
   237 {
   238     WIN_QuitModes(_this);
   239     WIN_QuitKeyboard(_this);
   240     WIN_QuitMouse(_this);
   241 }
   242 
   243 
   244 #define D3D_DEBUG_INFO
   245 #include <d3d9.h>
   246 
   247 SDL_bool 
   248 D3D_LoadDLL(void **pD3DDLL, IDirect3D9 **pDirect3D9Interface)
   249 {
   250     *pD3DDLL = SDL_LoadObject("D3D9.DLL");
   251     if (*pD3DDLL) {
   252         typedef IDirect3D9 *(WINAPI *Direct3DCreate9_t) (UINT SDKVersion);
   253         Direct3DCreate9_t Direct3DCreate9Func;
   254 
   255 #ifdef USE_D3D9EX
   256         typedef HRESULT (WINAPI *Direct3DCreate9Ex_t)(UINT SDKVersion, IDirect3D9Ex **ppD3D);
   257         Direct3DCreate9Ex_t Direct3DCreate9ExFunc;
   258 
   259         Direct3DCreate9ExFunc = (Direct3DCreate9Ex_t)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9Ex");
   260         if (Direct3DCreate9ExFunc) {
   261             IDirect3D9Ex *pDirect3D9ExInterface;
   262             HRESULT hr = Direct3DCreate9ExFunc(D3D_SDK_VERSION, &pDirect3D9ExInterface);
   263             if (SUCCEEDED(hr)) {
   264                 const GUID IDirect3D9_GUID = { 0x81bdcbca, 0x64d4, 0x426d, { 0xae, 0x8d, 0xad, 0x1, 0x47, 0xf4, 0x27, 0x5c } };
   265                 hr = IDirect3D9Ex_QueryInterface(pDirect3D9ExInterface, &IDirect3D9_GUID, (void**)pDirect3D9Interface);
   266                 IDirect3D9Ex_Release(pDirect3D9ExInterface);
   267                 if (SUCCEEDED(hr)) {
   268                     return SDL_TRUE;
   269                 }
   270             }
   271         }
   272 #endif /* USE_D3D9EX */
   273 
   274         Direct3DCreate9Func = (Direct3DCreate9_t)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9");
   275         if (Direct3DCreate9Func) {
   276             *pDirect3D9Interface = Direct3DCreate9Func(D3D_SDK_VERSION);
   277             if (*pDirect3D9Interface) {
   278                 return SDL_TRUE;
   279             }
   280         }
   281 
   282         SDL_UnloadObject(*pD3DDLL);
   283         *pD3DDLL = NULL;
   284     }
   285     *pDirect3D9Interface = NULL;
   286     return SDL_FALSE;
   287 }
   288 
   289 
   290 int
   291 SDL_Direct3D9GetAdapterIndex(int displayIndex)
   292 {
   293     void *pD3DDLL;
   294     IDirect3D9 *pD3D;
   295     if (!D3D_LoadDLL(&pD3DDLL, &pD3D)) {
   296         SDL_SetError("Unable to create Direct3D interface");
   297         return D3DADAPTER_DEFAULT;
   298     } else {
   299         SDL_DisplayData *pData = (SDL_DisplayData *)SDL_GetDisplayDriverData(displayIndex);
   300         int adapterIndex = D3DADAPTER_DEFAULT;
   301 
   302         if (!pData) {
   303             SDL_SetError("Invalid display index");
   304             adapterIndex = -1; /* make sure we return something invalid */
   305         } else {
   306             char *displayName = WIN_StringToUTF8(pData->DeviceName);
   307             unsigned int count = IDirect3D9_GetAdapterCount(pD3D);
   308             unsigned int i;
   309             for (i=0; i<count; i++) {
   310                 D3DADAPTER_IDENTIFIER9 id;
   311                 IDirect3D9_GetAdapterIdentifier(pD3D, i, 0, &id);
   312 
   313                 if (SDL_strcmp(id.DeviceName, displayName) == 0) {
   314                     adapterIndex = i;
   315                     break;
   316                 }
   317             }
   318             SDL_free(displayName);
   319         }
   320 
   321         /* free up the D3D stuff we inited */
   322         IDirect3D9_Release(pD3D);
   323         SDL_UnloadObject(pD3DDLL);
   324 
   325         return adapterIndex;
   326     }
   327 }
   328 
   329 #if HAVE_DXGI_H
   330 #define CINTERFACE
   331 #define COBJMACROS
   332 #include <dxgi.h>
   333 
   334 static SDL_bool
   335 DXGI_LoadDLL(void **pDXGIDLL, IDXGIFactory **pDXGIFactory)
   336 {
   337     *pDXGIDLL = SDL_LoadObject("DXGI.DLL");
   338     if (*pDXGIDLL) {
   339         HRESULT (WINAPI *CreateDXGI)(REFIID riid, void **ppFactory);
   340 
   341         CreateDXGI =
   342             (HRESULT (WINAPI *) (REFIID, void**)) SDL_LoadFunction(*pDXGIDLL,
   343             "CreateDXGIFactory");
   344         if (CreateDXGI) {
   345             GUID dxgiGUID = {0x7b7166ec,0x21c7,0x44ae,{0xb2,0x1a,0xc9,0xae,0x32,0x1a,0xe3,0x69}};
   346             if (!SUCCEEDED(CreateDXGI(&dxgiGUID, (void**)pDXGIFactory))) {
   347                 *pDXGIFactory = NULL;
   348             }
   349         }
   350         if (!*pDXGIFactory) {
   351             SDL_UnloadObject(*pDXGIDLL);
   352             *pDXGIDLL = NULL;
   353             return SDL_FALSE;
   354         }
   355 
   356         return SDL_TRUE;
   357     } else {
   358         *pDXGIFactory = NULL;
   359         return SDL_FALSE;
   360     }
   361 }
   362 #endif
   363 
   364 
   365 SDL_bool
   366 SDL_DXGIGetOutputInfo(int displayIndex, int *adapterIndex, int *outputIndex)
   367 {
   368 #if !HAVE_DXGI_H
   369     if (adapterIndex) *adapterIndex = -1;
   370     if (outputIndex) *outputIndex = -1;
   371     SDL_SetError("SDL was compiled without DXGI support due to missing dxgi.h header");
   372     return SDL_FALSE;
   373 #else
   374     SDL_DisplayData *pData = (SDL_DisplayData *)SDL_GetDisplayDriverData(displayIndex);
   375     void *pDXGIDLL;
   376     char *displayName;
   377     int nAdapter, nOutput;
   378     IDXGIFactory *pDXGIFactory;
   379     IDXGIAdapter *pDXGIAdapter;
   380     IDXGIOutput* pDXGIOutput;
   381 
   382     if (!adapterIndex) {
   383         SDL_InvalidParamError("adapterIndex");
   384         return SDL_FALSE;
   385     }
   386 
   387     if (!outputIndex) {
   388         SDL_InvalidParamError("outputIndex");
   389         return SDL_FALSE;
   390     }
   391 
   392     *adapterIndex = -1;
   393     *outputIndex = -1;
   394 
   395     if (!pData) {
   396         SDL_SetError("Invalid display index");
   397         return SDL_FALSE;
   398     }
   399 
   400     if (!DXGI_LoadDLL(&pDXGIDLL, &pDXGIFactory)) {
   401         SDL_SetError("Unable to create DXGI interface");
   402         return SDL_FALSE;
   403     }
   404 
   405     displayName = WIN_StringToUTF8(pData->DeviceName);
   406     nAdapter = 0;
   407     while (*adapterIndex == -1 && SUCCEEDED(IDXGIFactory_EnumAdapters(pDXGIFactory, nAdapter, &pDXGIAdapter))) {
   408         nOutput = 0;
   409         while (*adapterIndex == -1 && SUCCEEDED(IDXGIAdapter_EnumOutputs(pDXGIAdapter, nOutput, &pDXGIOutput))) {
   410             DXGI_OUTPUT_DESC outputDesc;
   411             if (SUCCEEDED(IDXGIOutput_GetDesc(pDXGIOutput, &outputDesc))) {
   412                 char *outputName = WIN_StringToUTF8(outputDesc.DeviceName);
   413                 if (SDL_strcmp(outputName, displayName) == 0) {
   414                     *adapterIndex = nAdapter;
   415                     *outputIndex = nOutput;
   416                 }
   417                 SDL_free(outputName);
   418             }
   419             IDXGIOutput_Release(pDXGIOutput);
   420             nOutput++;
   421         }
   422         IDXGIAdapter_Release(pDXGIAdapter);
   423         nAdapter++;
   424     }
   425     SDL_free(displayName);
   426 
   427     /* free up the DXGI factory */
   428     IDXGIFactory_Release(pDXGIFactory);
   429     SDL_UnloadObject(pDXGIDLL);
   430 
   431     if (*adapterIndex == -1) {
   432         return SDL_FALSE;
   433     } else {
   434         return SDL_TRUE;
   435     }
   436 #endif
   437 }
   438 
   439 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   440 
   441 /* vim: set ts=4 sw=4 expandtab: */