diff options
Diffstat (limited to 'platform/windows')
-rw-r--r-- | platform/windows/SCsub | 12 | ||||
-rw-r--r-- | platform/windows/detect.py | 12 | ||||
-rw-r--r-- | platform/windows/display_server_windows.cpp | 224 | ||||
-rw-r--r-- | platform/windows/display_server_windows.h | 69 | ||||
-rw-r--r-- | platform/windows/doc_classes/EditorExportPlatformWindows.xml | 2 | ||||
-rw-r--r-- | platform/windows/export/export_plugin.cpp | 12 | ||||
-rw-r--r-- | platform/windows/gl_manager_windows_native.cpp | 43 | ||||
-rw-r--r-- | platform/windows/gl_manager_windows_native.h | 2 | ||||
-rw-r--r-- | platform/windows/os_windows.cpp | 20 |
9 files changed, 308 insertions, 88 deletions
diff --git a/platform/windows/SCsub b/platform/windows/SCsub index f2fb8616ae..f8ed8b73f5 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -108,18 +108,6 @@ if env["d3d12"]: # Used in cases where we can have multiple archs side-by-side. arch_bin_dir = "#bin/" + env["arch"] - # DXC - if env["dxc_path"] != "" and os.path.exists(env["dxc_path"]): - dxc_dll = "dxil.dll" - # Whether this one is loaded from arch-specific directory or not can be determined at runtime. - # Let's copy to both and let the user decide the distribution model. - for v in ["#bin", arch_bin_dir]: - env.Command( - v + "/" + dxc_dll, - env["dxc_path"] + "/bin/" + dxc_arch_subdir + "/" + dxc_dll, - Copy("$TARGET", "$SOURCE"), - ) - # Agility SDK if env["agility_sdk_path"] != "" and os.path.exists(env["agility_sdk_path"]): agility_dlls = ["D3D12Core.dll", "d3d12SDKLayers.dll"] diff --git a/platform/windows/detect.py b/platform/windows/detect.py index fa94846416..3671bbef08 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -214,11 +214,6 @@ def get_opts(): os.path.join(d3d12_deps_folder, "mesa"), ), ( - "dxc_path", - "Path to the DirectX Shader Compiler distribution (required for D3D12)", - os.path.join(d3d12_deps_folder, "dxc"), - ), - ( "agility_sdk_path", "Path to the Agility SDK distribution (optional for D3D12)", os.path.join(d3d12_deps_folder, "agility_sdk"), @@ -592,7 +587,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): "libEGL.windows." + env["arch"] + prebuilt_lib_extra_suffix, "libGLES.windows." + env["arch"] + prebuilt_lib_extra_suffix, ] - LIBS += ["dxgi", "d3d9", "d3d11"] + LIBS += ["dxgi", "d3d9", "d3d11", "synchronization"] env.Prepend(CPPPATH=["#thirdparty/angle/include"]) if env["target"] in ["editor", "template_debug"]: @@ -649,7 +644,8 @@ def configure_mingw(env: "SConsEnvironment"): # TODO: Re-evaluate the need for this / streamline with common config. if env["target"] == "template_release": - env.Append(CCFLAGS=["-msse2"]) + if env["arch"] != "arm64": + env.Append(CCFLAGS=["-msse2"]) elif env.dev_build: # Allow big objects. It's supposed not to have drawbacks but seems to break # GCC LTO, so enabling for debug builds only (which are not built with LTO @@ -817,7 +813,7 @@ def configure_mingw(env: "SConsEnvironment"): "ANGLE.windows." + env["arch"], ] ) - env.Append(LIBS=["dxgi", "d3d9", "d3d11"]) + env.Append(LIBS=["dxgi", "d3d9", "d3d11", "synchronization"]) env.Prepend(CPPPATH=["#thirdparty/angle/include"]) env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)]) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 1f8748fa3d..f29048b16d 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -2009,7 +2009,7 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window) } if (p_mode == WINDOW_MODE_WINDOWED) { - ShowWindow(wd.hWnd, SW_RESTORE); + ShowWindow(wd.hWnd, SW_NORMAL); wd.maximized = false; wd.minimized = false; } @@ -2911,24 +2911,67 @@ Key DisplayServerWindows::keyboard_get_label_from_physical(Key p_keycode) const return p_keycode; } -String _get_full_layout_name_from_registry(HKL p_layout) { - String id = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\" + String::num_int64((int64_t)p_layout, 16, false).lpad(8, "0"); +String DisplayServerWindows::_get_keyboard_layout_display_name(const String &p_klid) const { String ret; + HKEY key; + if (RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts", &key) != ERROR_SUCCESS) { + return String(); + } - HKEY hkey; - WCHAR layout_text[1024]; - memset(layout_text, 0, 1024 * sizeof(WCHAR)); - - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, (LPCWSTR)(id.utf16().get_data()), 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) { - return ret; + WCHAR buffer[MAX_PATH] = {}; + DWORD buffer_size = MAX_PATH; + if (RegGetValueW(key, (LPCWSTR)p_klid.utf16().get_data(), L"Layout Display Name", RRF_RT_REG_SZ, nullptr, buffer, &buffer_size) == ERROR_SUCCESS) { + if (load_indirect_string) { + if (load_indirect_string(buffer, buffer, buffer_size, nullptr) == S_OK) { + ret = String::utf16((const char16_t *)buffer, buffer_size); + } + } + } else { + if (RegGetValueW(key, (LPCWSTR)p_klid.utf16().get_data(), L"Layout Text", RRF_RT_REG_SZ, nullptr, buffer, &buffer_size) == ERROR_SUCCESS) { + ret = String::utf16((const char16_t *)buffer, buffer_size); + } } - DWORD buffer = 1024; - DWORD vtype = REG_SZ; - if (RegQueryValueExW(hkey, L"Layout Text", nullptr, &vtype, (LPBYTE)layout_text, &buffer) == ERROR_SUCCESS) { - ret = String::utf16((const char16_t *)layout_text); + RegCloseKey(key); + return ret; +} + +String DisplayServerWindows::_get_klid(HKL p_hkl) const { + String ret; + + WORD device = HIWORD(p_hkl); + if ((device & 0xf000) == 0xf000) { + WORD layout_id = device & 0x0fff; + + HKEY key; + if (RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts", &key) != ERROR_SUCCESS) { + return String(); + } + + DWORD index = 0; + wchar_t klid_buffer[KL_NAMELENGTH]; + DWORD klid_buffer_size = KL_NAMELENGTH; + while (RegEnumKeyExW(key, index, klid_buffer, &klid_buffer_size, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS) { + wchar_t layout_id_buf[MAX_PATH] = {}; + DWORD layout_id_size = MAX_PATH; + if (RegGetValueW(key, klid_buffer, L"Layout Id", RRF_RT_REG_SZ, nullptr, layout_id_buf, &layout_id_size) == ERROR_SUCCESS) { + if (layout_id == String::utf16((char16_t *)layout_id_buf, layout_id_size).hex_to_int()) { + ret = String::utf16((const char16_t *)klid_buffer, klid_buffer_size).lpad(8, "0"); + break; + } + } + klid_buffer_size = KL_NAMELENGTH; + ++index; + } + + RegCloseKey(key); + } else { + if (device == 0) { + device = LOWORD(p_hkl); + } + ret = (String::num_uint64((uint64_t)device, 16, false)).lpad(8, "0"); } - RegCloseKey(hkey); + return ret; } @@ -2940,7 +2983,7 @@ String DisplayServerWindows::keyboard_get_layout_name(int p_index) const { HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL)); GetKeyboardLayoutList(layout_count, layouts); - String ret = _get_full_layout_name_from_registry(layouts[p_index]); // Try reading full name from Windows registry, fallback to locale name if failed (e.g. on Wine). + String ret = _get_keyboard_layout_display_name(_get_klid(layouts[p_index])); // Try reading full name from Windows registry, fallback to locale name if failed (e.g. on Wine). if (ret.is_empty()) { WCHAR buf[LOCALE_NAME_MAX_LENGTH]; memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(WCHAR)); @@ -3808,9 +3851,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_ACTIVATE: { // Activation can happen just after the window has been created, even before the callbacks are set. // Therefore, it's safer to defer the delivery of the event. - if (!windows[window_id].activate_timer_id) { - windows[window_id].activate_timer_id = SetTimer(windows[window_id].hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC) nullptr); - } + // It's important to set an nIDEvent different from the SetTimer for move_timer_id because + // if the same nIDEvent is passed, the timer is replaced and the same timer_id is returned. + windows[window_id].activate_timer_id = SetTimer(windows[window_id].hWnd, DisplayServerWindows::TIMER_ID_WINDOW_ACTIVATION, USER_TIMER_MINIMUM, (TIMERPROC) nullptr); windows[window_id].activate_state = GET_WM_ACTIVATE_STATE(wParam, lParam); return 0; } break; @@ -4161,6 +4204,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mm->set_relative_screen_position(mm->get_relative()); old_x = mm->get_position().x; old_y = mm->get_position().y; + if (windows[window_id].window_focused || window_get_active_popup() == window_id) { Input::get_singleton()->parse_input_event(mm); } @@ -4187,13 +4231,118 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA break; } + pointer_button[GET_POINTERID_WPARAM(wParam)] = MouseButton::NONE; windows[window_id].block_mm = true; return 0; } break; case WM_POINTERLEAVE: { + pointer_button[GET_POINTERID_WPARAM(wParam)] = MouseButton::NONE; windows[window_id].block_mm = false; return 0; } break; + case WM_POINTERDOWN: + case WM_POINTERUP: { + if (mouse_mode == MOUSE_MODE_CAPTURED && use_raw_input) { + break; + } + + if ((tablet_get_current_driver() != "winink") || !winink_available) { + break; + } + + Ref<InputEventMouseButton> mb; + mb.instantiate(); + mb->set_window_id(window_id); + + BitField<MouseButtonMask> last_button_state = 0; + if (IS_POINTER_FIRSTBUTTON_WPARAM(wParam)) { + last_button_state.set_flag(MouseButtonMask::LEFT); + mb->set_button_index(MouseButton::LEFT); + } + if (IS_POINTER_SECONDBUTTON_WPARAM(wParam)) { + last_button_state.set_flag(MouseButtonMask::RIGHT); + mb->set_button_index(MouseButton::RIGHT); + } + if (IS_POINTER_THIRDBUTTON_WPARAM(wParam)) { + last_button_state.set_flag(MouseButtonMask::MIDDLE); + mb->set_button_index(MouseButton::MIDDLE); + } + if (IS_POINTER_FOURTHBUTTON_WPARAM(wParam)) { + last_button_state.set_flag(MouseButtonMask::MB_XBUTTON1); + mb->set_button_index(MouseButton::MB_XBUTTON1); + } + if (IS_POINTER_FIFTHBUTTON_WPARAM(wParam)) { + last_button_state.set_flag(MouseButtonMask::MB_XBUTTON2); + mb->set_button_index(MouseButton::MB_XBUTTON2); + } + mb->set_button_mask(last_button_state); + + const BitField<WinKeyModifierMask> &mods = _get_mods(); + mb->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL)); + mb->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT)); + mb->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT)); + mb->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META)); + + POINT coords; // Client coords. + coords.x = GET_X_LPARAM(lParam); + coords.y = GET_Y_LPARAM(lParam); + + // Note: Handle popup closing here, since mouse event is not emulated and hook will not be called. + uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup; + if (delta > 250) { + Point2i pos = Point2i(coords.x, coords.y) - _get_screens_origin(); + List<WindowID>::Element *C = nullptr; + List<WindowID>::Element *E = popup_list.back(); + // Find top popup to close. + while (E) { + // Popup window area. + Rect2i win_rect = Rect2i(window_get_position_with_decorations(E->get()), window_get_size_with_decorations(E->get())); + // Area of the parent window, which responsible for opening sub-menu. + Rect2i safe_rect = window_get_popup_safe_rect(E->get()); + if (win_rect.has_point(pos)) { + break; + } else if (safe_rect != Rect2i() && safe_rect.has_point(pos)) { + break; + } else { + C = E; + E = E->prev(); + } + } + if (C) { + _send_window_event(windows[C->get()], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST); + } + } + + int64_t pen_id = GET_POINTERID_WPARAM(wParam); + if (uMsg == WM_POINTERDOWN) { + mb->set_pressed(true); + if (pointer_down_time.has(pen_id) && (pointer_prev_button[pen_id] == mb->get_button_index()) && (ABS(coords.y - pointer_last_pos[pen_id].y) < GetSystemMetrics(SM_CYDOUBLECLK)) && GetMessageTime() - pointer_down_time[pen_id] < (LONG)GetDoubleClickTime()) { + mb->set_double_click(true); + pointer_down_time[pen_id] = 0; + } else { + pointer_down_time[pen_id] = GetMessageTime(); + pointer_prev_button[pen_id] = mb->get_button_index(); + pointer_last_pos[pen_id] = Vector2(coords.x, coords.y); + } + pointer_button[pen_id] = mb->get_button_index(); + } else { + if (!pointer_button.has(pen_id)) { + return 0; + } + mb->set_pressed(false); + mb->set_button_index(pointer_button[pen_id]); + pointer_button[pen_id] = MouseButton::NONE; + } + + ScreenToClient(windows[window_id].hWnd, &coords); + + mb->set_position(Vector2(coords.x, coords.y)); + mb->set_global_position(Vector2(coords.x, coords.y)); + + Input::get_singleton()->parse_input_event(mb); + + return 0; + } break; case WM_POINTERUPDATE: { if (mouse_mode == MOUSE_MODE_CAPTURED && use_raw_input) { break; @@ -4271,7 +4420,23 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT)); mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META)); - mm->set_button_mask(mouse_get_button_state()); + BitField<MouseButtonMask> last_button_state = 0; + if (IS_POINTER_FIRSTBUTTON_WPARAM(wParam)) { + last_button_state.set_flag(MouseButtonMask::LEFT); + } + if (IS_POINTER_SECONDBUTTON_WPARAM(wParam)) { + last_button_state.set_flag(MouseButtonMask::RIGHT); + } + if (IS_POINTER_THIRDBUTTON_WPARAM(wParam)) { + last_button_state.set_flag(MouseButtonMask::MIDDLE); + } + if (IS_POINTER_FOURTHBUTTON_WPARAM(wParam)) { + last_button_state.set_flag(MouseButtonMask::MB_XBUTTON1); + } + if (IS_POINTER_FIFTHBUTTON_WPARAM(wParam)) { + last_button_state.set_flag(MouseButtonMask::MB_XBUTTON2); + } + mm->set_button_mask(last_button_state); POINT coords; // Client coords. coords.x = GET_X_LPARAM(lParam); @@ -4442,6 +4607,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mm->set_position(mm->get_position() - window_get_position(receiving_window_id) + window_get_position(window_id)); mm->set_global_position(mm->get_position()); } + Input::get_singleton()->parse_input_event(mm); } break; @@ -4728,7 +4894,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_ENTERSIZEMOVE: { Input::get_singleton()->release_pressed_events(); - windows[window_id].move_timer_id = SetTimer(windows[window_id].hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC) nullptr); + windows[window_id].move_timer_id = SetTimer(windows[window_id].hWnd, DisplayServerWindows::TIMER_ID_MOVE_REDRAW, USER_TIMER_MINIMUM, (TIMERPROC) nullptr); } break; case WM_EXITSIZEMOVE: { KillTimer(windows[window_id].hWnd, windows[window_id].move_timer_id); @@ -5247,6 +5413,9 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, ::DwmSetWindowAttribute(wd.hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value)); } + RECT real_client_rect; + GetClientRect(wd.hWnd, &real_client_rect); + #ifdef RD_ENABLED if (rendering_context) { union { @@ -5276,7 +5445,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, return INVALID_WINDOW_ID; } - rendering_context->window_set_size(id, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top); + rendering_context->window_set_size(id, real_client_rect.right - real_client_rect.left, real_client_rect.bottom - real_client_rect.top); rendering_context->window_set_vsync_mode(id, p_vsync_mode); wd.context_created = true; } @@ -5284,7 +5453,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, #ifdef GLES3_ENABLED if (gl_manager_native) { - if (gl_manager_native->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) { + if (gl_manager_native->window_create(id, wd.hWnd, hInstance, real_client_rect.right - real_client_rect.left, real_client_rect.bottom - real_client_rect.top) != OK) { memdelete(gl_manager_native); gl_manager_native = nullptr; windows.erase(id); @@ -5294,7 +5463,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, } if (gl_manager_angle) { - if (gl_manager_angle->window_create(id, nullptr, wd.hWnd, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) { + if (gl_manager_angle->window_create(id, nullptr, wd.hWnd, real_client_rect.right - real_client_rect.left, real_client_rect.bottom - real_client_rect.top) != OK) { memdelete(gl_manager_angle); gl_manager_angle = nullptr; windows.erase(id); @@ -5433,6 +5602,9 @@ GetPointerPenInfoPtr DisplayServerWindows::win8p_GetPointerPenInfo = nullptr; LogicalToPhysicalPointForPerMonitorDPIPtr DisplayServerWindows::win81p_LogicalToPhysicalPointForPerMonitorDPI = nullptr; PhysicalToLogicalPointForPerMonitorDPIPtr DisplayServerWindows::win81p_PhysicalToLogicalPointForPerMonitorDPI = nullptr; +// Shell API, +SHLoadIndirectStringPtr DisplayServerWindows::load_indirect_string = nullptr; + Vector2i _get_device_ids(const String &p_device_name) { if (p_device_name.is_empty()) { return Vector2i(); @@ -5606,6 +5778,12 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win FreeLibrary(nt_lib); } + // Load Shell API. + HMODULE shellapi_lib = LoadLibraryW(L"shlwapi.dll"); + if (shellapi_lib) { + load_indirect_string = (SHLoadIndirectStringPtr)GetProcAddress(shellapi_lib, "SHLoadIndirectString"); + } + // Load UXTheme, available on Windows 10+ only. if (os_ver.dwBuildNumber >= 10240) { HMODULE ux_theme_lib = LoadLibraryW(L"uxtheme.dll"); diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 382f18c239..650f0412ea 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -207,6 +207,50 @@ typedef UINT32 PEN_MASK; #define POINTER_MESSAGE_FLAG_FIRSTBUTTON 0x00000010 #endif +#ifndef POINTER_MESSAGE_FLAG_SECONDBUTTON +#define POINTER_MESSAGE_FLAG_SECONDBUTTON 0x00000020 +#endif + +#ifndef POINTER_MESSAGE_FLAG_THIRDBUTTON +#define POINTER_MESSAGE_FLAG_THIRDBUTTON 0x00000040 +#endif + +#ifndef POINTER_MESSAGE_FLAG_FOURTHBUTTON +#define POINTER_MESSAGE_FLAG_FOURTHBUTTON 0x00000080 +#endif + +#ifndef POINTER_MESSAGE_FLAG_FIFTHBUTTON +#define POINTER_MESSAGE_FLAG_FIFTHBUTTON 0x00000100 +#endif + +#ifndef IS_POINTER_FLAG_SET_WPARAM +#define IS_POINTER_FLAG_SET_WPARAM(wParam, flag) (((DWORD)HIWORD(wParam) & (flag)) == (flag)) +#endif + +#ifndef IS_POINTER_FIRSTBUTTON_WPARAM +#define IS_POINTER_FIRSTBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FIRSTBUTTON) +#endif + +#ifndef IS_POINTER_SECONDBUTTON_WPARAM +#define IS_POINTER_SECONDBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_SECONDBUTTON) +#endif + +#ifndef IS_POINTER_THIRDBUTTON_WPARAM +#define IS_POINTER_THIRDBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_THIRDBUTTON) +#endif + +#ifndef IS_POINTER_FOURTHBUTTON_WPARAM +#define IS_POINTER_FOURTHBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FOURTHBUTTON) +#endif + +#ifndef IS_POINTER_FIFTHBUTTON_WPARAM +#define IS_POINTER_FIFTHBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FIFTHBUTTON) +#endif + +#ifndef GET_POINTERID_WPARAM +#define GET_POINTERID_WPARAM(wParam) (LOWORD(wParam)) +#endif + #if WINVER < 0x0602 enum tagPOINTER_INPUT_TYPE { PT_POINTER = 0x00000001, @@ -274,10 +318,19 @@ typedef struct tagPOINTER_PEN_INFO { #define WM_POINTERLEAVE 0x024A #endif +#ifndef WM_POINTERDOWN +#define WM_POINTERDOWN 0x0246 +#endif + +#ifndef WM_POINTERUP +#define WM_POINTERUP 0x0247 +#endif + typedef BOOL(WINAPI *GetPointerTypePtr)(uint32_t p_id, POINTER_INPUT_TYPE *p_type); typedef BOOL(WINAPI *GetPointerPenInfoPtr)(uint32_t p_id, POINTER_PEN_INFO *p_pen_info); typedef BOOL(WINAPI *LogicalToPhysicalPointForPerMonitorDPIPtr)(HWND hwnd, LPPOINT lpPoint); typedef BOOL(WINAPI *PhysicalToLogicalPointForPerMonitorDPIPtr)(HWND hwnd, LPPOINT lpPoint); +typedef HRESULT(WINAPI *SHLoadIndirectStringPtr)(PCWSTR pszSource, PWSTR pszOutBuf, UINT cchOutBuf, void **ppvReserved); typedef struct { BYTE bWidth; // Width, in pixels, of the image @@ -328,10 +381,18 @@ class DisplayServerWindows : public DisplayServer { static LogicalToPhysicalPointForPerMonitorDPIPtr win81p_LogicalToPhysicalPointForPerMonitorDPI; static PhysicalToLogicalPointForPerMonitorDPIPtr win81p_PhysicalToLogicalPointForPerMonitorDPI; + // Shell API + static SHLoadIndirectStringPtr load_indirect_string; + void _update_tablet_ctx(const String &p_old_driver, const String &p_new_driver); String tablet_driver; Vector<String> tablet_drivers; + enum TimerID { + TIMER_ID_MOVE_REDRAW = 1, + TIMER_ID_WINDOW_ACTIVATION = 2, + }; + enum { KEY_EVENT_BUFFER_SIZE = 512 }; @@ -474,6 +535,11 @@ class DisplayServerWindows : public DisplayServer { IndicatorID indicator_id_counter = 0; HashMap<IndicatorID, IndicatorData> indicators; + HashMap<int64_t, MouseButton> pointer_prev_button; + HashMap<int64_t, MouseButton> pointer_button; + HashMap<int64_t, LONG> pointer_down_time; + HashMap<int64_t, Vector2> pointer_last_pos; + void _send_window_event(const WindowData &wd, WindowEvent p_event); void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex); @@ -526,6 +592,9 @@ class DisplayServerWindows : public DisplayServer { Error _file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb); + String _get_keyboard_layout_display_name(const String &p_klid) const; + String _get_klid(HKL p_hkl) const; + public: LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT MouseProc(int code, WPARAM wParam, LPARAM lParam); diff --git a/platform/windows/doc_classes/EditorExportPlatformWindows.xml b/platform/windows/doc_classes/EditorExportPlatformWindows.xml index 06b272c10e..9e2db756ce 100644 --- a/platform/windows/doc_classes/EditorExportPlatformWindows.xml +++ b/platform/windows/doc_classes/EditorExportPlatformWindows.xml @@ -26,7 +26,7 @@ If set to [code]1[/code], ANGLE libraries are exported with the exported application. If set to [code]0[/code], ANGLE libraries are exported only if [member ProjectSettings.rendering/gl_compatibility/driver] is set to [code]"opengl3_angle"[/code]. </member> <member name="application/export_d3d12" type="int" setter="" getter=""> - If set to [code]1[/code], Direct3D 12 runtime (DXIL, Agility SDK, PIX) libraries are exported with the exported application. If set to [code]0[/code], Direct3D 12 libraries are exported only if [member ProjectSettings.rendering/rendering_device/driver] is set to [code]"d3d12"[/code]. + If set to [code]1[/code], the Direct3D 12 runtime libraries (Agility SDK, PIX) are exported with the exported application. If set to [code]0[/code], Direct3D 12 libraries are exported only if [member ProjectSettings.rendering/rendering_device/driver] is set to [code]"d3d12"[/code]. </member> <member name="application/file_description" type="String" setter="" getter=""> File description to be presented to users. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url]. diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index 6ce9d27dc5..12694b0155 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -208,18 +208,14 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> int export_d3d12 = p_preset->get("application/export_d3d12"); bool agility_sdk_multiarch = p_preset->get("application/d3d12_agility_sdk_multiarch"); - bool include_dxil_libs = false; + bool include_d3d12_extra_libs = false; if (export_d3d12 == 0) { - include_dxil_libs = (String(GLOBAL_GET("rendering/rendering_device/driver.windows")) == "d3d12") && (String(GLOBAL_GET("rendering/renderer/rendering_method")) != "gl_compatibility"); + include_d3d12_extra_libs = (String(GLOBAL_GET("rendering/rendering_device/driver.windows")) == "d3d12") && (String(GLOBAL_GET("rendering/renderer/rendering_method")) != "gl_compatibility"); } else if (export_d3d12 == 1) { - include_dxil_libs = true; + include_d3d12_extra_libs = true; } - if (include_dxil_libs) { + if (include_d3d12_extra_libs) { Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (da->file_exists(template_path.get_base_dir().path_join("dxil." + arch + ".dll"))) { - da->make_dir_recursive(p_path.get_base_dir().path_join(arch)); - da->copy(template_path.get_base_dir().path_join("dxil." + arch + ".dll"), p_path.get_base_dir().path_join(arch).path_join("dxil.dll"), get_chmod_flags()); - } if (da->file_exists(template_path.get_base_dir().path_join("D3D12Core." + arch + ".dll"))) { if (agility_sdk_multiarch) { da->make_dir_recursive(p_path.get_base_dir().path_join(arch)); diff --git a/platform/windows/gl_manager_windows_native.cpp b/platform/windows/gl_manager_windows_native.cpp index c8d7534e26..f74aa4ced7 100644 --- a/platform/windows/gl_manager_windows_native.cpp +++ b/platform/windows/gl_manager_windows_native.cpp @@ -76,6 +76,8 @@ static String format_error_message(DWORD id) { const int OGL_THREAD_CONTROL_ID = 0x20C1221E; const int OGL_THREAD_CONTROL_DISABLE = 0x00000002; const int OGL_THREAD_CONTROL_ENABLE = 0x00000001; +const int VRR_MODE_ID = 0x1194F158; +const int VRR_MODE_FULLSCREEN_ONLY = 0x1; typedef int(__cdecl *NvAPI_Initialize_t)(); typedef int(__cdecl *NvAPI_Unload_t)(); @@ -104,10 +106,12 @@ static bool nvapi_err_check(const char *msg, int status) { return true; } -// On windows we have to disable threaded optimization when using NVIDIA graphics cards -// to avoid stuttering, see https://stackoverflow.com/questions/36959508/nvidia-graphics-driver-causing-noticeable-frame-stuttering/37632948 -// also see https://github.com/Ryujinx/Ryujinx/blob/master/src/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs -void GLManagerNative_Windows::_nvapi_disable_threaded_optimization() { +// On windows we have to customize the NVIDIA application profile: +// * disable threaded optimization when using NVIDIA cards to avoid stuttering, see +// https://stackoverflow.com/questions/36959508/nvidia-graphics-driver-causing-noticeable-frame-stuttering/37632948 +// https://github.com/Ryujinx/Ryujinx/blob/master/src/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs +// * disable G-SYNC in windowed mode, as it results in unstable editor refresh rates +void GLManagerNative_Windows::_nvapi_setup_profile() { HMODULE nvapi = nullptr; #ifdef _WIN64 nvapi = LoadLibraryA("nvapi64.dll"); @@ -239,21 +243,29 @@ void GLManagerNative_Windows::_nvapi_disable_threaded_optimization() { } } - NVDRS_SETTING setting; - setting.version = NVDRS_SETTING_VER; - setting.settingId = OGL_THREAD_CONTROL_ID; - setting.settingType = NVDRS_DWORD_TYPE; - setting.settingLocation = NVDRS_CURRENT_PROFILE_LOCATION; - setting.isCurrentPredefined = 0; - setting.isPredefinedValid = 0; + NVDRS_SETTING ogl_thread_control_setting = { 0 }; + ogl_thread_control_setting.version = NVDRS_SETTING_VER; + ogl_thread_control_setting.settingId = OGL_THREAD_CONTROL_ID; + ogl_thread_control_setting.settingType = NVDRS_DWORD_TYPE; int thread_control_val = OGL_THREAD_CONTROL_DISABLE; if (!GLOBAL_GET("rendering/gl_compatibility/nvidia_disable_threaded_optimization")) { thread_control_val = OGL_THREAD_CONTROL_ENABLE; } - setting.u32CurrentValue = thread_control_val; - setting.u32PredefinedValue = thread_control_val; + ogl_thread_control_setting.u32CurrentValue = thread_control_val; - if (!nvapi_err_check("NVAPI: Error calling NvAPI_DRS_SetSetting", NvAPI_DRS_SetSetting(session_handle, profile_handle, &setting))) { + if (!nvapi_err_check("NVAPI: Error calling NvAPI_DRS_SetSetting", NvAPI_DRS_SetSetting(session_handle, profile_handle, &ogl_thread_control_setting))) { + NvAPI_DRS_DestroySession(session_handle); + NvAPI_Unload(); + return; + } + + NVDRS_SETTING vrr_mode_setting = { 0 }; + vrr_mode_setting.version = NVDRS_SETTING_VER; + vrr_mode_setting.settingId = VRR_MODE_ID; + vrr_mode_setting.settingType = NVDRS_DWORD_TYPE; + vrr_mode_setting.u32CurrentValue = VRR_MODE_FULLSCREEN_ONLY; + + if (!nvapi_err_check("NVAPI: Error calling NvAPI_DRS_SetSetting", NvAPI_DRS_SetSetting(session_handle, profile_handle, &vrr_mode_setting))) { NvAPI_DRS_DestroySession(session_handle); NvAPI_Unload(); return; @@ -270,6 +282,7 @@ void GLManagerNative_Windows::_nvapi_disable_threaded_optimization() { } else { print_verbose("NVAPI: Enabled OpenGL threaded optimization successfully"); } + print_verbose("NVAPI: Disabled G-SYNC for windowed mode successfully"); NvAPI_DRS_DestroySession(session_handle); } @@ -495,7 +508,7 @@ void GLManagerNative_Windows::swap_buffers() { } Error GLManagerNative_Windows::initialize() { - _nvapi_disable_threaded_optimization(); + _nvapi_setup_profile(); return OK; } diff --git a/platform/windows/gl_manager_windows_native.h b/platform/windows/gl_manager_windows_native.h index b4e2a3acdf..532092ae74 100644 --- a/platform/windows/gl_manager_windows_native.h +++ b/platform/windows/gl_manager_windows_native.h @@ -78,7 +78,7 @@ private: int glx_minor, glx_major; private: - void _nvapi_disable_threaded_optimization(); + void _nvapi_setup_profile(); int _find_or_create_display(GLWindow &win); Error _create_context(GLWindow &win, GLDisplay &gl_display); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 157702655e..9025f53f42 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1634,26 +1634,6 @@ String OS_Windows::get_locale() const { return "en"; } -// We need this because GetSystemInfo() is unreliable on WOW64 -// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724381(v=vs.85).aspx -// Taken from MSDN -typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL); -LPFN_ISWOW64PROCESS fnIsWow64Process; - -BOOL is_wow64() { - BOOL wow64 = FALSE; - - fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); - - if (fnIsWow64Process) { - if (!fnIsWow64Process(GetCurrentProcess(), &wow64)) { - wow64 = FALSE; - } - } - - return wow64; -} - String OS_Windows::get_processor_name() const { const String id = "Hardware\\Description\\System\\CentralProcessor\\0"; |