libobs-winrt: Add dispatcher queue API
Suspected necessary for WGC stability.
This commit is contained in:
parent
cb98f456eb
commit
49bc89f2b2
@ -7,10 +7,12 @@ add_definitions(-DLIBOBS_EXPORTS)
|
|||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
set(libobs-winrt_SOURCES
|
set(libobs-winrt_SOURCES
|
||||||
winrt-capture.cpp)
|
winrt-capture.cpp
|
||||||
|
winrt-dispatch.cpp)
|
||||||
|
|
||||||
set(libobs-winrt_HEADERS
|
set(libobs-winrt_HEADERS
|
||||||
winrt-capture.h)
|
winrt-capture.h
|
||||||
|
winrt-dispatch.h)
|
||||||
|
|
||||||
add_library(libobs-winrt MODULE
|
add_library(libobs-winrt MODULE
|
||||||
${libobs-winrt_SOURCES}
|
${libobs-winrt_SOURCES}
|
||||||
@ -25,10 +27,12 @@ target_precompile_headers(libobs-winrt
|
|||||||
[["../libobs/util/windows/ComPtr.hpp"]]
|
[["../libobs/util/windows/ComPtr.hpp"]]
|
||||||
<obs-module.h>
|
<obs-module.h>
|
||||||
<d3d11.h>
|
<d3d11.h>
|
||||||
|
<DispatcherQueue.h>
|
||||||
<dwmapi.h>
|
<dwmapi.h>
|
||||||
<Windows.Graphics.Capture.Interop.h>
|
<Windows.Graphics.Capture.Interop.h>
|
||||||
<winrt/Windows.Foundation.Metadata.h>
|
<winrt/Windows.Foundation.Metadata.h>
|
||||||
<winrt/Windows.Graphics.Capture.h>)
|
<winrt/Windows.Graphics.Capture.h>
|
||||||
|
<winrt/Windows.System.h>)
|
||||||
target_link_libraries(libobs-winrt
|
target_link_libraries(libobs-winrt
|
||||||
libobs
|
libobs
|
||||||
Dwmapi
|
Dwmapi
|
||||||
|
@ -133,7 +133,6 @@ struct winrt_capture {
|
|||||||
D3D11_BOX client_box;
|
D3D11_BOX client_box;
|
||||||
bool client_box_available;
|
bool client_box_available;
|
||||||
|
|
||||||
bool thread_changed;
|
|
||||||
bool active;
|
bool active;
|
||||||
struct winrt_capture *next;
|
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)
|
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->frame_pool = nullptr;
|
||||||
capture->context = nullptr;
|
capture->context = nullptr;
|
||||||
capture->device = nullptr;
|
capture->device = nullptr;
|
||||||
|
capture->item = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void winrt_capture_device_loss_rebuild(void *device_void, void *data)
|
static void winrt_capture_device_loss_rebuild(void *device_void, void *data)
|
||||||
{
|
{
|
||||||
winrt_capture *capture = static_cast<winrt_capture *>(data);
|
winrt_capture *capture = static_cast<winrt_capture *>(data);
|
||||||
|
|
||||||
|
auto activation_factory = winrt::get_activation_factory<
|
||||||
|
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
||||||
|
auto interop_factory =
|
||||||
|
activation_factory.as<IGraphicsCaptureItemInterop>();
|
||||||
|
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
|
||||||
|
try {
|
||||||
|
interop_factory->CreateForWindow(
|
||||||
|
capture->window,
|
||||||
|
winrt::guid_of<ABI::Windows::Graphics::Capture::
|
||||||
|
IGraphicsCaptureItem>(),
|
||||||
|
reinterpret_cast<void **>(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;
|
ID3D11Device *const d3d_device = (ID3D11Device *)device_void;
|
||||||
ComPtr<IDXGIDevice> dxgi_device;
|
ComPtr<IDXGIDevice> dxgi_device;
|
||||||
if (FAILED(d3d_device->QueryInterface(&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,
|
DirectXPixelFormat::B8G8R8A8UIntNormalized,
|
||||||
2, capture->last_size);
|
2, capture->last_size);
|
||||||
const winrt::Windows::Graphics::Capture::GraphicsCaptureSession session =
|
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 */
|
/* disable cursor capture if possible since ours performs better */
|
||||||
#ifdef NTDDI_WIN10_VB
|
#ifdef NTDDI_WIN10_VB
|
||||||
@ -324,6 +343,7 @@ static void winrt_capture_device_loss_rebuild(void *device_void, void *data)
|
|||||||
session.IsCursorCaptureEnabled(false);
|
session.IsCursorCaptureEnabled(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
capture->item = item;
|
||||||
capture->device = device;
|
capture->device = device;
|
||||||
d3d_device->GetImmediateContext(&capture->context);
|
d3d_device->GetImmediateContext(&capture->context);
|
||||||
capture->frame_pool = frame_pool;
|
capture->frame_pool = frame_pool;
|
||||||
@ -335,8 +355,6 @@ static void winrt_capture_device_loss_rebuild(void *device_void, void *data)
|
|||||||
session.StartCapture();
|
session.StartCapture();
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_local bool initialized_tls;
|
|
||||||
|
|
||||||
extern "C" EXPORT struct winrt_capture *
|
extern "C" EXPORT struct winrt_capture *
|
||||||
winrt_capture_init(BOOL cursor, HWND window, BOOL client_area)
|
winrt_capture_init(BOOL cursor, HWND window, BOOL client_area)
|
||||||
try {
|
try {
|
||||||
@ -400,9 +418,6 @@ try {
|
|||||||
session.IsCursorCaptureEnabled(false);
|
session.IsCursorCaptureEnabled(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (capture_list == nullptr)
|
|
||||||
initialized_tls = true;
|
|
||||||
|
|
||||||
struct winrt_capture *capture = new winrt_capture{};
|
struct winrt_capture *capture = new winrt_capture{};
|
||||||
capture->window = window;
|
capture->window = window;
|
||||||
capture->client_area = client_area;
|
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,
|
extern "C" EXPORT void winrt_capture_render(struct winrt_capture *capture,
|
||||||
gs_effect_t *effect)
|
gs_effect_t *effect)
|
||||||
{
|
{
|
||||||
if (capture->texture_written) {
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_texture(capture, effect);
|
draw_texture(capture, effect);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" EXPORT uint32_t
|
extern "C" EXPORT uint32_t
|
||||||
@ -540,3 +535,22 @@ winrt_capture_height(const struct winrt_capture *capture)
|
|||||||
{
|
{
|
||||||
return capture ? capture->texture_height : 0;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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_width(const struct winrt_capture *capture);
|
||||||
EXPORT uint32_t winrt_capture_height(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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
64
libobs-winrt/winrt-dispatch.cpp
Normal file
64
libobs-winrt/winrt-dispatch.cpp
Normal file
@ -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());
|
||||||
|
}
|
19
libobs-winrt/winrt-dispatch.h
Normal file
19
libobs-winrt/winrt-dispatch.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <obs-module.h>
|
||||||
|
|
||||||
|
#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
|
Loading…
x
Reference in New Issue
Block a user