diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a80e3e2e --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# Build-folder where we put meson build files +# +# Example: +# meson build/ +# ninja -C build/ +# +build/ + +# Ignore directx headers, because we are not allowed to redistribute them? +include/native/directx/* +!include/native/directx/README.md diff --git a/include/native/directx/README.md b/include/native/directx/README.md new file mode 100644 index 00000000..4359061b --- /dev/null +++ b/include/native/directx/README.md @@ -0,0 +1,11 @@ +# include/native/directx + +Put your DirectX headers in here. These cannot be redisted due to current licensing reasons. + +Example of how to get them: +```sh +brew install mingw-w64 +# ...installing +cd ~/Cellar/mingw-w64/7.0.0_2/toolchain-x86_64/x86_64-w64-mingw32/include/ +cp d3d*.h dxgi*.h ~/git/github/Joshua-Ashton/dxvk-native/include/native/directx/ +``` \ No newline at end of file diff --git a/include/native/windows/oaidl.h b/include/native/windows/oaidl.h new file mode 100644 index 00000000..549fe36f --- /dev/null +++ b/include/native/windows/oaidl.h @@ -0,0 +1,3 @@ +#pragma once + +// Don't care. \ No newline at end of file diff --git a/include/native/windows/objbase.h b/include/native/windows/objbase.h new file mode 100644 index 00000000..549fe36f --- /dev/null +++ b/include/native/windows/objbase.h @@ -0,0 +1,3 @@ +#pragma once + +// Don't care. \ No newline at end of file diff --git a/include/native/windows/ocidl.h b/include/native/windows/ocidl.h new file mode 100644 index 00000000..549fe36f --- /dev/null +++ b/include/native/windows/ocidl.h @@ -0,0 +1,3 @@ +#pragma once + +// Don't care. \ No newline at end of file diff --git a/include/native/windows/ole2.h b/include/native/windows/ole2.h new file mode 100644 index 00000000..549fe36f --- /dev/null +++ b/include/native/windows/ole2.h @@ -0,0 +1,3 @@ +#pragma once + +// Don't care. \ No newline at end of file diff --git a/include/native/windows/rpc.h b/include/native/windows/rpc.h new file mode 100644 index 00000000..549fe36f --- /dev/null +++ b/include/native/windows/rpc.h @@ -0,0 +1,3 @@ +#pragma once + +// Don't care. \ No newline at end of file diff --git a/include/native/windows/rpcndr.h b/include/native/windows/rpcndr.h new file mode 100644 index 00000000..549fe36f --- /dev/null +++ b/include/native/windows/rpcndr.h @@ -0,0 +1,3 @@ +#pragma once + +// Don't care. \ No newline at end of file diff --git a/include/native/windows/unknwn.h b/include/native/windows/unknwn.h new file mode 100644 index 00000000..eb18fe3c --- /dev/null +++ b/include/native/windows/unknwn.h @@ -0,0 +1,16 @@ +#pragma once + +#include "windows_base.h" + +DEFINE_GUID(IID_IUnknown, 0x00000000,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46) +struct IUnknown { + +public: + + virtual HRESULT QueryInterface(REFIID riid, void** ppvObject) = 0; + + virtual ULONG AddRef() = 0; + virtual ULONG Release() = 0; + +}; +DECLARE_UUIDOF_HELPER(IUnknown, 0x00000000,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46) \ No newline at end of file diff --git a/include/native/windows/windows.h b/include/native/windows/windows.h new file mode 100644 index 00000000..5ffa7b21 --- /dev/null +++ b/include/native/windows/windows.h @@ -0,0 +1,4 @@ +#pragma once + +#include "windows_base.h" +#include "unknwn.h" \ No newline at end of file diff --git a/include/native/windows/windows_base.h b/include/native/windows/windows_base.h new file mode 100644 index 00000000..8b50c6de --- /dev/null +++ b/include/native/windows/windows_base.h @@ -0,0 +1,242 @@ +#pragma once + +#include +#include + +// GCC complains about the COM interfaces +// not having virtual destructors + +// and class conversion for C...DESC helper types +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic ignored "-Wclass-conversion" +#endif // __GNUC__ + +struct SDL_Window; + +using INT = int32_t; +using UINT = uint32_t; + +using LONG = int32_t; +using ULONG = uint32_t; + +using HRESULT = int32_t; + +using WCHAR = wchar_t; + +using BOOL = INT; +using WINBOOL = BOOL; + +using UINT16 = uint16_t; +using UINT32 = uint32_t; +using UINT64 = uint64_t; +using VOID = void; + +using SIZE_T = size_t; + +using UINT8 = uint8_t; +using BYTE = uint8_t; + +using SHORT = int16_t; +using USHORT = uint16_t; + +using LONGLONG = int64_t; +using ULONGLONG = uint64_t; + +using FLOAT = float; + +struct GUID { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +}; + +using UUID = GUID; +using REFIID = const GUID&; +using REFGUID = REFIID; + +template +constexpr GUID __uuidof_helper(); + +#define __uuidof(T) __uuidof_helper() + +inline bool operator==(const GUID& a, const GUID& b) { return std::memcmp(&a, &b, sizeof(GUID)) == 0; } +inline bool operator!=(const GUID& a, const GUID& b) { return std::memcmp(&a, &b, sizeof(GUID)) != 0; } + +using DWORD = uint32_t; +using WORD = int32_t; + +using HANDLE = void*; +using HMONITOR = HANDLE; +using HDC = HANDLE; +using HMODULE = HANDLE; +using HWND = HANDLE; + +using LPSTR = char*; +using LPCSTR = const char*; +using LPCWSTR = const wchar_t*; + +struct LUID { + DWORD LowPart; + LONG HighPart; +}; + +struct POINT { + LONG x; + LONG y; +}; + +struct RECT { + LONG left; + LONG top; + LONG right; + LONG bottom; +}; + +struct SIZE { + LONG cx; + LONG cy; +}; + +union LARGE_INTEGER { + struct { + DWORD LowPart; + LONG HighPart; + } u; + LONGLONG QuadPart; +}; + +struct SECURITY_ATTRIBUTES { + DWORD nLength; + void* lpSecurityDescriptor; + BOOL bInheritHandle; +}; + +struct PALETTEENTRY { + BYTE peRed; + BYTE peGreen; + BYTE peBlue; + BYTE peFlags; +}; + +struct RGNDATAHEADER { + DWORD dwSize; + DWORD iType; + DWORD nCount; + DWORD nRgnSize; + RECT rcBound; +}; + +struct RGNDATA { + RGNDATAHEADER rdh; + char Buffer[1]; +}; + +// Ignore these. +#define STDMETHODCALLTYPE +#define __stdcall + +#define CONST const + +constexpr BOOL TRUE = 1; +constexpr BOOL FALSE = 0; + +#define interface struct +#define MIDL_INTERFACE(x) struct +#define DEFINE_GUID(iid, a, b, c, d, e, f, g, h, i, j, k) constexpr GUID iid = {a,b,c,{d,e,f,g,h,i,j,k}}; + +#define DECLARE_UUIDOF_HELPER(type, a, b, c, d, e, f, g, h, i, j, k) extern "C++" { template <> constexpr GUID __uuidof_helper() { return GUID{a,b,c,{d,e,f,g,h,i,j,k}}; } } + +#define __CRT_UUID_DECL(type, a, b, c, d, e, f, g, h, i, j, k) DECLARE_UUIDOF_HELPER(type, a, b, c, d, e, f, g, h, i, j, k) + +constexpr HRESULT S_OK = 0; +constexpr HRESULT S_FALSE = 1; + +constexpr HRESULT E_INVALIDARG = 0x80070057; +constexpr HRESULT E_FAIL = 0x80004005; +constexpr HRESULT E_NOINTERFACE = 0x80004002; +constexpr HRESULT E_NOTIMPL = 0x80004001; +constexpr HRESULT E_OUTOFMEMORY = 0x8007000E; +constexpr HRESULT E_POINTER = 0x80004003; + +constexpr HRESULT DXGI_STATUS_OCCLUDED = 0x087a0001; +constexpr HRESULT DXGI_STATUS_CLIPPED = 0x087a0002; +constexpr HRESULT DXGI_STATUS_NO_REDIRECTION = 0x087a0004; +constexpr HRESULT DXGI_STATUS_NO_DESKTOP_ACCESS = 0x087a0005; +constexpr HRESULT DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE = 0x087a0006; +constexpr HRESULT DXGI_STATUS_MODE_CHANGED = 0x087a0007; +constexpr HRESULT DXGI_STATUS_MODE_CHANGE_IN_PROGRESS = 0x087a0008; +constexpr HRESULT DXGI_STATUS_UNOCCLUDED = 0x087a0009; +constexpr HRESULT DXGI_STATUS_DDA_WAS_STILL_DRAWING = 0x087a000a; +constexpr HRESULT DXGI_STATUS_PRESENT_REQUIRED = 0x087a002f; + +constexpr HRESULT DXGI_ERROR_INVALID_CALL = 0x887A0001; +constexpr HRESULT DXGI_ERROR_NOT_FOUND = 0x887A0002; +constexpr HRESULT DXGI_ERROR_MORE_DATA = 0x887A0003; +constexpr HRESULT DXGI_ERROR_UNSUPPORTED = 0x887A0004; +constexpr HRESULT DXGI_ERROR_DEVICE_REMOVED = 0x887A0005; +constexpr HRESULT DXGI_ERROR_DEVICE_HUNG = 0x887A0006; +constexpr HRESULT DXGI_ERROR_DEVICE_RESET = 0x887A0007; +constexpr HRESULT DXGI_ERROR_WAS_STILL_DRAWING = 0x887A000A; +constexpr HRESULT DXGI_ERROR_FRAME_STATISTICS_DISJOINT = 0x887A000B; +constexpr HRESULT DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE = 0x887A000C; +constexpr HRESULT DXGI_ERROR_DRIVER_INTERNAL_ERROR = 0x887A0020; +constexpr HRESULT DXGI_ERROR_NONEXCLUSIVE = 0x887A0021; +constexpr HRESULT DXGI_ERROR_NOT_CURRENTLY_AVAILABLE = 0x887A0022; +constexpr HRESULT DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED = 0x887A0023; +constexpr HRESULT DXGI_ERROR_REMOTE_OUTOFMEMORY = 0x887A0024; +constexpr HRESULT DXGI_ERROR_ACCESS_LOST = 0x887A0026; +constexpr HRESULT DXGI_ERROR_WAIT_TIMEOUT = 0x887A0027; +constexpr HRESULT DXGI_ERROR_SESSION_DISCONNECTED = 0x887A0028; +constexpr HRESULT DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE = 0x887A0029; +constexpr HRESULT DXGI_ERROR_CANNOT_PROTECT_CONTENT = 0x887A002A; +constexpr HRESULT DXGI_ERROR_ACCESS_DENIED = 0x887A002B; +constexpr HRESULT DXGI_ERROR_NAME_ALREADY_EXISTS = 0x887A002C; +constexpr HRESULT DXGI_ERROR_SDK_COMPONENT_MISSING = 0x887A002D; + +#define WINAPI +#define WINUSERAPI + +#define MAKE_HRESULT(sev,fac,code) \ + ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) + +#define STDMETHOD(name) virtual HRESULT name +#define STDMETHOD_(type, name) virtual type name + +#define THIS_ +#define THIS + +#define __C89_NAMELESSUNIONNAME +#define __C89_NAMELESSUNIONNAME1 +#define __C89_NAMELESSUNIONNAME2 +#define __C89_NAMELESSUNIONNAME3 +#define __C89_NAMELESSUNIONNAME4 +#define __C89_NAMELESSUNIONNAME5 +#define __C89_NAMELESSUNIONNAME6 +#define __C89_NAMELESSUNIONNAME7 +#define __C89_NAMELESSUNIONNAME8 +#define __C89_NAMELESS +#define DUMMYUNIONNAME +#define DUMMYSTRUCTNAME + +#define DECLARE_INTERFACE(x) struct x +#define DECLARE_INTERFACE_(x, y) struct x : public y + +#define BEGIN_INTERFACE +#define END_INTERFACE + +#define PURE = 0 + +#define DECLSPEC_SELECTANY + +#define __MSABI_LONG(x) x + +#define ENUM_CURRENT_SETTINGS ((DWORD)-1) +#define ENUM_REGISTRY_SETTINGS ((DWORD)-2) + +template +inline bool FAILED(T hr) { return HRESULT(hr) < 0; } + +template +inline bool SUCCEEDED(T hr) { return !FAILED(hr); } \ No newline at end of file diff --git a/include/native/wsi/native_sdl2.h b/include/native/wsi/native_sdl2.h new file mode 100644 index 00000000..9281c403 --- /dev/null +++ b/include/native/wsi/native_sdl2.h @@ -0,0 +1,26 @@ +#include +#include + +#include + +namespace dxvk::wsi { + + inline SDL_Window* fromHwnd(HWND hWindow) { + return reinterpret_cast(hWindow); + } + + inline HWND toHwnd(SDL_Window* pWindow) { + return reinterpret_cast(pWindow); + } + + // Offset so null HMONITORs go to -1 + inline int32_t fromHmonitor(HMONITOR hMonitor) { + return static_cast(reinterpret_cast(hMonitor)) - 1; + } + + // Offset so -1 display id goes to 0 == NULL + inline HMONITOR toHmonitor(int32_t displayId) { + return reinterpret_cast(static_cast(displayId + 1)); + } + +} \ No newline at end of file diff --git a/include/native/wsi/native_wsi.h b/include/native/wsi/native_wsi.h new file mode 100644 index 00000000..00a29906 --- /dev/null +++ b/include/native/wsi/native_wsi.h @@ -0,0 +1,9 @@ +#pragma once + +#ifdef DXVK_WSI_WIN32 +#error You shouldnt be using this code path. +#elif DXVK_WSI_SDL2 +#include "wsi/native_sdl2.h" +#else +#error Unknown wsi! +#endif \ No newline at end of file diff --git a/include/vulkan/vulkan_native.h b/include/vulkan/vulkan_native.h new file mode 100644 index 00000000..58f008cb --- /dev/null +++ b/include/vulkan/vulkan_native.h @@ -0,0 +1,91 @@ +#ifndef VULKAN_NATIVE_H_ +#define VULKAN_NATIVE_H_ 1 + +#include +#include + +/* This definitions in this file are an extract of vulkan_win32.h + * under the following license: */ +/* +** Copyright (c) 2015-2019 The Khronos Group Inc. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#define VK_EXT_full_screen_exclusive 1 +#define VK_EXT_FULL_SCREEN_EXCLUSIVE_SPEC_VERSION 4 +#define VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME "VK_EXT_full_screen_exclusive" + +typedef enum VkFullScreenExclusiveEXT { + VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT = 0, + VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT = 1, + VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT = 2, + VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT = 3, + VK_FULL_SCREEN_EXCLUSIVE_BEGIN_RANGE_EXT = VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT, + VK_FULL_SCREEN_EXCLUSIVE_END_RANGE_EXT = VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT, + VK_FULL_SCREEN_EXCLUSIVE_RANGE_SIZE_EXT = (VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT - VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT + 1), + VK_FULL_SCREEN_EXCLUSIVE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkFullScreenExclusiveEXT; +typedef struct VkSurfaceFullScreenExclusiveInfoEXT { + VkStructureType sType; + void* pNext; + VkFullScreenExclusiveEXT fullScreenExclusive; +} VkSurfaceFullScreenExclusiveInfoEXT; + +typedef struct VkSurfaceCapabilitiesFullScreenExclusiveEXT { + VkStructureType sType; + void* pNext; + VkBool32 fullScreenExclusiveSupported; +} VkSurfaceCapabilitiesFullScreenExclusiveEXT; + +typedef struct VkSurfaceFullScreenExclusiveWin32InfoEXT { + VkStructureType sType; + const void* pNext; + HMONITOR hmonitor; +} VkSurfaceFullScreenExclusiveWin32InfoEXT; + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); +typedef VkResult (VKAPI_PTR *PFN_vkAcquireFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain); +typedef VkResult (VKAPI_PTR *PFN_vkReleaseFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain); +typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModes2EXT)(VkDevice device, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkDeviceGroupPresentModeFlagsKHR* pModes); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModes2EXT( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, + uint32_t* pPresentModeCount, + VkPresentModeKHR* pPresentModes); + +VKAPI_ATTR VkResult VKAPI_CALL vkAcquireFullScreenExclusiveModeEXT( + VkDevice device, + VkSwapchainKHR swapchain); + +VKAPI_ATTR VkResult VKAPI_CALL vkReleaseFullScreenExclusiveModeEXT( + VkDevice device, + VkSwapchainKHR swapchain); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModes2EXT( + VkDevice device, + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, + VkDeviceGroupPresentModeFlagsKHR* pModes); +#endif + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/meson.build b/meson.build index 24e04e61..8be1791e 100644 --- a/meson.build +++ b/meson.build @@ -13,6 +13,8 @@ else dxvk_msvc=false endif +dxvk_native = (not meson.is_cross_build() and not dxvk_msvc) or get_option('dxvk_native_force') + if dxvk_compiler.get_id() == 'msvc' add_project_arguments('/std:' + dxvk_cpp_std, language : 'cpp') endif @@ -32,6 +34,10 @@ code = '''#ifndef __WINE__ dxvk_winelib = dxvk_compiler.compiles(code, name: 'winelib check') dxvk_extradep = [ ] +dxvk_platform = 'windows' +dxvk_wsi = 'win32' +so_prefix = '' + if dxvk_winelib if dxvk_compiler.has_argument('--no-gnu-unique') add_project_arguments('--no-gnu-unique', language : ['cpp']) @@ -48,7 +54,7 @@ if dxvk_winelib dll_ext = '.dll' res_ext = '.res' def_spec_ext = '.spec' -else +elif not dxvk_native if dxvk_compiler.get_id() == 'msvc' wrc = find_program('rc') else @@ -84,9 +90,36 @@ else res_ext = '.o' endif + def_spec_ext = '.def' +else + add_project_arguments('-DDXVK_NATIVE', language : 'cpp') + + dxvk_wsi = get_option('dxvk_native_wsi') + dxvk_platform = target_machine.system() + + if dxvk_platform == 'windows' + dxvk_include_path = include_directories('./include', './include/native/') + lib_vulkan = dxvk_compiler.find_library('vulkan-1', dirs : dxvk_library_path) + lib_sdl2 = dxvk_compiler.find_library('SDL2', dirs : dxvk_library_path) + wrc = find_program('rc') + so_prefix = 'dxvk_' + else + dxvk_include_path = include_directories('./include', './include/native/', './include/native/windows', './include/native/directx') + lib_vulkan = dxvk_compiler.find_library('vulkan') + lib_sdl2 = dxvk_compiler.find_library('SDL2') + wrc = find_program('echo') + so_prefix = 'libdxvk_' + endif + + res_ext = '' + exe_ext = '' + dll_ext = '' def_spec_ext = '.def' endif +add_project_arguments('-DDXVK_WSI_' + dxvk_wsi.to_upper(), language : 'cpp') +add_project_arguments('-DDXVK_PLATFORM_' + dxvk_platform.to_upper(), language : 'cpp') + glsl_compiler = find_program('glslangValidator') glsl_generator = generator(glsl_compiler, output : [ '@BASENAME@.h' ], @@ -96,6 +129,10 @@ if dxvk_compiler.get_id() == 'msvc' wrc_generator = generator(wrc, output : [ '@BASENAME@' + res_ext ], arguments : [ '/fo', '@OUTPUT@', '@INPUT@' ]) +elif dxvk_native + wrc_generator = generator(wrc, + output : [ '@BASENAME@_ignored.h' ], + arguments : [ 'Ignoring: ', '@INPUT@' ]) else wrc_generator = generator(wrc, output : [ '@BASENAME@' + res_ext ], diff --git a/meson_options.txt b/meson_options.txt index 2a4b5b4f..e0ae9772 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,3 +3,6 @@ option('enable_dxgi', type : 'boolean', value : true, description: 'Build DXGI' option('enable_d3d9', type : 'boolean', value : true, description: 'Build D3D9') option('enable_d3d10', type : 'boolean', value : true, description: 'Build D3D10') option('enable_d3d11', type : 'boolean', value : true, description: 'Build D3D11') + +option('dxvk_native_force', type : 'boolean', value : false, description: 'Force building using DXVK native. Eg. for Windows') +option('dxvk_native_wsi', type : 'string', value : 'sdl2', description: 'WSI system to use if building natively.') diff --git a/src/d3d10/d3d10_multithread.cpp b/src/d3d10/d3d10_multithread.cpp index bc93e92e..9625774d 100644 --- a/src/d3d10/d3d10_multithread.cpp +++ b/src/d3d10/d3d10_multithread.cpp @@ -17,7 +17,7 @@ namespace dxvk { bool D3D10DeviceMutex::try_lock() { - uint32_t threadId = GetCurrentThreadId(); + uint32_t threadId = dxvk::this_thread::get_id(); uint32_t expected = 0; bool status = m_owner.compare_exchange_weak( diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 6a231902..af207eef 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -2416,7 +2416,7 @@ namespace dxvk { // Make sure the back buffer size is not zero DXGI_SWAP_CHAIN_DESC1 desc = *pDesc; - GetWindowClientSize(hWnd, + wsi::getWindowSize(hWnd, desc.Width ? nullptr : &desc.Width, desc.Height ? nullptr : &desc.Height); diff --git a/src/d3d11/d3d11_gdi.cpp b/src/d3d11/d3d11_gdi.cpp index 0958886e..83e0618d 100644 --- a/src/d3d11/d3d11_gdi.cpp +++ b/src/d3d11/d3d11_gdi.cpp @@ -2,7 +2,9 @@ #include "d3d11_device.h" #include "d3d11_gdi.h" +#ifndef DXVK_NATIVE #include "../util/util_gdi.h" +#endif namespace dxvk { diff --git a/src/d3d11/d3d11_include.h b/src/d3d11/d3d11_include.h index 7daaf4e2..13febcaf 100644 --- a/src/d3d11/d3d11_include.h +++ b/src/d3d11/d3d11_include.h @@ -44,7 +44,7 @@ typedef enum D3D11_FORMAT_SUPPORT2 { #ifndef __WINE__ //MinGW-Headers supports these typedefs since 6.0.0 -#if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 6 +#if (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 6) && !defined(DXVK_NATIVE) typedef enum D3D11_COPY_FLAGS { D3D11_COPY_NO_OVERWRITE = 0x1, D3D11_COPY_DISCARD = 0x2, diff --git a/src/d3d11/d3d11_options.cpp b/src/d3d11/d3d11_options.cpp index cba4cf32..b22010ce 100644 --- a/src/d3d11/d3d11_options.cpp +++ b/src/d3d11/d3d11_options.cpp @@ -24,7 +24,7 @@ namespace dxvk { && DxvkGpuVendor(devInfo.core.properties.vendorID) != DxvkGpuVendor::Amd; bool apitraceAttached = false; - #ifndef __WINE__ + #if !defined(__WINE__) && !defined(DXVK_NATIVE) apitraceAttached = ::GetModuleHandle("dxgitrace.dll") != nullptr; #endif diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp index 686f87d9..94e2e31e 100644 --- a/src/d3d11/d3d11_swapchain.cpp +++ b/src/d3d11/d3d11_swapchain.cpp @@ -425,10 +425,15 @@ namespace dxvk { void D3D11SwapChain::CreateFrameLatencyEvent() { - m_frameLatencySignal = new sync::Win32Fence(m_frameId); + m_frameLatencySignal = new FrameLatencySignal(m_frameId); - if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) + if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) { +#ifndef DXVK_NATIVE m_frameLatencyEvent = CreateEvent(nullptr, false, true, nullptr); +#else + throw DxvkError("DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT not supported on this platform."); +#endif + } } @@ -667,7 +672,9 @@ namespace dxvk { void D3D11SwapChain::DestroyFrameLatencyEvent() { +#ifndef DXVK_NATIVE CloseHandle(m_frameLatencyEvent); +#endif } @@ -786,10 +793,12 @@ namespace dxvk { void D3D11SwapChain::SignalFrameLatencyEvent() { +#ifndef DXVK_NATIVE if (m_frameLatencyEvent) { // Signal event with the same value that we'd wait for during the next present. m_frameLatencySignal->setEvent(m_frameLatencyEvent, m_frameId - GetActualFrameLatency() + 1); } +#endif } diff --git a/src/d3d11/d3d11_swapchain.h b/src/d3d11/d3d11_swapchain.h index 4bc23b91..255bafee 100644 --- a/src/d3d11/d3d11_swapchain.h +++ b/src/d3d11/d3d11_swapchain.h @@ -4,7 +4,11 @@ #include "../dxvk/hud/dxvk_hud.h" +#ifndef DXVK_NATIVE #include "../util/sync/sync_signal_win32.h" +#else +#include "../util/sync/sync_signal.h" +#endif namespace dxvk { @@ -24,6 +28,13 @@ namespace dxvk { class D3D11SwapChain : public ComObject { constexpr static uint32_t DefaultFrameLatency = 1; + +#ifndef DXVK_NATIVE + using FrameLatencySignal = sync::Win32Fence; +#else + using FrameLatencySignal = sync::Fence; +#endif + public: D3D11SwapChain( @@ -130,7 +141,7 @@ namespace dxvk { uint32_t m_frameLatency = DefaultFrameLatency; uint32_t m_frameLatencyCap = 0; HANDLE m_frameLatencyEvent = nullptr; - Rc m_frameLatencySignal; + Rc m_frameLatencySignal; bool m_dirty = true; bool m_vsync = true; diff --git a/src/d3d11/d3d11_texture.cpp b/src/d3d11/d3d11_texture.cpp index 08b0e68c..2e5f95da 100644 --- a/src/d3d11/d3d11_texture.cpp +++ b/src/d3d11/d3d11_texture.cpp @@ -518,14 +518,18 @@ namespace dxvk { : m_resource (pResource), m_texture (pTexture), m_gdiSurface(nullptr) { +#ifndef DXVK_NATIVE if (pTexture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_GDI_COMPATIBLE) m_gdiSurface = new D3D11GDISurface(m_resource, 0); +#endif } D3D11DXGISurface::~D3D11DXGISurface() { +#ifndef DXVK_NATIVE if (m_gdiSurface) delete m_gdiSurface; +#endif } @@ -654,19 +658,23 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetDC( BOOL Discard, HDC* phdc) { - if (!m_gdiSurface) - return DXGI_ERROR_INVALID_CALL; +#ifndef DXVK_NATIVE + if (m_gdiSurface) + return m_gdiSurface->Acquire(Discard, phdc); +#endif - return m_gdiSurface->Acquire(Discard, phdc); + return DXGI_ERROR_INVALID_CALL; } HRESULT STDMETHODCALLTYPE D3D11DXGISurface::ReleaseDC( RECT* pDirtyRect) { - if (!m_gdiSurface) - return DXGI_ERROR_INVALID_CALL; +#ifndef DXVK_NATIVE + if (m_gdiSurface) + return m_gdiSurface->Release(pDirtyRect); +#endif - return m_gdiSurface->Release(pDirtyRect); + return DXGI_ERROR_INVALID_CALL; } diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index c6f93403..72e68a20 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -41,7 +41,6 @@ d3d11_src = [ 'd3d11_depth_stencil.cpp', 'd3d11_device.cpp', 'd3d11_enums.cpp', - 'd3d11_gdi.cpp', 'd3d11_initializer.cpp', 'd3d11_input_layout.cpp', 'd3d11_interop.cpp', @@ -63,12 +62,22 @@ d3d11_src = [ 'd3d11_view_uav.cpp', ] -d3d11_dll = shared_library('d3d11'+dll_ext, dxgi_common_src + d3d11_src + d3d10_src, glsl_generator.process(dxgi_shaders), d3d11_res, +if not dxvk_native + # We don't want to allow GDI interop on *any* native builds + # because the idea is for you to write once and run anywhere. + d3d11_src += 'd3d11_gdi.cpp' +endif + +if dxvk_native + lib_dxgi = dxgi_dep +endif + +d3d11_dll = shared_library(so_prefix+'d3d11'+dll_ext, dxgi_common_src + d3d11_src + d3d10_src, glsl_generator.process(dxgi_shaders), d3d11_res, name_prefix : '', - dependencies : [ lib_dxgi, dxbc_dep, dxvk_dep ], + dependencies : [ lib_dxgi, dxbc_dep, dxvk_dep, wsi_dep ], include_directories : dxvk_include_path, install : true, - objects : not dxvk_msvc ? 'd3d11'+def_spec_ext : [], + objects : not dxvk_msvc and not dxvk_native ? 'd3d11'+def_spec_ext : [], vs_module_defs : 'd3d11'+def_spec_ext, override_options : ['cpp_std='+dxvk_cpp_std]) diff --git a/src/d3d9/d3d9_adapter.cpp b/src/d3d9/d3d9_adapter.cpp index 2cab599c..6a1dda1b 100644 --- a/src/d3d9/d3d9_adapter.cpp +++ b/src/d3d9/d3d9_adapter.cpp @@ -5,9 +5,13 @@ #include "d3d9_caps.h" #include "d3d9_util.h" +#include "../wsi/wsi_mode.h" +#include "../wsi/wsi_monitor.h" + #include "../util/util_bit.h" #include "../util/util_luid.h" #include "../util/util_ratio.h" +#include "../util/util_string.h" #include @@ -54,6 +58,8 @@ namespace dxvk { const auto& props = m_adapter->deviceProperties(); + // TODO: Consolidate this! +#ifndef DXVK_NATIVE DISPLAY_DEVICEA device = { }; device.cb = sizeof(device); @@ -62,6 +68,19 @@ namespace dxvk { return D3DERR_INVALIDCALL; } + const char* displayName = device.DeviceName; +#else + WCHAR wideDisplayName[32] = { }; + if (!wsi::getDisplayName(GetDefaultMonitor(), wideDisplayName)) { + Logger::err("D3D9Adapter::GetAdapterIdentifier: Failed to query monitor info"); + return D3DERR_INVALIDCALL; + } + + std::string displayNameStr = str::fromws(wideDisplayName); + const char* displayName = displayNameStr.c_str(); +#endif + + GUID guid = bit::cast(m_adapter->devicePropertiesExt().coreDeviceId.deviceUUID); uint32_t vendorId = options.customVendorId == -1 ? props.vendorID : uint32_t(options.customVendorId); @@ -69,9 +88,9 @@ namespace dxvk { const char* desc = options.customDeviceDesc.empty() ? props.deviceName : options.customDeviceDesc.c_str(); const char* driver = GetDriverDLL(DxvkGpuVendor(vendorId)); - std::strncpy(pIdentifier->Description, desc, countof(pIdentifier->Description)); - std::strncpy(pIdentifier->DeviceName, device.DeviceName, countof(pIdentifier->DeviceName)); // The GDI device name. Not the actual device name. - std::strncpy(pIdentifier->Driver, driver, countof(pIdentifier->Driver)); // This is the driver's dll. + std::strncpy(pIdentifier->Description, desc, countof(pIdentifier->Description)); + std::strncpy(pIdentifier->DeviceName, displayName, countof(pIdentifier->DeviceName)); // The GDI device name. Not the actual device name. + std::strncpy(pIdentifier->Driver, driver, countof(pIdentifier->Driver)); // This is the driver's dll. pIdentifier->DeviceIdentifier = guid; pIdentifier->DeviceId = deviceId; @@ -674,20 +693,20 @@ namespace dxvk { if (pRotation != nullptr) *pRotation = D3DDISPLAYROTATION_IDENTITY; - DEVMODEW devMode = DEVMODEW(); - devMode.dmSize = sizeof(devMode); + wsi::WsiMode mode = { }; - if (!GetMonitorDisplayMode(GetDefaultMonitor(), ENUM_CURRENT_SETTINGS, &devMode)) { + if (!wsi::getCurrentDisplayMode(GetDefaultMonitor(), &mode)) { Logger::err("D3D9Adapter::GetAdapterDisplayModeEx: Failed to enum display settings"); return D3DERR_INVALIDCALL; } pMode->Size = sizeof(D3DDISPLAYMODEEX); - pMode->Width = devMode.dmPelsWidth; - pMode->Height = devMode.dmPelsHeight; - pMode->RefreshRate = devMode.dmDisplayFrequency; + pMode->Width = mode.width; + pMode->Height = mode.height; + pMode->RefreshRate = mode.refreshRate.numerator / mode.refreshRate.denominator; pMode->Format = D3DFMT_X8R8G8B8; pMode->ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE; + return D3D_OK; } @@ -762,30 +781,29 @@ namespace dxvk { // Walk over all modes that the display supports and // return those that match the requested format etc. - DEVMODEW devMode = { }; - devMode.dmSize = sizeof(DEVMODEW); + wsi::WsiMode devMode = { }; uint32_t modeIndex = 0; const auto forcedRatio = Ratio(options.forceAspectRatio); - while (GetMonitorDisplayMode(GetDefaultMonitor(), modeIndex++, &devMode)) { + while (wsi::getDisplayMode(GetDefaultMonitor(), modeIndex++, &devMode)) { // Skip interlaced modes altogether - if (devMode.dmDisplayFlags & DM_INTERLACED) + if (devMode.interlaced) continue; // Skip modes with incompatible formats - if (devMode.dmBitsPerPel != GetMonitorFormatBpp(Format)) + if (devMode.bitsPerPixel != GetMonitorFormatBpp(Format)) continue; - if (!forcedRatio.undefined() && Ratio(devMode.dmPelsWidth, devMode.dmPelsHeight) != forcedRatio) + if (!forcedRatio.undefined() && Ratio(devMode.width, devMode.height) != forcedRatio) continue; D3DDISPLAYMODEEX mode; mode.Size = sizeof(D3DDISPLAYMODEEX); - mode.Width = devMode.dmPelsWidth; - mode.Height = devMode.dmPelsHeight; - mode.RefreshRate = devMode.dmDisplayFrequency; + mode.Width = devMode.width; + mode.Height = devMode.height; + mode.RefreshRate = devMode.refreshRate.numerator / devMode.refreshRate.denominator; mode.Format = static_cast(Format); mode.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE; diff --git a/src/d3d9/d3d9_cursor.cpp b/src/d3d9/d3d9_cursor.cpp index 408268c1..510bbbc9 100644 --- a/src/d3d9/d3d9_cursor.cpp +++ b/src/d3d9/d3d9_cursor.cpp @@ -5,6 +5,7 @@ namespace dxvk { +#ifndef DXVK_NATIVE void D3D9Cursor::UpdateCursor(int X, int Y) { POINT currentPos = { }; if (::GetCursorPos(¤tPos) && currentPos == POINT{ X, Y }) @@ -43,5 +44,24 @@ namespace dxvk { return D3D_OK; } +#else + void D3D9Cursor::UpdateCursor(int X, int Y) { + Logger::warn("D3D9Cursor::UpdateCursor: Not supported on native"); + } + + + BOOL D3D9Cursor::ShowCursor(BOOL bShow) { + Logger::warn("D3D9Cursor::ShowCursor: Not supported on native"); + + return std::exchange(m_visible, bShow); + } + + + HRESULT D3D9Cursor::SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap) { + Logger::warn("D3D9Cursor::SetHardwareCursor: Not supported on native"); + + return D3DERR_INVALIDCALL; + } +#endif } \ No newline at end of file diff --git a/src/d3d9/d3d9_cursor.h b/src/d3d9/d3d9_cursor.h index 32645d26..1b541d14 100644 --- a/src/d3d9/d3d9_cursor.h +++ b/src/d3d9/d3d9_cursor.h @@ -26,7 +26,9 @@ namespace dxvk { BOOL m_visible = FALSE; +#ifndef DXVK_NATIVE HCURSOR m_hCursor = nullptr; +#endif }; diff --git a/src/d3d9/d3d9_include.h b/src/d3d9/d3d9_include.h index 32b36c4d..2c1157df 100644 --- a/src/d3d9/d3d9_include.h +++ b/src/d3d9/d3d9_include.h @@ -11,7 +11,7 @@ #include //for some reason we need to specify __declspec(dllexport) for MinGW -#if defined(__WINE__) +#if defined(__WINE__) || (defined(DXVK_NATIVE) && !defined(_WIN32)) #define DLLEXPORT __attribute__((visibility("default"))) #elif defined(_MSC_VER) #define DLLEXPORT diff --git a/src/d3d9/d3d9_interface.cpp b/src/d3d9/d3d9_interface.cpp index 43f14e89..dd141333 100644 --- a/src/d3d9/d3d9_interface.cpp +++ b/src/d3d9/d3d9_interface.cpp @@ -12,6 +12,8 @@ namespace dxvk { : m_instance ( new DxvkInstance() ) , m_extended ( bExtended ) , m_d3d9Options ( nullptr, m_instance->config() ) { + +#ifndef DXVK_NATIVE // D3D9 doesn't enumerate adapters like physical adapters... // only as connected displays. @@ -44,6 +46,7 @@ namespace dxvk { } } else +#endif { const uint32_t adapterCount = m_instance->adapterCount(); m_adapters.reserve(adapterCount); @@ -52,10 +55,12 @@ namespace dxvk { m_adapters.emplace_back(this, m_instance->enumAdapters(i), i, 0); } +#ifndef DXVK_NATIVE if (m_d3d9Options.dpiAware) { Logger::info("Process set as DPI aware"); SetProcessDPIAware(); } +#endif } diff --git a/src/d3d9/d3d9_monitor.cpp b/src/d3d9/d3d9_monitor.cpp index 9d9812ab..7ca3f056 100644 --- a/src/d3d9/d3d9_monitor.cpp +++ b/src/d3d9/d3d9_monitor.cpp @@ -2,6 +2,9 @@ #include "d3d9_format.h" +#include "../wsi/wsi_window.h" +#include "../wsi/wsi_monitor.h" + namespace dxvk { uint32_t GetMonitorFormatBpp(D3D9Format Format) { diff --git a/src/d3d9/d3d9_multithread.cpp b/src/d3d9/d3d9_multithread.cpp index 3089e47f..f5bc8296 100644 --- a/src/d3d9/d3d9_multithread.cpp +++ b/src/d3d9/d3d9_multithread.cpp @@ -17,7 +17,7 @@ namespace dxvk { bool D3D9DeviceMutex::try_lock() { - uint32_t threadId = GetCurrentThreadId(); + uint32_t threadId = dxvk::this_thread::get_id(); uint32_t expected = 0; bool status = m_owner.compare_exchange_weak( diff --git a/src/d3d9/d3d9_shader.cpp b/src/d3d9/d3d9_shader.cpp index 2e40737b..de36941e 100644 --- a/src/d3d9/d3d9_shader.cpp +++ b/src/d3d9/d3d9_shader.cpp @@ -5,6 +5,42 @@ namespace dxvk { +#ifndef DXVK_NATIVE + typedef HRESULT (STDMETHODCALLTYPE *D3DXDisassembleShader) ( + const void* pShader, + BOOL EnableColorCode, + char* pComments, + ID3DBlob** ppDisassembly); // ppDisassembly is actually a D3DXBUFFER, but it has the exact same vtable as a ID3DBlob at the start. + + D3DXDisassembleShader g_pfnDisassembleShader = nullptr; + + HRESULT DisassembleShader( + const void* pShader, + BOOL EnableColorCode, + char* pComments, + ID3DBlob** ppDisassembly) { + if (g_pfnDisassembleShader == nullptr) { + HMODULE d3d9x = LoadLibraryA("d3dx9.dll"); + + if (d3d9x == nullptr) + d3d9x = LoadLibraryA("d3dx9_43.dll"); + + g_pfnDisassembleShader = + reinterpret_cast(GetProcAddress(d3d9x, "D3DXDisassembleShader")); + } + + if (g_pfnDisassembleShader == nullptr) + return D3DERR_INVALIDCALL; + + return g_pfnDisassembleShader( + pShader, + EnableColorCode, + pComments, + ppDisassembly); + } +#endif + + D3D9CommonShader::D3D9CommonShader() {} D3D9CommonShader::D3D9CommonShader( @@ -24,10 +60,10 @@ namespace dxvk { const std::string name = shaderKey.toString(); Logger::debug(str::format("Compiling shader ", name)); + const std::string dumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH"); +#ifndef DXVK_NATIVE // If requested by the user, dump both the raw DXBC // shader and the compiled SPIR-V module to a file. - const std::string dumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH"); - if (dumpPath.size() != 0) { DxsoReader reader( reinterpret_cast(pShaderBytecode)); @@ -50,6 +86,7 @@ namespace dxvk { blob->GetBufferSize()); } } +#endif // Decide whether we need to create a pass-through // geometry shader for vertex shader stream output @@ -80,7 +117,7 @@ namespace dxvk { // Lets lie about the shader key type for the state cache. m_shaders[1]->setShaderKey({ VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, *pHash }); } - + if (dumpPath.size() != 0) { std::ofstream dumpStream( str::format(dumpPath, "/", name, ".spv"), diff --git a/src/d3d9/d3d9_surface.cpp b/src/d3d9/d3d9_surface.cpp index f4189d5d..310ff265 100644 --- a/src/d3d9/d3d9_surface.cpp +++ b/src/d3d9/d3d9_surface.cpp @@ -132,6 +132,7 @@ namespace dxvk { } HRESULT STDMETHODCALLTYPE D3D9Surface::GetDC(HDC *phDC) { +#ifndef DXVK_NATIVE if (phDC == nullptr) return D3DERR_INVALIDCALL; @@ -165,9 +166,17 @@ namespace dxvk { *phDC = m_dcDesc.hDC; return D3D_OK; +#else + if (phDC != nullptr) + *phDC = nullptr; + + Logger::warn("D3D9Surface::GetDC: GDI interop not supported on native"); + return D3DERR_INVALIDCALL; +#endif } HRESULT STDMETHODCALLTYPE D3D9Surface::ReleaseDC(HDC hDC) { +#ifndef DXVK_NATIVE if (m_dcDesc.hDC == nullptr || m_dcDesc.hDC != hDC) return D3DERR_INVALIDCALL; @@ -178,6 +187,10 @@ namespace dxvk { return hr; return D3D_OK; +#else + Logger::warn("D3D9Surface::ReleaseDC: GDI interop not supported on native"); + return D3DERR_INVALIDCALL; +#endif } } diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp index 7264c342..786ca1b8 100644 --- a/src/d3d9/d3d9_swapchain.cpp +++ b/src/d3d9/d3d9_swapchain.cpp @@ -9,7 +9,7 @@ namespace dxvk { - +#ifndef DXVK_NATIVE struct D3D9WindowData { bool unicode; WNDPROC proc; @@ -46,6 +46,7 @@ namespace dxvk { ? CallWindowProcW(windowData.proc, window, message, wparam, lparam) : CallWindowProcA(windowData.proc, window, message, wparam, lparam); } +#endif static uint16_t MapGammaControlPoint(float x) { @@ -61,6 +62,25 @@ namespace dxvk { }; + static inline void ConvertDisplayMode(const D3DDISPLAYMODEEX& mode, wsi::WsiMode* wsiMode) { + wsiMode->width = mode.Width; + wsiMode->height = mode.Height; + wsiMode->refreshRate = wsi::WsiRational{ mode.RefreshRate, 1 }; + wsiMode->bitsPerPixel = GetMonitorFormatBpp(EnumerateFormat(mode.Format)); + wsiMode->interlaced = false; + } + + + static inline void ConvertDisplayMode(const wsi::WsiMode& devMode, D3DDISPLAYMODEEX* pMode) { + pMode->Size = sizeof(D3DDISPLAYMODEEX); + pMode->Width = devMode.width; + pMode->Height = devMode.height; + pMode->RefreshRate = devMode.refreshRate.numerator / devMode.refreshRate.denominator; + pMode->Format = D3DFMT_X8R8G8B8; + pMode->ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE; + } + + D3D9SwapChainEx::D3D9SwapChainEx( D3D9DeviceEx* pDevice, D3DPRESENT_PARAMETERS* pPresentParams, @@ -94,8 +114,12 @@ namespace dxvk { D3D9SwapChainEx::~D3D9SwapChainEx() { +#ifndef DXVK_NATIVE ResetWindowProc(); - RestoreDisplayMode(m_monitor); +#endif + + if (!wsi::restoreDisplayMode(m_monitor)) + Logger::warn("D3D9: LeaveFullscreenMode: Failed to restore display mode"); m_device->waitForSubmission(&m_presentStatus); m_device->waitForIdle(); @@ -472,20 +496,14 @@ namespace dxvk { *pRotation = D3DDISPLAYROTATION_IDENTITY; if (pMode != nullptr) { - DEVMODEW devMode = DEVMODEW(); - devMode.dmSize = sizeof(devMode); + wsi::WsiMode devMode = { }; - if (!GetMonitorDisplayMode(GetDefaultMonitor(), ENUM_CURRENT_SETTINGS, &devMode)) { + if (!wsi::getCurrentDisplayMode(GetDefaultMonitor(), &devMode)) { Logger::err("D3D9SwapChainEx::GetDisplayModeEx: Failed to enum display settings"); return D3DERR_INVALIDCALL; } - pMode->Size = sizeof(D3DDISPLAYMODEEX); - pMode->Width = devMode.dmPelsWidth; - pMode->Height = devMode.dmPelsHeight; - pMode->RefreshRate = devMode.dmDisplayFrequency; - pMode->Format = D3DFMT_X8R8G8B8; - pMode->ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE; + ConvertDisplayMode(devMode, pMode); } return D3D_OK; @@ -509,33 +527,16 @@ namespace dxvk { if (changeFullscreen) this->LeaveFullscreenMode(); - // Adjust window position and size - RECT newRect = { 0, 0, 0, 0 }; - RECT oldRect = { 0, 0, 0, 0 }; - - ::GetWindowRect(m_window, &oldRect); - ::SetRect(&newRect, 0, 0, pPresentParams->BackBufferWidth, pPresentParams->BackBufferHeight); - ::AdjustWindowRectEx(&newRect, - ::GetWindowLongW(m_window, GWL_STYLE), FALSE, - ::GetWindowLongW(m_window, GWL_EXSTYLE)); - ::SetRect(&newRect, 0, 0, newRect.right - newRect.left, newRect.bottom - newRect.top); - ::OffsetRect(&newRect, oldRect.left, oldRect.top); - ::MoveWindow(m_window, newRect.left, newRect.top, - newRect.right - newRect.left, newRect.bottom - newRect.top, TRUE); + wsi::resizeWindow( + m_window, &m_windowState, + pPresentParams->BackBufferWidth, + pPresentParams->BackBufferHeight); } else { if (changeFullscreen) this->EnterFullscreenMode(pPresentParams, pFullscreenDisplayMode); else - ChangeDisplayMode(pPresentParams, pFullscreenDisplayMode); - - // Move the window so that it covers the entire output - RECT rect; - GetMonitorRect(GetDefaultMonitor(), &rect); - - ::SetWindowPos(m_window, HWND_TOPMOST, - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, - SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE); + ChangeDisplayMode(pPresentParams, pFullscreenDisplayMode, false); } m_presentParams = *pPresentParams; @@ -1283,15 +1284,13 @@ namespace dxvk { HRESULT D3D9SwapChainEx::EnterFullscreenMode( D3DPRESENT_PARAMETERS* pPresentParams, - const D3DDISPLAYMODEEX* pFullscreenDisplayMode) { - // Find a display mode that matches what we need - ::GetWindowRect(m_window, &m_windowState.rect); - - if (FAILED(ChangeDisplayMode(pPresentParams, pFullscreenDisplayMode))) { + const D3DDISPLAYMODEEX* pFullscreenDisplayMode) { + if (FAILED(ChangeDisplayMode(pPresentParams, pFullscreenDisplayMode, true))) { Logger::err("D3D9: EnterFullscreenMode: Failed to change display mode"); - return D3DERR_INVALIDCALL; + return D3DERR_NOTAVAILABLE; } +#ifndef DXVK_NATIVE // Testing shows we shouldn't hook WM_NCCALCSIZE but we shouldn't change // windows style either. // @@ -1299,69 +1298,45 @@ namespace dxvk { // also required. Doing it will allow us to create fullscreen windows // regardless of their style and it also appears to work on Windows. HookWindowProc(); - - // Change the window flags to remove the decoration etc. - LONG style = ::GetWindowLongW(m_window, GWL_STYLE); - LONG exstyle = ::GetWindowLongW(m_window, GWL_EXSTYLE); - - m_windowState.style = style; - m_windowState.exstyle = exstyle; - - style &= ~WS_OVERLAPPEDWINDOW; - exstyle &= ~WS_EX_OVERLAPPEDWINDOW; - - ::SetWindowLongW(m_window, GWL_STYLE, style); - ::SetWindowLongW(m_window, GWL_EXSTYLE, exstyle); - - // Move the window so that it covers the entire output - RECT rect; - GetMonitorRect(GetDefaultMonitor(), &rect); - - ::SetWindowPos(m_window, HWND_TOPMOST, - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, - SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE); +#endif m_monitor = GetDefaultMonitor(); + + if (!wsi::enterFullscreenMode(m_monitor, m_window, &m_windowState, true)) { + Logger::err("D3D9: EnterFullscreenMode: Failed to enter fullscreen mode"); + return D3DERR_NOTAVAILABLE; + } + return D3D_OK; } - HRESULT D3D9SwapChainEx::LeaveFullscreenMode() { - if (!IsWindow(m_window)) - return D3DERR_INVALIDCALL; - - if (FAILED(RestoreDisplayMode(m_monitor))) + HRESULT D3D9SwapChainEx::LeaveFullscreenMode() { + if (!wsi::restoreDisplayMode(m_monitor)) Logger::warn("D3D9: LeaveFullscreenMode: Failed to restore display mode"); m_monitor = nullptr; +#ifndef DXVK_NATIVE ResetWindowProc(); +#endif - // Only restore the window style if the application hasn't - // changed them. This is in line with what native D3D9 does. - LONG curStyle = ::GetWindowLongW(m_window, GWL_STYLE) & ~WS_VISIBLE; - LONG curExstyle = ::GetWindowLongW(m_window, GWL_EXSTYLE) & ~WS_EX_TOPMOST; - - if (curStyle == (m_windowState.style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW)) - && curExstyle == (m_windowState.exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) { - ::SetWindowLongW(m_window, GWL_STYLE, m_windowState.style); - ::SetWindowLongW(m_window, GWL_EXSTYLE, m_windowState.exstyle); + if (!wsi::isWindow(m_window)) + return D3D_OK; + + if (!wsi::leaveFullscreenMode(m_window, &m_windowState)) { + Logger::err("D3D9: LeaveFullscreenMode: Failed to exit fullscreen mode"); + return D3DERR_NOTAVAILABLE; } - // Restore window position and apply the style - const RECT rect = m_windowState.rect; - - ::SetWindowPos(m_window, 0, - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, - SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE); - return D3D_OK; } HRESULT D3D9SwapChainEx::ChangeDisplayMode( D3DPRESENT_PARAMETERS* pPresentParams, - const D3DDISPLAYMODEEX* pFullscreenDisplayMode) { + const D3DDISPLAYMODEEX* pFullscreenDisplayMode, + bool EnteringFullscreen) { D3DDISPLAYMODEEX mode; if (pFullscreenDisplayMode) { @@ -1375,33 +1350,16 @@ namespace dxvk { mode.Size = sizeof(D3DDISPLAYMODEEX); } - DEVMODEW devMode = { }; - devMode.dmSize = sizeof(devMode); - devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; - devMode.dmPelsWidth = mode.Width; - devMode.dmPelsHeight = mode.Height; - devMode.dmBitsPerPel = GetMonitorFormatBpp(EnumerateFormat(mode.Format)); - - if (mode.RefreshRate != 0) { - devMode.dmFields |= DM_DISPLAYFREQUENCY; - devMode.dmDisplayFrequency = mode.RefreshRate; - } - - return SetMonitorDisplayMode(GetDefaultMonitor(), &devMode) - ? D3D_OK - : D3DERR_NOTAVAILABLE; - } - - - HRESULT D3D9SwapChainEx::RestoreDisplayMode(HMONITOR hMonitor) { - if (hMonitor == nullptr) - return D3DERR_INVALIDCALL; - - return RestoreMonitorDisplayMode(hMonitor) - ? D3D_OK - : D3DERR_NOTAVAILABLE; + wsi::WsiMode wsiMode = { }; + ConvertDisplayMode(mode, &wsiMode); + + if (!wsi::setWindowMode(GetDefaultMonitor(), m_window, &wsiMode, EnteringFullscreen)) + return D3DERR_NOTAVAILABLE; + + return D3D_OK; } + bool D3D9SwapChainEx::UpdatePresentRegion(const RECT* pSourceRect, const RECT* pDestRect) { if (pSourceRect == nullptr) { m_srcRect.top = 0; @@ -1455,7 +1413,7 @@ namespace dxvk { return this->GetParent()->IsExtended() ? "D3D9Ex" : "D3D9"; } - +#ifndef DXVK_NATIVE void D3D9SwapChainEx::HookWindowProc() { std::lock_guard lock(windowProcMapMutex); @@ -1488,5 +1446,6 @@ namespace dxvk { windowProcMap.erase(m_window); } +#endif } \ No newline at end of file diff --git a/src/d3d9/d3d9_swapchain.h b/src/d3d9/d3d9_swapchain.h index 1b27bcff..4b2ffb46 100644 --- a/src/d3d9/d3d9_swapchain.h +++ b/src/d3d9/d3d9_swapchain.h @@ -6,6 +6,10 @@ #include "../dxvk/hud/dxvk_hud.h" +#include "../wsi/wsi_mode.h" +#include "../wsi/wsi_window.h" +#include "../wsi/wsi_monitor.h" + #include "../util/sync/sync_signal.h" #include @@ -92,13 +96,6 @@ namespace dxvk { Gamma = 1, }; - - struct WindowState { - LONG style = 0; - LONG exstyle = 0; - RECT rect = { 0, 0, 0, 0 }; - }; - D3DPRESENT_PARAMETERS m_presentParams; D3DGAMMARAMP m_ramp; @@ -152,7 +149,7 @@ namespace dxvk { HWND m_window = nullptr; HMONITOR m_monitor = nullptr; - WindowState m_windowState; + wsi::DxvkWindowState m_windowState; void PresentImage(UINT PresentInterval); @@ -209,9 +206,8 @@ namespace dxvk { HRESULT ChangeDisplayMode( D3DPRESENT_PARAMETERS* pPresentParams, - const D3DDISPLAYMODEEX* pFullscreenDisplayMode); - - HRESULT RestoreDisplayMode(HMONITOR hMonitor); + const D3DDISPLAYMODEEX* pFullscreenDisplayMode, + bool EnteringFullscreen); bool UpdatePresentRegion(const RECT* pSourceRect, const RECT* pDestRect); @@ -221,9 +217,11 @@ namespace dxvk { std::string GetApiName(); +#ifndef DXVK_NATIVE void HookWindowProc(); void ResetWindowProc(); +#endif }; diff --git a/src/d3d9/d3d9_util.cpp b/src/d3d9/d3d9_util.cpp index 6ca5f1e1..1298cec6 100644 --- a/src/d3d9/d3d9_util.cpp +++ b/src/d3d9/d3d9_util.cpp @@ -2,40 +2,6 @@ namespace dxvk { - typedef HRESULT (STDMETHODCALLTYPE *D3DXDisassembleShader) ( - const void* pShader, - BOOL EnableColorCode, - char* pComments, - ID3DBlob** ppDisassembly); // ppDisassembly is actually a D3DXBUFFER, but it has the exact same vtable as a ID3DBlob at the start. - - D3DXDisassembleShader g_pfnDisassembleShader = nullptr; - - HRESULT DisassembleShader( - const void* pShader, - BOOL EnableColorCode, - char* pComments, - ID3DBlob** ppDisassembly) { - if (g_pfnDisassembleShader == nullptr) { - HMODULE d3d9x = LoadLibraryA("d3dx9.dll"); - - if (d3d9x == nullptr) - d3d9x = LoadLibraryA("d3dx9_43.dll"); - - g_pfnDisassembleShader = - reinterpret_cast(GetProcAddress(d3d9x, "D3DXDisassembleShader")); - } - - if (g_pfnDisassembleShader == nullptr) - return D3DERR_INVALIDCALL; - - return g_pfnDisassembleShader( - pShader, - EnableColorCode, - pComments, - ppDisassembly); - } - - HRESULT DecodeMultiSampleType( D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, diff --git a/src/d3d9/d3d9_util.h b/src/d3d9/d3d9_util.h index 177da89f..78a9e83b 100644 --- a/src/d3d9/d3d9_util.h +++ b/src/d3d9/d3d9_util.h @@ -84,12 +84,6 @@ namespace dxvk { AddRef ? castedPtr->AddRefPrivate() : castedPtr->ReleasePrivate(); } - HRESULT DisassembleShader( - const void* pShader, - BOOL EnableColorCode, - char* pComments, - ID3DBlob** ppDisassembly); - HRESULT DecodeMultiSampleType( D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, diff --git a/src/d3d9/meson.build b/src/d3d9/meson.build index 2c28d03a..38a889b1 100644 --- a/src/d3d9/meson.build +++ b/src/d3d9/meson.build @@ -41,12 +41,12 @@ d3d9_src = [ 'd3d9_hud.cpp' ] -d3d9_dll = shared_library('d3d9'+dll_ext, d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res, +d3d9_dll = shared_library(so_prefix+'d3d9'+dll_ext, d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res, name_prefix : '', - dependencies : [ dxso_dep, dxvk_dep ], + dependencies : [ dxso_dep, dxvk_dep, wsi_dep ], include_directories : dxvk_include_path, install : true, - objects : not dxvk_msvc ? 'd3d9'+def_spec_ext : [], + objects : not dxvk_msvc and not dxvk_native ? 'd3d9'+def_spec_ext : [], vs_module_defs : 'd3d9'+def_spec_ext, override_options : ['cpp_std='+dxvk_cpp_std]) diff --git a/src/dxgi/dxgi_adapter.cpp b/src/dxgi/dxgi_adapter.cpp index abce251b..10444fbf 100644 --- a/src/dxgi/dxgi_adapter.cpp +++ b/src/dxgi/dxgi_adapter.cpp @@ -10,6 +10,7 @@ #include "dxgi_options.h" #include "dxgi_output.h" +#include "../wsi/wsi_monitor.h" #include "../util/util_luid.h" namespace dxvk { @@ -134,14 +135,14 @@ namespace dxvk { if (ppOutput == nullptr) return E_INVALIDARG; + + HMONITOR monitor = wsi::enumMonitors(Output); - if (Output > 0) { + if (!monitor) { *ppOutput = nullptr; return DXGI_ERROR_NOT_FOUND; } - - // TODO support multiple monitors - HMONITOR monitor = ::MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); + *ppOutput = ref(new DxgiOutput(m_factory, this, monitor)); return S_OK; } diff --git a/src/dxgi/dxgi_include.h b/src/dxgi/dxgi_include.h index 7c4d302f..d570ab77 100644 --- a/src/dxgi/dxgi_include.h +++ b/src/dxgi/dxgi_include.h @@ -1,7 +1,7 @@ #pragma once //for some reason we need to specify __declspec(dllexport) for MinGW -#if defined(__WINE__) +#if defined(__WINE__) || (defined(DXVK_NATIVE) && !defined(_WIN32)) #define DLLEXPORT __attribute__((visibility("default"))) #elif defined(_MSC_VER) #define DLLEXPORT diff --git a/src/dxgi/dxgi_monitor.cpp b/src/dxgi/dxgi_monitor.cpp index 94ed886b..b56d87ca 100644 --- a/src/dxgi/dxgi_monitor.cpp +++ b/src/dxgi/dxgi_monitor.cpp @@ -88,5 +88,22 @@ namespace dxvk { return 32; } } - + + DXGI_FORMAT GetBppMonitorFormat(uint32_t bpp) { + switch (bpp) { + case 32: + return DXGI_FORMAT_R8G8B8A8_UNORM; + + case 64: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + + default: + Logger::warn(str::format( + "GetBppMonitorFormat: Unknown bpp: ", + bpp)); + return DXGI_FORMAT_R8G8B8A8_UNORM; + } + } + + } \ No newline at end of file diff --git a/src/dxgi/dxgi_monitor.h b/src/dxgi/dxgi_monitor.h index 0cac8289..48fa36d6 100644 --- a/src/dxgi/dxgi_monitor.h +++ b/src/dxgi/dxgi_monitor.h @@ -5,6 +5,8 @@ #include "dxgi_interfaces.h" +#include "../wsi/wsi_mode.h" + namespace dxvk { class DxgiSwapChain; @@ -55,4 +57,41 @@ namespace dxvk { uint32_t GetMonitorFormatBpp( DXGI_FORMAT Format); + /** + * \brief Queries bits per pixel for a format + * + * \param [in] Bits per pixel to query + * \returns Format The DXGI format + */ + DXGI_FORMAT GetBppMonitorFormat( + uint32_t bpp); + + /** + * \brief Converts two display modes + */ + inline void ConvertDisplayMode( + const wsi::WsiMode& WsiMode, + DXGI_MODE_DESC1* pDxgiMode) { + pDxgiMode->Width = WsiMode.width; + pDxgiMode->Height = WsiMode.height; + pDxgiMode->RefreshRate = DXGI_RATIONAL{ WsiMode.refreshRate.numerator, WsiMode.refreshRate.denominator }; + pDxgiMode->Format = GetBppMonitorFormat(WsiMode.bitsPerPixel); + pDxgiMode->ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE; + pDxgiMode->Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + pDxgiMode->Stereo = FALSE; + } + + /** + * \brief Converts two display modes + */ + inline void ConvertDisplayMode( + const DXGI_MODE_DESC1& DxgiMode, + wsi::WsiMode* pWsiMode) { + pWsiMode->width = DxgiMode.Width; + pWsiMode->height = DxgiMode.Height; + pWsiMode->refreshRate = wsi::WsiRational{ DxgiMode.RefreshRate.Numerator, DxgiMode.RefreshRate.Denominator }; + pWsiMode->bitsPerPixel = GetMonitorFormatBpp(DxgiMode.Format); + pWsiMode->interlaced = false; + } + } \ No newline at end of file diff --git a/src/dxgi/dxgi_output.cpp b/src/dxgi/dxgi_output.cpp index 91fb5670..ce3d56fa 100644 --- a/src/dxgi/dxgi_output.cpp +++ b/src/dxgi/dxgi_output.cpp @@ -12,6 +12,7 @@ #include "dxgi_output.h" #include "dxgi_swapchain.h" +#include "../wsi/wsi_mode.h" #include "../dxvk/dxvk_format.h" namespace dxvk { @@ -120,20 +121,12 @@ namespace dxvk { // Both or neither must be zero if ((pModeToMatch->Width == 0) ^ (pModeToMatch->Height == 0)) return DXGI_ERROR_INVALID_CALL; + + wsi::WsiMode activeWsiMode = { }; + wsi::getCurrentDisplayMode(m_monitor, &activeWsiMode); - DEVMODEW devMode; - devMode.dmSize = sizeof(devMode); - - if (!GetMonitorDisplayMode(m_monitor, ENUM_CURRENT_SETTINGS, &devMode)) - return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; - - DXGI_MODE_DESC activeMode = { }; - activeMode.Width = devMode.dmPelsWidth; - activeMode.Height = devMode.dmPelsHeight; - activeMode.RefreshRate = { devMode.dmDisplayFrequency, 1 }; - activeMode.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; // FIXME - activeMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE; - activeMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + DXGI_MODE_DESC1 activeMode = { }; + ConvertDisplayMode(activeWsiMode, &activeMode); DXGI_MODE_DESC1 defaultMode; defaultMode.Width = 0; @@ -200,18 +193,17 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE DxgiOutput::GetDesc(DXGI_OUTPUT_DESC *pDesc) { if (pDesc == nullptr) return DXGI_ERROR_INVALID_CALL; - - ::MONITORINFOEXW monInfo; - monInfo.cbSize = sizeof(monInfo); - if (!::GetMonitorInfoW(m_monitor, reinterpret_cast(&monInfo))) { - Logger::err("DXGI: Failed to query monitor info"); + if (!wsi::getDesktopCoordinates(m_monitor, &pDesc->DesktopCoordinates)) { + Logger::err("DXGI: Failed to query monitor coords"); return E_FAIL; } - - std::memcpy(pDesc->DeviceName, monInfo.szDevice, std::size(pDesc->DeviceName)); - - pDesc->DesktopCoordinates = monInfo.rcMonitor; + + if (!wsi::getDisplayName(m_monitor, pDesc->DeviceName)) { + Logger::err("DXGI: Failed to query monitor name"); + return E_FAIL; + } + pDesc->AttachedToDesktop = 1; pDesc->Rotation = DXGI_MODE_ROTATION_UNSPECIFIED; pDesc->Monitor = m_monitor; @@ -265,28 +257,27 @@ namespace dxvk { // Walk over all modes that the display supports and // return those that match the requested format etc. - DEVMODEW devMode = { }; - devMode.dmSize = sizeof(DEVMODEW); + wsi::WsiMode devMode = { }; uint32_t srcModeId = 0; uint32_t dstModeId = 0; std::vector modeList; - while (GetMonitorDisplayMode(m_monitor, srcModeId++, &devMode)) { + while (wsi::getDisplayMode(m_monitor, srcModeId++, &devMode)) { // Skip interlaced modes altogether - if (devMode.dmDisplayFlags & DM_INTERLACED) + if (devMode.interlaced) continue; // Skip modes with incompatible formats - if (devMode.dmBitsPerPel != GetMonitorFormatBpp(EnumFormat)) + if (devMode.bitsPerPixel != GetMonitorFormatBpp(EnumFormat)) continue; if (pDesc != nullptr) { DXGI_MODE_DESC1 mode; - mode.Width = devMode.dmPelsWidth; - mode.Height = devMode.dmPelsHeight; - mode.RefreshRate = { devMode.dmDisplayFrequency * 1000, 1000 }; + mode.Width = devMode.width; + mode.Height = devMode.height; + mode.RefreshRate = { devMode.refreshRate.numerator, devMode.refreshRate.denominator }; mode.Format = EnumFormat; mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE; mode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index a10c0269..50a99425 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -36,7 +36,7 @@ namespace dxvk { DxgiSwapChain::~DxgiSwapChain() { - RestoreDisplayMode(m_monitor); + wsi::restoreDisplayMode(m_monitor); // Decouple swap chain from monitor if necessary DXGI_VK_MONITOR_DATA* monitorInfo = nullptr; @@ -97,23 +97,15 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetContainingOutput(IDXGIOutput** ppOutput) { InitReturnPtr(ppOutput); - if (!IsWindow(m_window)) + if (!wsi::isWindow(m_window)) return DXGI_ERROR_INVALID_CALL; if (m_target != nullptr) { *ppOutput = m_target.ref(); return S_OK; } - - RECT windowRect = { 0, 0, 0, 0 }; - ::GetWindowRect(m_window, &windowRect); - - HMONITOR monitor = ::MonitorFromPoint( - { (windowRect.left + windowRect.right) / 2, - (windowRect.top + windowRect.bottom) / 2 }, - MONITOR_DEFAULTTOPRIMARY); - return GetOutputFromMonitor(monitor, ppOutput); + return GetOutputFromMonitor(wsi::getWindowMonitor(m_window), ppOutput); } @@ -182,6 +174,9 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetFullscreenState( BOOL* pFullscreen, IDXGIOutput** ppTarget) { + if (!wsi::isWindow(m_window)) + return DXGI_ERROR_INVALID_CALL; + HRESULT hr = S_OK; if (pFullscreen != nullptr) @@ -249,7 +244,7 @@ namespace dxvk { UINT SyncInterval, UINT PresentFlags, const DXGI_PRESENT_PARAMETERS* pPresentParameters) { - if (!IsWindow(m_window)) + if (!wsi::isWindow(m_window)) return DXGI_ERROR_INVALID_CALL; if (SyncInterval > 4) @@ -273,7 +268,7 @@ namespace dxvk { UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) { - if (!IsWindow(m_window)) + if (!wsi::isWindow(m_window)) return DXGI_ERROR_INVALID_CALL; constexpr UINT PreserveFlags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; @@ -285,7 +280,7 @@ namespace dxvk { m_desc.Width = Width; m_desc.Height = Height; - GetWindowClientSize(m_window, + wsi::getWindowSize(m_window, m_desc.Width ? nullptr : &m_desc.Width, m_desc.Height ? nullptr : &m_desc.Height); @@ -323,7 +318,7 @@ namespace dxvk { if (pNewTargetParameters == nullptr) return DXGI_ERROR_INVALID_CALL; - if (!IsWindow(m_window)) + if (!wsi::isWindow(m_window)) return DXGI_ERROR_INVALID_CALL; // Update the swap chain description @@ -334,19 +329,10 @@ namespace dxvk { m_descFs.Scaling = pNewTargetParameters->Scaling; if (m_descFs.Windowed) { - // Adjust window position and size - RECT newRect = { 0, 0, 0, 0 }; - RECT oldRect = { 0, 0, 0, 0 }; - - ::GetWindowRect(m_window, &oldRect); - ::SetRect(&newRect, 0, 0, pNewTargetParameters->Width, pNewTargetParameters->Height); - ::AdjustWindowRectEx(&newRect, - ::GetWindowLongW(m_window, GWL_STYLE), FALSE, - ::GetWindowLongW(m_window, GWL_EXSTYLE)); - ::SetRect(&newRect, 0, 0, newRect.right - newRect.left, newRect.bottom - newRect.top); - ::OffsetRect(&newRect, oldRect.left, oldRect.top); - ::MoveWindow(m_window, newRect.left, newRect.top, - newRect.right - newRect.left, newRect.bottom - newRect.top, TRUE); + wsi::resizeWindow( + m_window, &m_windowState, + pNewTargetParameters->Width, + pNewTargetParameters->Height); } else { Com output; @@ -357,16 +343,7 @@ namespace dxvk { // If the swap chain allows it, change the display mode if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH) - ChangeDisplayMode(output.ptr(), pNewTargetParameters); - - // Resize and reposition the window to - DXGI_OUTPUT_DESC desc; - output->GetDesc(&desc); - - RECT newRect = desc.DesktopCoordinates; - - ::MoveWindow(m_window, newRect.left, newRect.top, - newRect.right - newRect.left, newRect.bottom - newRect.top, TRUE); + ChangeDisplayMode(output.ptr(), pNewTargetParameters, false); } return S_OK; @@ -543,7 +520,7 @@ namespace dxvk { HRESULT DxgiSwapChain::EnterFullscreenMode(IDXGIOutput* pTarget) { Com output = pTarget; - if (!IsWindow(m_window)) + if (!wsi::isWindow(m_window)) return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; if (output == nullptr) { @@ -552,11 +529,10 @@ namespace dxvk { return E_FAIL; } } + + const bool modeSwitch = m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; - // Find a display mode that matches what we need - ::GetWindowRect(m_window, &m_windowState.rect); - - if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH) { + if (modeSwitch) { DXGI_MODE_DESC displayMode; displayMode.Width = m_desc.Width; displayMode.Height = m_desc.Height; @@ -567,7 +543,7 @@ namespace dxvk { displayMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; displayMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - if (FAILED(ChangeDisplayMode(output.ptr(), &displayMode))) { + if (FAILED(ChangeDisplayMode(output.ptr(), &displayMode, true))) { Logger::err("DXGI: EnterFullscreenMode: Failed to change display mode"); return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; } @@ -575,29 +551,15 @@ namespace dxvk { // Update swap chain description m_descFs.Windowed = FALSE; - - // Change the window flags to remove the decoration etc. - LONG style = ::GetWindowLongW(m_window, GWL_STYLE); - LONG exstyle = ::GetWindowLongW(m_window, GWL_EXSTYLE); - - m_windowState.style = style; - m_windowState.exstyle = exstyle; - - style &= ~WS_OVERLAPPEDWINDOW; - exstyle &= ~WS_EX_OVERLAPPEDWINDOW; - - ::SetWindowLongW(m_window, GWL_STYLE, style); - ::SetWindowLongW(m_window, GWL_EXSTYLE, exstyle); - + // Move the window so that it covers the entire output DXGI_OUTPUT_DESC desc; output->GetDesc(&desc); - - const RECT rect = desc.DesktopCoordinates; - - ::SetWindowPos(m_window, HWND_TOPMOST, - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, - SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE); + + if (!wsi::enterFullscreenMode(desc.Monitor, m_window, &m_windowState, modeSwitch)) { + Logger::err("DXGI: EnterFullscreenMode: Failed to enter fullscreen mode"); + return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; + } m_monitor = desc.Monitor; m_target = std::move(output); @@ -618,7 +580,7 @@ namespace dxvk { HRESULT DxgiSwapChain::LeaveFullscreenMode() { - if (FAILED(RestoreDisplayMode(m_monitor))) + if (!wsi::restoreDisplayMode(m_monitor)) Logger::warn("DXGI: LeaveFullscreenMode: Failed to restore display mode"); // Reset gamma control and decouple swap chain from monitor @@ -637,34 +599,22 @@ namespace dxvk { m_monitor = nullptr; m_target = nullptr; - if (!IsWindow(m_window)) + if (!wsi::isWindow(m_window)) return S_OK; - // Only restore the window style if the application hasn't - // changed them. This is in line with what native DXGI does. - LONG curStyle = ::GetWindowLongW(m_window, GWL_STYLE) & ~WS_VISIBLE; - LONG curExstyle = ::GetWindowLongW(m_window, GWL_EXSTYLE) & ~WS_EX_TOPMOST; - - if (curStyle == (m_windowState.style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW)) - && curExstyle == (m_windowState.exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) { - ::SetWindowLongW(m_window, GWL_STYLE, m_windowState.style); - ::SetWindowLongW(m_window, GWL_EXSTYLE, m_windowState.exstyle); + if (!wsi::leaveFullscreenMode(m_window, &m_windowState)) { + Logger::err("DXGI: LeaveFullscreenMode: Failed to exit fullscreen mode"); + return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; } - // Restore window position and apply the style - const RECT rect = m_windowState.rect; - - ::SetWindowPos(m_window, 0, - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, - SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE); - return S_OK; } HRESULT DxgiSwapChain::ChangeDisplayMode( IDXGIOutput* pOutput, - const DXGI_MODE_DESC* pDisplayMode) { + const DXGI_MODE_DESC* pDisplayMode, + BOOL EnteringFullscreen) { if (!pOutput) return DXGI_ERROR_INVALID_CALL; @@ -689,33 +639,23 @@ namespace dxvk { "@", preferredMode.RefreshRate.Numerator / preferredMode.RefreshRate.Denominator)); return hr; } - - DEVMODEW devMode = { }; - devMode.dmSize = sizeof(devMode); - devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; - devMode.dmPelsWidth = selectedMode.Width; - devMode.dmPelsHeight = selectedMode.Height; - devMode.dmBitsPerPel = GetMonitorFormatBpp(selectedMode.Format); - - if (selectedMode.RefreshRate.Numerator != 0) { - devMode.dmFields |= DM_DISPLAYFREQUENCY; - devMode.dmDisplayFrequency = selectedMode.RefreshRate.Numerator - / selectedMode.RefreshRate.Denominator; - } - return SetMonitorDisplayMode(outputDesc.Monitor, &devMode) - ? S_OK - : DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; - } - - - HRESULT DxgiSwapChain::RestoreDisplayMode(HMONITOR hMonitor) { - if (!hMonitor) - return DXGI_ERROR_INVALID_CALL; - - return RestoreMonitorDisplayMode(hMonitor) - ? S_OK - : DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; + DXGI_MODE_DESC1 selectedMode1; + selectedMode1.Width = selectedMode.Width; + selectedMode1.Height = selectedMode.Height; + selectedMode1.RefreshRate = selectedMode.RefreshRate; + selectedMode1.Format = selectedMode.Format; + selectedMode1.ScanlineOrdering = selectedMode.ScanlineOrdering; + selectedMode1.Scaling = selectedMode.Scaling; + selectedMode1.Stereo = false; + + wsi::WsiMode wsiMode = { }; + ConvertDisplayMode(selectedMode1, &wsiMode); + + if (!wsi::setWindowMode(outputDesc.Monitor, m_window, &wsiMode, EnteringFullscreen)) + return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; + + return S_OK; } diff --git a/src/dxgi/dxgi_swapchain.h b/src/dxgi/dxgi_swapchain.h index b39ff6f4..7ed6ea15 100644 --- a/src/dxgi/dxgi_swapchain.h +++ b/src/dxgi/dxgi_swapchain.h @@ -11,6 +11,10 @@ #include "../spirv/spirv_module.h" +#include "../wsi/wsi_window.h" +#include "../wsi/wsi_monitor.h" +#include "../wsi/wsi_mode.h" + namespace dxvk { class DxgiDevice; @@ -167,12 +171,6 @@ namespace dxvk { private: - struct WindowState { - LONG style = 0; - LONG exstyle = 0; - RECT rect = { 0, 0, 0, 0 }; - }; - std::recursive_mutex m_lockWindow; std::mutex m_lockBuffer; @@ -189,8 +187,8 @@ namespace dxvk { Com m_presenter; HMONITOR m_monitor; - WindowState m_windowState; - + wsi::DxvkWindowState m_windowState; + HRESULT EnterFullscreenMode( IDXGIOutput *pTarget); @@ -198,10 +196,8 @@ namespace dxvk { HRESULT ChangeDisplayMode( IDXGIOutput* pOutput, - const DXGI_MODE_DESC* pDisplayMode); - - HRESULT RestoreDisplayMode( - HMONITOR hMonitor); + const DXGI_MODE_DESC* pDisplayMode, + BOOL EnteringFullscreen); HRESULT GetSampleCount( UINT Count, diff --git a/src/dxgi/meson.build b/src/dxgi/meson.build index 9e7bf33b..7892c9ab 100644 --- a/src/dxgi/meson.build +++ b/src/dxgi/meson.build @@ -12,13 +12,13 @@ dxgi_src = [ 'dxgi_swapchain.cpp', ] -dxgi_dll = shared_library('dxgi'+dll_ext, dxgi_src, dxgi_res, +dxgi_dll = shared_library(so_prefix+'dxgi'+dll_ext, dxgi_src, dxgi_res, name_prefix : '', - dependencies : [ dxvk_dep ], + dependencies : [ dxvk_dep, wsi_dep ], include_directories : dxvk_include_path, install : true, vs_module_defs : 'dxgi'+def_spec_ext, - objects : not dxvk_msvc ? 'dxgi'+def_spec_ext : [], + objects : not dxvk_msvc and not dxvk_native ? 'dxgi'+def_spec_ext : [], override_options : ['cpp_std='+dxvk_cpp_std]) dxgi_dep = declare_dependency( diff --git a/src/dxvk/dxvk_instance.cpp b/src/dxvk/dxvk_instance.cpp index 6e7245c6..daf19566 100644 --- a/src/dxvk/dxvk_instance.cpp +++ b/src/dxvk/dxvk_instance.cpp @@ -20,8 +20,10 @@ namespace dxvk { m_extProviders.push_back(&DxvkPlatformExts::s_instance); +#ifndef DXVK_NATIVE if (m_options.enableOpenVR) m_extProviders.push_back(&VrInstance::s_instance); +#endif Logger::info("Built-in extension providers:"); for (const auto& provider : m_extProviders) diff --git a/src/dxvk/dxvk_state_cache.cpp b/src/dxvk/dxvk_state_cache.cpp index f8ccf65b..49e4cb71 100644 --- a/src/dxvk/dxvk_state_cache.cpp +++ b/src/dxvk/dxvk_state_cache.cpp @@ -169,7 +169,11 @@ namespace dxvk { for (uint32_t i = 0; i < numWorkers; i++) { m_workerThreads.emplace_back([this] () { workerFunc(); }); + + // TODO: better solution for this. +#ifndef DXVK_NATIVE m_workerThreads[i].set_priority(ThreadPriority::Lowest); +#endif } m_writerThread = dxvk::thread([this] () { writerFunc(); }); diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 1dc113c3..e16401d3 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -51,7 +51,7 @@ dxvk_shaders = files([ 'hud/shaders/hud_text_vert.vert', ]) -dxvk_src = files([ +dxvk_src = [ 'dxvk_adapter.cpp', 'dxvk_barrier.cpp', 'dxvk_buffer.cpp', @@ -80,7 +80,6 @@ dxvk_src = files([ 'dxvk_meta_mipgen.cpp', 'dxvk_meta_pack.cpp', 'dxvk_meta_resolve.cpp', - 'dxvk_openvr.cpp', 'dxvk_options.cpp', 'dxvk_pipecache.cpp', 'dxvk_pipelayout.cpp', @@ -98,14 +97,29 @@ dxvk_src = files([ 'dxvk_stats.cpp', 'dxvk_unbound.cpp', 'dxvk_util.cpp', - - 'platform/dxvk_win32_exts.cpp', 'hud/dxvk_hud.cpp', 'hud/dxvk_hud_font.cpp', 'hud/dxvk_hud_item.cpp', 'hud/dxvk_hud_renderer.cpp', -]) +] + +dxvk_src_win32 = [ + 'dxvk_openvr.cpp', + 'platform/dxvk_win32_exts.cpp' +] + +dxvk_src_sdl2 = [ + 'platform/dxvk_sdl2_exts.cpp' +] + +if dxvk_wsi == 'win32' + dxvk_src += dxvk_src_win32 +elif dxvk_wsi == 'sdl2' + dxvk_src += dxvk_src_sdl2 +else + error('Unknown platform for dxvk') +endif thread_dep = dependency('threads') diff --git a/src/dxvk/platform/dxvk_sdl2_exts.cpp b/src/dxvk/platform/dxvk_sdl2_exts.cpp new file mode 100644 index 00000000..09de7843 --- /dev/null +++ b/src/dxvk/platform/dxvk_sdl2_exts.cpp @@ -0,0 +1,60 @@ +#include "../dxvk_platform_exts.h" + +#include +#include + +namespace dxvk { + + DxvkPlatformExts DxvkPlatformExts::s_instance; + + std::string_view DxvkPlatformExts::getName() { + return "SDL2 WSI"; + } + + + DxvkNameSet DxvkPlatformExts::getInstanceExtensions() { + SDL_Window* window = SDL_CreateWindow( + "Dummy Window", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + 1, 1, + SDL_WINDOW_HIDDEN | SDL_WINDOW_VULKAN); + + if (window == nullptr) + throw DxvkError(str::format("SDL2 WSI: Failed to create dummy window. ", SDL_GetError())); + + uint32_t extensionCount = 0; + if (!SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, nullptr)) + throw DxvkError(str::format("SDL2 WSI: Failed to get instance extension count. ", SDL_GetError())); + + auto extensionNames = std::vector(extensionCount); + if (!SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, extensionNames.data())) + throw DxvkError(str::format("SDL2 WSI: Failed to get instance extensions. ", SDL_GetError())); + + DxvkNameSet names; + for (const char* name : extensionNames) + names.add(name); + + SDL_DestroyWindow(window); + + return names; + } + + + DxvkNameSet DxvkPlatformExts::getDeviceExtensions( + uint32_t adapterId) { + return DxvkNameSet(); + } + + + void DxvkPlatformExts::initInstanceExtensions() { + + } + + + void DxvkPlatformExts::initDeviceExtensions( + const DxvkInstance* instance) { + + } + +} \ No newline at end of file diff --git a/src/meson.build b/src/meson.build index c5d2753a..895eae2a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,36 +1,48 @@ subdir('util') subdir('spirv') +subdir('wsi') subdir('vulkan') subdir('dxvk') -if get_option('enable_dxgi') - if not get_option('enable_d3d11') +enable_dxgi = get_option('enable_dxgi') +enable_d3d9 = get_option('enable_d3d9') +enable_d3d10 = get_option('enable_d3d10') +enable_d3d11 = get_option('enable_d3d11') +enable_tests = get_option('enable_tests') + +if enable_d3d10 and dxvk_native + warning('Ignoring D3D10... Not supported for DXVK native.') + enable_d3d10 = false +endif + +if enable_dxgi + if not enable_d3d11 error('D3D11 is required for DXGI.') endif subdir('dxgi') endif -if get_option('enable_d3d10') or get_option('enable_d3d11') or get_option('enable_tests') +if enable_d3d10 or enable_d3d11 or enable_tests subdir('dxbc') endif -if get_option('enable_d3d11') +if enable_d3d11 subdir('d3d11') endif -if get_option('enable_d3d10') - if not get_option('enable_d3d11') +if enable_d3d10 + if not enable_d3d11 error('D3D11 is required for D3D10.') endif subdir('d3d10') endif -if get_option('enable_d3d9') +if enable_d3d9 subdir('dxso') subdir('d3d9') endif # Nothing selected -if not get_option('enable_d3d9') and not get_option('enable_d3d10') and not get_option('enable_d3d11') and not get_option('enable_tests') +if not enable_d3d9 and not enable_d3d10 and not enable_d3d11 and not enable_tests warning('Nothing selected to be built. Are you missing a frontend or tests?') endif diff --git a/src/util/meson.build b/src/util/meson.build index 80fe0be2..855692eb 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -1,8 +1,5 @@ -util_src = files([ +util_src = [ 'util_env.cpp', - 'util_string.cpp', - 'util_gdi.cpp', - 'util_luid.cpp', 'util_matrix.cpp', 'util_monitor.cpp', @@ -16,7 +13,30 @@ util_src = files([ 'sha1/sha1.c', 'sha1/sha1_util.cpp', -]) +] + +util_src_win32 = [ + 'util_gdi.cpp', + + 'platform/util_luid_win32.cpp', + 'platform/util_env_win32.cpp', + 'platform/util_string_win32.cpp' +] + +util_src_linux = [ + 'platform/util_luid_linux.cpp', + 'platform/util_env_linux.cpp', + 'platform/util_string_linux.cpp', + 'platform/thread_native.cpp', +] + +if dxvk_platform == 'windows' + util_src += util_src_win32 +elif dxvk_platform == 'linux' + util_src += util_src_linux +else + error('Unknown platform for util') +endif util_lib = static_library('util', util_src, include_directories : [ dxvk_include_path ], diff --git a/src/util/platform/thread_native.cpp b/src/util/platform/thread_native.cpp new file mode 100644 index 00000000..5337afd4 --- /dev/null +++ b/src/util/platform/thread_native.cpp @@ -0,0 +1,21 @@ +#include "../thread.h" +#include "../util_likely.h" + +#include + +namespace dxvk::this_thread { + + std::atomic g_threadCtr = { 0u }; + thread_local uint32_t g_threadId = 0u; + + // This implementation returns thread ids unique to the current instance. + // Ie. if you use this across multiple .so's then you might get conflicting ids. + // This isn't an issue for us as we only use it in d3d11, but do check if this changes. + uint32_t get_id() { + if (unlikely(!g_threadId)) + g_threadId = ++g_threadCtr; + + return g_threadId; + } + +} \ No newline at end of file diff --git a/src/util/platform/util_env_linux.cpp b/src/util/platform/util_env_linux.cpp new file mode 100644 index 00000000..ef7cfbdf --- /dev/null +++ b/src/util/platform/util_env_linux.cpp @@ -0,0 +1,25 @@ +#include "util_env.h" + +#include +#include + +namespace dxvk::env { + + std::string getExePath() { + std::array exePath = {}; + + size_t count = readlink("/proc/self/exe", exePath.data(), exePath.size()); + + return std::string(exePath.begin(), exePath.begin() + count); + } + + + void setThreadName(const std::string& name) { + } + + + bool createDirectory(const std::string& path) { + return std::filesystem::create_directories(path); + } + +} \ No newline at end of file diff --git a/src/util/platform/util_env_win32.cpp b/src/util/platform/util_env_win32.cpp new file mode 100644 index 00000000..8b86bccf --- /dev/null +++ b/src/util/platform/util_env_win32.cpp @@ -0,0 +1,38 @@ +#include "util_env.h" + +#include "./com/com_include.h" + +namespace dxvk::env { + + std::string getExePath() { + std::vector exePath; + exePath.resize(MAX_PATH + 1); + + DWORD len = ::GetModuleFileNameW(NULL, exePath.data(), MAX_PATH); + exePath.resize(len); + + return str::fromws(exePath.data()); + } + + + void setThreadName(const std::string& name) { + using SetThreadDescriptionProc = HRESULT (WINAPI *) (HANDLE, PCWSTR); + + static auto proc = reinterpret_cast( + ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "SetThreadDescription")); + + if (proc != nullptr) { + auto wideName = std::vector(name.length() + 1); + str::tows(name.c_str(), wideName.data(), wideName.size()); + (*proc)(::GetCurrentThread(), wideName.data()); + } + } + + + bool createDirectory(const std::string& path) { + WCHAR widePath[MAX_PATH]; + str::tows(path.c_str(), widePath); + return !!CreateDirectoryW(widePath, nullptr); + } + +} \ No newline at end of file diff --git a/src/util/platform/util_luid_linux.cpp b/src/util/platform/util_luid_linux.cpp new file mode 100644 index 00000000..9c3aa05b --- /dev/null +++ b/src/util/platform/util_luid_linux.cpp @@ -0,0 +1,13 @@ +#include "util_luid.h" + +#include "./log/log.h" + +namespace dxvk { + + LUID GetAdapterLUID(UINT Adapter) { + Logger::warn("GetAdapterLUID: native stub"); + + return LUID(); + } + +} diff --git a/src/util/util_luid.cpp b/src/util/platform/util_luid_win32.cpp similarity index 100% rename from src/util/util_luid.cpp rename to src/util/platform/util_luid_win32.cpp diff --git a/src/util/platform/util_string_linux.cpp b/src/util/platform/util_string_linux.cpp new file mode 100644 index 00000000..dbce6458 --- /dev/null +++ b/src/util/platform/util_string_linux.cpp @@ -0,0 +1,19 @@ +#include "util_string.h" + +#include +#include + +namespace dxvk::str { + + std::string fromws(const WCHAR *ws) { + size_t count = wcslen(ws); + + return std::string(ws, ws + count); + } + + + void tows(const char* mbs, WCHAR* wcs, size_t wcsLen) { + std::mbstowcs(wcs, mbs, wcsLen); + } + +} diff --git a/src/util/util_string.cpp b/src/util/platform/util_string_win32.cpp similarity index 100% rename from src/util/util_string.cpp rename to src/util/platform/util_string_win32.cpp diff --git a/src/util/thread.h b/src/util/thread.h index c96cb1c0..8ca2f5ea 100644 --- a/src/util/thread.h +++ b/src/util/thread.h @@ -9,8 +9,13 @@ #include "./rc/util_rc.h" #include "./rc/util_rc_ptr.h" +#ifndef _WIN32 +#include +#endif + namespace dxvk { +#ifdef _WIN32 /** * \brief Thread priority */ @@ -138,10 +143,28 @@ namespace dxvk { }; - namespace this_thread { inline void yield() { Sleep(0); } + + inline uint32_t get_id() { + return GetCurrentThreadId(); + } + } + +#else + + using thread = std::thread; + + namespace this_thread { + inline void yield() { + std::this_thread::yield(); + } + + uint32_t get_id(); } + +#endif + } diff --git a/src/util/util_env.cpp b/src/util/util_env.cpp index a804de6a..84bba040 100644 --- a/src/util/util_env.cpp +++ b/src/util/util_env.cpp @@ -1,9 +1,14 @@ #include "util_env.h" -#include "./com/com_include.h" - namespace dxvk::env { +#ifndef DXVK_NATIVE + constexpr char dirSlash = '\\'; +#else + constexpr char dirSlash = '/'; +#endif + + std::string getEnvVar(const char* name) { char* result = std::getenv(name); return (result) @@ -14,43 +19,11 @@ namespace dxvk::env { std::string getExeName() { std::string fullPath = getExePath(); - auto n = fullPath.find_last_of('\\'); + auto n = fullPath.find_last_of(dirSlash); return (n != std::string::npos) ? fullPath.substr(n + 1) : fullPath; } - - - std::string getExePath() { - std::vector exePath; - exePath.resize(MAX_PATH + 1); - - DWORD len = ::GetModuleFileNameW(NULL, exePath.data(), MAX_PATH); - exePath.resize(len); - - return str::fromws(exePath.data()); - } - - - void setThreadName(const std::string& name) { - using SetThreadDescriptionProc = HRESULT (WINAPI *) (HANDLE, PCWSTR); - - static auto proc = reinterpret_cast( - ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "SetThreadDescription")); - - if (proc != nullptr) { - auto wideName = std::vector(name.length() + 1); - str::tows(name.c_str(), wideName.data(), wideName.size()); - (*proc)(::GetCurrentThread(), wideName.data()); - } - } - - - bool createDirectory(const std::string& path) { - WCHAR widePath[MAX_PATH]; - str::tows(path.c_str(), widePath); - return !!CreateDirectoryW(widePath, nullptr); - } } diff --git a/src/util/util_monitor.cpp b/src/util/util_monitor.cpp index 1b84714f..10fe0f42 100644 --- a/src/util/util_monitor.cpp +++ b/src/util/util_monitor.cpp @@ -1,88 +1,16 @@ #include "util_monitor.h" #include "util_string.h" +#include "../wsi/wsi_mode.h" +#include "../wsi/wsi_monitor.h" +#include "../wsi/wsi_window.h" + #include "./log/log.h" namespace dxvk { HMONITOR GetDefaultMonitor() { - return ::MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); - } - - - BOOL SetMonitorDisplayMode( - HMONITOR hMonitor, - DEVMODEW* pMode) { - ::MONITORINFOEXW monInfo; - monInfo.cbSize = sizeof(monInfo); - - if (!::GetMonitorInfoW(hMonitor, reinterpret_cast(&monInfo))) { - Logger::err("Failed to query monitor info"); - return E_FAIL; - } - - Logger::info(str::format("Setting display mode: ", - pMode->dmPelsWidth, "x", pMode->dmPelsHeight, "@", - pMode->dmDisplayFrequency)); - - DEVMODEW curMode = { }; - curMode.dmSize = sizeof(curMode); - - if (GetMonitorDisplayMode(hMonitor, ENUM_CURRENT_SETTINGS, &curMode)) { - bool eq = curMode.dmPelsWidth == pMode->dmPelsWidth - && curMode.dmPelsHeight == pMode->dmPelsHeight - && curMode.dmBitsPerPel == pMode->dmBitsPerPel; - - if (pMode->dmFields & DM_DISPLAYFREQUENCY) - eq &= curMode.dmDisplayFrequency == pMode->dmDisplayFrequency; - - if (eq) - return true; - } - - LONG status = ::ChangeDisplaySettingsExW(monInfo.szDevice, - pMode, nullptr, CDS_FULLSCREEN, nullptr); - - if (status != DISP_CHANGE_SUCCESSFUL) { - pMode->dmFields &= ~DM_DISPLAYFREQUENCY; - - status = ::ChangeDisplaySettingsExW(monInfo.szDevice, - pMode, nullptr, CDS_FULLSCREEN, nullptr); - } - - return status == DISP_CHANGE_SUCCESSFUL; - } - - - BOOL GetMonitorDisplayMode( - HMONITOR hMonitor, - DWORD modeNum, - DEVMODEW* pMode) { - ::MONITORINFOEXW monInfo; - monInfo.cbSize = sizeof(monInfo); - - if (!::GetMonitorInfoW(hMonitor, reinterpret_cast(&monInfo))) { - Logger::err("Failed to query monitor info"); - return false; - } - - return ::EnumDisplaySettingsW(monInfo.szDevice, modeNum, pMode); - } - - - BOOL RestoreMonitorDisplayMode( - HMONITOR hMonitor) { - DEVMODEW devMode = { }; - devMode.dmSize = sizeof(devMode); - - if (!GetMonitorDisplayMode(hMonitor, ENUM_REGISTRY_SETTINGS, &devMode)) - return false; - - Logger::info(str::format("Restoring display mode: ", - devMode.dmPelsWidth, "x", devMode.dmPelsHeight, "@", - devMode.dmDisplayFrequency)); - - return SetMonitorDisplayMode(hMonitor, &devMode); + return wsi::enumMonitors(0); } @@ -90,14 +18,7 @@ namespace dxvk { HWND hWnd, UINT* pWidth, UINT* pHeight) { - RECT rect = { }; - ::GetClientRect(hWnd, &rect); - - if (pWidth) - *pWidth = rect.right - rect.left; - - if (pHeight) - *pHeight = rect.bottom - rect.top; + wsi::getWindowSize(hWnd, pWidth, pHeight); } @@ -105,15 +26,12 @@ namespace dxvk { HMONITOR hMonitor, UINT* pWidth, UINT* pHeight) { - ::MONITORINFOEXW monInfo; - monInfo.cbSize = sizeof(monInfo); + RECT rect; - if (!::GetMonitorInfoW(hMonitor, reinterpret_cast(&monInfo))) { - Logger::err("Failed to query monitor info"); + if (!wsi::getDesktopCoordinates(hMonitor, &rect)) { + Logger::err("D3D9: Failed to query monitor info"); return; } - - auto rect = monInfo.rcMonitor; if (pWidth) *pWidth = rect.right - rect.left; @@ -126,15 +44,8 @@ namespace dxvk { void GetMonitorRect( HMONITOR hMonitor, RECT* pRect) { - ::MONITORINFOEXW monInfo; - monInfo.cbSize = sizeof(monInfo); - - if (!::GetMonitorInfoW(hMonitor, reinterpret_cast(&monInfo))) { - Logger::err("Failed to query monitor info"); - return; - } - - *pRect = monInfo.rcMonitor; + if (!wsi::getDesktopCoordinates(hMonitor, pRect)) + Logger::err("D3D9: Failed to query monitor info"); } } diff --git a/src/util/util_monitor.h b/src/util/util_monitor.h index c89520a9..7d8c2c19 100644 --- a/src/util/util_monitor.h +++ b/src/util/util_monitor.h @@ -10,31 +10,6 @@ namespace dxvk { */ HMONITOR GetDefaultMonitor(); - /** - * \brief Sets monitor display mode - * - * Note that \c pMode may be altered by this function. - * \param [in] hMonitor The monitor to change - * \param [in] pMode The desired display mode - * \returns \c true on success - */ - BOOL SetMonitorDisplayMode( - HMONITOR hMonitor, - DEVMODEW* pMode); - - /** - * \brief Enumerates monitor display modes - * - * \param [in] hMonitor The monitor to query - * \param [in] modeNum Mode number or enum - * \param [in] pMode The display mode - * \returns \c true on success - */ - BOOL GetMonitorDisplayMode( - HMONITOR hMonitor, - DWORD modeNum, - DEVMODEW* pMode); - /** * \brief Change display mode to registry settings * diff --git a/src/vulkan/meson.build b/src/vulkan/meson.build index 82635523..d075531d 100644 --- a/src/vulkan/meson.build +++ b/src/vulkan/meson.build @@ -1,13 +1,15 @@ -vkcommon_src = files([ +vkcommon_src = [ 'vulkan_loader.cpp', 'vulkan_names.cpp', 'vulkan_presenter.cpp', -]) +] thread_dep = dependency('threads') +vkcommon_deps = [ thread_dep, wsi_dep, lib_vulkan ] + vkcommon_lib = static_library('vkcommon', vkcommon_src, - dependencies : [ thread_dep, lib_vulkan ], + dependencies : vkcommon_deps, override_options : ['cpp_std='+dxvk_cpp_std], include_directories : [ dxvk_include_path ]) diff --git a/src/vulkan/vulkan_loader_fn.h b/src/vulkan/vulkan_loader_fn.h index ecdd82a3..f7e18a65 100644 --- a/src/vulkan/vulkan_loader_fn.h +++ b/src/vulkan/vulkan_loader_fn.h @@ -11,9 +11,16 @@ #undef _WIN32 #endif +#ifdef _WIN32 #define VK_USE_PLATFORM_WIN32_KHR 1 +#endif + #include +#ifndef _WIN32 +#include +#endif + #ifdef __WINE__ #pragma pop_macro("_WIN32") #endif diff --git a/src/vulkan/vulkan_presenter.cpp b/src/vulkan/vulkan_presenter.cpp index 6958e576..ce7a4d4f 100644 --- a/src/vulkan/vulkan_presenter.cpp +++ b/src/vulkan/vulkan_presenter.cpp @@ -1,6 +1,7 @@ #include "vulkan_presenter.h" #include "../dxvk/dxvk_format.h" +#include "../wsi/wsi_presenter.h" namespace dxvk::vk { @@ -436,18 +437,7 @@ namespace dxvk::vk { VkResult Presenter::createSurface() { - HINSTANCE instance = reinterpret_cast( - GetWindowLongPtr(m_window, GWLP_HINSTANCE)); - - VkWin32SurfaceCreateInfoKHR info; - info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - info.pNext = nullptr; - info.flags = 0; - info.hinstance = instance; - info.hwnd = m_window; - - VkResult status = m_vki->vkCreateWin32SurfaceKHR( - m_vki->instance(), &info, nullptr, &m_surface); + VkResult status = wsi::createSurface(m_window, m_vki, &m_surface); if (status != VK_SUCCESS) return status; diff --git a/src/wsi/meson.build b/src/wsi/meson.build new file mode 100644 index 00000000..6ab147be --- /dev/null +++ b/src/wsi/meson.build @@ -0,0 +1,32 @@ +wsi_win32_src = [ + 'win32/wsi_mode_win32.cpp', + 'win32/wsi_monitor_win32.cpp', + 'win32/wsi_presenter_win32.cpp', + 'win32/wsi_window_win32.cpp', +] + +wsi_sdl2_src = [ + 'sdl2/wsi_mode_sdl2.cpp', + 'sdl2/wsi_monitor_sdl2.cpp', + 'sdl2/wsi_presenter_sdl2.cpp', + 'sdl2/wsi_window_sdl2.cpp', +] + +if dxvk_wsi == 'win32' + wsi_src = wsi_win32_src + wsi_deps = [] +elif dxvk_wsi == 'sdl2' + wsi_src = wsi_sdl2_src + wsi_deps = [ lib_sdl2 ] +else + error('Unknown wsi') +endif + +wsi_lib = static_library('wsi', wsi_src, + dependencies : wsi_deps, + override_options : ['cpp_std='+dxvk_cpp_std], + include_directories : [ dxvk_include_path ]) + +wsi_dep = declare_dependency( + link_with : [ wsi_lib ], + include_directories : [ dxvk_include_path ]) diff --git a/src/wsi/sdl2/wsi_helpers_sdl2.h b/src/wsi/sdl2/wsi_helpers_sdl2.h new file mode 100644 index 00000000..781a6882 --- /dev/null +++ b/src/wsi/sdl2/wsi_helpers_sdl2.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include "../wsi_monitor.h" + +namespace dxvk { + + inline bool isDisplayValid(int32_t displayId) { + const int32_t displayCount = SDL_GetNumVideoDisplays(); + + return displayId < displayCount && displayId >= 0; + } + +} \ No newline at end of file diff --git a/src/wsi/sdl2/wsi_mode_sdl2.cpp b/src/wsi/sdl2/wsi_mode_sdl2.cpp new file mode 100644 index 00000000..291a1d8b --- /dev/null +++ b/src/wsi/sdl2/wsi_mode_sdl2.cpp @@ -0,0 +1,93 @@ +#include "../wsi_mode.h" + +#include "wsi_helpers_sdl2.h" + +#include + +#include "../../util/util_string.h" +#include "../../util/log/log.h" + +namespace dxvk::wsi { + + static inline uint32_t roundToNextPow2(uint32_t num) { + if (num-- == 0) + return 0; + + num |= num >> 1; num |= num >> 2; + num |= num >> 4; num |= num >> 8; + num |= num >> 16; + + return ++num; + } + + + static inline void convertMode(const SDL_DisplayMode& mode, WsiMode* pMode) { + pMode->width = uint32_t(mode.w); + pMode->height = uint32_t(mode.h); + pMode->refreshRate = WsiRational{ uint32_t(mode.refresh_rate) * 1000, 1000 }; + // BPP should always be a power of two + // to match Windows behaviour of including padding. + pMode->bitsPerPixel = roundToNextPow2(SDL_BITSPERPIXEL(mode.format)); + pMode->interlaced = false; + } + + + bool getDisplayMode( + HMONITOR hMonitor, + uint32_t ModeNumber, + WsiMode* pMode) { + const int32_t displayId = fromHmonitor(hMonitor); + + if (!isDisplayValid(displayId)) + return false; + + SDL_DisplayMode mode = { }; + if (SDL_GetDisplayMode(displayId, ModeNumber, &mode) != 0) + return false; + + convertMode(mode, pMode); + + return true; + } + + + bool getCurrentDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode) { + const int32_t displayId = fromHmonitor(hMonitor); + + if (!isDisplayValid(displayId)) + return false; + + SDL_DisplayMode mode = { }; + if (SDL_GetCurrentDisplayMode(displayId, &mode) != 0) { + Logger::err(str::format("SDL_GetCurrentDisplayMode: ", SDL_GetError())); + return false; + } + + convertMode(mode, pMode); + + return true; + } + + + bool getDesktopDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode) { + const int32_t displayId = fromHmonitor(hMonitor); + + if (!isDisplayValid(displayId)) + return false; + + SDL_DisplayMode mode = { }; + if (SDL_GetDesktopDisplayMode(displayId, &mode) != 0) { + Logger::err(str::format("SDL_GetCurrentDisplayMode: ", SDL_GetError())); + return false; + } + + convertMode(mode, pMode); + + return true; + } + +} \ No newline at end of file diff --git a/src/wsi/sdl2/wsi_monitor_sdl2.cpp b/src/wsi/sdl2/wsi_monitor_sdl2.cpp new file mode 100644 index 00000000..ea2c8ae4 --- /dev/null +++ b/src/wsi/sdl2/wsi_monitor_sdl2.cpp @@ -0,0 +1,59 @@ +#include "../wsi_monitor.h" + +#include "wsi_helpers_sdl2.h" + +#include +#include + +#include +#include + +namespace dxvk::wsi { + + HMONITOR enumMonitors(uint32_t index) { + return isDisplayValid(int32_t(index)) + ? toHmonitor(index) + : nullptr; + } + + + bool getDisplayName( + HMONITOR hMonitor, + WCHAR (&Name)[32]) { + const int32_t displayId = fromHmonitor(hMonitor); + + if (!isDisplayValid(displayId)) + return false; + + std::wstringstream nameStream; + nameStream << LR"(\\.\DISPLAY)" << (displayId + 1); + + std::wstring name = nameStream.str(); + + std::memset(Name, 0, sizeof(Name)); + name.copy(Name, name.length(), 0); + + return true; + } + + + bool getDesktopCoordinates( + HMONITOR hMonitor, + RECT* pRect) { + const int32_t displayId = fromHmonitor(hMonitor); + + if (!isDisplayValid(displayId)) + return false; + + SDL_Rect rect = { }; + SDL_GetDisplayBounds(displayId, &rect); + + pRect->left = rect.x; + pRect->top = rect.y; + pRect->right = rect.x + rect.w; + pRect->bottom = rect.y + rect.h; + + return true; + } + +} \ No newline at end of file diff --git a/src/wsi/sdl2/wsi_presenter_sdl2.cpp b/src/wsi/sdl2/wsi_presenter_sdl2.cpp new file mode 100644 index 00000000..1bf222f3 --- /dev/null +++ b/src/wsi/sdl2/wsi_presenter_sdl2.cpp @@ -0,0 +1,21 @@ +#include "../wsi_presenter.h" + +#include +#include + +#include + +namespace dxvk::wsi { + + VkResult createSurface( + HWND hWindow, + const Rc& vki, + VkSurfaceKHR* pSurface) { + SDL_Window* window = fromHwnd(hWindow); + + return SDL_Vulkan_CreateSurface(window, vki->instance(), pSurface) + ? VK_SUCCESS + : VK_ERROR_OUT_OF_HOST_MEMORY; + } + +} \ No newline at end of file diff --git a/src/wsi/sdl2/wsi_window_sdl2.cpp b/src/wsi/sdl2/wsi_window_sdl2.cpp new file mode 100644 index 00000000..a2ba7c6a --- /dev/null +++ b/src/wsi/sdl2/wsi_window_sdl2.cpp @@ -0,0 +1,134 @@ +#include "../wsi_window.h" + +#include "wsi_helpers_sdl2.h" + +#include +#include + +#include "../../util/util_string.h" +#include "../../util/log/log.h" + +namespace dxvk::wsi { + + void getWindowSize( + HWND hWindow, + uint32_t* pWidth, + uint32_t* pHeight) { + SDL_Window* window = fromHwnd(hWindow); + + int32_t w, h; + SDL_GetWindowSize(window, &w, &h); + + if (pWidth) + *pWidth = uint32_t(w); + + if (pHeight) + *pHeight = uint32_t(h); + } + + + void resizeWindow( + HWND hWindow, + DxvkWindowState* pState, + uint32_t Width, + uint32_t Height) { + SDL_Window* window = fromHwnd(hWindow); + + SDL_SetWindowSize(window, int32_t(Width), int32_t(Height)); + } + + + bool setWindowMode( + HMONITOR hMonitor, + HWND hWindow, + const WsiMode* pMode, + bool EnteringFullscreen) { + const int32_t displayId = fromHmonitor(hMonitor); + SDL_Window* window = fromHwnd(hWindow); + + if (!isDisplayValid(displayId)) + return false; + + SDL_DisplayMode wantedMode = { }; + wantedMode.w = pMode->width; + wantedMode.h = pMode->height; + wantedMode.refresh_rate = pMode->refreshRate.numerator != 0 + ? pMode->refreshRate.numerator / pMode->refreshRate.denominator + : 0; + // TODO: Implement lookup format for bitsPerPixel here. + + SDL_DisplayMode mode = { }; + if (SDL_GetClosestDisplayMode(displayId, &wantedMode, &mode) == nullptr) { + Logger::err(str::format("SDL2 WSI: setWindowMode: SDL_GetClosestDisplayMode: ", SDL_GetError())); + return false; + } + + if (SDL_SetWindowDisplayMode(window, &mode) != 0) { + Logger::err(str::format("SDL2 WSI: setWindowMode: SDL_SetWindowDisplayMode: ", SDL_GetError())); + return false; + } + + return true; + } + + + + bool enterFullscreenMode( + HMONITOR hMonitor, + HWND hWindow, + DxvkWindowState* pState, + bool ModeSwitch) { + const int32_t displayId = fromHmonitor(hMonitor); + SDL_Window* window = fromHwnd(hWindow); + + if (!isDisplayValid(displayId)) + return false; + + uint32_t flags = ModeSwitch + ? SDL_WINDOW_FULLSCREEN + : SDL_WINDOW_FULLSCREEN_DESKTOP; + + // TODO: Set this on the correct monitor. + // Docs aren't clear on this... + if (SDL_SetWindowFullscreen(window, flags) != 0) { + Logger::err(str::format("SDL2 WSI: enterFullscreenMode: SDL_SetWindowFullscreen: ", SDL_GetError())); + return false; + } + + return true; + } + + + bool leaveFullscreenMode( + HWND hWindow, + DxvkWindowState* pState) { + SDL_Window* window = fromHwnd(hWindow); + + if (SDL_SetWindowFullscreen(window, 0) != 0) { + Logger::err(str::format("SDL2 WSI: leaveFullscreenMode: SDL_SetWindowFullscreen: ", SDL_GetError())); + return false; + } + + return true; + } + + + bool restoreDisplayMode(HMONITOR hMonitor) { + return true; + } + + + HMONITOR getWindowMonitor(HWND hWindow) { + SDL_Window* window = fromHwnd(hWindow); + const int32_t displayId = SDL_GetWindowDisplayIndex(window); + + return toHmonitor(displayId); + } + + + bool isWindow(HWND hWindow) { + SDL_Window* window = fromHwnd(hWindow); + return window != nullptr; + } + +} \ No newline at end of file diff --git a/src/wsi/win32/wsi_mode_win32.cpp b/src/wsi/win32/wsi_mode_win32.cpp new file mode 100644 index 00000000..45987945 --- /dev/null +++ b/src/wsi/win32/wsi_mode_win32.cpp @@ -0,0 +1,62 @@ +#include "../wsi_mode.h" + +#include "../../util/log/log.h" + +namespace dxvk::wsi { + + static inline void convertMode(const DEVMODEW& mode, WsiMode* pMode) { + pMode->width = mode.dmPelsWidth; + pMode->height = mode.dmPelsHeight; + pMode->refreshRate = WsiRational{ mode.dmDisplayFrequency * 1000, 1000 }; + pMode->bitsPerPixel = mode.dmBitsPerPel; + pMode->interlaced = mode.dmDisplayFlags & DM_INTERLACED; + } + + + static inline bool retrieveDisplayMode( + HMONITOR hMonitor, + DWORD ModeNumber, + WsiMode* pMode) { + // Query monitor info to get the device name + ::MONITORINFOEXW monInfo; + monInfo.cbSize = sizeof(monInfo); + + if (!::GetMonitorInfoW(hMonitor, reinterpret_cast(&monInfo))) { + Logger::err("Win32 WSI: retrieveDisplayMode: Failed to query monitor info"); + return false; + } + + DEVMODEW devMode = { }; + devMode.dmSize = sizeof(devMode); + + if (!::EnumDisplaySettingsW(monInfo.szDevice, ModeNumber, &devMode)) + return false; + + convertMode(devMode, pMode); + + return true; + } + + + bool getDisplayMode( + HMONITOR hMonitor, + uint32_t ModeNumber, + WsiMode* pMode) { + return retrieveDisplayMode(hMonitor, ModeNumber, pMode); + } + + + bool getCurrentDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode) { + return retrieveDisplayMode(hMonitor, ENUM_CURRENT_SETTINGS, pMode); + } + + + bool getDesktopDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode) { + return retrieveDisplayMode(hMonitor, ENUM_REGISTRY_SETTINGS, pMode); + } + +} \ No newline at end of file diff --git a/src/wsi/win32/wsi_monitor_win32.cpp b/src/wsi/win32/wsi_monitor_win32.cpp new file mode 100644 index 00000000..9c99fd57 --- /dev/null +++ b/src/wsi/win32/wsi_monitor_win32.cpp @@ -0,0 +1,52 @@ +#include "../wsi_monitor.h" + +#include "../../util/log/log.h" + +#include + +namespace dxvk::wsi { + + HMONITOR enumMonitors(uint32_t index) { + // TODO: Multi monitor support. + if (index > 0) + return nullptr; + + return ::MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); + } + + + bool getDisplayName( + HMONITOR hMonitor, + WCHAR (&Name)[32]) { + // Query monitor info to get the device name + ::MONITORINFOEXW monInfo; + monInfo.cbSize = sizeof(monInfo); + + if (!::GetMonitorInfoW(hMonitor, reinterpret_cast(&monInfo))) { + Logger::err("Win32 WSI: getDisplayName: Failed to query monitor info"); + return false; + } + + std::memcpy(Name, monInfo.szDevice, sizeof(Name)); + + return true; + } + + + bool getDesktopCoordinates( + HMONITOR hMonitor, + RECT* pRect) { + ::MONITORINFOEXW monInfo; + monInfo.cbSize = sizeof(monInfo); + + if (!::GetMonitorInfoW(hMonitor, reinterpret_cast(&monInfo))) { + Logger::err("Win32 WSI: getDisplayName: Failed to query monitor info"); + return false; + } + + *pRect = monInfo.rcMonitor; + + return true; + } + +} \ No newline at end of file diff --git a/src/wsi/win32/wsi_presenter_win32.cpp b/src/wsi/win32/wsi_presenter_win32.cpp new file mode 100644 index 00000000..b3ff9b5a --- /dev/null +++ b/src/wsi/win32/wsi_presenter_win32.cpp @@ -0,0 +1,23 @@ +#include "../wsi_presenter.h" + +namespace dxvk::wsi { + + VkResult createSurface( + HWND hWindow, + const Rc& vki, + VkSurfaceKHR* pSurface) { + HINSTANCE hInstance = reinterpret_cast( + GetWindowLongPtr(hWindow, GWLP_HINSTANCE)); + + VkWin32SurfaceCreateInfoKHR info; + info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + info.pNext = nullptr; + info.flags = 0; + info.hinstance = hInstance; + info.hwnd = hWindow; + + return vki->vkCreateWin32SurfaceKHR( + vki->instance(), &info, nullptr, pSurface); + } + +} \ No newline at end of file diff --git a/src/wsi/win32/wsi_window_win32.cpp b/src/wsi/win32/wsi_window_win32.cpp new file mode 100644 index 00000000..8369bae1 --- /dev/null +++ b/src/wsi/win32/wsi_window_win32.cpp @@ -0,0 +1,187 @@ +#include "../wsi_window.h" +#include "../wsi_mode.h" +#include "../wsi_monitor.h" + +#include "../../util/util_string.h" +#include "../../util/log/log.h" + +namespace dxvk::wsi { + + void getWindowSize( + HWND hWindow, + uint32_t* pWidth, + uint32_t* pHeight) { + RECT rect = { }; + ::GetClientRect(hWindow, &rect); + + if (pWidth) + *pWidth = rect.right - rect.left; + + if (pHeight) + *pHeight = rect.bottom - rect.top; + } + + + void resizeWindow( + HWND hWindow, + DxvkWindowState* pState, + uint32_t Width, + uint32_t Height) { + // Adjust window position and size + RECT newRect = { 0, 0, 0, 0 }; + RECT oldRect = { 0, 0, 0, 0 }; + + ::GetWindowRect(hWindow, &oldRect); + ::SetRect(&newRect, 0, 0, Width, Height); + ::AdjustWindowRectEx(&newRect, + ::GetWindowLongW(hWindow, GWL_STYLE), FALSE, + ::GetWindowLongW(hWindow, GWL_EXSTYLE)); + ::SetRect(&newRect, 0, 0, newRect.right - newRect.left, newRect.bottom - newRect.top); + ::OffsetRect(&newRect, oldRect.left, oldRect.top); + ::MoveWindow(hWindow, newRect.left, newRect.top, + newRect.right - newRect.left, newRect.bottom - newRect.top, TRUE); + } + + + bool setWindowMode( + HMONITOR hMonitor, + HWND hWindow, + const WsiMode* pMode, + bool EnteringFullscreen) { + ::MONITORINFOEXW monInfo; + monInfo.cbSize = sizeof(monInfo); + + if (!::GetMonitorInfoW(hMonitor, reinterpret_cast(&monInfo))) { + Logger::err("Win32 WSI: setWindowMode: Failed to query monitor info"); + return false; + } + + DEVMODEW devMode = { }; + devMode.dmSize = sizeof(devMode); + devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; + devMode.dmPelsWidth = pMode->width; + devMode.dmPelsHeight = pMode->height; + devMode.dmBitsPerPel = pMode->bitsPerPixel; + + if (pMode->refreshRate.numerator != 0) { + devMode.dmFields |= DM_DISPLAYFREQUENCY; + devMode.dmDisplayFrequency = pMode->refreshRate.numerator + / pMode->refreshRate.denominator; + } + + Logger::info(str::format("Setting display mode: ", + devMode.dmPelsWidth, "x", devMode.dmPelsHeight, "@", + devMode.dmDisplayFrequency)); + + LONG status = ::ChangeDisplaySettingsExW( + monInfo.szDevice, &devMode, nullptr, CDS_FULLSCREEN, nullptr); + + if (status != DISP_CHANGE_SUCCESSFUL && pMode->refreshRate.numerator != 0) { + // Let's try again without display freq + // if that failed. + + devMode.dmFields &= ~DM_DISPLAYFREQUENCY; + + status = ::ChangeDisplaySettingsExW( + monInfo.szDevice, &devMode, nullptr, CDS_FULLSCREEN, nullptr); + } + + if (!EnteringFullscreen && hWindow != nullptr) { + RECT newRect = { }; + getDesktopCoordinates(hMonitor, &newRect); + + ::MoveWindow(hWindow, newRect.left, newRect.top, + newRect.right - newRect.left, newRect.bottom - newRect.top, TRUE); + } + + return status == DISP_CHANGE_SUCCESSFUL; + } + + + bool enterFullscreenMode( + HMONITOR hMonitor, + HWND hWindow, + DxvkWindowState* pState, + bool ModeSwitch) { + // Find a display mode that matches what we need + ::GetWindowRect(hWindow, &pState->rect); + + // Change the window flags to remove the decoration etc. + LONG style = ::GetWindowLongW(hWindow, GWL_STYLE); + LONG exstyle = ::GetWindowLongW(hWindow, GWL_EXSTYLE); + + pState->style = style; + pState->exstyle = exstyle; + + style &= ~WS_OVERLAPPEDWINDOW; + exstyle &= ~WS_EX_OVERLAPPEDWINDOW; + + ::SetWindowLongW(hWindow, GWL_STYLE, style); + ::SetWindowLongW(hWindow, GWL_EXSTYLE, exstyle); + + RECT rect = { }; + getDesktopCoordinates(hMonitor, &rect); + + ::SetWindowPos(hWindow, HWND_TOPMOST, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE); + + return true; + } + + + bool leaveFullscreenMode( + HWND hWindow, + DxvkWindowState* pState) { + // Only restore the window style if the application hasn't + // changed them. This is in line with what native DXGI does. + LONG curStyle = ::GetWindowLongW(hWindow, GWL_STYLE) & ~WS_VISIBLE; + LONG curExstyle = ::GetWindowLongW(hWindow, GWL_EXSTYLE) & ~WS_EX_TOPMOST; + + if (curStyle == (pState->style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW)) + && curExstyle == (pState->exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) { + ::SetWindowLongW(hWindow, GWL_STYLE, pState->style); + ::SetWindowLongW(hWindow, GWL_EXSTYLE, pState->exstyle); + } + + // Restore window position and apply the style + const RECT rect = pState->rect; + + ::SetWindowPos(hWindow, 0, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE); + + return true; + } + + + bool restoreDisplayMode(HMONITOR hMonitor) { + if (!hMonitor) + return false; + + WsiMode desktopMode = { }; + if (!getDesktopDisplayMode(hMonitor, &desktopMode)) + return false; + + return setWindowMode(hMonitor, nullptr, &desktopMode, false); + } + + + HMONITOR getWindowMonitor(HWND hWindow) { + RECT windowRect = { 0, 0, 0, 0 }; + ::GetWindowRect(hWindow, &windowRect); + + HMONITOR monitor = ::MonitorFromPoint( + { (windowRect.left + windowRect.right) / 2, + (windowRect.top + windowRect.bottom) / 2 }, + MONITOR_DEFAULTTOPRIMARY); + + return monitor; + } + + + bool isWindow(HWND hWindow) { + return ::IsWindow(hWindow); + } + +} \ No newline at end of file diff --git a/src/wsi/wsi_mode.h b/src/wsi/wsi_mode.h new file mode 100644 index 00000000..56ac18aa --- /dev/null +++ b/src/wsi/wsi_mode.h @@ -0,0 +1,70 @@ +#pragma once + +#include + +#include + +#include "wsi_monitor.h" + +namespace dxvk::wsi { + + /** + * \brief Rational number. Eg. 2/3 + */ + struct WsiRational { + uint32_t numerator; + uint32_t denominator; + }; + + /** + * \brief Display mode + */ + struct WsiMode { + uint32_t width; + uint32_t height; + WsiRational refreshRate; + uint32_t bitsPerPixel; + bool interlaced; + }; + + /** + * \brief Get the nth display mode + * + * \param [in] hMonitor The monitor + * \param [in] ModeNumber The nth mode + * \param [out] pMode The resultant mode + * \returns \c true on success, \c false if the mode could not be found + */ + bool getDisplayMode( + HMONITOR hMonitor, + uint32_t ModeNumber, + WsiMode* pMode); + + /** + * \brief Get the current display mode + * + * This is the display mode right now. + * + * \param [in] hMonitor The monitor + * \param [out] pMode The resultant mode + * \returns \c true on success, \c false on failure + */ + bool getCurrentDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode); + + /** + * \brief Get the current display mode + * + * This is the display mode of the user's + * default desktop. + * + * \param [in] hMonitor The monitor + * \param [out] pMode The resultant mode + * \returns \c true on success, \c false on failure + */ + bool getDesktopDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode); + +} \ No newline at end of file diff --git a/src/wsi/wsi_monitor.h b/src/wsi/wsi_monitor.h new file mode 100644 index 00000000..1cf661ac --- /dev/null +++ b/src/wsi/wsi_monitor.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include + +namespace dxvk::wsi { + + /** + * \brief Enumerators monitors on the system + * + * \returns The monitor of given index + */ + HMONITOR enumMonitors(uint32_t index); + + /** + * \brief Get the GDI name of a HMONITOR + * + * Get the GDI Device Name of a HMONITOR to + * return to the end user. + * + * This typically looks like \.\\DISPLAY1 + * and has a maximum length of 32 chars. + * + * \param [in] hMonitor The monitor + * \param [out] Name The GDI display name + * \returns \c true on success, \c false if an error occured + */ + bool getDisplayName( + HMONITOR hMonitor, + WCHAR (&Name)[32]); + + /** + * \brief Get the encompassing coords of a monitor + */ + bool getDesktopCoordinates( + HMONITOR hMonitor, + RECT* pRect); + +} \ No newline at end of file diff --git a/src/wsi/wsi_presenter.h b/src/wsi/wsi_presenter.h new file mode 100644 index 00000000..152d05a5 --- /dev/null +++ b/src/wsi/wsi_presenter.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "../vulkan/vulkan_loader.h" + +namespace dxvk::wsi { + + /** + * \brief Create a surface for a window + * + * \param [in] hWindow The window + * \param [in] vki The instance + * \param [out] pSurface The surface + */ + VkResult createSurface( + HWND hWindow, + const Rc& vki, + VkSurfaceKHR* pSurface); + +} \ No newline at end of file diff --git a/src/wsi/wsi_window.h b/src/wsi/wsi_window.h new file mode 100644 index 00000000..5de022b2 --- /dev/null +++ b/src/wsi/wsi_window.h @@ -0,0 +1,115 @@ +#pragma once + +// The windows.h will define HWND/HMONITOR +// to be types that it wants for the wsi we are compiling against. +// ie. HWND = their own window data ptr (eg. SDL_Window) +// HMONTIOR = their own monitor data ptr/a display index + +#include + +#include "wsi_mode.h" + +namespace dxvk::wsi { + + /** + * \brief Impl-dependent state + */ + struct DxvkWindowState { +#ifdef DXVK_WSI_WIN32 + LONG style = 0; + LONG exstyle = 0; + RECT rect = { 0, 0, 0, 0 }; +#endif + }; + + /** + * \brief The size of the window + * + * \param [in] hWindow The window + * \param [out] pWidth The width (optional) + * \param [out] pHeight The height (optional) + */ + void getWindowSize( + HWND hWindow, + uint32_t* pWidth, + uint32_t* pWeight); + + /** + * \brief Resize a window + * + * \param [in] hWindow The window + * \param [in] pState The swapchain's window state + * \param [in] Width The new width + * \param [in] Height The new height + */ + void resizeWindow( + HWND hWindow, + DxvkWindowState* pState, + uint32_t Width, + uint32_t Height); + + /** + * \brief Sets the display mode for a window/monitor + * + * \param [in] hMonitor The monitor + * \param [in] hWindow The window + * \param [in] pMode The mode + * \param [in] EnteringFullscreen Are we entering fullscreen? + * \returns \c true on success, \c false on failure + */ + bool setWindowMode( + HMONITOR hMonitor, + HWND hWindow, + const WsiMode* pMode, + bool EnteringFullscreen); + + /** + * \brief Enter fullscreen mode for a window & monitor + * + * \param [in] hMonitor The monitor + * \param [in] hWindow The window + * \param [in] pState The swapchain's window state + * \param [in] ModeSwitch Whether mode switching is allowed + * \returns \c true on success, \c false on failure + */ + bool enterFullscreenMode( + HMONITOR hMonitor, + HWND hWindow, + DxvkWindowState* pState, + bool ModeSwitch); + + /** + * \brief Exit fullscreen mode for a window + * + * \param [in] hWindow The window + * \param [in] pState The swapchain's window state + * \returns \c true on success, \c false on failure + */ + bool leaveFullscreenMode( + HWND hWindow, + DxvkWindowState* pState); + + /** + * \brief Restores the display mode if necessary + * + * \param [in] hMonitor The monitor to restore the mode of + * \returns \c true on success, \c false on failure + */ + bool restoreDisplayMode(HMONITOR hMonitor); + + /** + * \brief The monitor a window is on + * + * \param [in] hWindow The window + * \returns The monitor the window is on + */ + HMONITOR getWindowMonitor(HWND hWindow); + + /** + * \brief Is a HWND a window? + * + * \param [in] hWindow The window + * \returns Is it a window? + */ + bool isWindow(HWND hWindow); +} \ No newline at end of file