diff options
Diffstat (limited to 'platform/windows')
20 files changed, 859 insertions, 194 deletions
diff --git a/platform/windows/SCsub b/platform/windows/SCsub index efbb47d965..1b6908d2bb 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -16,7 +16,9 @@ common_win = [ "tts_windows.cpp", "windows_terminal_logger.cpp", "vulkan_context_win.cpp", - "gl_manager_windows.cpp", + "gl_manager_windows_native.cpp", + "gl_manager_windows_angle.cpp", + "wgl_detect_version.cpp", ] common_win_wrap = [ @@ -44,6 +46,7 @@ if env["windows_subsystem"] == "gui": env_wrap.Append(LIBS=["version"]) prog_wrap = env_wrap.add_program("#bin/godot", common_win_wrap + res_wrap_obj, PROGSUFFIX=env["PROGSUFFIX_WRAP"]) + env_wrap.Depends(prog_wrap, prog) # Microsoft Visual Studio Project Generation if env["vsproj"]: diff --git a/platform/windows/crash_handler_windows.h b/platform/windows/crash_handler_windows.h index ef5831f10c..3871210977 100644 --- a/platform/windows/crash_handler_windows.h +++ b/platform/windows/crash_handler_windows.h @@ -35,7 +35,7 @@ #include <windows.h> // Crash handler exception only enabled with MSVC -#if defined(DEBUG_ENABLED) && defined(MSVC) +#if defined(DEBUG_ENABLED) && defined(_MSC_VER) #define CRASH_HANDLER_EXCEPTION 1 extern DWORD CrashHandlerException(EXCEPTION_POINTERS *ep); diff --git a/platform/windows/detect.py b/platform/windows/detect.py index bec1fd2cb6..bdacdbb9ba 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -185,6 +185,8 @@ def get_opts(): BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True), BoolVariable("use_asan", "Use address sanitizer (ASAN)", False), BoolVariable("debug_crt", "Compile with MSVC's debug CRT (/MDd)", False), + BoolVariable("incremental_link", "Use MSVC incremental linking. May increase or decrease build times.", False), + ("angle_libs", "Path to the ANGLE static libraries", ""), ] @@ -355,6 +357,10 @@ def configure_msvc(env, vcvars_msvc_config): else: env.AppendUnique(CCFLAGS=["/MD"]) + # MSVC incremental linking is broken and may _increase_ link time (GH-77968). + if not env["incremental_link"]: + env.Append(LINKFLAGS=["/INCREMENTAL:NO"]) + if env["arch"] == "x86_32": env["x86_libtheora_opt_vc"] = True @@ -379,7 +385,6 @@ def configure_msvc(env, vcvars_msvc_config): "WINMIDI_ENABLED", "TYPED_METHOD_BIND", "WIN32", - "MSVC", "WINVER=%s" % env["target_win_version"], "_WIN32_WINNT=%s" % env["target_win_version"], ] @@ -414,6 +419,7 @@ def configure_msvc(env, vcvars_msvc_config): "dwmapi", "dwrite", "wbemuuid", + "ntdll", ] if env.debug_features: @@ -426,7 +432,16 @@ def configure_msvc(env, vcvars_msvc_config): if env["opengl3"]: env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"]) - LIBS += ["opengl32"] + if env["angle_libs"] != "": + env.AppendUnique(CPPDEFINES=["EGL_STATIC"]) + env.Append(LIBPATH=[env["angle_libs"]]) + LIBS += [ + "libANGLE.windows." + env["arch"], + "libEGL.windows." + env["arch"], + "libGLES.windows." + env["arch"], + ] + LIBS += ["dxgi", "d3d9", "d3d11"] + env.Prepend(CPPPATH=["#thirdparty/angle/include"]) env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS]) @@ -596,6 +611,7 @@ def configure_mingw(env): "dwmapi", "dwrite", "wbemuuid", + "ntdll", ] ) @@ -609,7 +625,18 @@ def configure_mingw(env): if env["opengl3"]: env.Append(CPPDEFINES=["GLES3_ENABLED"]) - env.Append(LIBS=["opengl32"]) + if env["angle_libs"] != "": + env.AppendUnique(CPPDEFINES=["EGL_STATIC"]) + env.Append(LIBPATH=[env["angle_libs"]]) + env.Append( + LIBS=[ + "EGL.windows." + env["arch"], + "GLES.windows." + env["arch"], + "ANGLE.windows." + env["arch"], + ] + ) + env.Append(LIBS=["dxgi", "d3d9", "d3d11"]) + 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 b1dccdcefe..bb0b64ba10 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -31,6 +31,7 @@ #include "display_server_windows.h" #include "os_windows.h" +#include "wgl_detect_version.h" #include "core/config/project_settings.h" #include "core/io/marshalls.h" @@ -184,61 +185,82 @@ void DisplayServerWindows::_register_raw_input_devices(WindowID p_target_window) } bool DisplayServerWindows::tts_is_speaking() const { - ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_V_MSG(tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); return tts->is_speaking(); } bool DisplayServerWindows::tts_is_paused() const { - ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_V_MSG(tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); return tts->is_paused(); } TypedArray<Dictionary> DisplayServerWindows::tts_get_voices() const { - ERR_FAIL_COND_V_MSG(!tts, TypedArray<Dictionary>(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_V_MSG(tts, TypedArray<Dictionary>(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); return tts->get_voices(); } void DisplayServerWindows::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { - ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); tts->speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt); } void DisplayServerWindows::tts_pause() { - ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); tts->pause(); } void DisplayServerWindows::tts_resume() { - ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); tts->resume(); } void DisplayServerWindows::tts_stop() { - ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); + ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); tts->stop(); } Error DisplayServerWindows::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) { _THREAD_SAFE_METHOD_ + ERR_FAIL_INDEX_V(int(p_mode), FILE_DIALOG_MODE_SAVE_MAX, FAILED); + Vector<Char16String> filter_names; Vector<Char16String> filter_exts; for (const String &E : p_filters) { Vector<String> tokens = E.split(";"); - if (tokens.size() == 2) { - filter_exts.push_back(tokens[0].strip_edges().utf16()); - filter_names.push_back(tokens[1].strip_edges().utf16()); - } else if (tokens.size() == 1) { - filter_exts.push_back(tokens[0].strip_edges().utf16()); - filter_names.push_back(tokens[0].strip_edges().utf16()); + if (tokens.size() >= 1) { + String flt = tokens[0].strip_edges(); + int filter_slice_count = flt.get_slice_count(","); + Vector<String> exts; + for (int j = 0; j < filter_slice_count; j++) { + String str = (flt.get_slice(",", j).strip_edges()); + if (!str.is_empty()) { + exts.push_back(str); + } + } + if (!exts.is_empty()) { + String str = String(";").join(exts); + filter_exts.push_back(str.utf16()); + if (tokens.size() == 2) { + filter_names.push_back(tokens[1].strip_edges().utf16()); + } else { + filter_names.push_back(str.utf16()); + } + } } } + if (filter_names.is_empty()) { + filter_exts.push_back(String("*.*").utf16()); + filter_names.push_back(RTR("All Files").utf16()); + } Vector<COMDLG_FILTERSPEC> filters; for (int i = 0; i < filter_names.size(); i++) { filters.push_back({ (LPCWSTR)filter_names[i].ptr(), (LPCWSTR)filter_exts[i].ptr() }); } + WindowID prev_focus = last_focused_window; + HRESULT hr = S_OK; IFileDialog *pfd = nullptr; if (p_mode == FILE_DIALOG_MODE_SAVE_FILE) { @@ -278,7 +300,15 @@ Error DisplayServerWindows::file_dialog_show(const String &p_title, const String pfd->SetFileTypes(filters.size(), filters.ptr()); pfd->SetFileTypeIndex(0); - hr = pfd->Show(nullptr); + WindowID window_id = _get_focused_window_or_popup(); + if (!windows.has(window_id)) { + window_id = MAIN_WINDOW_ID; + } + + hr = pfd->Show(windows[window_id].hWnd); + UINT index = 0; + pfd->GetFileTypeIndex(&index); + if (SUCCEEDED(hr)) { Vector<String> file_names; @@ -316,24 +346,37 @@ Error DisplayServerWindows::file_dialog_show(const String &p_title, const String } } if (!p_callback.is_null()) { - Variant v_status = true; + Variant v_result = true; Variant v_files = file_names; - Variant *v_args[2] = { &v_status, &v_files }; + Variant v_index = index; Variant ret; Callable::CallError ce; - p_callback.callp((const Variant **)&v_args, 2, ret, ce); + const Variant *args[3] = { &v_result, &v_files, &v_index }; + + p_callback.callp(args, 3, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat(RTR("Failed to execute file dialogs callback: %s."), Variant::get_callable_error_text(p_callback, args, 3, ce))); + } } } else { if (!p_callback.is_null()) { - Variant v_status = false; + Variant v_result = false; Variant v_files = Vector<String>(); - Variant *v_args[2] = { &v_status, &v_files }; + Variant v_index = index; Variant ret; Callable::CallError ce; - p_callback.callp((const Variant **)&v_args, 2, ret, ce); + const Variant *args[3] = { &v_result, &v_files, &v_index }; + + p_callback.callp(args, 3, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat(RTR("Failed to execute file dialogs callback: %s."), Variant::get_callable_error_text(p_callback, args, 3, ce))); + } } } pfd->Release(); + if (prev_focus != INVALID_WINDOW_ID) { + callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(prev_focus); + } return OK; } else { @@ -408,7 +451,7 @@ void DisplayServerWindows::clipboard_set(const String &p_text) { Char16String utf16 = text.utf16(); HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (utf16.length() + 1) * sizeof(WCHAR)); - ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents."); + ERR_FAIL_NULL_MSG(mem, "Unable to allocate memory for clipboard contents."); LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem); memcpy(lptstrCopy, utf16.get_data(), (utf16.length() + 1) * sizeof(WCHAR)); @@ -419,7 +462,7 @@ void DisplayServerWindows::clipboard_set(const String &p_text) { // Set the CF_TEXT version (not needed?). CharString utf8 = text.utf8(); mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1); - ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents."); + ERR_FAIL_NULL_MSG(mem, "Unable to allocate memory for clipboard contents."); LPTSTR ptr = (LPTSTR)GlobalLock(mem); memcpy(ptr, utf8.get_data(), utf8.length()); @@ -1065,8 +1108,11 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) { } #endif #ifdef GLES3_ENABLED - if (gl_manager) { - gl_manager->window_destroy(p_window); + if (gl_manager_angle) { + gl_manager_angle->window_destroy(p_window); + } + if (gl_manager_native) { + gl_manager_native->window_destroy(p_window); } #endif @@ -1084,8 +1130,11 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) { void DisplayServerWindows::gl_window_make_current(DisplayServer::WindowID p_window_id) { #if defined(GLES3_ENABLED) - if (gl_manager) { - gl_manager->window_make_current(p_window_id); + if (gl_manager_angle) { + gl_manager_angle->window_make_current(p_window_id); + } + if (gl_manager_native) { + gl_manager_native->window_make_current(p_window_id); } #endif } @@ -1101,14 +1150,18 @@ int64_t DisplayServerWindows::window_get_native_handle(HandleType p_handle_type, } #if defined(GLES3_ENABLED) case WINDOW_VIEW: { - if (gl_manager) { - return (int64_t)gl_manager->get_hdc(p_window); + if (gl_manager_native) { + return (int64_t)gl_manager_native->get_hdc(p_window); + } else { + return (int64_t)GetDC(windows[p_window].hWnd); } - return 0; } case OPENGL_CONTEXT: { - if (gl_manager) { - return (int64_t)gl_manager->get_hglrc(p_window); + if (gl_manager_native) { + return (int64_t)gl_manager_native->get_hglrc(p_window); + } + if (gl_manager_angle) { + return (int64_t)gl_manager_angle->get_context(p_window); } return 0; } @@ -1175,6 +1228,51 @@ void DisplayServerWindows::window_set_title(const String &p_title, WindowID p_wi SetWindowTextW(windows[p_window].hWnd, (LPCWSTR)(p_title.utf16().get_data())); } +Size2i DisplayServerWindows::window_get_title_size(const String &p_title, WindowID p_window) const { + _THREAD_SAFE_METHOD_ + + Size2i size; + ERR_FAIL_COND_V(!windows.has(p_window), size); + + const WindowData &wd = windows[p_window]; + if (wd.fullscreen || wd.minimized || wd.borderless) { + return size; + } + + HDC hdc = GetDCEx(wd.hWnd, NULL, DCX_WINDOW); + if (hdc) { + Char16String s = p_title.utf16(); + SIZE text_size; + if (GetTextExtentPoint32W(hdc, (LPCWSTR)(s.get_data()), s.length(), &text_size)) { + size.x = text_size.cx; + size.y = text_size.cy; + } + + ReleaseDC(wd.hWnd, hdc); + } + RECT rect; + if (DwmGetWindowAttribute(wd.hWnd, DWMWA_CAPTION_BUTTON_BOUNDS, &rect, sizeof(RECT)) == S_OK) { + if (rect.right - rect.left > 0) { + ClientToScreen(wd.hWnd, (POINT *)&rect.left); + ClientToScreen(wd.hWnd, (POINT *)&rect.right); + + if (win81p_PhysicalToLogicalPointForPerMonitorDPI) { + win81p_PhysicalToLogicalPointForPerMonitorDPI(0, (POINT *)&rect.left); + win81p_PhysicalToLogicalPointForPerMonitorDPI(0, (POINT *)&rect.right); + } + + size.x += (rect.right - rect.left); + size.y = MAX(size.y, rect.bottom - rect.top); + } + } + if (icon.is_valid()) { + size.x += 32; + } else { + size.x += 16; + } + return size; +} + void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) { _THREAD_SAFE_METHOD_ @@ -1442,8 +1540,11 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo } #endif #if defined(GLES3_ENABLED) - if (gl_manager) { - gl_manager->window_resize(p_window, w, h); + if (gl_manager_native) { + gl_manager_native->window_resize(p_window, w, h); + } + if (gl_manager_angle) { + gl_manager_angle->window_resize(p_window, w, h); } #endif @@ -1506,7 +1607,7 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre if (p_fullscreen || p_borderless) { r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past. - if (p_fullscreen && p_multiwindow_fs) { + if ((p_fullscreen && p_multiwindow_fs) || p_maximized) { r_style |= WS_BORDER; // Allows child windows to be displayed on top of full screen. } } else { @@ -2313,8 +2414,11 @@ void DisplayServerWindows::make_rendering_thread() { void DisplayServerWindows::swap_buffers() { #if defined(GLES3_ENABLED) - if (gl_manager) { - gl_manager->swap_buffers(); + if (gl_manager_angle) { + gl_manager_angle->swap_buffers(); + } + if (gl_manager_native) { + gl_manager_native->swap_buffers(); } #endif } @@ -2385,7 +2489,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) { f->seek(pos); f->get_buffer((uint8_t *)&data_big.write[0], bytecount_big); HICON icon_big = CreateIconFromResource((PBYTE)&data_big.write[0], bytecount_big, TRUE, 0x00030000); - ERR_FAIL_COND_MSG(!icon_big, "Could not create " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + "."); + ERR_FAIL_NULL_MSG(icon_big, "Could not create " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + "."); // Read the small icon. DWORD bytecount_small = icon_dir->idEntries[small_icon_index].dwBytesInRes; @@ -2395,7 +2499,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) { f->seek(pos); f->get_buffer((uint8_t *)&data_small.write[0], bytecount_small); HICON icon_small = CreateIconFromResource((PBYTE)&data_small.write[0], bytecount_small, TRUE, 0x00030000); - ERR_FAIL_COND_MSG(!icon_small, "Could not create 16x16 @" + itos(small_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + "."); + ERR_FAIL_NULL_MSG(icon_small, "Could not create 16x16 @" + itos(small_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + "."); // Online tradition says to be sure last error is cleared and set the small icon first. int err = 0; @@ -2460,7 +2564,7 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) { } HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000); - ERR_FAIL_COND(!hicon); + ERR_FAIL_NULL(hicon); icon = img; @@ -2485,8 +2589,11 @@ void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsyn #endif #if defined(GLES3_ENABLED) - if (gl_manager) { - gl_manager->set_use_vsync(p_window, p_vsync_mode != DisplayServer::VSYNC_DISABLED); + if (gl_manager_native) { + gl_manager_native->set_use_vsync(p_window, p_vsync_mode != DisplayServer::VSYNC_DISABLED); + } + if (gl_manager_angle) { + gl_manager_angle->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED); } #endif } @@ -2500,8 +2607,11 @@ DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_ #endif #if defined(GLES3_ENABLED) - if (gl_manager) { - return gl_manager->is_using_vsync(p_window) ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED; + if (gl_manager_native) { + return gl_manager_native->is_using_vsync(p_window) ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED; + } + if (gl_manager_angle) { + return gl_manager_angle->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED; } #endif @@ -2563,12 +2673,9 @@ void DisplayServerWindows::_drag_event(WindowID p_window, float p_x, float p_y, } void DisplayServerWindows::_send_window_event(const WindowData &wd, WindowEvent p_event) { - if (!wd.event_callback.is_null()) { + if (wd.event_callback.is_valid()) { Variant event = int(p_event); - Variant *eventp = &event; - Variant ret; - Callable::CallError ce; - wd.event_callback.callp((const Variant **)&eventp, 1, ret, ce); + wd.event_callback.call(event); } } @@ -2581,12 +2688,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) if (in_dispatch_input_event) { return; } - in_dispatch_input_event = true; - Variant ev = p_event; - Variant *evp = &ev; - Variant ret; - Callable::CallError ce; { List<WindowID>::Element *E = popup_list.back(); @@ -2595,7 +2697,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) if (windows.has(E->get())) { Callable callable = windows[E->get()].input_event_callback; if (callable.is_valid()) { - callable.callp((const Variant **)&evp, 1, ret, ce); + callable.call(p_event); } } in_dispatch_input_event = false; @@ -2609,7 +2711,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) if (windows.has(event_from_window->get_window_id())) { Callable callable = windows[event_from_window->get_window_id()].input_event_callback; if (callable.is_valid()) { - callable.callp((const Variant **)&evp, 1, ret, ce); + callable.call(p_event); } } } else { @@ -2617,7 +2719,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) for (const KeyValue<WindowID, WindowData> &E : windows) { const Callable callable = E.value.input_event_callback; if (callable.is_valid()) { - callable.callp((const Variant **)&evp, 1, ret, ce); + callable.call(p_event); } } } @@ -2735,7 +2837,7 @@ LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam) // Find top popup to close. while (E) { // Popup window area. - Rect2i win_rect = Rect2i(window_get_position(E->get()), window_get_size(E->get())); + 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)) { @@ -2824,6 +2926,30 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA // Process window messages. switch (uMsg) { + case WM_NCPAINT: { + if (RenderingServer::get_singleton() && (windows[window_id].borderless || (windows[window_id].fullscreen && windows[window_id].multiwindow_fs))) { + Color color = RenderingServer::get_singleton()->get_default_clear_color(); + HDC hdc = GetWindowDC(hWnd); + if (hdc) { + HPEN pen = CreatePen(PS_SOLID, 1, RGB(color.r * 255.f, color.g * 255.f, color.b * 255.f)); + if (pen) { + HGDIOBJ prev_pen = SelectObject(hdc, pen); + HGDIOBJ prev_brush = SelectObject(hdc, GetStockObject(NULL_BRUSH)); + + RECT rc; + GetWindowRect(hWnd, &rc); + OffsetRect(&rc, -rc.left, -rc.top); + Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom); + + SelectObject(hdc, prev_pen); + SelectObject(hdc, prev_brush); + DeleteObject(pen); + } + ReleaseDC(hWnd, hdc); + } + return 0; + } + } break; case WM_NCHITTEST: { if (windows[window_id].mpass) { return HTTRANSPARENT; @@ -3656,11 +3782,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (rect_changed) { if (!window.rect_changed_callback.is_null()) { - Variant size = Rect2i(window.last_pos.x, window.last_pos.y, window.width, window.height); - const Variant *args[] = { &size }; - Variant ret; - Callable::CallError ce; - window.rect_changed_callback.callp(args, 1, ret, ce); + window.rect_changed_callback.call(Rect2i(window.last_pos.x, window.last_pos.y, window.width, window.height)); } // Update cursor clip region after window rect has changed. @@ -3877,11 +3999,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } if (files.size() && !windows[window_id].drop_files_callback.is_null()) { - Variant v = files; - Variant *vp = &v; - Variant ret; - Callable::CallError ce; - windows[window_id].drop_files_callback.callp((const Variant **)&vp, 1, ret, ce); + windows[window_id].drop_files_callback.call(files); } } break; default: { @@ -4219,10 +4337,20 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, #endif #ifdef GLES3_ENABLED - if (gl_manager) { - if (gl_manager->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) { - memdelete(gl_manager); - gl_manager = nullptr; + if (gl_manager_native) { + if (gl_manager_native->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) { + memdelete(gl_manager_native); + gl_manager_native = nullptr; + windows.erase(id); + ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window."); + } + window_set_vsync_mode(p_vsync_mode, id); + } + + if (gl_manager_angle) { + if (gl_manager_angle->window_create(id, nullptr, wd.hWnd, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) { + memdelete(gl_manager_angle); + gl_manager_angle = nullptr; windows.erase(id); ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window."); } @@ -4323,6 +4451,7 @@ bool DisplayServerWindows::winink_available = false; GetPointerTypePtr DisplayServerWindows::win8p_GetPointerType = nullptr; GetPointerPenInfoPtr DisplayServerWindows::win8p_GetPointerPenInfo = nullptr; LogicalToPhysicalPointForPerMonitorDPIPtr DisplayServerWindows::win81p_LogicalToPhysicalPointForPerMonitorDPI = nullptr; +PhysicalToLogicalPointForPerMonitorDPIPtr DisplayServerWindows::win81p_PhysicalToLogicalPointForPerMonitorDPI = nullptr; typedef enum _SHC_PROCESS_DPI_AWARENESS { SHC_PROCESS_DPI_UNAWARE = 0, @@ -4460,6 +4589,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType"); win8p_GetPointerPenInfo = (GetPointerPenInfoPtr)GetProcAddress(user32_lib, "GetPointerPenInfo"); win81p_LogicalToPhysicalPointForPerMonitorDPI = (LogicalToPhysicalPointForPerMonitorDPIPtr)GetProcAddress(user32_lib, "LogicalToPhysicalPointForPerMonitorDPI"); + win81p_PhysicalToLogicalPointForPerMonitorDPI = (PhysicalToLogicalPointForPerMonitorDPIPtr)GetProcAddress(user32_lib, "PhysicalToLogicalPointForPerMonitorDPI"); winink_available = win8p_GetPointerType && win8p_GetPointerPenInfo; } @@ -4517,19 +4647,50 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win // Init context and rendering device #if defined(GLES3_ENABLED) + bool fallback = GLOBAL_GET("rendering/gl_compatibility/fallback_to_angle"); + if (fallback && (rendering_driver == "opengl3")) { + Dictionary gl_info = detect_wgl(); + + bool force_angle = false; + + Array device_list = GLOBAL_GET("rendering/gl_compatibility/force_angle_on_devices"); + for (int i = 0; i < device_list.size(); i++) { + const Dictionary &device = device_list[i]; + if (device.has("vendor") && device.has("name") && device["vendor"].operator String().to_upper() == gl_info["vendor"].operator String().to_upper() && (device["name"] == "*" || device["name"].operator String().to_upper() == gl_info["name"].operator String().to_upper())) { + force_angle = true; + break; + } + } + + if (force_angle || (gl_info["version"].operator int() < 30003)) { + WARN_PRINT("Your video card drivers seem not to support the required OpenGL 3.3 version, switching to ANGLE."); + rendering_driver = "opengl3_angle"; + } + } + if (rendering_driver == "opengl3") { - GLManager_Windows::ContextType opengl_api_type = GLManager_Windows::GLES_3_0_COMPATIBLE; + gl_manager_native = memnew(GLManagerNative_Windows); - gl_manager = memnew(GLManager_Windows(opengl_api_type)); + if (gl_manager_native->initialize() != OK) { + memdelete(gl_manager_native); + gl_manager_native = nullptr; + r_error = ERR_UNAVAILABLE; + return; + } + + RasterizerGLES3::make_current(true); + } + if (rendering_driver == "opengl3_angle") { + gl_manager_angle = memnew(GLManagerANGLE_Windows); - if (gl_manager->initialize() != OK) { - memdelete(gl_manager); - gl_manager = nullptr; + if (gl_manager_angle->initialize() != OK) { + memdelete(gl_manager_angle); + gl_manager_angle = nullptr; r_error = ERR_UNAVAILABLE; return; } - RasterizerGLES3::make_current(); + RasterizerGLES3::make_current(false); } #endif @@ -4603,6 +4764,7 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() { #endif #ifdef GLES3_ENABLED drivers.push_back("opengl3"); + drivers.push_back("opengl3_angle"); #endif return drivers; @@ -4688,9 +4850,13 @@ DisplayServerWindows::~DisplayServerWindows() { SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, 0, 0); } #ifdef GLES3_ENABLED - if (gl_manager) { - memdelete(gl_manager); - gl_manager = nullptr; + if (gl_manager_angle) { + memdelete(gl_manager_angle); + gl_manager_angle = nullptr; + } + if (gl_manager_native) { + memdelete(gl_manager_native); + gl_manager_native = nullptr; } #endif if (tts) { diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 59c4442604..48c8c20280 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -59,8 +59,9 @@ #endif #if defined(GLES3_ENABLED) -#include "gl_manager_windows.h" -#endif +#include "gl_manager_windows_angle.h" +#include "gl_manager_windows_native.h" +#endif // GLES3_ENABLED #include <io.h> #include <stdio.h> @@ -261,6 +262,7 @@ typedef struct tagPOINTER_PEN_INFO { 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 struct { BYTE bWidth; // Width, in pixels, of the image @@ -308,6 +310,7 @@ class DisplayServerWindows : public DisplayServer { // DPI conversion API static LogicalToPhysicalPointForPerMonitorDPIPtr win81p_LogicalToPhysicalPointForPerMonitorDPI; + static PhysicalToLogicalPointForPerMonitorDPIPtr win81p_PhysicalToLogicalPointForPerMonitorDPI; void _update_tablet_ctx(const String &p_old_driver, const String &p_new_driver); String tablet_driver; @@ -335,7 +338,8 @@ class DisplayServerWindows : public DisplayServer { Point2i center; #if defined(GLES3_ENABLED) - GLManager_Windows *gl_manager = nullptr; + GLManagerANGLE_Windows *gl_manager_angle = nullptr; + GLManagerNative_Windows *gl_manager_native = nullptr; #endif #if defined(VULKAN_ENABLED) @@ -567,6 +571,7 @@ public: virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override; + virtual Size2i window_get_title_size(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) const override; virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID) override; virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override; diff --git a/platform/windows/doc_classes/EditorExportPlatformWindows.xml b/platform/windows/doc_classes/EditorExportPlatformWindows.xml index fc068efc75..2a286de100 100644 --- a/platform/windows/doc_classes/EditorExportPlatformWindows.xml +++ b/platform/windows/doc_classes/EditorExportPlatformWindows.xml @@ -18,6 +18,9 @@ <member name="application/copyright" type="String" setter="" getter=""> Copyright notice for the bundle visible to the user. Optional. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url]. </member> + <member name="application/export_angle" type="int" setter="" getter=""> + 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/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]. </member> diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index 07c6a8d6e4..4185c36d77 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -38,6 +38,7 @@ #include "editor/editor_node.h" #include "editor/editor_paths.h" #include "editor/editor_scale.h" +#include "editor/editor_string_names.h" #include "editor/export/editor_export.h" #include "modules/modules_enabled.gen.h" // For svg. @@ -168,16 +169,45 @@ Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPres Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { if (p_preset->get("application/modify_resources")) { - _rcedit_add_data(p_preset, p_path, true); + _rcedit_add_data(p_preset, p_path, false); String wrapper_path = p_path.get_basename() + ".console.exe"; if (FileAccess::exists(wrapper_path)) { - _rcedit_add_data(p_preset, wrapper_path, false); + _rcedit_add_data(p_preset, wrapper_path, true); } } return OK; } Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { + int export_angle = p_preset->get("application/export_angle"); + bool include_angle_libs = false; + if (export_angle == 0) { + include_angle_libs = String(GLOBAL_GET("rendering/gl_compatibility/driver.windows")) == "opengl3_angle"; + } else if (export_angle == 1) { + include_angle_libs = true; + } + + if (include_angle_libs) { + String custom_debug = p_preset->get("custom_template/debug"); + String custom_release = p_preset->get("custom_template/release"); + String arch = p_preset->get("binary_format/architecture"); + + String template_path = p_debug ? custom_debug : custom_release; + + template_path = template_path.strip_edges(); + + if (template_path.is_empty()) { + template_path = find_export_template(get_template_file_name(p_debug ? "debug" : "release", arch)); + } + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (da->file_exists(template_path.get_base_dir().path_join("libEGL." + arch + ".dll"))) { + da->copy(template_path.get_base_dir().path_join("libEGL." + arch + ".dll"), p_path.get_base_dir().path_join("libEGL.dll"), get_chmod_flags()); + } + if (da->file_exists(template_path.get_base_dir().path_join("libGLESv2." + arch + ".dll"))) { + da->copy(template_path.get_base_dir().path_join("libGLESv2." + arch + ".dll"), p_path.get_base_dir().path_join("libGLESv2.dll"), get_chmod_flags()); + } + } + bool export_as_zip = p_path.ends_with("zip"); bool embedded = p_preset->get("binary_format/embed_pck"); @@ -310,7 +340,7 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExpor // Hide resources. bool mod_res = p_preset->get("application/modify_resources"); - if (!mod_res && p_option != "application/modify_resources" && p_option.begins_with("application/")) { + if (!mod_res && p_option != "application/modify_resources" && p_option != "application/export_angle" && p_option.begins_with("application/")) { return false; } @@ -349,6 +379,7 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_angle", PROPERTY_HINT_ENUM, "Auto,Yes,No"), 0, true)); String run_script = "Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'\n" "$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'\n" @@ -1020,7 +1051,7 @@ EditorExportPlatformWindows::EditorExportPlatformWindows() { Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); if (theme.is_valid()) { - stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); + stop_icon = theme->get_icon(SNAME("Stop"), EditorStringName(EditorIcons)); } else { stop_icon.instantiate(); } diff --git a/platform/windows/gl_manager_windows_angle.cpp b/platform/windows/gl_manager_windows_angle.cpp new file mode 100644 index 0000000000..3086edc7f2 --- /dev/null +++ b/platform/windows/gl_manager_windows_angle.cpp @@ -0,0 +1,70 @@ +/**************************************************************************/ +/* gl_manager_windows_angle.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "gl_manager_windows_angle.h" + +#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED) + +#include <stdio.h> +#include <stdlib.h> + +#include <EGL/eglext_angle.h> + +const char *GLManagerANGLE_Windows::_get_platform_extension_name() const { + return "EGL_ANGLE_platform_angle"; +} + +EGLenum GLManagerANGLE_Windows::_get_platform_extension_enum() const { + return EGL_PLATFORM_ANGLE_ANGLE; +} + +Vector<EGLAttrib> GLManagerANGLE_Windows::_get_platform_display_attributes() const { + Vector<EGLAttrib> ret; + ret.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE); + ret.push_back(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE); + ret.push_back(EGL_NONE); + + return ret; +} + +EGLenum GLManagerANGLE_Windows::_get_platform_api_enum() const { + return EGL_OPENGL_ES_API; +} + +Vector<EGLint> GLManagerANGLE_Windows::_get_platform_context_attribs() const { + Vector<EGLint> ret; + ret.push_back(EGL_CONTEXT_CLIENT_VERSION); + ret.push_back(3); + ret.push_back(EGL_NONE); + + return ret; +} + +#endif // WINDOWS_ENABLED && GLES3_ENABLED diff --git a/platform/windows/gl_manager_windows_angle.h b/platform/windows/gl_manager_windows_angle.h new file mode 100644 index 0000000000..d8dc651cfd --- /dev/null +++ b/platform/windows/gl_manager_windows_angle.h @@ -0,0 +1,61 @@ +/**************************************************************************/ +/* gl_manager_windows_angle.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef GL_MANAGER_WINDOWS_ANGLE_H +#define GL_MANAGER_WINDOWS_ANGLE_H + +#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED) + +#include "core/error/error_list.h" +#include "core/os/os.h" +#include "core/templates/local_vector.h" +#include "drivers/egl/egl_manager.h" +#include "servers/display_server.h" + +#include <windows.h> + +class GLManagerANGLE_Windows : public EGLManager { +private: + virtual const char *_get_platform_extension_name() const override; + virtual EGLenum _get_platform_extension_enum() const override; + virtual EGLenum _get_platform_api_enum() const override; + virtual Vector<EGLAttrib> _get_platform_display_attributes() const override; + virtual Vector<EGLint> _get_platform_context_attribs() const override; + +public: + void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {} + + GLManagerANGLE_Windows(){}; + ~GLManagerANGLE_Windows(){}; +}; + +#endif // WINDOWS_ENABLED && GLES3_ENABLED + +#endif // GL_MANAGER_WINDOWS_ANGLE_H diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows_native.cpp index d3972c7bbc..b350786d11 100644 --- a/platform/windows/gl_manager_windows.cpp +++ b/platform/windows/gl_manager_windows_native.cpp @@ -1,5 +1,5 @@ /**************************************************************************/ -/* gl_manager_windows.cpp */ +/* gl_manager_windows_native.cpp */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#include "gl_manager_windows.h" +#include "gl_manager_windows_native.h" #if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED) @@ -52,11 +52,14 @@ #if defined(__GNUC__) // Workaround GCC warning from -Wcast-function-type. -#define wglGetProcAddress (void *)wglGetProcAddress #define GetProcAddress (void *)GetProcAddress #endif +typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXT)(HDC); +typedef BOOL(APIENTRY *PFNWGLDELETECONTEXT)(HGLRC); +typedef BOOL(APIENTRY *PFNWGLMAKECURRENT)(HDC, HGLRC); typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *); +typedef void *(APIENTRY *PFNWGLGETPROCADDRESS)(LPCSTR); static String format_error_message(DWORD id) { LPWSTR messageBuffer = nullptr; @@ -85,6 +88,7 @@ typedef int(__cdecl *NvAPI_DRS_CreateApplication_t)(NvDRSSessionHandle, NvDRSPro typedef int(__cdecl *NvAPI_DRS_SaveSettings_t)(NvDRSSessionHandle); typedef int(__cdecl *NvAPI_DRS_SetSetting_t)(NvDRSSessionHandle, NvDRSProfileHandle, NVDRS_SETTING *); typedef int(__cdecl *NvAPI_DRS_FindProfileByName_t)(NvDRSSessionHandle, NvAPI_UnicodeString, NvDRSProfileHandle *); +typedef int(__cdecl *NvAPI_DRS_FindApplicationByName_t)(NvDRSSessionHandle, NvAPI_UnicodeString, NvDRSProfileHandle *, NVDRS_APPLICATION *); NvAPI_GetErrorMessage_t NvAPI_GetErrorMessage__; static bool nvapi_err_check(const char *msg, int status) { @@ -102,7 +106,7 @@ static bool nvapi_err_check(const char *msg, int status) { // On windows we have to disable threaded optimization when using NVIDIA graphics cards // to avoid stuttering, see https://github.com/microsoft/vscode-cpptools/issues/6592 // also see https://github.com/Ryujinx/Ryujinx/blob/master/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs -void GLManager_Windows::_nvapi_disable_threaded_optimization() { +void GLManagerNative_Windows::_nvapi_disable_threaded_optimization() { HMODULE nvapi = 0; #ifdef _WIN64 nvapi = LoadLibraryA("nvapi64.dll"); @@ -116,7 +120,7 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() { void *(__cdecl * NvAPI_QueryInterface)(unsigned int interface_id) = 0; - NvAPI_QueryInterface = (void *(__cdecl *)(unsigned int))GetProcAddress(nvapi, "nvapi_QueryInterface"); + NvAPI_QueryInterface = (void *(__cdecl *)(unsigned int))(void *)GetProcAddress(nvapi, "nvapi_QueryInterface"); if (NvAPI_QueryInterface == NULL) { print_verbose("Error getting NVAPI NvAPI_QueryInterface"); @@ -135,6 +139,7 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() { NvAPI_DRS_SaveSettings_t NvAPI_DRS_SaveSettings = (NvAPI_DRS_SaveSettings_t)NvAPI_QueryInterface(0xFCBC7E14); NvAPI_DRS_SetSetting_t NvAPI_DRS_SetSetting = (NvAPI_DRS_SetSetting_t)NvAPI_QueryInterface(0x577DD202); NvAPI_DRS_FindProfileByName_t NvAPI_DRS_FindProfileByName = (NvAPI_DRS_FindProfileByName_t)NvAPI_QueryInterface(0x7E4A9A0B); + NvAPI_DRS_FindApplicationByName_t NvAPI_DRS_FindApplicationByName = (NvAPI_DRS_FindApplicationByName_t)NvAPI_QueryInterface(0xEEE566B2); if (!nvapi_err_check("NVAPI: Init failed", NvAPI_Initialize())) { return; @@ -169,9 +174,9 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() { NvDRSProfileHandle profile_handle = 0; - int status = NvAPI_DRS_FindProfileByName(session_handle, (NvU16 *)(app_profile_name_u16.ptrw()), &profile_handle); + int profile_status = NvAPI_DRS_FindProfileByName(session_handle, (NvU16 *)(app_profile_name_u16.ptrw()), &profile_handle); - if (status != 0) { + if (profile_status != 0) { print_verbose("NVAPI: Profile not found, creating...."); NVDRS_PROFILE profile_info; @@ -184,9 +189,17 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() { NvAPI_Unload(); return; } + } + + NvDRSProfileHandle app_profile_handle = 0; + NVDRS_APPLICATION_V4 app; + app.version = NVDRS_APPLICATION_VER_V4; + + int app_status = NvAPI_DRS_FindApplicationByName(session_handle, (NvU16 *)(app_executable_name_u16.ptrw()), &app_profile_handle, &app); + + if (app_status != 0) { + print_verbose("NVAPI: Application not found, adding to profile..."); - NVDRS_APPLICATION_V4 app; - app.version = NVDRS_APPLICATION_VER_V4; app.isPredefined = 0; app.isMetro = 1; app.isCommandLine = 1; @@ -235,7 +248,7 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() { NvAPI_DRS_DestroySession(session_handle); } -int GLManager_Windows::_find_or_create_display(GLWindow &win) { +int GLManagerNative_Windows::_find_or_create_display(GLWindow &win) { // find display NYI, only 1 supported so far if (_displays.size()) { return 0; @@ -297,19 +310,36 @@ static Error _configure_pixel_format(HDC hDC) { return OK; } -Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) { +PFNWGLCREATECONTEXT gd_wglCreateContext; +PFNWGLMAKECURRENT gd_wglMakeCurrent; +PFNWGLDELETECONTEXT gd_wglDeleteContext; +PFNWGLGETPROCADDRESS gd_wglGetProcAddress; + +Error GLManagerNative_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) { Error err = _configure_pixel_format(win.hDC); if (err != OK) { return err; } - gl_display.hRC = wglCreateContext(win.hDC); + HMODULE module = LoadLibraryW(L"opengl32.dll"); + if (!module) { + return ERR_CANT_CREATE; + } + gd_wglCreateContext = (PFNWGLCREATECONTEXT)GetProcAddress(module, "wglCreateContext"); + gd_wglMakeCurrent = (PFNWGLMAKECURRENT)GetProcAddress(module, "wglMakeCurrent"); + gd_wglDeleteContext = (PFNWGLDELETECONTEXT)GetProcAddress(module, "wglDeleteContext"); + gd_wglGetProcAddress = (PFNWGLGETPROCADDRESS)GetProcAddress(module, "wglGetProcAddress"); + if (!gd_wglCreateContext || !gd_wglMakeCurrent || !gd_wglDeleteContext || !gd_wglGetProcAddress) { + return ERR_CANT_CREATE; + } + + gl_display.hRC = gd_wglCreateContext(win.hDC); if (!gl_display.hRC) // Are We Able To Get A Rendering Context? { return ERR_CANT_CREATE; // Return FALSE } - if (!wglMakeCurrent(win.hDC, gl_display.hRC)) { + if (!gd_wglMakeCurrent(win.hDC, gl_display.hRC)) { ERR_PRINT("Could not attach OpenGL context to newly created window: " + format_error_message(GetLastError())); } @@ -323,45 +353,45 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) { }; //zero indicates the end of the array PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; //pointer to the method - wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)gd_wglGetProcAddress("wglCreateContextAttribsARB"); if (wglCreateContextAttribsARB == nullptr) //OpenGL 3.0 is not supported { - wglDeleteContext(gl_display.hRC); + gd_wglDeleteContext(gl_display.hRC); gl_display.hRC = 0; return ERR_CANT_CREATE; } HGLRC new_hRC = wglCreateContextAttribsARB(win.hDC, 0, attribs); if (!new_hRC) { - wglDeleteContext(gl_display.hRC); + gd_wglDeleteContext(gl_display.hRC); gl_display.hRC = 0; return ERR_CANT_CREATE; } - if (!wglMakeCurrent(win.hDC, nullptr)) { + if (!gd_wglMakeCurrent(win.hDC, nullptr)) { ERR_PRINT("Could not detach OpenGL context from newly created window: " + format_error_message(GetLastError())); } - wglDeleteContext(gl_display.hRC); + gd_wglDeleteContext(gl_display.hRC); gl_display.hRC = new_hRC; - if (!wglMakeCurrent(win.hDC, gl_display.hRC)) // Try To Activate The Rendering Context + if (!gd_wglMakeCurrent(win.hDC, gl_display.hRC)) // Try to activate the rendering context. { ERR_PRINT("Could not attach OpenGL context to newly created window with replaced OpenGL context: " + format_error_message(GetLastError())); - wglDeleteContext(gl_display.hRC); + gd_wglDeleteContext(gl_display.hRC); gl_display.hRC = 0; return ERR_CANT_CREATE; } if (!wglSwapIntervalEXT) { - wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)gd_wglGetProcAddress("wglSwapIntervalEXT"); } return OK; } -Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height) { +Error GLManagerNative_Windows::window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height) { HDC hDC = GetDC(p_hwnd); if (!hDC) { return ERR_CANT_CREATE; @@ -374,8 +404,6 @@ Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND } GLWindow win; - win.width = p_width; - win.height = p_height; win.hwnd = p_hwnd; win.hDC = hDC; @@ -395,24 +423,11 @@ Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND return OK; } -void GLManager_Windows::_internal_set_current_window(GLWindow *p_win) { +void GLManagerNative_Windows::_internal_set_current_window(GLWindow *p_win) { _current_window = p_win; } -void GLManager_Windows::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) { - get_window(p_window_id).width = p_width; - get_window(p_window_id).height = p_height; -} - -int GLManager_Windows::window_get_width(DisplayServer::WindowID p_window_id) { - return get_window(p_window_id).width; -} - -int GLManager_Windows::window_get_height(DisplayServer::WindowID p_window_id) { - return get_window(p_window_id).height; -} - -void GLManager_Windows::window_destroy(DisplayServer::WindowID p_window_id) { +void GLManagerNative_Windows::window_destroy(DisplayServer::WindowID p_window_id) { GLWindow &win = get_window(p_window_id); if (_current_window == &win) { _current_window = nullptr; @@ -420,17 +435,17 @@ void GLManager_Windows::window_destroy(DisplayServer::WindowID p_window_id) { _windows.erase(p_window_id); } -void GLManager_Windows::release_current() { +void GLManagerNative_Windows::release_current() { if (!_current_window) { return; } - if (!wglMakeCurrent(_current_window->hDC, nullptr)) { + if (!gd_wglMakeCurrent(_current_window->hDC, nullptr)) { ERR_PRINT("Could not detach OpenGL context from window marked current: " + format_error_message(GetLastError())); } } -void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id) { +void GLManagerNative_Windows::window_make_current(DisplayServer::WindowID p_window_id) { if (p_window_id == -1) { return; } @@ -444,33 +459,33 @@ void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id) } const GLDisplay &disp = get_display(win.gldisplay_id); - if (!wglMakeCurrent(win.hDC, disp.hRC)) { + if (!gd_wglMakeCurrent(win.hDC, disp.hRC)) { ERR_PRINT("Could not switch OpenGL context to other window: " + format_error_message(GetLastError())); } _internal_set_current_window(&win); } -void GLManager_Windows::make_current() { +void GLManagerNative_Windows::make_current() { if (!_current_window) { return; } const GLDisplay &disp = get_current_display(); - if (!wglMakeCurrent(_current_window->hDC, disp.hRC)) { + if (!gd_wglMakeCurrent(_current_window->hDC, disp.hRC)) { ERR_PRINT("Could not switch OpenGL context to window marked current: " + format_error_message(GetLastError())); } } -void GLManager_Windows::swap_buffers() { +void GLManagerNative_Windows::swap_buffers() { SwapBuffers(_current_window->hDC); } -Error GLManager_Windows::initialize() { +Error GLManagerNative_Windows::initialize() { _nvapi_disable_threaded_optimization(); return OK; } -void GLManager_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool p_use) { +void GLManagerNative_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool p_use) { GLWindow &win = get_window(p_window_id); GLWindow *current = _current_window; @@ -480,7 +495,12 @@ void GLManager_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool if (wglSwapIntervalEXT) { win.use_vsync = p_use; - wglSwapIntervalEXT(p_use ? 1 : 0); + + if (!wglSwapIntervalEXT(p_use ? 1 : 0)) { + WARN_PRINT("Could not set V-Sync mode."); + } + } else { + WARN_PRINT("Could not set V-Sync mode. V-Sync is not supported."); } if (current != _current_window) { @@ -489,29 +509,27 @@ void GLManager_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool } } -bool GLManager_Windows::is_using_vsync(DisplayServer::WindowID p_window_id) const { +bool GLManagerNative_Windows::is_using_vsync(DisplayServer::WindowID p_window_id) const { return get_window(p_window_id).use_vsync; } -HDC GLManager_Windows::get_hdc(DisplayServer::WindowID p_window_id) { +HDC GLManagerNative_Windows::get_hdc(DisplayServer::WindowID p_window_id) { return get_window(p_window_id).hDC; } -HGLRC GLManager_Windows::get_hglrc(DisplayServer::WindowID p_window_id) { +HGLRC GLManagerNative_Windows::get_hglrc(DisplayServer::WindowID p_window_id) { const GLWindow &win = get_window(p_window_id); const GLDisplay &disp = get_display(win.gldisplay_id); return disp.hRC; } -GLManager_Windows::GLManager_Windows(ContextType p_context_type) { - context_type = p_context_type; - +GLManagerNative_Windows::GLManagerNative_Windows() { direct_render = false; glx_minor = glx_major = 0; _current_window = nullptr; } -GLManager_Windows::~GLManager_Windows() { +GLManagerNative_Windows::~GLManagerNative_Windows() { release_current(); } diff --git a/platform/windows/gl_manager_windows.h b/platform/windows/gl_manager_windows_native.h index 482b00a1ba..829c53b3d2 100644 --- a/platform/windows/gl_manager_windows.h +++ b/platform/windows/gl_manager_windows_native.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* gl_manager_windows.h */ +/* gl_manager_windows_native.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GL_MANAGER_WINDOWS_H -#define GL_MANAGER_WINDOWS_H +#ifndef GL_MANAGER_WINDOWS_NATIVE_H +#define GL_MANAGER_WINDOWS_NATIVE_H #if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED) @@ -43,17 +43,10 @@ typedef bool(APIENTRY *PFNWGLSWAPINTERVALEXTPROC)(int interval); typedef int(APIENTRY *PFNWGLGETSWAPINTERVALEXTPROC)(void); -class GLManager_Windows { -public: - enum ContextType { - GLES_3_0_COMPATIBLE, - }; - +class GLManagerNative_Windows { private: // any data specific to the window struct GLWindow { - int width = 0; - int height = 0; bool use_vsync = false; // windows specific @@ -86,7 +79,6 @@ private: bool direct_render; int glx_minor, glx_major; - ContextType context_type; private: void _nvapi_disable_threaded_optimization(); @@ -96,11 +88,7 @@ private: public: Error window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height); void window_destroy(DisplayServer::WindowID p_window_id); - void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height); - - // get directly from the cached GLWindow - int window_get_width(DisplayServer::WindowID p_window_id = 0); - int window_get_height(DisplayServer::WindowID p_window_id = 0); + void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {} void release_current(); void make_current(); @@ -116,10 +104,10 @@ public: HDC get_hdc(DisplayServer::WindowID p_window_id); HGLRC get_hglrc(DisplayServer::WindowID p_window_id); - GLManager_Windows(ContextType p_context_type); - ~GLManager_Windows(); + GLManagerNative_Windows(); + ~GLManagerNative_Windows(); }; #endif // WINDOWS_ENABLED && GLES3_ENABLED -#endif // GL_MANAGER_WINDOWS_H +#endif // GL_MANAGER_WINDOWS_NATIVE_H diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp index 0ac6c2c8b0..60edb00dd2 100644 --- a/platform/windows/joypad_windows.cpp +++ b/platform/windows/joypad_windows.cpp @@ -109,6 +109,7 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) { static GUID IID_XOneSWirelessGamepad = { MAKELONG(0x045E, 0x02EA), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_XOneSBluetoothGamepad = { MAKELONG(0x045E, 0x02E0), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_XOneEliteWirelessGamepad = { MAKELONG(0x045E, 0x02E3), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneElite2WirelessGamepad = { MAKELONG(0x045E, 0x0B22), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; if (memcmp(p_guid, &IID_ValveStreamingGamepad, sizeof(*p_guid)) == 0 || memcmp(p_guid, &IID_X360WiredGamepad, sizeof(*p_guid)) == 0 || @@ -120,7 +121,8 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) { memcmp(p_guid, &IID_XOneNewWirelessGamepad, sizeof(*p_guid)) == 0 || memcmp(p_guid, &IID_XOneSWirelessGamepad, sizeof(*p_guid)) == 0 || memcmp(p_guid, &IID_XOneSBluetoothGamepad, sizeof(*p_guid)) == 0 || - memcmp(p_guid, &IID_XOneEliteWirelessGamepad, sizeof(*p_guid)) == 0) + memcmp(p_guid, &IID_XOneEliteWirelessGamepad, sizeof(*p_guid)) == 0 || + memcmp(p_guid, &IID_XOneElite2WirelessGamepad, sizeof(*p_guid)) == 0) return true; PRAWINPUTDEVICELIST dev_list = nullptr; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index df93631ef0..1d3b80e21e 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -395,7 +395,7 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han } } #else - ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, format_error_message(GetLastError()))); + ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, format_error_message(GetLastError()))); #endif if (cookie) { @@ -1356,18 +1356,13 @@ Error OS_Windows::shell_open(String p_uri) { } Error OS_Windows::shell_show_in_file_manager(String p_path, bool p_open_folder) { - p_path = p_path.trim_suffix("file://"); - bool open_folder = false; if (DirAccess::dir_exists_absolute(p_path) && p_open_folder) { open_folder = true; } - if (p_path.begins_with("\"")) { - p_path = String("\"") + p_path; - } - if (p_path.ends_with("\"")) { - p_path = p_path + String("\""); + if (!p_path.is_quoted()) { + p_path = p_path.quote(); } p_path = p_path.replace("/", "\\"); @@ -1683,7 +1678,7 @@ Error OS_Windows::move_to_trash(const String &p_path) { String OS_Windows::get_system_ca_certificates() { HCERTSTORE cert_store = CertOpenSystemStoreA(0, "ROOT"); - ERR_FAIL_COND_V_MSG(!cert_store, "", "Failed to read the root certificate store."); + ERR_FAIL_NULL_V_MSG(cert_store, "", "Failed to read the root certificate store."); FILETIME curr_time; GetSystemTimeAsFileTime(&curr_time); @@ -1714,7 +1709,7 @@ String OS_Windows::get_system_ca_certificates() { OS_Windows::OS_Windows(HINSTANCE _hInstance) { hInstance = _hInstance; - CoInitializeEx(nullptr, COINIT_MULTITHREADED); + CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); #ifdef WASAPI_ENABLED AudioDriverManager::add_driver(&driver_wasapi); diff --git a/platform/windows/platform_config.h b/platform/windows/platform_config.h index ae4e51e3fb..964e341ce4 100644 --- a/platform/windows/platform_config.h +++ b/platform/windows/platform_config.h @@ -29,5 +29,3 @@ /**************************************************************************/ #include <malloc.h> - -#define OPENGL_INCLUDE_H "thirdparty/glad/glad/gl.h" diff --git a/platform/windows/platform_gl.h b/platform/windows/platform_gl.h new file mode 100644 index 0000000000..e4af8b0ccd --- /dev/null +++ b/platform/windows/platform_gl.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* platform_gl.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef PLATFORM_GL_H +#define PLATFORM_GL_H + +#ifndef GL_API_ENABLED +#define GL_API_ENABLED // Allow using desktop GL. +#endif + +#ifndef GLES_API_ENABLED +#define GLES_API_ENABLED // Allow using GLES (ANGLE). +#endif + +#ifdef EGL_STATIC +#define KHRONOS_STATIC 1 +#include "thirdparty/angle/include/EGL/egl.h" +#include "thirdparty/angle/include/EGL/eglext.h" +#undef KHRONOS_STATIC +#else +#include "thirdparty/glad/glad/egl.h" +#endif + +#include "thirdparty/glad/glad/gl.h" + +#endif // PLATFORM_GL_H diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py index b522a75a9c..51652fa814 100644 --- a/platform/windows/platform_windows_builders.py +++ b/platform/windows/platform_windows_builders.py @@ -5,14 +5,24 @@ All such functions are invoked in a subprocess on Windows to prevent build flaki """ import os from detect import get_mingw_bin_prefix +from detect import try_cmd from platform_methods import subprocess_main def make_debug_mingw(target, source, env): mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) - os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0])) - os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0])) - os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0])) + if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]): + os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0])) + else: + os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0])) + if try_cmd("strip --version", env["mingw_prefix"], env["arch"]): + os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0])) + else: + os.system("strip --strip-debug --strip-unneeded {0}".format(target[0])) + if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]): + os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0])) + else: + os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0])) if __name__ == "__main__": diff --git a/platform/windows/tts_windows.cpp b/platform/windows/tts_windows.cpp index 907096d890..11d63d85ee 100644 --- a/platform/windows/tts_windows.cpp +++ b/platform/windows/tts_windows.cpp @@ -114,7 +114,7 @@ void TTS_Windows::_update_tts() { } bool TTS_Windows::is_speaking() const { - ERR_FAIL_COND_V(!synth, false); + ERR_FAIL_NULL_V(synth, false); SPVOICESTATUS status; synth->GetStatus(&status, nullptr); @@ -122,7 +122,7 @@ bool TTS_Windows::is_speaking() const { } bool TTS_Windows::is_paused() const { - ERR_FAIL_COND_V(!synth, false); + ERR_FAIL_NULL_V(synth, false); return paused; } @@ -185,7 +185,7 @@ Array TTS_Windows::get_voices() const { } void TTS_Windows::speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { - ERR_FAIL_COND(!synth); + ERR_FAIL_NULL(synth); if (p_interrupt) { stop(); } @@ -212,7 +212,7 @@ void TTS_Windows::speak(const String &p_text, const String &p_voice, int p_volum } void TTS_Windows::pause() { - ERR_FAIL_COND(!synth); + ERR_FAIL_NULL(synth); if (!paused) { if (synth->Pause() == S_OK) { paused = true; @@ -221,13 +221,13 @@ void TTS_Windows::pause() { } void TTS_Windows::resume() { - ERR_FAIL_COND(!synth); + ERR_FAIL_NULL(synth); synth->Resume(); paused = false; } void TTS_Windows::stop() { - ERR_FAIL_COND(!synth); + ERR_FAIL_NULL(synth); SPVOICESTATUS status; synth->GetStatus(&status, nullptr); diff --git a/platform/windows/wgl_detect_version.cpp b/platform/windows/wgl_detect_version.cpp new file mode 100644 index 0000000000..49da4b58c7 --- /dev/null +++ b/platform/windows/wgl_detect_version.cpp @@ -0,0 +1,197 @@ +/**************************************************************************/ +/* wgl_detect_version.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED) + +#include "wgl_detect_version.h" +#include "os_windows.h" + +#include "core/string/print_string.h" +#include "core/string/ustring.h" +#include "core/variant/dictionary.h" + +#include <windows.h> + +#include <dwmapi.h> +#include <stdio.h> +#include <stdlib.h> + +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_VENDOR 0x1F00 +#define WGL_RENDERER 0x1F01 +#define WGL_VERSION 0x1F02 + +#if defined(__GNUC__) +// Workaround GCC warning from -Wcast-function-type. +#define GetProcAddress (void *)GetProcAddress +#endif + +typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXT)(HDC); +typedef BOOL(APIENTRY *PFNWGLDELETECONTEXT)(HGLRC); +typedef BOOL(APIENTRY *PFNWGLMAKECURRENT)(HDC, HGLRC); +typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *); +typedef void *(APIENTRY *PFNWGLGETPROCADDRESS)(LPCSTR); +typedef const char *(APIENTRY *PFNWGLGETSTRINGPROC)(unsigned int); + +Dictionary detect_wgl() { + Dictionary gl_info; + gl_info["version"] = 0; + gl_info["vendor"] = String(); + gl_info["name"] = String(); + + PFNWGLCREATECONTEXT gd_wglCreateContext; + PFNWGLMAKECURRENT gd_wglMakeCurrent; + PFNWGLDELETECONTEXT gd_wglDeleteContext; + PFNWGLGETPROCADDRESS gd_wglGetProcAddress; + + HMODULE module = LoadLibraryW(L"opengl32.dll"); + if (!module) { + return gl_info; + } + gd_wglCreateContext = (PFNWGLCREATECONTEXT)GetProcAddress(module, "wglCreateContext"); + gd_wglMakeCurrent = (PFNWGLMAKECURRENT)GetProcAddress(module, "wglMakeCurrent"); + gd_wglDeleteContext = (PFNWGLDELETECONTEXT)GetProcAddress(module, "wglDeleteContext"); + gd_wglGetProcAddress = (PFNWGLGETPROCADDRESS)GetProcAddress(module, "wglGetProcAddress"); + if (!gd_wglCreateContext || !gd_wglMakeCurrent || !gd_wglDeleteContext || !gd_wglGetProcAddress) { + return gl_info; + } + + LPCWSTR class_name = L"EngineWGLDetect"; + HINSTANCE hInstance = static_cast<OS_Windows *>(OS::get_singleton())->get_hinstance(); + WNDCLASSW wc = {}; + + wc.lpfnWndProc = DefWindowProcW; + wc.hInstance = hInstance; + wc.lpszClassName = class_name; + + RegisterClassW(&wc); + + HWND hWnd = CreateWindowExW(WS_EX_APPWINDOW, class_name, L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr); + if (hWnd) { + HDC hDC = GetDC(hWnd); + if (hDC) { + static PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, + (BYTE)PFD_TYPE_RGBA, + (BYTE)(OS::get_singleton()->is_layered_allowed() ? 32 : 24), + (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Color Bits Ignored + (BYTE)(OS::get_singleton()->is_layered_allowed() ? 8 : 0), // Alpha Buffer + (BYTE)0, // Shift Bit Ignored + (BYTE)0, // No Accumulation Buffer + (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Accumulation Bits Ignored + (BYTE)24, // 24Bit Z-Buffer (Depth Buffer) + (BYTE)0, // No Stencil Buffer + (BYTE)0, // No Auxiliary Buffer + (BYTE)PFD_MAIN_PLANE, // Main Drawing Layer + (BYTE)0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + int pixel_format = ChoosePixelFormat(hDC, &pfd); + SetPixelFormat(hDC, pixel_format, &pfd); + + HGLRC hRC = gd_wglCreateContext(hDC); + if (hRC) { + if (gd_wglMakeCurrent(hDC, hRC)) { + int attribs[] = { + WGL_CONTEXT_MAJOR_VERSION_ARB, 3, + WGL_CONTEXT_MINOR_VERSION_ARB, 3, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + 0 + }; + + PFNWGLCREATECONTEXTATTRIBSARBPROC gd_wglCreateContextAttribsARB = nullptr; + gd_wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)gd_wglGetProcAddress("wglCreateContextAttribsARB"); + if (gd_wglCreateContextAttribsARB) { + HGLRC new_hRC = gd_wglCreateContextAttribsARB(hDC, 0, attribs); + if (new_hRC) { + if (gd_wglMakeCurrent(hDC, new_hRC)) { + PFNWGLGETSTRINGPROC gd_wglGetString = (PFNWGLGETSTRINGPROC)GetProcAddress(module, "glGetString"); + if (gd_wglGetString) { + const char *prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + "OpenGL SC ", + nullptr + }; + const char *version = (const char *)gd_wglGetString(WGL_VERSION); + if (version) { + const String device_vendor = String::utf8((const char *)gd_wglGetString(WGL_VENDOR)).strip_edges().trim_suffix(" Corporation"); + const String device_name = String::utf8((const char *)gd_wglGetString(WGL_RENDERER)).strip_edges().trim_suffix("/PCIe/SSE2"); + for (int i = 0; prefixes[i]; i++) { + size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + int major = 0; + int minor = 0; +#ifdef _MSC_VER + sscanf_s(version, "%d.%d", &major, &minor); +#else + sscanf(version, "%d.%d", &major, &minor); +#endif + print_verbose(vformat("Native OpenGL API detected: %d.%d: %s - %s", major, minor, device_vendor, device_name)); + gl_info["vendor"] = device_vendor; + gl_info["name"] = device_name; + gl_info["version"] = major * 10000 + minor; + } + } + } + gd_wglMakeCurrent(nullptr, nullptr); + gd_wglDeleteContext(new_hRC); + } + } + } + gd_wglMakeCurrent(nullptr, nullptr); + gd_wglDeleteContext(hRC); + } + ReleaseDC(hWnd, hDC); + } + DestroyWindow(hWnd); + } + UnregisterClassW(class_name, hInstance); + + return gl_info; +} + +#endif // WINDOWS_ENABLED && GLES3_ENABLED diff --git a/platform/windows/wgl_detect_version.h b/platform/windows/wgl_detect_version.h new file mode 100644 index 0000000000..c110b1219e --- /dev/null +++ b/platform/windows/wgl_detect_version.h @@ -0,0 +1,42 @@ +/**************************************************************************/ +/* wgl_detect_version.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef WGL_DETECT_VERSION_H +#define WGL_DETECT_VERSION_H + +#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED) + +class Dictionary; + +Dictionary detect_wgl(); + +#endif // WINDOWS_ENABLED && GLES3_ENABLED + +#endif // WGL_DETECT_VERSION_H diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp index bb223628a8..6881a75596 100644 --- a/platform/windows/windows_terminal_logger.cpp +++ b/platform/windows/windows_terminal_logger.cpp @@ -81,12 +81,9 @@ void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file return; } -#ifndef UWP_ENABLED HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE); if (!hCon || hCon == INVALID_HANDLE_VALUE) { -#endif StdLogger::log_error(p_function, p_file, p_line, p_code, p_rationale, p_type); -#ifndef UWP_ENABLED } else { CONSOLE_SCREEN_BUFFER_INFO sbi; //original GetConsoleScreenBufferInfo(hCon, &sbi); @@ -159,7 +156,6 @@ void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file SetConsoleTextAttribute(hCon, sbi.wAttributes); } -#endif } WindowsTerminalLogger::~WindowsTerminalLogger() {} |
