From 39fb0334590e8ec2bb3f4152515f5f8e5a5a0650 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 22:41:10 +0000 Subject: [PATCH 01/32] [build] Simplify src/meson.build Makes this slightly more readable and extensible if we have any other edgecases where we wanna force-disable a frontend. --- src/meson.build | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/meson.build b/src/meson.build index c5d2753a..5cf4b6aa 100644 --- a/src/meson.build +++ b/src/meson.build @@ -3,34 +3,40 @@ subdir('spirv') 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_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 From 7d9acf37f29784debee53c46c412e2e677d74abf Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 22:43:29 +0000 Subject: [PATCH 02/32] [build] Setup base build scripts for native building Determine WSI/Platform and store in a variable from later on. Add some options to force native/a specific wsi. --- meson.build | 32 +++++++++++++++++++++++++++++++- meson_options.txt | 3 +++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 24e04e61..aa79aa1b 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 @@ -85,8 +91,28 @@ else 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() + + 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') + res_ext = '' + exe_ext = '' + dll_ext = '' + def_spec_ext = '.def' + so_prefix = 'lib' 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 +122,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.') From d2649af41517d9d087c1116856e6d22ae309c323 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 22:44:18 +0000 Subject: [PATCH 03/32] [build] Ignore D3D10 for DXVK Native We can't ever use this frontend as its super quirky (intergrates with shader compiler and stuff) No need to support it either as going from D3D10 -> D3D11 is a piece of cake --- src/meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/meson.build b/src/meson.build index 5cf4b6aa..dea61ffa 100644 --- a/src/meson.build +++ b/src/meson.build @@ -9,6 +9,11 @@ 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.') From c573230babe7acc0a59841362e0e7e462d611542 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 22:46:12 +0000 Subject: [PATCH 04/32] [include] Basic Windows headers/definitions for native Includes some basic defs/hresults etc A setup for implementing __uuidof is also included using constexpr + templates --- include/native/directx/README.txt | 1 + include/native/windows/oaidl.h | 3 + include/native/windows/objbase.h | 3 + include/native/windows/ocidl.h | 3 + include/native/windows/ole2.h | 3 + include/native/windows/rpc.h | 3 + include/native/windows/rpcndr.h | 3 + include/native/windows/unknwn.h | 16 ++ include/native/windows/windows.h | 4 + include/native/windows/windows_base.h | 239 ++++++++++++++++++++++++++ 10 files changed, 278 insertions(+) create mode 100644 include/native/directx/README.txt create mode 100644 include/native/windows/oaidl.h create mode 100644 include/native/windows/objbase.h create mode 100644 include/native/windows/ocidl.h create mode 100644 include/native/windows/ole2.h create mode 100644 include/native/windows/rpc.h create mode 100644 include/native/windows/rpcndr.h create mode 100644 include/native/windows/unknwn.h create mode 100644 include/native/windows/windows.h create mode 100644 include/native/windows/windows_base.h diff --git a/include/native/directx/README.txt b/include/native/directx/README.txt new file mode 100644 index 00000000..f9626ecf --- /dev/null +++ b/include/native/directx/README.txt @@ -0,0 +1 @@ +Put your DirectX headers in here. These cannot be redisted due to current licensing reasons. \ 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..c5ca0ee0 --- /dev/null +++ b/include/native/windows/windows_base.h @@ -0,0 +1,239 @@ +#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 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 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 From 56780182939b0c977cb775554523832898e4deb7 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 22:47:50 +0000 Subject: [PATCH 05/32] [include] Implement SDL2 wsi helpers --- include/native/windows/windows.h | 10 +++++++++- include/native/wsi/native_sdl2.h | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 include/native/wsi/native_sdl2.h diff --git a/include/native/windows/windows.h b/include/native/windows/windows.h index 5ffa7b21..c56e4c4a 100644 --- a/include/native/windows/windows.h +++ b/include/native/windows/windows.h @@ -1,4 +1,12 @@ #pragma once #include "windows_base.h" -#include "unknwn.h" \ No newline at end of file +#include "unknwn.h" + +#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/native/wsi/native_sdl2.h b/include/native/wsi/native_sdl2.h new file mode 100644 index 00000000..a27de072 --- /dev/null +++ b/include/native/wsi/native_sdl2.h @@ -0,0 +1,15 @@ +#include "windows_base.h" + +using HWND = SDL_Window*; + +// Offset so null HMONITORs go to -1 +inline int32_t monitor_cast(HMONITOR hMonitor) { + return static_cast(reinterpret_cast(hMonitor)) - 1; +} + +// Offset so -1 display id goes to 0 == NULL +inline HMONITOR monitor_cast(int32_t displayId) { + return reinterpret_cast(static_cast(displayId + 1)); +} + +inline BOOL IsWindow(HWND hWnd) { return hWnd != nullptr; } \ No newline at end of file From e210ed0d8e07838593fcdd99fdc761cf32a4e11e Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 22:51:25 +0000 Subject: [PATCH 06/32] [wsi] Implement WSI abstraction module --- src/meson.build | 1 + src/wsi/meson.build | 22 ++++ src/wsi/win32/wsi_mode_win32.cpp | 62 +++++++++ src/wsi/win32/wsi_monitor_win32.cpp | 52 ++++++++ src/wsi/win32/wsi_presenter_win32.cpp | 23 ++++ src/wsi/win32/wsi_window_win32.cpp | 182 ++++++++++++++++++++++++++ src/wsi/wsi_mode.h | 70 ++++++++++ src/wsi/wsi_monitor.h | 40 ++++++ src/wsi/wsi_presenter.h | 21 +++ src/wsi/wsi_window.h | 108 +++++++++++++++ 10 files changed, 581 insertions(+) create mode 100644 src/wsi/meson.build create mode 100644 src/wsi/win32/wsi_mode_win32.cpp create mode 100644 src/wsi/win32/wsi_monitor_win32.cpp create mode 100644 src/wsi/win32/wsi_presenter_win32.cpp create mode 100644 src/wsi/win32/wsi_window_win32.cpp create mode 100644 src/wsi/wsi_mode.h create mode 100644 src/wsi/wsi_monitor.h create mode 100644 src/wsi/wsi_presenter.h create mode 100644 src/wsi/wsi_window.h diff --git a/src/meson.build b/src/meson.build index dea61ffa..895eae2a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,5 +1,6 @@ subdir('util') subdir('spirv') +subdir('wsi') subdir('vulkan') subdir('dxvk') diff --git a/src/wsi/meson.build b/src/wsi/meson.build new file mode 100644 index 00000000..58ca2a72 --- /dev/null +++ b/src/wsi/meson.build @@ -0,0 +1,22 @@ +wsi_win32_src = [ + 'win32/wsi_mode_win32.cpp', + 'win32/wsi_monitor_win32.cpp', + 'win32/wsi_presenter_win32.cpp', + 'win32/wsi_window_win32.cpp', +] + +if dxvk_wsi == 'win32' + wsi_src = wsi_win32_src + wsi_deps = [] +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/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..73085247 --- /dev/null +++ b/src/wsi/win32/wsi_window_win32.cpp @@ -0,0 +1,182 @@ +#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; + } + +} \ 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..f7f76d69 --- /dev/null +++ b/src/wsi/wsi_window.h @@ -0,0 +1,108 @@ +#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); + +} \ No newline at end of file From e20e99e2e6567c71818f236a533c34cab417a6aa Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 22:51:43 +0000 Subject: [PATCH 07/32] [wsi] Implement SDL2 WSI --- src/wsi/meson.build | 10 +++ src/wsi/sdl2/wsi_helpers_sdl2.h | 16 ++++ src/wsi/sdl2/wsi_mode_sdl2.cpp | 93 ++++++++++++++++++++++ src/wsi/sdl2/wsi_monitor_sdl2.cpp | 58 ++++++++++++++ src/wsi/sdl2/wsi_presenter_sdl2.cpp | 17 ++++ src/wsi/sdl2/wsi_window_sdl2.cpp | 118 ++++++++++++++++++++++++++++ 6 files changed, 312 insertions(+) create mode 100644 src/wsi/sdl2/wsi_helpers_sdl2.h create mode 100644 src/wsi/sdl2/wsi_mode_sdl2.cpp create mode 100644 src/wsi/sdl2/wsi_monitor_sdl2.cpp create mode 100644 src/wsi/sdl2/wsi_presenter_sdl2.cpp create mode 100644 src/wsi/sdl2/wsi_window_sdl2.cpp diff --git a/src/wsi/meson.build b/src/wsi/meson.build index 58ca2a72..6ab147be 100644 --- a/src/wsi/meson.build +++ b/src/wsi/meson.build @@ -5,9 +5,19 @@ wsi_win32_src = [ '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 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..cfb06964 --- /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, + DWORD ModeNumber, + WsiMode* pMode) { + const int32_t displayId = monitor_cast(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 = monitor_cast(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 = monitor_cast(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..ff59bffd --- /dev/null +++ b/src/wsi/sdl2/wsi_monitor_sdl2.cpp @@ -0,0 +1,58 @@ +#include "../wsi_monitor.h" + +#include "wsi_helpers_sdl2.h" + +#include + +#include +#include + +namespace dxvk::wsi { + + HMONITOR enumMonitors(uint32_t index) { + return isDisplayValid(int32_t(index)) + ? monitor_cast(index) + : nullptr; + } + + + bool getDisplayName( + HMONITOR hMonitor, + WCHAR (&Name)[32]) { + const int32_t displayId = monitor_cast(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 = monitor_cast(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..5af8f193 --- /dev/null +++ b/src/wsi/sdl2/wsi_presenter_sdl2.cpp @@ -0,0 +1,17 @@ +#include "../wsi_presenter.h" + +#include +#include + +namespace dxvk::wsi { + + VkResult createSurface( + HWND hWindow, + const Rc& vki, + VkSurfaceKHR* pSurface) { + return SDL_Vulkan_CreateSurface(hWindow, 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..d911b1cf --- /dev/null +++ b/src/wsi/sdl2/wsi_window_sdl2.cpp @@ -0,0 +1,118 @@ +#include "../wsi_window.h" + +#include "wsi_helpers_sdl2.h" + +#include + +#include "../../util/util_string.h" +#include "../../util/log/log.h" + +namespace dxvk::wsi { + + void getWindowSize( + HWND hWindow, + uint32_t* pWidth, + uint32_t* pHeight) { + int32_t w, h; + SDL_GetWindowSize(hWindow, &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_SetWindowSize(hWindow, int32_t(Width), int32_t(Height)); + } + + + bool setWindowMode( + HMONITOR hMonitor, + HWND hWindow, + const WsiMode* pMode, + bool EnteringFullscreen) { + const int32_t displayId = monitor_cast(hMonitor); + + 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(hWindow, &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 = monitor_cast(hMonitor); + + 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(hWindow, flags) != 0) { + Logger::err(str::format("SDL2 WSI: enterFullscreenMode: SDL_SetWindowFullscreen: ", SDL_GetError())); + return false; + } + + return true; + } + + + bool leaveFullscreenMode( + HWND hWindow, + DxvkWindowState* pState) { + if (SDL_SetWindowFullscreen(hWindow, 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) { + const int32_t displayId = SDL_GetWindowDisplayIndex(hWindow); + + return monitor_cast(displayId); + } + +} \ No newline at end of file From 55c491525f0aa02e331322cfe817b7a79a30b92e Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 22:52:11 +0000 Subject: [PATCH 08/32] [vulkan] Hook up presenter to new WSI abstraction --- src/vulkan/meson.build | 8 +++++--- src/vulkan/vulkan_loader_fn.h | 3 +++ src/vulkan/vulkan_presenter.cpp | 14 ++------------ 3 files changed, 10 insertions(+), 15 deletions(-) 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..b28eeec1 100644 --- a/src/vulkan/vulkan_loader_fn.h +++ b/src/vulkan/vulkan_loader_fn.h @@ -11,7 +11,10 @@ #undef _WIN32 #endif +#ifdef _WIN32 #define VK_USE_PLATFORM_WIN32_KHR 1 +#endif + #include #ifdef __WINE__ 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; From ca4f2cfcbb5d77e4b54200993f3981217efae196 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:01:18 +0000 Subject: [PATCH 09/32] [util] Move win32 specific implementations to their own files --- src/util/meson.build | 22 ++++++++--- src/util/platform/util_env_win32.cpp | 38 +++++++++++++++++++ .../util_luid_win32.cpp} | 0 .../util_string_win32.cpp} | 0 src/util/util_env.cpp | 34 ----------------- 5 files changed, 54 insertions(+), 40 deletions(-) create mode 100644 src/util/platform/util_env_win32.cpp rename src/util/{util_luid.cpp => platform/util_luid_win32.cpp} (100%) rename src/util/{util_string.cpp => platform/util_string_win32.cpp} (100%) diff --git a/src/util/meson.build b/src/util/meson.build index 80fe0be2..16ac25bd 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -1,8 +1,4 @@ -util_src = files([ - 'util_env.cpp', - 'util_string.cpp', - 'util_gdi.cpp', - 'util_luid.cpp', +util_src = [ 'util_matrix.cpp', 'util_monitor.cpp', @@ -16,7 +12,21 @@ 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' +] + +if dxvk_platform == 'windows' + util_src += util_src_win32 +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/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/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/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/util_env.cpp b/src/util/util_env.cpp index a804de6a..a34c21b6 100644 --- a/src/util/util_env.cpp +++ b/src/util/util_env.cpp @@ -1,7 +1,5 @@ #include "util_env.h" -#include "./com/com_include.h" - namespace dxvk::env { std::string getEnvVar(const char* name) { @@ -20,37 +18,5 @@ namespace dxvk::env { ? 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); - } } From 0a08738c70b0f462160003d9af45ae8a9b266676 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:01:44 +0000 Subject: [PATCH 10/32] [util] Use native directory slash for delimiting exe name --- src/util/util_env.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/util/util_env.cpp b/src/util/util_env.cpp index a34c21b6..84bba040 100644 --- a/src/util/util_env.cpp +++ b/src/util/util_env.cpp @@ -2,6 +2,13 @@ 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) @@ -12,7 +19,7 @@ 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) From ae59643b5ad6b8880761c643b6fbd0647b282968 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:03:04 +0000 Subject: [PATCH 11/32] [util] Native linux implementations Use native std::threads, ids using a counter --- src/util/meson.build | 10 ++++++++++ src/util/platform/thread_native.cpp | 21 +++++++++++++++++++++ src/util/platform/util_env_linux.cpp | 25 +++++++++++++++++++++++++ src/util/platform/util_luid_linux.cpp | 13 +++++++++++++ src/util/platform/util_string_linux.cpp | 19 +++++++++++++++++++ src/util/thread.h | 25 ++++++++++++++++++++++++- 6 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/util/platform/thread_native.cpp create mode 100644 src/util/platform/util_env_linux.cpp create mode 100644 src/util/platform/util_luid_linux.cpp create mode 100644 src/util/platform/util_string_linux.cpp diff --git a/src/util/meson.build b/src/util/meson.build index 16ac25bd..855692eb 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -1,4 +1,5 @@ util_src = [ + 'util_env.cpp', 'util_matrix.cpp', 'util_monitor.cpp', @@ -22,8 +23,17 @@ util_src_win32 = [ '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 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_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/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/thread.h b/src/util/thread.h index c96cb1c0..11f1a17a 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" +#ifdef DXVK_NATIVE +#include +#endif + namespace dxvk { +#ifndef DXVK_NATIVE /** * \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 + } From 3edf98cd32b11b5f6cd71ae29f67c9f28c4d4085 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:04:17 +0000 Subject: [PATCH 12/32] [dxvk] Implement SDL2 WSI Disable OpenVR for this WSI also. --- src/dxvk/dxvk_instance.cpp | 2 + src/dxvk/meson.build | 24 ++++++++--- src/dxvk/platform/dxvk_sdl2_exts.cpp | 60 ++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 src/dxvk/platform/dxvk_sdl2_exts.cpp 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/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 From e033609719e9b94cff1682dd7429645cf8a066f0 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:05:07 +0000 Subject: [PATCH 13/32] [dxvk] Disable thread priority for state cache workers when building native Currently unimplemented as there is no real nice way to do so without getting pthread involved. --- src/dxvk/dxvk_state_cache.cpp | 4 ++++ 1 file changed, 4 insertions(+) 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(); }); From 1d6325a139ded2b8e99390f5fb5998c01f1a7994 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:06:44 +0000 Subject: [PATCH 14/32] [dxgi] Hook DXGI up to new WSI abstractions --- src/dxgi/dxgi_adapter.cpp | 9 ++- src/dxgi/dxgi_include.h | 2 +- src/dxgi/dxgi_monitor.cpp | 19 ++++- src/dxgi/dxgi_monitor.h | 39 ++++++++++ src/dxgi/dxgi_output.cpp | 51 ++++++------- src/dxgi/dxgi_swapchain.cpp | 143 ++++++++++-------------------------- src/dxgi/dxgi_swapchain.h | 20 ++--- src/dxgi/meson.build | 2 +- 8 files changed, 133 insertions(+), 152 deletions(-) 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..c7fdcaa9 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) #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..a9a3d560 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; @@ -104,16 +104,8 @@ namespace dxvk { *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); } @@ -285,7 +277,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); @@ -334,19 +326,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 +340,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; @@ -552,11 +526,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 +540,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 +548,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 +577,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 @@ -640,31 +599,19 @@ namespace dxvk { if (!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 +636,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..9ced1ec2 100644 --- a/src/dxgi/meson.build +++ b/src/dxgi/meson.build @@ -14,7 +14,7 @@ dxgi_src = [ dxgi_dll = shared_library('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, From 5aff06e9960e039c629feed0c575d1f95ae58b6e Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:07:13 +0000 Subject: [PATCH 15/32] [build] Fix dxgi's so name on native, and disable definition spec similarly --- src/dxgi/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dxgi/meson.build b/src/dxgi/meson.build index 9ced1ec2..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, 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( From 77a98a04695b2eb867e7235dbbd85fecef5aecdd Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:08:06 +0000 Subject: [PATCH 16/32] [d3d10] Use get_id platform abstraction for device mutex --- src/d3d10/d3d10_multithread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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( From e32a451e72e688da71157701f9f87aa78e5a8e75 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:32:09 +0000 Subject: [PATCH 17/32] [d3d11] Hook up D3D11 to new WSI abstraction --- src/d3d11/d3d11_device.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From b9816db0d70c0390c82de444da727263a5e08b70 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:33:45 +0000 Subject: [PATCH 18/32] [build] Fix d3d11's so name on native, and disable definition spec smilarly --- src/d3d11/meson.build | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index c6f93403..2f0ce3fe 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -63,12 +63,16 @@ 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 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]) From a50b9b729eeba5db4c5f80dd9459dc2a6aa8b42a Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:35:19 +0000 Subject: [PATCH 19/32] [d3d11] Fix MinGW include version checks for native --- src/d3d11/d3d11_include.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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, From f9d68c8c6d64f0ed8d7ddbc52b5af24c93c57e87 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:35:29 +0000 Subject: [PATCH 20/32] [d3d11] Disable apitrace checking for native --- src/d3d11/d3d11_options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 7fc9d35f77d3222f504940cdad5542072d74c67c Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 16 Nov 2019 23:42:48 +0000 Subject: [PATCH 21/32] [d3d11] Disable GDI when building native --- src/d3d11/d3d11_gdi.cpp | 2 ++ src/d3d11/d3d11_texture.cpp | 20 ++++++++++++++------ src/d3d11/meson.build | 9 ++++++++- 3 files changed, 24 insertions(+), 7 deletions(-) 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_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 2f0ce3fe..68f68cfe 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,6 +62,14 @@ d3d11_src = [ 'd3d11_view_uav.cpp', ] +d3d11_src_win32 = [ + 'd3d11_gdi.cpp' +] + +if dxvk_platform == 'windows' + d3d11_src += d3d11_src_win32 +endif + if dxvk_native lib_dxgi = dxgi_dep endif From e6224c8aec5f322cf6c3e027ca5a435bb5923810 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 30 Nov 2019 18:53:30 +0000 Subject: [PATCH 22/32] [d3d11] Make frame latency events/fence code platform agnostic --- src/d3d11/d3d11_swapchain.cpp | 13 +++++++++++-- src/d3d11/d3d11_swapchain.h | 13 ++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) 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; From 8bc619d780d3a4089c7833c53602418b9c2bc34c Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 30 Nov 2019 20:26:49 +0000 Subject: [PATCH 23/32] [wsi] Support building natively on Windows --- include/native/windows/windows.h | 10 +--------- include/native/windows/windows_base.h | 1 + include/native/wsi/native_sdl2.h | 17 +++++++++++----- include/native/wsi/native_wsi.h | 9 +++++++++ meson.build | 19 ++++++++++++------ src/d3d11/meson.build | 10 ++++------ src/dxgi/dxgi_include.h | 2 +- src/dxgi/dxgi_swapchain.cpp | 15 ++++++++------ src/util/thread.h | 4 ++-- src/wsi/sdl2/wsi_mode_sdl2.cpp | 4 ++-- src/wsi/sdl2/wsi_monitor_sdl2.cpp | 1 + src/wsi/sdl2/wsi_presenter_sdl2.cpp | 6 +++++- src/wsi/sdl2/wsi_window_sdl2.cpp | 28 +++++++++++++++++++++------ src/wsi/win32/wsi_window_win32.cpp | 5 +++++ src/wsi/wsi_window.h | 7 +++++++ 15 files changed, 94 insertions(+), 44 deletions(-) create mode 100644 include/native/wsi/native_wsi.h diff --git a/include/native/windows/windows.h b/include/native/windows/windows.h index c56e4c4a..5ffa7b21 100644 --- a/include/native/windows/windows.h +++ b/include/native/windows/windows.h @@ -1,12 +1,4 @@ #pragma once #include "windows_base.h" -#include "unknwn.h" - -#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 +#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 index c5ca0ee0..8bd63a68 100644 --- a/include/native/windows/windows_base.h +++ b/include/native/windows/windows_base.h @@ -71,6 +71,7 @@ using HANDLE = void*; using HMONITOR = HANDLE; using HDC = HANDLE; using HMODULE = HANDLE; +using HWND = HANDLE; using LPSTR = char*; using LPCSTR = const char*; diff --git a/include/native/wsi/native_sdl2.h b/include/native/wsi/native_sdl2.h index a27de072..9494bcba 100644 --- a/include/native/wsi/native_sdl2.h +++ b/include/native/wsi/native_sdl2.h @@ -1,6 +1,15 @@ -#include "windows_base.h" +#include +#include -using HWND = SDL_Window*; +#include + +inline SDL_Window* window_cast(HWND hWindow) { + return reinterpret_cast(hWindow); +} + +inline HWND window_cast(SDL_Window* pWindow) { + return reinterpret_cast(pWindow); +} // Offset so null HMONITORs go to -1 inline int32_t monitor_cast(HMONITOR hMonitor) { @@ -10,6 +19,4 @@ inline int32_t monitor_cast(HMONITOR hMonitor) { // Offset so -1 display id goes to 0 == NULL inline HMONITOR monitor_cast(int32_t displayId) { return reinterpret_cast(static_cast(displayId + 1)); -} - -inline BOOL IsWindow(HWND hWnd) { return hWnd != nullptr; } \ No newline at end of file +} \ 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/meson.build b/meson.build index aa79aa1b..8be1791e 100644 --- a/meson.build +++ b/meson.build @@ -97,17 +97,24 @@ else dxvk_wsi = get_option('dxvk_native_wsi') dxvk_platform = target_machine.system() - 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') + 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 - wrc = find_program('echo') res_ext = '' exe_ext = '' dll_ext = '' def_spec_ext = '.def' - so_prefix = 'lib' endif add_project_arguments('-DDXVK_WSI_' + dxvk_wsi.to_upper(), language : 'cpp') diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index 68f68cfe..72e68a20 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -62,12 +62,10 @@ d3d11_src = [ 'd3d11_view_uav.cpp', ] -d3d11_src_win32 = [ - 'd3d11_gdi.cpp' -] - -if dxvk_platform == 'windows' - d3d11_src += d3d11_src_win32 +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 diff --git a/src/dxgi/dxgi_include.h b/src/dxgi/dxgi_include.h index c7fdcaa9..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__) || defined(DXVK_NATIVE) +#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_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index a9a3d560..50a99425 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -97,7 +97,7 @@ 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) { @@ -174,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) @@ -241,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) @@ -265,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; @@ -315,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 @@ -517,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) { @@ -596,7 +599,7 @@ namespace dxvk { m_monitor = nullptr; m_target = nullptr; - if (!IsWindow(m_window)) + if (!wsi::isWindow(m_window)) return S_OK; if (!wsi::leaveFullscreenMode(m_window, &m_windowState)) { diff --git a/src/util/thread.h b/src/util/thread.h index 11f1a17a..8ca2f5ea 100644 --- a/src/util/thread.h +++ b/src/util/thread.h @@ -9,13 +9,13 @@ #include "./rc/util_rc.h" #include "./rc/util_rc_ptr.h" -#ifdef DXVK_NATIVE +#ifndef _WIN32 #include #endif namespace dxvk { -#ifndef DXVK_NATIVE +#ifdef _WIN32 /** * \brief Thread priority */ diff --git a/src/wsi/sdl2/wsi_mode_sdl2.cpp b/src/wsi/sdl2/wsi_mode_sdl2.cpp index cfb06964..4045de49 100644 --- a/src/wsi/sdl2/wsi_mode_sdl2.cpp +++ b/src/wsi/sdl2/wsi_mode_sdl2.cpp @@ -2,7 +2,7 @@ #include "wsi_helpers_sdl2.h" -#include +#include #include "../../util/util_string.h" #include "../../util/log/log.h" @@ -34,7 +34,7 @@ namespace dxvk::wsi { bool getDisplayMode( HMONITOR hMonitor, - DWORD ModeNumber, + uint32_t ModeNumber, WsiMode* pMode) { const int32_t displayId = monitor_cast(hMonitor); diff --git a/src/wsi/sdl2/wsi_monitor_sdl2.cpp b/src/wsi/sdl2/wsi_monitor_sdl2.cpp index ff59bffd..a5412d89 100644 --- a/src/wsi/sdl2/wsi_monitor_sdl2.cpp +++ b/src/wsi/sdl2/wsi_monitor_sdl2.cpp @@ -3,6 +3,7 @@ #include "wsi_helpers_sdl2.h" #include +#include #include #include diff --git a/src/wsi/sdl2/wsi_presenter_sdl2.cpp b/src/wsi/sdl2/wsi_presenter_sdl2.cpp index 5af8f193..c9c1ec56 100644 --- a/src/wsi/sdl2/wsi_presenter_sdl2.cpp +++ b/src/wsi/sdl2/wsi_presenter_sdl2.cpp @@ -3,13 +3,17 @@ #include #include +#include + namespace dxvk::wsi { VkResult createSurface( HWND hWindow, const Rc& vki, VkSurfaceKHR* pSurface) { - return SDL_Vulkan_CreateSurface(hWindow, vki->instance(), pSurface) + SDL_Window* window = window_cast(hWindow); + + return SDL_Vulkan_CreateSurface(window, vki->instance(), pSurface) ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; } diff --git a/src/wsi/sdl2/wsi_window_sdl2.cpp b/src/wsi/sdl2/wsi_window_sdl2.cpp index d911b1cf..80099901 100644 --- a/src/wsi/sdl2/wsi_window_sdl2.cpp +++ b/src/wsi/sdl2/wsi_window_sdl2.cpp @@ -3,6 +3,7 @@ #include "wsi_helpers_sdl2.h" #include +#include #include "../../util/util_string.h" #include "../../util/log/log.h" @@ -13,8 +14,10 @@ namespace dxvk::wsi { HWND hWindow, uint32_t* pWidth, uint32_t* pHeight) { + SDL_Window* window = window_cast(hWindow); + int32_t w, h; - SDL_GetWindowSize(hWindow, &w, &h); + SDL_GetWindowSize(window, &w, &h); if (pWidth) *pWidth = uint32_t(w); @@ -29,7 +32,9 @@ namespace dxvk::wsi { DxvkWindowState* pState, uint32_t Width, uint32_t Height) { - SDL_SetWindowSize(hWindow, int32_t(Width), int32_t(Height)); + SDL_Window* window = window_cast(hWindow); + + SDL_SetWindowSize(window, int32_t(Width), int32_t(Height)); } @@ -39,6 +44,7 @@ namespace dxvk::wsi { const WsiMode* pMode, bool EnteringFullscreen) { const int32_t displayId = monitor_cast(hMonitor); + SDL_Window* window = window_cast(hWindow); if (!isDisplayValid(displayId)) return false; @@ -57,7 +63,7 @@ namespace dxvk::wsi { return false; } - if (SDL_SetWindowDisplayMode(hWindow, &mode) != 0) { + if (SDL_SetWindowDisplayMode(window, &mode) != 0) { Logger::err(str::format("SDL2 WSI: setWindowMode: SDL_SetWindowDisplayMode: ", SDL_GetError())); return false; } @@ -73,6 +79,7 @@ namespace dxvk::wsi { DxvkWindowState* pState, bool ModeSwitch) { const int32_t displayId = monitor_cast(hMonitor); + SDL_Window* window = window_cast(hWindow); if (!isDisplayValid(displayId)) return false; @@ -83,7 +90,7 @@ namespace dxvk::wsi { // TODO: Set this on the correct monitor. // Docs aren't clear on this... - if (SDL_SetWindowFullscreen(hWindow, flags) != 0) { + if (SDL_SetWindowFullscreen(window, flags) != 0) { Logger::err(str::format("SDL2 WSI: enterFullscreenMode: SDL_SetWindowFullscreen: ", SDL_GetError())); return false; } @@ -95,7 +102,9 @@ namespace dxvk::wsi { bool leaveFullscreenMode( HWND hWindow, DxvkWindowState* pState) { - if (SDL_SetWindowFullscreen(hWindow, 0) != 0) { + SDL_Window* window = window_cast(hWindow); + + if (SDL_SetWindowFullscreen(window, 0) != 0) { Logger::err(str::format("SDL2 WSI: leaveFullscreenMode: SDL_SetWindowFullscreen: ", SDL_GetError())); return false; } @@ -110,9 +119,16 @@ namespace dxvk::wsi { HMONITOR getWindowMonitor(HWND hWindow) { - const int32_t displayId = SDL_GetWindowDisplayIndex(hWindow); + SDL_Window* window = window_cast(hWindow); + const int32_t displayId = SDL_GetWindowDisplayIndex(window); return monitor_cast(displayId); } + + bool isWindow(HWND hWindow) { + SDL_Window* window = window_cast(hWindow); + return window != nullptr; + } + } \ No newline at end of file diff --git a/src/wsi/win32/wsi_window_win32.cpp b/src/wsi/win32/wsi_window_win32.cpp index 73085247..8369bae1 100644 --- a/src/wsi/win32/wsi_window_win32.cpp +++ b/src/wsi/win32/wsi_window_win32.cpp @@ -179,4 +179,9 @@ namespace dxvk::wsi { return monitor; } + + bool isWindow(HWND hWindow) { + return ::IsWindow(hWindow); + } + } \ No newline at end of file diff --git a/src/wsi/wsi_window.h b/src/wsi/wsi_window.h index f7f76d69..5de022b2 100644 --- a/src/wsi/wsi_window.h +++ b/src/wsi/wsi_window.h @@ -105,4 +105,11 @@ namespace dxvk::wsi { */ 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 From abe20d5c1beaef84f690006aa3e4b838c3fa1dfb Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 30 Nov 2019 23:16:15 +0000 Subject: [PATCH 24/32] [wsi] Rename monitor_cast/window_cast to toHwnd/toMonitor --- include/native/wsi/native_sdl2.h | 30 ++++++++++++++++------------- src/wsi/sdl2/wsi_mode_sdl2.cpp | 6 +++--- src/wsi/sdl2/wsi_monitor_sdl2.cpp | 6 +++--- src/wsi/sdl2/wsi_presenter_sdl2.cpp | 2 +- src/wsi/sdl2/wsi_window_sdl2.cpp | 20 +++++++++---------- 5 files changed, 34 insertions(+), 30 deletions(-) diff --git a/include/native/wsi/native_sdl2.h b/include/native/wsi/native_sdl2.h index 9494bcba..9281c403 100644 --- a/include/native/wsi/native_sdl2.h +++ b/include/native/wsi/native_sdl2.h @@ -3,20 +3,24 @@ #include -inline SDL_Window* window_cast(HWND hWindow) { - return reinterpret_cast(hWindow); -} +namespace dxvk::wsi { -inline HWND window_cast(SDL_Window* pWindow) { - return reinterpret_cast(pWindow); -} + inline SDL_Window* fromHwnd(HWND hWindow) { + return reinterpret_cast(hWindow); + } -// Offset so null HMONITORs go to -1 -inline int32_t monitor_cast(HMONITOR hMonitor) { - return static_cast(reinterpret_cast(hMonitor)) - 1; -} + 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)); + } -// Offset so -1 display id goes to 0 == NULL -inline HMONITOR monitor_cast(int32_t displayId) { - return reinterpret_cast(static_cast(displayId + 1)); } \ No newline at end of file diff --git a/src/wsi/sdl2/wsi_mode_sdl2.cpp b/src/wsi/sdl2/wsi_mode_sdl2.cpp index 4045de49..291a1d8b 100644 --- a/src/wsi/sdl2/wsi_mode_sdl2.cpp +++ b/src/wsi/sdl2/wsi_mode_sdl2.cpp @@ -36,7 +36,7 @@ namespace dxvk::wsi { HMONITOR hMonitor, uint32_t ModeNumber, WsiMode* pMode) { - const int32_t displayId = monitor_cast(hMonitor); + const int32_t displayId = fromHmonitor(hMonitor); if (!isDisplayValid(displayId)) return false; @@ -54,7 +54,7 @@ namespace dxvk::wsi { bool getCurrentDisplayMode( HMONITOR hMonitor, WsiMode* pMode) { - const int32_t displayId = monitor_cast(hMonitor); + const int32_t displayId = fromHmonitor(hMonitor); if (!isDisplayValid(displayId)) return false; @@ -74,7 +74,7 @@ namespace dxvk::wsi { bool getDesktopDisplayMode( HMONITOR hMonitor, WsiMode* pMode) { - const int32_t displayId = monitor_cast(hMonitor); + const int32_t displayId = fromHmonitor(hMonitor); if (!isDisplayValid(displayId)) return false; diff --git a/src/wsi/sdl2/wsi_monitor_sdl2.cpp b/src/wsi/sdl2/wsi_monitor_sdl2.cpp index a5412d89..ea2c8ae4 100644 --- a/src/wsi/sdl2/wsi_monitor_sdl2.cpp +++ b/src/wsi/sdl2/wsi_monitor_sdl2.cpp @@ -12,7 +12,7 @@ namespace dxvk::wsi { HMONITOR enumMonitors(uint32_t index) { return isDisplayValid(int32_t(index)) - ? monitor_cast(index) + ? toHmonitor(index) : nullptr; } @@ -20,7 +20,7 @@ namespace dxvk::wsi { bool getDisplayName( HMONITOR hMonitor, WCHAR (&Name)[32]) { - const int32_t displayId = monitor_cast(hMonitor); + const int32_t displayId = fromHmonitor(hMonitor); if (!isDisplayValid(displayId)) return false; @@ -40,7 +40,7 @@ namespace dxvk::wsi { bool getDesktopCoordinates( HMONITOR hMonitor, RECT* pRect) { - const int32_t displayId = monitor_cast(hMonitor); + const int32_t displayId = fromHmonitor(hMonitor); if (!isDisplayValid(displayId)) return false; diff --git a/src/wsi/sdl2/wsi_presenter_sdl2.cpp b/src/wsi/sdl2/wsi_presenter_sdl2.cpp index c9c1ec56..1bf222f3 100644 --- a/src/wsi/sdl2/wsi_presenter_sdl2.cpp +++ b/src/wsi/sdl2/wsi_presenter_sdl2.cpp @@ -11,7 +11,7 @@ namespace dxvk::wsi { HWND hWindow, const Rc& vki, VkSurfaceKHR* pSurface) { - SDL_Window* window = window_cast(hWindow); + SDL_Window* window = fromHwnd(hWindow); return SDL_Vulkan_CreateSurface(window, vki->instance(), pSurface) ? VK_SUCCESS diff --git a/src/wsi/sdl2/wsi_window_sdl2.cpp b/src/wsi/sdl2/wsi_window_sdl2.cpp index 80099901..a2ba7c6a 100644 --- a/src/wsi/sdl2/wsi_window_sdl2.cpp +++ b/src/wsi/sdl2/wsi_window_sdl2.cpp @@ -14,7 +14,7 @@ namespace dxvk::wsi { HWND hWindow, uint32_t* pWidth, uint32_t* pHeight) { - SDL_Window* window = window_cast(hWindow); + SDL_Window* window = fromHwnd(hWindow); int32_t w, h; SDL_GetWindowSize(window, &w, &h); @@ -32,7 +32,7 @@ namespace dxvk::wsi { DxvkWindowState* pState, uint32_t Width, uint32_t Height) { - SDL_Window* window = window_cast(hWindow); + SDL_Window* window = fromHwnd(hWindow); SDL_SetWindowSize(window, int32_t(Width), int32_t(Height)); } @@ -43,8 +43,8 @@ namespace dxvk::wsi { HWND hWindow, const WsiMode* pMode, bool EnteringFullscreen) { - const int32_t displayId = monitor_cast(hMonitor); - SDL_Window* window = window_cast(hWindow); + const int32_t displayId = fromHmonitor(hMonitor); + SDL_Window* window = fromHwnd(hWindow); if (!isDisplayValid(displayId)) return false; @@ -78,8 +78,8 @@ namespace dxvk::wsi { HWND hWindow, DxvkWindowState* pState, bool ModeSwitch) { - const int32_t displayId = monitor_cast(hMonitor); - SDL_Window* window = window_cast(hWindow); + const int32_t displayId = fromHmonitor(hMonitor); + SDL_Window* window = fromHwnd(hWindow); if (!isDisplayValid(displayId)) return false; @@ -102,7 +102,7 @@ namespace dxvk::wsi { bool leaveFullscreenMode( HWND hWindow, DxvkWindowState* pState) { - SDL_Window* window = window_cast(hWindow); + SDL_Window* window = fromHwnd(hWindow); if (SDL_SetWindowFullscreen(window, 0) != 0) { Logger::err(str::format("SDL2 WSI: leaveFullscreenMode: SDL_SetWindowFullscreen: ", SDL_GetError())); @@ -119,15 +119,15 @@ namespace dxvk::wsi { HMONITOR getWindowMonitor(HWND hWindow) { - SDL_Window* window = window_cast(hWindow); + SDL_Window* window = fromHwnd(hWindow); const int32_t displayId = SDL_GetWindowDisplayIndex(window); - return monitor_cast(displayId); + return toHmonitor(displayId); } bool isWindow(HWND hWindow) { - SDL_Window* window = window_cast(hWindow); + SDL_Window* window = fromHwnd(hWindow); return window != nullptr; } From 01d8cc051f6d41ef1fb14be394858afd3aab78f8 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Mon, 30 Dec 2019 22:49:56 +0000 Subject: [PATCH 25/32] [vulkan] Add a vulkan_native header for VkFullScreenExclusiveEXT --- include/vulkan/vulkan_native.h | 91 ++++++++++++++++++++++++++++++++++ src/vulkan/vulkan_loader_fn.h | 4 ++ 2 files changed, 95 insertions(+) create mode 100644 include/vulkan/vulkan_native.h 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/src/vulkan/vulkan_loader_fn.h b/src/vulkan/vulkan_loader_fn.h index b28eeec1..f7e18a65 100644 --- a/src/vulkan/vulkan_loader_fn.h +++ b/src/vulkan/vulkan_loader_fn.h @@ -17,6 +17,10 @@ #include +#ifndef _WIN32 +#include +#endif + #ifdef __WINE__ #pragma pop_macro("_WIN32") #endif From 866475741df25c70d421dd069b5f39e284e4201d Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Tue, 31 Dec 2019 20:08:34 +0000 Subject: [PATCH 26/32] [d3d9] Hook up D3D9 to new WSI --- src/d3d9/d3d9_adapter.cpp | 54 +++++++---- src/d3d9/d3d9_cursor.cpp | 20 ++++ src/d3d9/d3d9_cursor.h | 2 + src/d3d9/d3d9_include.h | 2 +- src/d3d9/d3d9_interface.cpp | 5 + src/d3d9/d3d9_monitor.cpp | 3 + src/d3d9/d3d9_multithread.cpp | 2 +- src/d3d9/d3d9_shader.cpp | 43 ++++++++- src/d3d9/d3d9_surface.cpp | 13 +++ src/d3d9/d3d9_swapchain.cpp | 175 +++++++++++++--------------------- src/d3d9/d3d9_swapchain.h | 20 ++-- src/d3d9/d3d9_util.cpp | 34 ------- src/d3d9/d3d9_util.h | 6 -- src/d3d9/meson.build | 6 +- 14 files changed, 200 insertions(+), 185 deletions(-) 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]) From 09535a19b917c9fd821ae7d5237c630f58c1f6ae Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Wed, 11 Mar 2020 22:38:47 +0000 Subject: [PATCH 27/32] [util] Use WSI abstraction for util_monitor --- src/util/util_monitor.cpp | 111 ++++---------------------------------- src/util/util_monitor.h | 25 --------- 2 files changed, 11 insertions(+), 125 deletions(-) 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 * From c1e4d5e5980acd47effeec6d75d1ac5da09b00f6 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 28 Mar 2020 04:42:13 +0000 Subject: [PATCH 28/32] [include] Declare DUMMYUNIONNAME and DUMMYSTRUCTNAME --- include/native/windows/windows_base.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/native/windows/windows_base.h b/include/native/windows/windows_base.h index 8bd63a68..8b50c6de 100644 --- a/include/native/windows/windows_base.h +++ b/include/native/windows/windows_base.h @@ -217,6 +217,8 @@ constexpr HRESULT DXGI_ERROR_SDK_COMPONENT_MISSING = 0x887A002D; #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 From a6b7544dfd091fca9744f2f1d5b982531a3cb55b Mon Sep 17 00:00:00 2001 From: Jonas Johan Solsvik Date: Mon, 6 Apr 2020 00:27:51 +0200 Subject: [PATCH 29/32] add .gitignore - Ignore build/ - Ignore include/native/directx --- .gitignore | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..43330ee2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# 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? +# +# Example of how to get them: +# 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/ +# +include/native/directx/ From c3b7f69265de67d157c230c1d4e75df805477d28 Mon Sep 17 00:00:00 2001 From: Jonas Johan Solsvik Date: Mon, 6 Apr 2020 00:33:59 +0200 Subject: [PATCH 30/32] .gitignore - !include/native/directx/README.txt --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 43330ee2..b4e8fefa 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ build/ # cp d3d*.h dxgi*.h ~/git/github/Joshua-Ashton/dxvk-native/include/native/directx/ # include/native/directx/ +!include/native/directx/README.txt \ No newline at end of file From 263ac9cf8eef1771d6e7bc4feef62ba21ecc5f74 Mon Sep 17 00:00:00 2001 From: Jonas Johan Solsvik Date: Mon, 6 Apr 2020 00:37:18 +0200 Subject: [PATCH 31/32] change README.txt -> README.md --- .gitignore | 11 ++--------- include/native/directx/README.md | 11 +++++++++++ include/native/directx/README.txt | 1 - 3 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 include/native/directx/README.md delete mode 100644 include/native/directx/README.txt diff --git a/.gitignore b/.gitignore index b4e8fefa..940d1bf1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,12 +7,5 @@ build/ # Ignore directx headers, because we are not allowed to redistribute them? -# -# Example of how to get them: -# 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/ -# -include/native/directx/ -!include/native/directx/README.txt \ No newline at end of file +include/native/directx/* +!include/native/directx/README.md \ No newline at end of file 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/directx/README.txt b/include/native/directx/README.txt deleted file mode 100644 index f9626ecf..00000000 --- a/include/native/directx/README.txt +++ /dev/null @@ -1 +0,0 @@ -Put your DirectX headers in here. These cannot be redisted due to current licensing reasons. \ No newline at end of file From 5330dedd7e50f9bd16e1f54385db418d7cc65358 Mon Sep 17 00:00:00 2001 From: Jonas Johan Solsvik Date: Mon, 6 Apr 2020 00:39:06 +0200 Subject: [PATCH 32/32] .gitignore - add newline --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 940d1bf1..a80e3e2e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,4 @@ build/ # Ignore directx headers, because we are not allowed to redistribute them? include/native/directx/* -!include/native/directx/README.md \ No newline at end of file +!include/native/directx/README.md