diff --git a/libobs-winrt/CMakeLists.txt b/libobs-winrt/CMakeLists.txt index fe0806323..70f0c3920 100644 --- a/libobs-winrt/CMakeLists.txt +++ b/libobs-winrt/CMakeLists.txt @@ -7,10 +7,12 @@ add_definitions(-DLIBOBS_EXPORTS) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(libobs-winrt_SOURCES - winrt-capture.cpp) + winrt-capture.cpp + winrt-dispatch.cpp) set(libobs-winrt_HEADERS - winrt-capture.h) + winrt-capture.h + winrt-dispatch.h) add_library(libobs-winrt MODULE ${libobs-winrt_SOURCES} @@ -25,10 +27,12 @@ target_precompile_headers(libobs-winrt [["../libobs/util/windows/ComPtr.hpp"]] + - ) + + ) target_link_libraries(libobs-winrt libobs Dwmapi diff --git a/libobs-winrt/winrt-capture.cpp b/libobs-winrt/winrt-capture.cpp index 533b83d07..1935a491f 100644 --- a/libobs-winrt/winrt-capture.cpp +++ b/libobs-winrt/winrt-capture.cpp @@ -133,7 +133,6 @@ struct winrt_capture { D3D11_BOX client_box; bool client_box_available; - bool thread_changed; bool active; struct winrt_capture *next; @@ -276,7 +275,7 @@ struct winrt_capture { } }; -struct winrt_capture *capture_list; +static struct winrt_capture *capture_list; static void winrt_capture_device_loss_release(void *data) { @@ -289,12 +288,32 @@ static void winrt_capture_device_loss_release(void *data) capture->frame_pool = nullptr; capture->context = nullptr; capture->device = nullptr; + capture->item = nullptr; } static void winrt_capture_device_loss_rebuild(void *device_void, void *data) { winrt_capture *capture = static_cast(data); + auto activation_factory = winrt::get_activation_factory< + winrt::Windows::Graphics::Capture::GraphicsCaptureItem>(); + auto interop_factory = + activation_factory.as(); + winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr}; + try { + interop_factory->CreateForWindow( + capture->window, + winrt::guid_of(), + reinterpret_cast(winrt::put_abi(item))); + } catch (winrt::hresult_error &err) { + blog(LOG_ERROR, "CreateForWindow (0x%08X): %ls", err.to_abi(), + err.message().c_str()); + } catch (...) { + blog(LOG_ERROR, "CreateForWindow (0x%08X)", + winrt::to_hresult()); + } + ID3D11Device *const d3d_device = (ID3D11Device *)device_void; ComPtr dxgi_device; if (FAILED(d3d_device->QueryInterface(&dxgi_device))) @@ -316,7 +335,7 @@ static void winrt_capture_device_loss_rebuild(void *device_void, void *data) DirectXPixelFormat::B8G8R8A8UIntNormalized, 2, capture->last_size); const winrt::Windows::Graphics::Capture::GraphicsCaptureSession session = - frame_pool.CreateCaptureSession(capture->item); + frame_pool.CreateCaptureSession(item); /* disable cursor capture if possible since ours performs better */ #ifdef NTDDI_WIN10_VB @@ -324,6 +343,7 @@ static void winrt_capture_device_loss_rebuild(void *device_void, void *data) session.IsCursorCaptureEnabled(false); #endif + capture->item = item; capture->device = device; d3d_device->GetImmediateContext(&capture->context); capture->frame_pool = frame_pool; @@ -335,8 +355,6 @@ static void winrt_capture_device_loss_rebuild(void *device_void, void *data) session.StartCapture(); } -thread_local bool initialized_tls; - extern "C" EXPORT struct winrt_capture * winrt_capture_init(BOOL cursor, HWND window, BOOL client_area) try { @@ -400,9 +418,6 @@ try { session.IsCursorCaptureEnabled(false); #endif - if (capture_list == nullptr) - initialized_tls = true; - struct winrt_capture *capture = new winrt_capture{}; capture->window = window; capture->client_area = client_area; @@ -505,28 +520,8 @@ extern "C" EXPORT void winrt_capture_show_cursor(struct winrt_capture *capture, extern "C" EXPORT void winrt_capture_render(struct winrt_capture *capture, gs_effect_t *effect) { - if (capture->texture_written) { - if (!initialized_tls) { - struct winrt_capture *current = capture_list; - while (current) { - current->thread_changed = true; - current = current->next; - } - - initialized_tls = true; - } - - if (capture->thread_changed) { - /* new graphics thread. treat like device loss. */ - winrt_capture_device_loss_release(capture); - winrt_capture_device_loss_rebuild(gs_get_device_obj(), - capture); - - capture->thread_changed = false; - } - + if (capture->texture_written) draw_texture(capture, effect); - } } extern "C" EXPORT uint32_t @@ -540,3 +535,22 @@ winrt_capture_height(const struct winrt_capture *capture) { return capture ? capture->texture_height : 0; } + +extern "C" EXPORT void winrt_capture_thread_start() +{ + struct winrt_capture *capture = capture_list; + void *const device = gs_get_device_obj(); + while (capture) { + winrt_capture_device_loss_rebuild(device, capture); + capture = capture->next; + } +} + +extern "C" EXPORT void winrt_capture_thread_stop() +{ + struct winrt_capture *capture = capture_list; + while (capture) { + winrt_capture_device_loss_release(capture); + capture = capture->next; + } +} diff --git a/libobs-winrt/winrt-capture.h b/libobs-winrt/winrt-capture.h index 815395946..67904fe0e 100644 --- a/libobs-winrt/winrt-capture.h +++ b/libobs-winrt/winrt-capture.h @@ -23,6 +23,9 @@ EXPORT void winrt_capture_render(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); +EXPORT void winrt_capture_thread_start(); +EXPORT void winrt_capture_thread_stop(); + #ifdef __cplusplus } #endif diff --git a/libobs-winrt/winrt-dispatch.cpp b/libobs-winrt/winrt-dispatch.cpp new file mode 100644 index 000000000..02b7a9fa0 --- /dev/null +++ b/libobs-winrt/winrt-dispatch.cpp @@ -0,0 +1,64 @@ +extern "C" EXPORT void winrt_initialize() +{ + winrt::init_apartment(winrt::apartment_type::single_threaded); +} + +extern "C" EXPORT void winrt_uninitialize() +{ + winrt::uninit_apartment(); +} + +static winrt::Windows::System::DispatcherQueueController +CreateDispatcherQueueController() +{ + DispatcherQueueOptions options{sizeof(DispatcherQueueOptions), + DQTYPE_THREAD_CURRENT, DQTAT_COM_STA}; + + winrt::Windows::System::DispatcherQueueController controller{nullptr}; + winrt::check_hresult(CreateDispatcherQueueController( + options, + reinterpret_cast< + ABI::Windows::System::IDispatcherQueueController **>( + winrt::put_abi(controller)))); + return controller; +} + +struct winrt_disaptcher { + winrt::Windows::System::DispatcherQueueController controller{nullptr}; +}; + +extern "C" EXPORT struct winrt_disaptcher *winrt_dispatcher_init() +{ + struct winrt_disaptcher *dispatcher = NULL; + try { + if (winrt::Windows::Foundation::Metadata::ApiInformation:: + IsApiContractPresent( + L"Windows.Foundation.UniversalApiContract", + 5)) { + winrt::Windows::System::DispatcherQueueController + controller = CreateDispatcherQueueController(); + + dispatcher = new struct winrt_disaptcher; + dispatcher->controller = std::move(controller); + } + } catch (const winrt::hresult_error &err) { + blog(LOG_ERROR, "winrt_dispatcher_init (0x%08X): %ls", + err.to_abi(), err.message().c_str()); + } catch (...) { + blog(LOG_ERROR, "winrt_dispatcher_init (0x%08X)", + winrt::to_hresult()); + } + + return dispatcher; +} + +extern "C" EXPORT void +winrt_dispatcher_free(struct winrt_disaptcher *dispatcher) +try { + delete dispatcher; +} catch (const winrt::hresult_error &err) { + blog(LOG_ERROR, "winrt_dispatcher_free (0x%08X): %ls", err.to_abi(), + err.message().c_str()); +} catch (...) { + blog(LOG_ERROR, "winrt_dispatcher_free (0x%08X)", winrt::to_hresult()); +} diff --git a/libobs-winrt/winrt-dispatch.h b/libobs-winrt/winrt-dispatch.h new file mode 100644 index 000000000..e2d01b8a1 --- /dev/null +++ b/libobs-winrt/winrt-dispatch.h @@ -0,0 +1,19 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +EXPORT void winrt_initialize(); +EXPORT void winrt_uninitialize(); +EXPORT struct winrt_disaptcher *winrt_dispatcher_init(); +EXPORT void winrt_dispatcher_free(struct winrt_disaptcher *dispatcher); + +#ifdef __cplusplus +} +#endif