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
This commit is contained in:
parent
aa57bb0473
commit
9584f24be5
|
@ -247,10 +247,6 @@ public:
|
||||||
virtual bool get_window_per_pixel_transparency_enabled() const { return false; }
|
virtual bool get_window_per_pixel_transparency_enabled() const { return false; }
|
||||||
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled) {}
|
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_active(const bool p_active) {}
|
||||||
virtual void set_ime_position(const Point2 &p_pos) {}
|
virtual void set_ime_position(const Point2 &p_pos) {}
|
||||||
virtual Point2 get_ime_selection() const { return Point2(); }
|
virtual Point2 get_ime_selection() const { return Point2(); }
|
||||||
|
|
|
@ -448,18 +448,7 @@ void RasterizerGLES2::output_lens_distorted_to_screen(RID p_render_target, const
|
||||||
void RasterizerGLES2::end_frame(bool p_swap_buffers) {
|
void RasterizerGLES2::end_frame(bool p_swap_buffers) {
|
||||||
|
|
||||||
if (OS::get_singleton()->is_layered_allowed()) {
|
if (OS::get_singleton()->is_layered_allowed()) {
|
||||||
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
|
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 {
|
|
||||||
//clear alpha
|
//clear alpha
|
||||||
glColorMask(false, false, false, true);
|
glColorMask(false, false, false, true);
|
||||||
glClearColor(0, 0, 0, 1);
|
glClearColor(0, 0, 0, 1);
|
||||||
|
|
|
@ -372,18 +372,7 @@ void RasterizerGLES3::output_lens_distorted_to_screen(RID p_render_target, const
|
||||||
void RasterizerGLES3::end_frame(bool p_swap_buffers) {
|
void RasterizerGLES3::end_frame(bool p_swap_buffers) {
|
||||||
|
|
||||||
if (OS::get_singleton()->is_layered_allowed()) {
|
if (OS::get_singleton()->is_layered_allowed()) {
|
||||||
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
|
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 {
|
|
||||||
//clear alpha
|
//clear alpha
|
||||||
glColorMask(false, false, false, true);
|
glColorMask(false, false, false, true);
|
||||||
glClearColor(0, 0, 0, 1);
|
glClearColor(0, 0, 0, 1);
|
||||||
|
|
|
@ -974,27 +974,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
maximized = false;
|
maximized = false;
|
||||||
minimized = 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
|
//return 0; // Jump Back
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -2233,77 +2212,29 @@ void OS_Windows::set_window_per_pixel_transparency_enabled(bool p_enabled) {
|
||||||
if (p_enabled) {
|
if (p_enabled) {
|
||||||
set_borderless_window(true);
|
set_borderless_window(true);
|
||||||
//enable per-pixel alpha
|
//enable per-pixel alpha
|
||||||
hDC_dib = CreateCompatibleDC(GetDC(hWnd));
|
|
||||||
|
|
||||||
SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
|
DWM_BLURBEHIND bb = { 0 };
|
||||||
|
HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
|
||||||
RECT r;
|
bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
|
||||||
GetWindowRect(hWnd, &r);
|
bb.hRgnBlur = hRgn;
|
||||||
dib_size = Size2(r.right - r.left, r.bottom - r.top);
|
bb.fEnable = TRUE;
|
||||||
|
DwmEnableBlurBehindWindow(hWnd, &bb);
|
||||||
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);
|
|
||||||
|
|
||||||
layered_window = true;
|
layered_window = true;
|
||||||
} else {
|
} else {
|
||||||
//disable per-pixel alpha
|
//disable per-pixel alpha
|
||||||
layered_window = false;
|
layered_window = false;
|
||||||
|
|
||||||
SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
|
DWM_BLURBEHIND bb = { 0 };
|
||||||
|
HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
|
||||||
//cleanup
|
bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
|
||||||
DeleteObject(hBitmap);
|
bb.hRgnBlur = hRgn;
|
||||||
DeleteDC(hDC_dib);
|
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) {
|
void OS_Windows::set_borderless_window(bool p_borderless) {
|
||||||
if (video_mode.borderless_window == p_borderless)
|
if (video_mode.borderless_window == p_borderless)
|
||||||
return;
|
return;
|
||||||
|
@ -3477,7 +3408,6 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) {
|
||||||
drop_events = false;
|
drop_events = false;
|
||||||
key_event_pos = 0;
|
key_event_pos = 0;
|
||||||
layered_window = false;
|
layered_window = false;
|
||||||
hBitmap = NULL;
|
|
||||||
force_quit = false;
|
force_quit = false;
|
||||||
alt_mem = false;
|
alt_mem = false;
|
||||||
gr_mem = false;
|
gr_mem = false;
|
||||||
|
@ -3534,11 +3464,6 @@ OS_Windows::~OS_Windows() {
|
||||||
wintab_WTClose(wtctx);
|
wintab_WTClose(wtctx);
|
||||||
wtctx = 0;
|
wtctx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_layered_allowed() && layered_window) {
|
|
||||||
DeleteObject(hBitmap);
|
|
||||||
DeleteDC(hDC_dib);
|
|
||||||
}
|
|
||||||
#ifdef STDOUT_FILE
|
#ifdef STDOUT_FILE
|
||||||
fclose(stdo);
|
fclose(stdo);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "drivers/xaudio2/audio_driver_xaudio2.h"
|
#include "drivers/xaudio2/audio_driver_xaudio2.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <dwmapi.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -297,10 +298,6 @@ class OS_Windows : public OS {
|
||||||
HWND hWnd;
|
HWND hWnd;
|
||||||
Point2 last_pos;
|
Point2 last_pos;
|
||||||
|
|
||||||
HBITMAP hBitmap; //DIB section for layered window
|
|
||||||
uint8_t *dib_data;
|
|
||||||
Size2 dib_size;
|
|
||||||
HDC hDC_dib;
|
|
||||||
bool layered_window;
|
bool layered_window;
|
||||||
|
|
||||||
uint32_t move_timer_id;
|
uint32_t move_timer_id;
|
||||||
|
@ -452,10 +449,6 @@ public:
|
||||||
virtual bool get_window_per_pixel_transparency_enabled() const;
|
virtual bool get_window_per_pixel_transparency_enabled() const;
|
||||||
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
|
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 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 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);
|
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false);
|
||||||
|
|
Loading…
Reference in New Issue