diff --git a/crates/overlay/Cargo.toml b/crates/overlay/Cargo.toml index bee1e845..fc3d793a 100644 --- a/crates/overlay/Cargo.toml +++ b/crates/overlay/Cargo.toml @@ -28,7 +28,6 @@ windows-core = "0.62.2" workspace = true features = [ "Win32_Foundation", - "Win32_UI_HiDpi", "Win32_UI_WindowsAndMessaging", "Win32_System_LibraryLoader", "Win32_Graphics_Gdi", diff --git a/crates/overlay/src/hook/opengl.rs b/crates/overlay/src/hook/opengl.rs index 6a572dee..c93c557c 100644 --- a/crates/overlay/src/hook/opengl.rs +++ b/crates/overlay/src/hook/opengl.rs @@ -1,5 +1,6 @@ mod data; mod proc; +mod util; use core::{ ffi::{CStr, c_void}, @@ -7,18 +8,18 @@ use core::{ }; use std::{collections::HashSet, ffi::CString}; -use anyhow::Context; +use anyhow::{Context, bail}; use asdf_overlay_event::{SurfaceInfo, SurfaceType}; use asdf_overlay_hook::DetourHook; +use dashmap::Entry; use once_cell::sync::{Lazy, OnceCell}; -use scopeguard::defer; use tracing::{Level, debug, error, info, trace}; use windows::{ Win32::{ Foundation::{HMODULE, HWND, LUID}, Graphics::{ Dxgi::{CreateDXGIFactory1, IDXGIAdapter, IDXGIFactory1}, - Gdi::{GetDC, HDC, ReleaseDC, WindowFromDC}, + Gdi::{HDC, WindowFromDC}, OpenGL::{ HGLRC, wglGetCurrentContext, wglGetCurrentDC, wglGetProcAddress, wglMakeCurrent, }, @@ -31,12 +32,12 @@ use windows::{ use crate::{ event_sink::OverlayEventSink, gl, - hook::opengl::data::with_renderer_gl_data, + hook::opengl::{data::with_renderer_gl_data, util::get_client_size}, interop::DxInterop, renderer::opengl::OpenglRenderer, surface::{SurfaceState, Surfaces}, types::IntDashMap, - util::{find_adapter_by_luid, get_client_size}, + util::find_adapter_by_luid, wgl, }; @@ -52,8 +53,8 @@ struct GlData { extensions: HashSet, renderer: Option, } -// hwnd -> GlData -static MAP: Lazy> = Lazy::new(IntDashMap::default); +// HDC -> GlData +static MAP: Lazy> = Lazy::new(IntDashMap::default); #[tracing::instrument(level = Level::DEBUG)] pub fn hook(dummy_hwnd: HWND) { @@ -90,30 +91,23 @@ extern "system" fn hooked_wgl_delete_context(hglrc: HGLRC) -> BOOL { let current_hdc = unsafe { wglGetCurrentDC() }; let current_hglrc = unsafe { wglGetCurrentContext() }; let mut renderer_cleanup = false; - MAP.retain(|&key, gl_data| { + MAP.retain(|&hdc, gl_data| { if gl_data.hglrc != hglrc.0 as usize { return true; } - if !renderer_cleanup { - renderer_cleanup = true; - } - info!("OpenGL renderer cleanup"); - Surfaces::cleanup_state(key); + Surfaces::cleanup_state(hdc as _); let Some(renderer) = gl_data.renderer.take() else { return false; }; - let hwnd = HWND(key as _); - let hdc = unsafe { GetDC(Some(hwnd)) }; - defer!(unsafe { - _ = ReleaseDC(Some(hwnd), hdc); - }); + if !renderer_cleanup { + renderer_cleanup = true; + } - _ = unsafe { wglMakeCurrent(hdc, HGLRC(gl_data.hglrc as _)) }; + _ = unsafe { wglMakeCurrent(HDC(hdc as _), hglrc) }; drop(renderer); - false }); @@ -166,36 +160,33 @@ fn draw_overlay(hdc: HDC) { return; } - let hwnd = unsafe { WindowFromDC(hdc) }; - if hwnd.is_invalid() { - return; - } + let key = hdc.0 as u32; + let mut data = match MAP.entry(key) { + Entry::Occupied(r) => r.into_ref(), + Entry::Vacant(entry) => { + let data = match setup_gl_data(hdc) { + Ok(data) => data, + Err(err) => { + error!("Failed to setup opengl data. err: {:?}", err); + return; + } + }; - if !gl::GetIntegerv::is_loaded() { - debug!("Setting up opengl"); - if let Err(err) = setup_gl() { - error!("OpenGL setup failed. err: {:?}", err); - return; + entry.insert(data) } - } - - let key = hwnd.0 as u64; - let mut data = if let Some(r) = MAP.get_mut(&key) { - r - } else { - MAP.entry(key).or_insert_with(|| setup_gl_data(hwnd)) }; if let Err(err) = Surfaces::with( - key, - || setup_fn(unsafe { WindowFromDC(hdc) }), + key as _, + || setup_fn(hdc), |backend| inner(backend, &mut data), ) { error!("Failed to draw opengl overlay. err: {:?}", err); } } -fn setup_fn(hwnd: HWND) -> anyhow::Result { +fn setup_fn(hdc: HDC) -> anyhow::Result { + let hwnd = unsafe { WindowFromDC(hdc) }; let size = get_client_size(hwnd).unwrap_or_default(); let interop = DxInterop::new(get_dxgi_adapter().as_ref())?; let gpu_id = interop.gpu_id; @@ -212,7 +203,21 @@ fn setup_fn(hwnd: HWND) -> anyhow::Result { ) } -fn setup_gl_data(hwnd: HWND) -> GlData { +fn setup_gl_data(hdc: HDC) -> anyhow::Result { + if !gl::GetIntegerv::is_loaded() { + debug!("Setting up opengl"); + setup_gl().context("Opengl setup")?; + } + + if hdc.is_invalid() { + bail!("invalid hdc"); + } + + let hwnd = unsafe { WindowFromDC(hdc) }; + if hwnd.is_invalid() { + bail!("invalid hwnd"); + } + proc::install(hwnd); let mut extensions = HashSet::new(); @@ -225,11 +230,11 @@ fn setup_gl_data(hwnd: HWND) -> GlData { load_wgl_extensions(&mut extensions); } - GlData { + Ok(GlData { hglrc: unsafe { wglGetCurrentContext() }.0 as usize, renderer: None, extensions, - } + }) } fn load_gl_extensions(set: &mut HashSet) { diff --git a/crates/overlay/src/hook/opengl/data.rs b/crates/overlay/src/hook/opengl/data.rs index cfdec6f4..f8e83fce 100644 --- a/crates/overlay/src/hook/opengl/data.rs +++ b/crates/overlay/src/hook/opengl/data.rs @@ -23,6 +23,7 @@ pub fn with_renderer_gl_data(f: impl FnOnce() -> R) -> R { // bindings, mode get_gl_int!(last_active_texture = gl::ACTIVE_TEXTURE); + gl::ActiveTexture(gl::TEXTURE0); get_gl_int!(last_program = gl::CURRENT_PROGRAM); get_gl_int!(last_texture = gl::TEXTURE_BINDING_2D); get_gl_int!(last_array_buffer = gl::ARRAY_BUFFER_BINDING); diff --git a/crates/overlay/src/hook/opengl/proc.rs b/crates/overlay/src/hook/opengl/proc.rs index 1d8b3881..64bd222d 100644 --- a/crates/overlay/src/hook/opengl/proc.rs +++ b/crates/overlay/src/hook/opengl/proc.rs @@ -12,7 +12,8 @@ use windows::Win32::{ }; use crate::{ - event_sink::OverlayEventSink, surface::Surfaces, types::IntDashMap, util::get_client_size, + event_sink::OverlayEventSink, hook::opengl::util::get_client_size, surface::Surfaces, + types::IntDashMap, }; // HWND -> last WNDPROC diff --git a/crates/overlay/src/hook/opengl/util.rs b/crates/overlay/src/hook/opengl/util.rs new file mode 100644 index 00000000..1786e4c9 --- /dev/null +++ b/crates/overlay/src/hook/opengl/util.rs @@ -0,0 +1,13 @@ +use windows::Win32::{ + Foundation::{HWND, RECT}, + UI::WindowsAndMessaging::GetClientRect, +}; + +/// Get client area size of the window. +pub fn get_client_size(hwnd: HWND) -> anyhow::Result<(u32, u32)> { + unsafe { + let mut rect = RECT::default(); + GetClientRect(hwnd, &mut rect)?; + Ok((rect.right as u32, rect.bottom as u32)) + } +} diff --git a/crates/overlay/src/renderer/opengl.rs b/crates/overlay/src/renderer/opengl.rs index d661c418..3f2b6879 100644 --- a/crates/overlay/src/renderer/opengl.rs +++ b/crates/overlay/src/renderer/opengl.rs @@ -142,7 +142,6 @@ impl OpenglRenderer { gl::Uniform4f(self.rect_loc, rect[0], rect[1], rect[2], rect[3]); gl::Uniform1i(self.tex_loc, 0); - gl::ActiveTexture(gl::TEXTURE0); texture.bind(gl::TEXTURE_2D, || { gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4); }); diff --git a/crates/overlay/src/util.rs b/crates/overlay/src/util.rs index 8d4bd9f1..6b211dac 100644 --- a/crates/overlay/src/util.rs +++ b/crates/overlay/src/util.rs @@ -5,14 +5,10 @@ use core::mem::{self, ManuallyDrop}; use scopeguard::defer; use windows::{ Win32::{ - Foundation::{HWND, LPARAM, LUID, RECT}, + Foundation::{HWND, LPARAM, LUID}, Graphics::Dxgi::{IDXGIAdapter, IDXGIFactory, IDXGIKeyedMutex}, - UI::{ - HiDpi::{DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, SetThreadDpiAwarenessContext}, - WindowsAndMessaging::{ - CreateDialogIndirectParamA, DLGITEMTEMPLATE, DLGTEMPLATE, DestroyWindow, - GetClientRect, - }, + UI::WindowsAndMessaging::{ + CreateDialogIndirectParamA, DLGITEMTEMPLATE, DLGTEMPLATE, DestroyWindow, }, }, core::Interface, @@ -24,20 +20,6 @@ pub unsafe fn wrap_com_manually_drop(inf: &T) -> ManuallyDrop anyhow::Result<(u32, u32)> { - unsafe { - let old_context = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); - defer!({ - SetThreadDpiAwarenessContext(old_context); - }); - - let mut rect = RECT::default(); - GetClientRect(hwnd, &mut rect)?; - Ok((rect.right as u32, rect.bottom as u32)) - } -} - /// Create dummy class and window for various operation. /// /// Creating another dummy windows in closures fail.