From 2111a3a02fa136711b1aae859d1f70ac72e9d524 Mon Sep 17 00:00:00 2001 From: jpark37 Date: Mon, 24 Feb 2020 21:21:52 -0800 Subject: [PATCH] libobs-winrt: win-capture: Support client area toggle for WGC --- libobs-winrt/CMakeLists.txt | 2 + libobs-winrt/winrt-capture.cpp | 110 ++++++++++++++++++---- libobs-winrt/winrt-capture.h | 7 +- plugins/win-capture/data/locale/en-US.ini | 1 + plugins/win-capture/window-capture.c | 19 +++- 5 files changed, 116 insertions(+), 23 deletions(-) diff --git a/libobs-winrt/CMakeLists.txt b/libobs-winrt/CMakeLists.txt index f6a88326c..1739fd50f 100644 --- a/libobs-winrt/CMakeLists.txt +++ b/libobs-winrt/CMakeLists.txt @@ -24,11 +24,13 @@ target_precompile_headers(libobs-winrt [["../libobs/util/windows/ComPtr.hpp"]] + ) target_link_libraries(libobs-winrt libobs + Dwmapi windowsapp) install_obs_core(libobs-winrt) diff --git a/libobs-winrt/winrt-capture.cpp b/libobs-winrt/winrt-capture.cpp index b426d1a16..7fb6a68ce 100644 --- a/libobs-winrt/winrt-capture.cpp +++ b/libobs-winrt/winrt-capture.cpp @@ -31,8 +31,56 @@ static winrt::com_ptr GetDXGIInterfaceFromObject( return result; } +static bool get_client_box(HWND window, uint32_t width, uint32_t height, + D3D11_BOX *client_box) +{ + RECT client_rect, window_rect{}; + POINT upper_left{}; + + const bool client_box_available = + GetClientRect(window, &client_rect) && + (DwmGetWindowAttribute(window, DWMWA_EXTENDED_FRAME_BOUNDS, + &window_rect, + sizeof(window_rect)) == S_OK) && + ClientToScreen(window, &upper_left); + if (client_box_available) { + const uint32_t left = + (upper_left.x > window_rect.left) + ? (upper_left.x - window_rect.left) + : 0; + client_box->left = left; + + const uint32_t top = (upper_left.y > window_rect.top) + ? (upper_left.y - window_rect.top) + : 0; + client_box->top = top; + + uint32_t texture_width = 1; + if (width > left) { + texture_width = + min(width - left, (uint32_t)client_rect.right); + } + + uint32_t texture_height = 1; + if (height > top) { + texture_height = + min(height - top, (uint32_t)client_rect.bottom); + } + + client_box->right = left + texture_width; + client_box->bottom = top + texture_height; + + client_box->front = 0; + client_box->back = 1; + } + + return client_box_available; +} + struct winrt_capture { bool capture_cursor; + HWND window; + bool client_area; gs_texture_t *texture; bool texture_written; @@ -48,6 +96,11 @@ struct winrt_capture { winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool:: FrameArrived_revoker frame_arrived; + uint32_t texture_width; + uint32_t texture_height; + D3D11_BOX client_box; + bool client_box_available; + bool thread_changed; struct winrt_capture *next; @@ -70,23 +123,45 @@ struct winrt_capture { D3D11_TEXTURE2D_DESC desc; frame_surface->GetDesc(&desc); + client_box_available = false; + if (client_area) { + client_box_available = get_client_box( + window, desc.Width, desc.Height, &client_box); + } + + if (client_box_available) { + texture_width = client_box.right - client_box.left; + texture_height = client_box.bottom - client_box.top; + } else { + texture_width = desc.Width; + texture_height = desc.Height; + } + if (texture) { - if (desc.Width != gs_texture_get_width(texture) || - desc.Height != gs_texture_get_height(texture)) { + if (texture_width != gs_texture_get_width(texture) || + texture_height != gs_texture_get_height(texture)) { gs_texture_destroy(texture); texture = nullptr; } } if (!texture) { - texture = gs_texture_create(desc.Width, desc.Height, - GS_BGRA, 1, nullptr, 0); + texture = gs_texture_create(texture_width, + texture_height, GS_BGRA, 1, + nullptr, 0); } - /* if they gave an SRV, we could avoid this copy */ - context->CopyResource( - (ID3D11Texture2D *)gs_texture_get_obj(texture), - frame_surface.get()); + if (client_box_available) { + context->CopySubresourceRegion( + (ID3D11Texture2D *)gs_texture_get_obj(texture), + 0, 0, 0, 0, frame_surface.get(), 0, + &client_box); + } else { + /* if they gave an SRV, we could avoid this copy */ + context->CopyResource( + (ID3D11Texture2D *)gs_texture_get_obj(texture), + frame_surface.get()); + } texture_written = true; @@ -160,8 +235,8 @@ static void winrt_capture_device_loss_rebuild(void *device_void, void *data) thread_local bool initialized_tls; -extern "C" EXPORT struct winrt_capture *winrt_capture_init(bool cursor, - HWND window) +extern "C" EXPORT struct winrt_capture * +winrt_capture_init(bool cursor, HWND window, bool client_area) { ID3D11Device *const d3d_device = (ID3D11Device *)gs_get_device_obj(); ComPtr dxgi_device; @@ -192,8 +267,9 @@ extern "C" EXPORT struct winrt_capture *winrt_capture_init(bool cursor, IGraphicsCaptureItem>(), reinterpret_cast(winrt::put_abi(item))); } catch (winrt::hresult_invalid_argument &) { - blog(LOG_WARNING, "[winrt_capture_init] Failed to " - "create GraphicsCaptureItem"); + /* too spammy */ + //blog(LOG_WARNING, "[winrt_capture_init] Failed to " + // "create GraphicsCaptureItem"); return nullptr; } @@ -216,6 +292,8 @@ extern "C" EXPORT struct winrt_capture *winrt_capture_init(bool cursor, struct winrt_capture *capture = new winrt_capture{}; capture->capture_cursor = cursor; + capture->window = window; + capture->client_area = client_area; capture->item = item; capture->device = device; d3d_device->GetImmediateContext(&capture->context); @@ -315,14 +393,14 @@ extern "C" EXPORT void winrt_capture_render(struct winrt_capture *capture, } } -extern "C" EXPORT int32_t +extern "C" EXPORT uint32_t winrt_capture_width(const struct winrt_capture *capture) { - return capture ? capture->last_size.Width : 0; + return capture ? capture->texture_width : 0; } -extern "C" EXPORT int32_t +extern "C" EXPORT uint32_t winrt_capture_height(const struct winrt_capture *capture) { - return capture ? capture->last_size.Height : 0; + return capture ? capture->texture_height : 0; } diff --git a/libobs-winrt/winrt-capture.h b/libobs-winrt/winrt-capture.h index a42e05579..ae5cefb1f 100644 --- a/libobs-winrt/winrt-capture.h +++ b/libobs-winrt/winrt-capture.h @@ -10,13 +10,14 @@ extern "C" { #endif EXPORT bool winrt_capture_supported(); -EXPORT struct winrt_capture *winrt_capture_init(bool cursor, HWND window); +EXPORT struct winrt_capture *winrt_capture_init(bool cursor, HWND window, + bool client_area); EXPORT void winrt_capture_free(struct winrt_capture *capture); EXPORT void winrt_capture_render(struct winrt_capture *capture, gs_effect_t *effect); -EXPORT int32_t winrt_capture_width(const struct winrt_capture *capture); -EXPORT int32_t winrt_capture_height(const struct winrt_capture *capture); +EXPORT uint32_t winrt_capture_width(const struct winrt_capture *capture); +EXPORT uint32_t winrt_capture_height(const struct winrt_capture *capture); #ifdef __cplusplus } diff --git a/plugins/win-capture/data/locale/en-US.ini b/plugins/win-capture/data/locale/en-US.ini index 9c517e5aa..a8aae008c 100644 --- a/plugins/win-capture/data/locale/en-US.ini +++ b/plugins/win-capture/data/locale/en-US.ini @@ -11,6 +11,7 @@ WindowCapture.Priority.Class="Match title, otherwise find window of same type" WindowCapture.Priority.Exe="Match title, otherwise find window of same executable" CaptureCursor="Capture Cursor" Compatibility="Multi-adapter Compatibility" +ClientArea="Client Area" SLIFix="SLI/Crossfire Capture Mode (Slow)" AllowTransparency="Allow Transparency" Monitor="Display" diff --git a/plugins/win-capture/window-capture.c b/plugins/win-capture/window-capture.c index 631eedd0b..9e43aee05 100644 --- a/plugins/win-capture/window-capture.c +++ b/plugins/win-capture/window-capture.c @@ -19,6 +19,7 @@ #define TEXT_MATCH_EXE obs_module_text("WindowCapture.Priority.Exe") #define TEXT_CAPTURE_CURSOR obs_module_text("CaptureCursor") #define TEXT_COMPATIBILITY obs_module_text("Compatibility") +#define TEXT_CLIENT_AREA obs_module_text("ClientArea") /* clang-format on */ @@ -26,12 +27,13 @@ struct winrt_exports { bool *(*winrt_capture_supported)(); - struct winrt_capture *(*winrt_capture_init)(bool cursor, HWND window); + struct winrt_capture *(*winrt_capture_init)(bool cursor, HWND window, + bool client_area); void (*winrt_capture_free)(struct winrt_capture *capture); void (*winrt_capture_render)(struct winrt_capture *capture, gs_effect_t *effect); - int32_t (*winrt_capture_width)(const struct winrt_capture *capture); - int32_t (*winrt_capture_height)(const struct winrt_capture *capture); + uint32_t (*winrt_capture_width)(const struct winrt_capture *capture); + uint32_t (*winrt_capture_height)(const struct winrt_capture *capture); }; enum window_capture_method { @@ -50,6 +52,7 @@ struct window_capture { enum window_priority priority; bool cursor; bool compatibility; + bool client_area; bool use_wildcards; /* TODO */ struct dc_capture capture; @@ -139,6 +142,7 @@ static void update_settings(struct window_capture *wc, obs_data_t *s) wc->cursor = obs_data_get_bool(s, "cursor"); wc->use_wildcards = obs_data_get_bool(s, "use_wildcards"); wc->compatibility = obs_data_get_bool(s, "compatibility"); + wc->client_area = obs_data_get_bool(s, "client_area"); } /* ------------------------------------------------------------------------- */ @@ -252,18 +256,23 @@ static void wc_defaults(obs_data_t *defaults) obs_data_set_default_int(defaults, "method", METHOD_AUTO); obs_data_set_default_bool(defaults, "cursor", true); obs_data_set_default_bool(defaults, "compatibility", false); + obs_data_set_default_bool(defaults, "client_area", true); } static void update_settings_visibility(obs_properties_t *props, enum window_capture_method method) { const bool bitblt_options = method == METHOD_BITBLT; + const bool wgc_options = method == METHOD_WGC; obs_property_t *p = obs_properties_get(props, "cursor"); obs_property_set_visible(p, bitblt_options); p = obs_properties_get(props, "compatibility"); obs_property_set_visible(p, bitblt_options); + + p = obs_properties_get(props, "client_area"); + obs_property_set_visible(p, wgc_options); } static bool wc_capture_method_changed(obs_properties_t *props, @@ -321,6 +330,8 @@ static obs_properties_t *wc_properties(void *data) obs_properties_add_bool(ppts, "compatibility", TEXT_COMPATIBILITY); + obs_properties_add_bool(ppts, "client_area", TEXT_CLIENT_AREA); + return ppts; } @@ -441,7 +452,7 @@ static void wc_tick(void *data, float seconds) } else if (wc->method == METHOD_WGC) { if (wc->window && (wc->capture_winrt == NULL)) { wc->capture_winrt = wc->exports.winrt_capture_init( - wc->cursor, wc->window); + wc->cursor, wc->window, wc->client_area); } }