From 9584f24be5dd423bfd7e3a16cd89307af16524a9 Mon Sep 17 00:00:00 2001 From: Technohacker Date: Sun, 10 May 2020 18:10:19 +0530 Subject: [PATCH 1/2] Use DWMEnableBlurBehindWindow instead of WS_EX_LAYERED Affects per-pixel transparency The current method renders to the screen by copying the GLES output to a DIB for transparency using the CPU instead of rendering directly to the window via the GPU. This is slower and also forces the window to be borderless as WS_EX_LAYERED affects the non-client region as well. This change uses DWMEnableBlurBehindWindow which allows using the standard glClearColor() background alpha and is also performed through the GPU, eliminating CPU bottlenecks --- core/os/os.h | 4 -- drivers/gles2/rasterizer_gles2.cpp | 13 +--- drivers/gles3/rasterizer_gles3.cpp | 13 +--- platform/windows/os_windows.cpp | 99 ++++-------------------------- platform/windows/os_windows.h | 9 +-- 5 files changed, 15 insertions(+), 123 deletions(-) diff --git a/core/os/os.h b/core/os/os.h index 4bab7eeb74..f355cc09e5 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -247,10 +247,6 @@ public: virtual bool get_window_per_pixel_transparency_enabled() const { return false; } virtual void set_window_per_pixel_transparency_enabled(bool p_enabled) {} - virtual uint8_t *get_layered_buffer_data() { return NULL; } - virtual Size2 get_layered_buffer_size() { return Size2(0, 0); } - virtual void swap_layered_buffer() {} - virtual void set_ime_active(const bool p_active) {} virtual void set_ime_position(const Point2 &p_pos) {} virtual Point2 get_ime_selection() const { return Point2(); } diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index 9539cb3eb7..9f40ce57ed 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -448,18 +448,7 @@ void RasterizerGLES2::output_lens_distorted_to_screen(RID p_render_target, const void RasterizerGLES2::end_frame(bool p_swap_buffers) { if (OS::get_singleton()->is_layered_allowed()) { - if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { -#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) - Size2 wndsize = OS::get_singleton()->get_layered_buffer_size(); - uint8_t *data = OS::get_singleton()->get_layered_buffer_data(); - if (data) { - glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data); - OS::get_singleton()->swap_layered_buffer(); - - return; - } -#endif - } else { + if (!OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { //clear alpha glColorMask(false, false, false, true); glClearColor(0, 0, 0, 1); diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 4f6a56549a..9ad8b68b32 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -372,18 +372,7 @@ void RasterizerGLES3::output_lens_distorted_to_screen(RID p_render_target, const void RasterizerGLES3::end_frame(bool p_swap_buffers) { if (OS::get_singleton()->is_layered_allowed()) { - if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { -#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) - Size2 wndsize = OS::get_singleton()->get_layered_buffer_size(); - uint8_t *data = OS::get_singleton()->get_layered_buffer_data(); - if (data) { - glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data); - OS::get_singleton()->swap_layered_buffer(); - - return; - } -#endif - } else { + if (!OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { //clear alpha glColorMask(false, false, false, true); glClearColor(0, 0, 0, 1); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 7db4f9899e..40cee5d15f 100755 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -974,27 +974,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) maximized = false; minimized = false; } - if (is_layered_allowed() && layered_window) { - DeleteObject(hBitmap); - - RECT r; - GetWindowRect(hWnd, &r); - dib_size = Size2i(r.right - r.left, r.bottom - r.top); - - BITMAPINFO bmi; - ZeroMemory(&bmi, sizeof(BITMAPINFO)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = dib_size.x; - bmi.bmiHeader.biHeight = dib_size.y; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biSizeImage = dib_size.x * dib_size.y * 4; - hBitmap = CreateDIBSection(hDC_dib, &bmi, DIB_RGB_COLORS, (void **)&dib_data, NULL, 0x0); - SelectObject(hDC_dib, hBitmap); - - ZeroMemory(dib_data, dib_size.x * dib_size.y * 4); - } //return 0; // Jump Back } break; @@ -2233,77 +2212,29 @@ void OS_Windows::set_window_per_pixel_transparency_enabled(bool p_enabled) { if (p_enabled) { set_borderless_window(true); //enable per-pixel alpha - hDC_dib = CreateCompatibleDC(GetDC(hWnd)); - SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED); - - RECT r; - GetWindowRect(hWnd, &r); - dib_size = Size2(r.right - r.left, r.bottom - r.top); - - BITMAPINFO bmi; - ZeroMemory(&bmi, sizeof(BITMAPINFO)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = dib_size.x; - bmi.bmiHeader.biHeight = dib_size.y; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biSizeImage = dib_size.x * dib_size.y * 4; - hBitmap = CreateDIBSection(hDC_dib, &bmi, DIB_RGB_COLORS, (void **)&dib_data, NULL, 0x0); - SelectObject(hDC_dib, hBitmap); - - ZeroMemory(dib_data, dib_size.x * dib_size.y * 4); + DWM_BLURBEHIND bb = { 0 }; + HRGN hRgn = CreateRectRgn(0, 0, -1, -1); + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = hRgn; + bb.fEnable = TRUE; + DwmEnableBlurBehindWindow(hWnd, &bb); layered_window = true; } else { //disable per-pixel alpha layered_window = false; - SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) & ~WS_EX_LAYERED); - - //cleanup - DeleteObject(hBitmap); - DeleteDC(hDC_dib); + DWM_BLURBEHIND bb = { 0 }; + HRGN hRgn = CreateRectRgn(0, 0, -1, -1); + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = hRgn; + bb.fEnable = FALSE; + DwmEnableBlurBehindWindow(hWnd, &bb); } } } -uint8_t *OS_Windows::get_layered_buffer_data() { - - return (is_layered_allowed() && layered_window) ? dib_data : NULL; -} - -Size2 OS_Windows::get_layered_buffer_size() { - - return (is_layered_allowed() && layered_window) ? dib_size : Size2(); -} - -void OS_Windows::swap_layered_buffer() { - - if (is_layered_allowed() && layered_window) { - - //premultiply alpha - for (int y = 0; y < dib_size.y; y++) { - for (int x = 0; x < dib_size.x; x++) { - float alpha = (float)dib_data[y * (int)dib_size.x * 4 + x * 4 + 3] / (float)0xFF; - dib_data[y * (int)dib_size.x * 4 + x * 4 + 0] *= alpha; - dib_data[y * (int)dib_size.x * 4 + x * 4 + 1] *= alpha; - dib_data[y * (int)dib_size.x * 4 + x * 4 + 2] *= alpha; - } - } - //swap layered window buffer - POINT ptSrc = { 0, 0 }; - SIZE sizeWnd = { (long)dib_size.x, (long)dib_size.y }; - BLENDFUNCTION bf; - bf.BlendOp = AC_SRC_OVER; - bf.BlendFlags = 0; - bf.AlphaFormat = AC_SRC_ALPHA; - bf.SourceConstantAlpha = 0xFF; - UpdateLayeredWindow(hWnd, NULL, NULL, &sizeWnd, hDC_dib, &ptSrc, 0, &bf, ULW_ALPHA); - } -} - void OS_Windows::set_borderless_window(bool p_borderless) { if (video_mode.borderless_window == p_borderless) return; @@ -3477,7 +3408,6 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { drop_events = false; key_event_pos = 0; layered_window = false; - hBitmap = NULL; force_quit = false; alt_mem = false; gr_mem = false; @@ -3534,11 +3464,6 @@ OS_Windows::~OS_Windows() { wintab_WTClose(wtctx); wtctx = 0; } - - if (is_layered_allowed() && layered_window) { - DeleteObject(hBitmap); - DeleteDC(hDC_dib); - } #ifdef STDOUT_FILE fclose(stdo); #endif diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 21bd8c3c91..98fe78f15f 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -49,6 +49,7 @@ #include "drivers/xaudio2/audio_driver_xaudio2.h" #endif +#include #include #include #include @@ -297,10 +298,6 @@ class OS_Windows : public OS { HWND hWnd; Point2 last_pos; - HBITMAP hBitmap; //DIB section for layered window - uint8_t *dib_data; - Size2 dib_size; - HDC hDC_dib; bool layered_window; uint32_t move_timer_id; @@ -452,10 +449,6 @@ public: virtual bool get_window_per_pixel_transparency_enabled() const; virtual void set_window_per_pixel_transparency_enabled(bool p_enabled); - virtual uint8_t *get_layered_buffer_data(); - virtual Size2 get_layered_buffer_size(); - virtual void swap_layered_buffer(); - virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); virtual Error close_dynamic_library(void *p_library_handle); virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false); From 0456311be3ee2233a55b2a007c95e070a06dce3d Mon Sep 17 00:00:00 2001 From: Technohacker Date: Sun, 10 May 2020 19:19:35 +0530 Subject: [PATCH 2/2] Don't force borderless mode when using per-pixel transparency --- platform/osx/os_osx.mm | 4 ---- platform/windows/os_windows.cpp | 4 ---- platform/x11/os_x11.cpp | 4 ---- 3 files changed, 12 deletions(-) diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 53fe11b3bb..df3e57e282 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -2661,7 +2661,6 @@ void OS_OSX::set_window_per_pixel_transparency_enabled(bool p_enabled) { if (!is_layered_allowed()) return; if (layered_window != p_enabled) { if (p_enabled) { - set_borderless_window(true); GLint opacity = 0; [window_object setBackgroundColor:[NSColor clearColor]]; [window_object setOpaque:NO]; @@ -2691,9 +2690,6 @@ void OS_OSX::set_borderless_window(bool p_borderless) { if (p_borderless) { [window_object setStyleMask:NSWindowStyleMaskBorderless]; } else { - if (layered_window) - set_window_per_pixel_transparency_enabled(false); - [window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (resizable ? NSWindowStyleMaskResizable : 0)]; // Force update of the window styles diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 40cee5d15f..a8c3551671 100755 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -2210,7 +2210,6 @@ void OS_Windows::set_window_per_pixel_transparency_enabled(bool p_enabled) { if (!is_layered_allowed()) return; if (layered_window != p_enabled) { if (p_enabled) { - set_borderless_window(true); //enable per-pixel alpha DWM_BLURBEHIND bb = { 0 }; @@ -2239,9 +2238,6 @@ void OS_Windows::set_borderless_window(bool p_borderless) { if (video_mode.borderless_window == p_borderless) return; - if (!p_borderless && layered_window) - set_window_per_pixel_transparency_enabled(false); - video_mode.borderless_window = p_borderless; preserve_window_size = true; diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 2a1bdb6b81..9b9d141f7a 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -964,7 +964,6 @@ void OS_X11::set_window_per_pixel_transparency_enabled(bool p_enabled) { if (!is_layered_allowed()) return; if (layered_window != p_enabled) { if (p_enabled) { - set_borderless_window(true); layered_window = true; } else { layered_window = false; @@ -1683,9 +1682,6 @@ void OS_X11::set_borderless_window(bool p_borderless) { if (get_borderless_window() == p_borderless) return; - if (!p_borderless && layered_window) - set_window_per_pixel_transparency_enabled(false); - current_videomode.borderless_window = p_borderless; Hints hints;