clang: adjust formatting rules (#1015)
This commit is contained in:
@@ -6,16 +6,15 @@
|
||||
// http://eretik.omegahg.com/
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#undef DEFINE_GUID
|
||||
#ifdef __cplusplus
|
||||
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) EXTERN_C const GUID DECLSPEC_SELECTANY name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
|
||||
#else
|
||||
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID DECLSPEC_SELECTANY name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
|
||||
#endif
|
||||
#undef DEFINE_GUID
|
||||
#ifdef __cplusplus
|
||||
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) EXTERN_C const GUID DECLSPEC_SELECTANY name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
|
||||
#else
|
||||
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID DECLSPEC_SELECTANY name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
|
||||
#endif
|
||||
|
||||
DEFINE_GUID(IID_IPolicyConfig, 0xf8679f50, 0x850a, 0x41cf, 0x9c, 0x72, 0x43, 0x0f, 0x29, 0x02, 0x90, 0xc8);
|
||||
DEFINE_GUID(CLSID_CPolicyConfigClient, 0x870af99c, 0x171d, 0x4f9e, 0xaf, 0x0d, 0xe6, 0x3d, 0xf4, 0x0c, 0x2b, 0xc9);
|
||||
@@ -37,13 +36,15 @@ class DECLSPEC_UUID("870af99c-171d-4f9e-af0d-e63df40c2bc9") CPolicyConfigClient;
|
||||
//
|
||||
// @compatible: Windows 7 and Later
|
||||
// ----------------------------------------------------------------------------
|
||||
interface IPolicyConfig : public IUnknown {
|
||||
interface IPolicyConfig: public IUnknown {
|
||||
public:
|
||||
virtual HRESULT GetMixFormat(
|
||||
virtual HRESULT
|
||||
GetMixFormat(
|
||||
PCWSTR,
|
||||
WAVEFORMATEX **);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetDeviceFormat(
|
||||
PCWSTR,
|
||||
INT,
|
||||
WAVEFORMATEX **);
|
||||
@@ -51,7 +52,8 @@ public:
|
||||
virtual HRESULT STDMETHODCALLTYPE ResetDeviceFormat(
|
||||
PCWSTR);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetDeviceFormat(
|
||||
PCWSTR,
|
||||
WAVEFORMATEX *,
|
||||
WAVEFORMATEX *);
|
||||
@@ -66,25 +68,30 @@ public:
|
||||
PCWSTR,
|
||||
PINT64);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetShareMode(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetShareMode(
|
||||
PCWSTR,
|
||||
struct DeviceShareMode *);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetShareMode(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetShareMode(
|
||||
PCWSTR,
|
||||
struct DeviceShareMode *);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetPropertyValue(
|
||||
PCWSTR,
|
||||
const PROPERTYKEY &,
|
||||
PROPVARIANT *);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetPropertyValue(
|
||||
PCWSTR,
|
||||
const PROPERTYKEY &,
|
||||
PROPVARIANT *);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetDefaultEndpoint(
|
||||
PCWSTR wszDeviceId,
|
||||
ERole eRole);
|
||||
|
||||
@@ -108,18 +115,21 @@ class DECLSPEC_UUID("294935CE-F637-4E7C-A41B-AB255460B862") CPolicyConfigVistaCl
|
||||
//
|
||||
// @compatible: Windows Vista and Later
|
||||
// ----------------------------------------------------------------------------
|
||||
interface IPolicyConfigVista : public IUnknown {
|
||||
interface IPolicyConfigVista: public IUnknown {
|
||||
public:
|
||||
virtual HRESULT GetMixFormat(
|
||||
virtual HRESULT
|
||||
GetMixFormat(
|
||||
PCWSTR,
|
||||
WAVEFORMATEX **); // not available on Windows 7, use method from IPolicyConfig
|
||||
WAVEFORMATEX **); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetDeviceFormat(
|
||||
PCWSTR,
|
||||
INT,
|
||||
WAVEFORMATEX **);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetDeviceFormat(
|
||||
PCWSTR,
|
||||
WAVEFORMATEX *,
|
||||
WAVEFORMATEX *);
|
||||
@@ -128,37 +138,42 @@ public:
|
||||
PCWSTR,
|
||||
INT,
|
||||
PINT64,
|
||||
PINT64); // not available on Windows 7, use method from IPolicyConfig
|
||||
PINT64); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetProcessingPeriod(
|
||||
PCWSTR,
|
||||
PINT64); // not available on Windows 7, use method from IPolicyConfig
|
||||
PINT64); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetShareMode(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetShareMode(
|
||||
PCWSTR,
|
||||
struct DeviceShareMode *); // not available on Windows 7, use method from IPolicyConfig
|
||||
struct DeviceShareMode *); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetShareMode(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetShareMode(
|
||||
PCWSTR,
|
||||
struct DeviceShareMode *); // not available on Windows 7, use method from IPolicyConfig
|
||||
struct DeviceShareMode *); // not available on Windows 7, use method from IPolicyConfig
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetPropertyValue(
|
||||
PCWSTR,
|
||||
const PROPERTYKEY &,
|
||||
PROPVARIANT *);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetPropertyValue(
|
||||
PCWSTR,
|
||||
const PROPERTYKEY &,
|
||||
PROPVARIANT *);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
SetDefaultEndpoint(
|
||||
PCWSTR wszDeviceId,
|
||||
ERole eRole);
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetEndpointVisibility(
|
||||
PCWSTR,
|
||||
INT); // not available on Windows 7, use method from IPolicyConfig
|
||||
INT); // not available on Windows 7, use method from IPolicyConfig
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,196 +16,229 @@
|
||||
#include "src/utility.h"
|
||||
|
||||
namespace platf::dxgi {
|
||||
extern const char *format_str[];
|
||||
extern const char *format_str[];
|
||||
|
||||
// Add D3D11_CREATE_DEVICE_DEBUG here to enable the D3D11 debug runtime.
|
||||
// You should have a debugger like WinDbg attached to receive debug messages.
|
||||
auto constexpr D3D11_CREATE_DEVICE_FLAGS = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
|
||||
// Add D3D11_CREATE_DEVICE_DEBUG here to enable the D3D11 debug runtime.
|
||||
// You should have a debugger like WinDbg attached to receive debug messages.
|
||||
auto constexpr D3D11_CREATE_DEVICE_FLAGS = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
|
||||
|
||||
template<class T>
|
||||
void Release(T *dxgi) {
|
||||
dxgi->Release();
|
||||
}
|
||||
|
||||
using factory1_t = util::safe_ptr<IDXGIFactory1, Release<IDXGIFactory1>>;
|
||||
using dxgi_t = util::safe_ptr<IDXGIDevice, Release<IDXGIDevice>>;
|
||||
using dxgi1_t = util::safe_ptr<IDXGIDevice1, Release<IDXGIDevice1>>;
|
||||
using device_t = util::safe_ptr<ID3D11Device, Release<ID3D11Device>>;
|
||||
using device1_t = util::safe_ptr<ID3D11Device1, Release<ID3D11Device1>>;
|
||||
using device_ctx_t = util::safe_ptr<ID3D11DeviceContext, Release<ID3D11DeviceContext>>;
|
||||
using adapter_t = util::safe_ptr<IDXGIAdapter1, Release<IDXGIAdapter1>>;
|
||||
using output_t = util::safe_ptr<IDXGIOutput, Release<IDXGIOutput>>;
|
||||
using output1_t = util::safe_ptr<IDXGIOutput1, Release<IDXGIOutput1>>;
|
||||
using output5_t = util::safe_ptr<IDXGIOutput5, Release<IDXGIOutput5>>;
|
||||
using output6_t = util::safe_ptr<IDXGIOutput6, Release<IDXGIOutput6>>;
|
||||
using dup_t = util::safe_ptr<IDXGIOutputDuplication, Release<IDXGIOutputDuplication>>;
|
||||
using texture2d_t = util::safe_ptr<ID3D11Texture2D, Release<ID3D11Texture2D>>;
|
||||
using texture1d_t = util::safe_ptr<ID3D11Texture1D, Release<ID3D11Texture1D>>;
|
||||
using resource_t = util::safe_ptr<IDXGIResource, Release<IDXGIResource>>;
|
||||
using resource1_t = util::safe_ptr<IDXGIResource1, Release<IDXGIResource1>>;
|
||||
using multithread_t = util::safe_ptr<ID3D11Multithread, Release<ID3D11Multithread>>;
|
||||
using vs_t = util::safe_ptr<ID3D11VertexShader, Release<ID3D11VertexShader>>;
|
||||
using ps_t = util::safe_ptr<ID3D11PixelShader, Release<ID3D11PixelShader>>;
|
||||
using blend_t = util::safe_ptr<ID3D11BlendState, Release<ID3D11BlendState>>;
|
||||
using input_layout_t = util::safe_ptr<ID3D11InputLayout, Release<ID3D11InputLayout>>;
|
||||
using render_target_t = util::safe_ptr<ID3D11RenderTargetView, Release<ID3D11RenderTargetView>>;
|
||||
using shader_res_t = util::safe_ptr<ID3D11ShaderResourceView, Release<ID3D11ShaderResourceView>>;
|
||||
using buf_t = util::safe_ptr<ID3D11Buffer, Release<ID3D11Buffer>>;
|
||||
using raster_state_t = util::safe_ptr<ID3D11RasterizerState, Release<ID3D11RasterizerState>>;
|
||||
using sampler_state_t = util::safe_ptr<ID3D11SamplerState, Release<ID3D11SamplerState>>;
|
||||
using blob_t = util::safe_ptr<ID3DBlob, Release<ID3DBlob>>;
|
||||
using depth_stencil_state_t = util::safe_ptr<ID3D11DepthStencilState, Release<ID3D11DepthStencilState>>;
|
||||
using depth_stencil_view_t = util::safe_ptr<ID3D11DepthStencilView, Release<ID3D11DepthStencilView>>;
|
||||
using keyed_mutex_t = util::safe_ptr<IDXGIKeyedMutex, Release<IDXGIKeyedMutex>>;
|
||||
|
||||
namespace video {
|
||||
using device_t = util::safe_ptr<ID3D11VideoDevice, Release<ID3D11VideoDevice>>;
|
||||
using ctx_t = util::safe_ptr<ID3D11VideoContext, Release<ID3D11VideoContext>>;
|
||||
using processor_t = util::safe_ptr<ID3D11VideoProcessor, Release<ID3D11VideoProcessor>>;
|
||||
using processor_out_t = util::safe_ptr<ID3D11VideoProcessorOutputView, Release<ID3D11VideoProcessorOutputView>>;
|
||||
using processor_in_t = util::safe_ptr<ID3D11VideoProcessorInputView, Release<ID3D11VideoProcessorInputView>>;
|
||||
using processor_enum_t = util::safe_ptr<ID3D11VideoProcessorEnumerator, Release<ID3D11VideoProcessorEnumerator>>;
|
||||
} // namespace video
|
||||
|
||||
class hwdevice_t;
|
||||
struct cursor_t {
|
||||
std::vector<std::uint8_t> img_data;
|
||||
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info;
|
||||
int x, y;
|
||||
bool visible;
|
||||
};
|
||||
|
||||
class gpu_cursor_t {
|
||||
public:
|
||||
gpu_cursor_t() : cursor_view { 0, 0, 0, 0, 0.0f, 1.0f } {};
|
||||
void set_pos(LONG rel_x, LONG rel_y, bool visible) {
|
||||
cursor_view.TopLeftX = rel_x;
|
||||
cursor_view.TopLeftY = rel_y;
|
||||
|
||||
this->visible = visible;
|
||||
template <class T>
|
||||
void
|
||||
Release(T *dxgi) {
|
||||
dxgi->Release();
|
||||
}
|
||||
|
||||
void set_texture(LONG width, LONG height, texture2d_t &&texture) {
|
||||
cursor_view.Width = width;
|
||||
cursor_view.Height = height;
|
||||
using factory1_t = util::safe_ptr<IDXGIFactory1, Release<IDXGIFactory1>>;
|
||||
using dxgi_t = util::safe_ptr<IDXGIDevice, Release<IDXGIDevice>>;
|
||||
using dxgi1_t = util::safe_ptr<IDXGIDevice1, Release<IDXGIDevice1>>;
|
||||
using device_t = util::safe_ptr<ID3D11Device, Release<ID3D11Device>>;
|
||||
using device1_t = util::safe_ptr<ID3D11Device1, Release<ID3D11Device1>>;
|
||||
using device_ctx_t = util::safe_ptr<ID3D11DeviceContext, Release<ID3D11DeviceContext>>;
|
||||
using adapter_t = util::safe_ptr<IDXGIAdapter1, Release<IDXGIAdapter1>>;
|
||||
using output_t = util::safe_ptr<IDXGIOutput, Release<IDXGIOutput>>;
|
||||
using output1_t = util::safe_ptr<IDXGIOutput1, Release<IDXGIOutput1>>;
|
||||
using output5_t = util::safe_ptr<IDXGIOutput5, Release<IDXGIOutput5>>;
|
||||
using output6_t = util::safe_ptr<IDXGIOutput6, Release<IDXGIOutput6>>;
|
||||
using dup_t = util::safe_ptr<IDXGIOutputDuplication, Release<IDXGIOutputDuplication>>;
|
||||
using texture2d_t = util::safe_ptr<ID3D11Texture2D, Release<ID3D11Texture2D>>;
|
||||
using texture1d_t = util::safe_ptr<ID3D11Texture1D, Release<ID3D11Texture1D>>;
|
||||
using resource_t = util::safe_ptr<IDXGIResource, Release<IDXGIResource>>;
|
||||
using resource1_t = util::safe_ptr<IDXGIResource1, Release<IDXGIResource1>>;
|
||||
using multithread_t = util::safe_ptr<ID3D11Multithread, Release<ID3D11Multithread>>;
|
||||
using vs_t = util::safe_ptr<ID3D11VertexShader, Release<ID3D11VertexShader>>;
|
||||
using ps_t = util::safe_ptr<ID3D11PixelShader, Release<ID3D11PixelShader>>;
|
||||
using blend_t = util::safe_ptr<ID3D11BlendState, Release<ID3D11BlendState>>;
|
||||
using input_layout_t = util::safe_ptr<ID3D11InputLayout, Release<ID3D11InputLayout>>;
|
||||
using render_target_t = util::safe_ptr<ID3D11RenderTargetView, Release<ID3D11RenderTargetView>>;
|
||||
using shader_res_t = util::safe_ptr<ID3D11ShaderResourceView, Release<ID3D11ShaderResourceView>>;
|
||||
using buf_t = util::safe_ptr<ID3D11Buffer, Release<ID3D11Buffer>>;
|
||||
using raster_state_t = util::safe_ptr<ID3D11RasterizerState, Release<ID3D11RasterizerState>>;
|
||||
using sampler_state_t = util::safe_ptr<ID3D11SamplerState, Release<ID3D11SamplerState>>;
|
||||
using blob_t = util::safe_ptr<ID3DBlob, Release<ID3DBlob>>;
|
||||
using depth_stencil_state_t = util::safe_ptr<ID3D11DepthStencilState, Release<ID3D11DepthStencilState>>;
|
||||
using depth_stencil_view_t = util::safe_ptr<ID3D11DepthStencilView, Release<ID3D11DepthStencilView>>;
|
||||
using keyed_mutex_t = util::safe_ptr<IDXGIKeyedMutex, Release<IDXGIKeyedMutex>>;
|
||||
|
||||
this->texture = std::move(texture);
|
||||
}
|
||||
namespace video {
|
||||
using device_t = util::safe_ptr<ID3D11VideoDevice, Release<ID3D11VideoDevice>>;
|
||||
using ctx_t = util::safe_ptr<ID3D11VideoContext, Release<ID3D11VideoContext>>;
|
||||
using processor_t = util::safe_ptr<ID3D11VideoProcessor, Release<ID3D11VideoProcessor>>;
|
||||
using processor_out_t = util::safe_ptr<ID3D11VideoProcessorOutputView, Release<ID3D11VideoProcessorOutputView>>;
|
||||
using processor_in_t = util::safe_ptr<ID3D11VideoProcessorInputView, Release<ID3D11VideoProcessorInputView>>;
|
||||
using processor_enum_t = util::safe_ptr<ID3D11VideoProcessorEnumerator, Release<ID3D11VideoProcessorEnumerator>>;
|
||||
} // namespace video
|
||||
|
||||
texture2d_t texture;
|
||||
shader_res_t input_res;
|
||||
class hwdevice_t;
|
||||
struct cursor_t {
|
||||
std::vector<std::uint8_t> img_data;
|
||||
|
||||
D3D11_VIEWPORT cursor_view;
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info;
|
||||
int x, y;
|
||||
bool visible;
|
||||
};
|
||||
|
||||
bool visible;
|
||||
};
|
||||
class gpu_cursor_t {
|
||||
public:
|
||||
gpu_cursor_t():
|
||||
cursor_view { 0, 0, 0, 0, 0.0f, 1.0f } {};
|
||||
void
|
||||
set_pos(LONG rel_x, LONG rel_y, bool visible) {
|
||||
cursor_view.TopLeftX = rel_x;
|
||||
cursor_view.TopLeftY = rel_y;
|
||||
|
||||
class duplication_t {
|
||||
public:
|
||||
dup_t dup;
|
||||
bool has_frame {};
|
||||
bool use_dwmflush {};
|
||||
this->visible = visible;
|
||||
}
|
||||
|
||||
capture_e next_frame(DXGI_OUTDUPL_FRAME_INFO &frame_info, std::chrono::milliseconds timeout, resource_t::pointer *res_p);
|
||||
capture_e reset(dup_t::pointer dup_p = dup_t::pointer());
|
||||
capture_e release_frame();
|
||||
void
|
||||
set_texture(LONG width, LONG height, texture2d_t &&texture) {
|
||||
cursor_view.Width = width;
|
||||
cursor_view.Height = height;
|
||||
|
||||
~duplication_t();
|
||||
};
|
||||
this->texture = std::move(texture);
|
||||
}
|
||||
|
||||
class display_base_t : public display_t {
|
||||
public:
|
||||
int init(const ::video::config_t &config, const std::string &display_name);
|
||||
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override;
|
||||
texture2d_t texture;
|
||||
shader_res_t input_res;
|
||||
|
||||
std::chrono::nanoseconds delay;
|
||||
D3D11_VIEWPORT cursor_view;
|
||||
|
||||
factory1_t factory;
|
||||
adapter_t adapter;
|
||||
output_t output;
|
||||
device_t device;
|
||||
device_ctx_t device_ctx;
|
||||
duplication_t dup;
|
||||
bool visible;
|
||||
};
|
||||
|
||||
DXGI_FORMAT capture_format;
|
||||
D3D_FEATURE_LEVEL feature_level;
|
||||
class duplication_t {
|
||||
public:
|
||||
dup_t dup;
|
||||
bool has_frame {};
|
||||
bool use_dwmflush {};
|
||||
|
||||
typedef enum _D3DKMT_SCHEDULINGPRIORITYCLASS {
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_IDLE,
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_BELOW_NORMAL,
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_NORMAL,
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_ABOVE_NORMAL,
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_HIGH,
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_REALTIME
|
||||
} D3DKMT_SCHEDULINGPRIORITYCLASS;
|
||||
capture_e
|
||||
next_frame(DXGI_OUTDUPL_FRAME_INFO &frame_info, std::chrono::milliseconds timeout, resource_t::pointer *res_p);
|
||||
capture_e
|
||||
reset(dup_t::pointer dup_p = dup_t::pointer());
|
||||
capture_e
|
||||
release_frame();
|
||||
|
||||
typedef NTSTATUS WINAPI (*PD3DKMTSetProcessSchedulingPriorityClass)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS);
|
||||
~duplication_t();
|
||||
};
|
||||
|
||||
virtual bool is_hdr() override;
|
||||
virtual bool get_hdr_metadata(SS_HDR_METADATA &metadata) override;
|
||||
class display_base_t: public display_t {
|
||||
public:
|
||||
int
|
||||
init(const ::video::config_t &config, const std::string &display_name);
|
||||
capture_e
|
||||
capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override;
|
||||
|
||||
protected:
|
||||
int get_pixel_pitch() {
|
||||
return (capture_format == DXGI_FORMAT_R16G16B16A16_FLOAT) ? 8 : 4;
|
||||
}
|
||||
std::chrono::nanoseconds delay;
|
||||
|
||||
const char *dxgi_format_to_string(DXGI_FORMAT format);
|
||||
const char *colorspace_to_string(DXGI_COLOR_SPACE_TYPE type);
|
||||
factory1_t factory;
|
||||
adapter_t adapter;
|
||||
output_t output;
|
||||
device_t device;
|
||||
device_ctx_t device_ctx;
|
||||
duplication_t dup;
|
||||
|
||||
virtual capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) = 0;
|
||||
virtual int complete_img(img_t *img, bool dummy) = 0;
|
||||
virtual std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() = 0;
|
||||
virtual std::vector<DXGI_FORMAT> get_supported_hdr_capture_formats() = 0;
|
||||
};
|
||||
DXGI_FORMAT capture_format;
|
||||
D3D_FEATURE_LEVEL feature_level;
|
||||
|
||||
class display_ram_t : public display_base_t {
|
||||
public:
|
||||
virtual capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) override;
|
||||
typedef enum _D3DKMT_SCHEDULINGPRIORITYCLASS {
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_IDLE,
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_BELOW_NORMAL,
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_NORMAL,
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_ABOVE_NORMAL,
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_HIGH,
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_REALTIME
|
||||
} D3DKMT_SCHEDULINGPRIORITYCLASS;
|
||||
|
||||
std::shared_ptr<img_t> alloc_img() override;
|
||||
int dummy_img(img_t *img) override;
|
||||
int complete_img(img_t *img, bool dummy) override;
|
||||
std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() override;
|
||||
std::vector<DXGI_FORMAT> get_supported_hdr_capture_formats() override;
|
||||
typedef NTSTATUS WINAPI (*PD3DKMTSetProcessSchedulingPriorityClass)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS);
|
||||
|
||||
int init(const ::video::config_t &config, const std::string &display_name);
|
||||
virtual bool
|
||||
is_hdr() override;
|
||||
virtual bool
|
||||
get_hdr_metadata(SS_HDR_METADATA &metadata) override;
|
||||
|
||||
cursor_t cursor;
|
||||
D3D11_MAPPED_SUBRESOURCE img_info;
|
||||
texture2d_t texture;
|
||||
};
|
||||
protected:
|
||||
int
|
||||
get_pixel_pitch() {
|
||||
return (capture_format == DXGI_FORMAT_R16G16B16A16_FLOAT) ? 8 : 4;
|
||||
}
|
||||
|
||||
class display_vram_t : public display_base_t, public std::enable_shared_from_this<display_vram_t> {
|
||||
public:
|
||||
virtual capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) override;
|
||||
const char *
|
||||
dxgi_format_to_string(DXGI_FORMAT format);
|
||||
const char *
|
||||
colorspace_to_string(DXGI_COLOR_SPACE_TYPE type);
|
||||
|
||||
std::shared_ptr<img_t> alloc_img() override;
|
||||
int dummy_img(img_t *img_base) override;
|
||||
int complete_img(img_t *img_base, bool dummy) override;
|
||||
std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() override;
|
||||
std::vector<DXGI_FORMAT> get_supported_hdr_capture_formats() override;
|
||||
virtual capture_e
|
||||
snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) = 0;
|
||||
virtual int
|
||||
complete_img(img_t *img, bool dummy) = 0;
|
||||
virtual std::vector<DXGI_FORMAT>
|
||||
get_supported_sdr_capture_formats() = 0;
|
||||
virtual std::vector<DXGI_FORMAT>
|
||||
get_supported_hdr_capture_formats() = 0;
|
||||
};
|
||||
|
||||
int init(const ::video::config_t &config, const std::string &display_name);
|
||||
class display_ram_t: public display_base_t {
|
||||
public:
|
||||
virtual capture_e
|
||||
snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) override;
|
||||
|
||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) override;
|
||||
std::shared_ptr<img_t>
|
||||
alloc_img() override;
|
||||
int
|
||||
dummy_img(img_t *img) override;
|
||||
int
|
||||
complete_img(img_t *img, bool dummy) override;
|
||||
std::vector<DXGI_FORMAT>
|
||||
get_supported_sdr_capture_formats() override;
|
||||
std::vector<DXGI_FORMAT>
|
||||
get_supported_hdr_capture_formats() override;
|
||||
|
||||
sampler_state_t sampler_linear;
|
||||
int
|
||||
init(const ::video::config_t &config, const std::string &display_name);
|
||||
|
||||
blend_t blend_alpha;
|
||||
blend_t blend_invert;
|
||||
blend_t blend_disable;
|
||||
cursor_t cursor;
|
||||
D3D11_MAPPED_SUBRESOURCE img_info;
|
||||
texture2d_t texture;
|
||||
};
|
||||
|
||||
ps_t scene_ps;
|
||||
vs_t scene_vs;
|
||||
class display_vram_t: public display_base_t, public std::enable_shared_from_this<display_vram_t> {
|
||||
public:
|
||||
virtual capture_e
|
||||
snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) override;
|
||||
|
||||
gpu_cursor_t cursor_alpha;
|
||||
gpu_cursor_t cursor_xor;
|
||||
std::shared_ptr<img_t>
|
||||
alloc_img() override;
|
||||
int
|
||||
dummy_img(img_t *img_base) override;
|
||||
int
|
||||
complete_img(img_t *img_base, bool dummy) override;
|
||||
std::vector<DXGI_FORMAT>
|
||||
get_supported_sdr_capture_formats() override;
|
||||
std::vector<DXGI_FORMAT>
|
||||
get_supported_hdr_capture_formats() override;
|
||||
|
||||
texture2d_t last_frame_copy;
|
||||
int
|
||||
init(const ::video::config_t &config, const std::string &display_name);
|
||||
|
||||
std::atomic<uint32_t> next_image_id;
|
||||
};
|
||||
} // namespace platf::dxgi
|
||||
std::shared_ptr<platf::hwdevice_t>
|
||||
make_hwdevice(pix_fmt_e pix_fmt) override;
|
||||
|
||||
sampler_state_t sampler_linear;
|
||||
|
||||
blend_t blend_alpha;
|
||||
blend_t blend_invert;
|
||||
blend_t blend_disable;
|
||||
|
||||
ps_t scene_ps;
|
||||
vs_t scene_vs;
|
||||
|
||||
gpu_cursor_t cursor_alpha;
|
||||
gpu_cursor_t cursor_xor;
|
||||
|
||||
texture2d_t last_frame_copy;
|
||||
|
||||
std::atomic<uint32_t> next_image_id;
|
||||
};
|
||||
} // namespace platf::dxgi
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,366 +2,378 @@
|
||||
#include "src/main.h"
|
||||
|
||||
namespace platf {
|
||||
using namespace std::literals;
|
||||
using namespace std::literals;
|
||||
}
|
||||
|
||||
namespace platf::dxgi {
|
||||
struct img_t : public ::platf::img_t {
|
||||
~img_t() override {
|
||||
delete[] data;
|
||||
data = nullptr;
|
||||
}
|
||||
};
|
||||
struct img_t: public ::platf::img_t {
|
||||
~img_t() override {
|
||||
delete[] data;
|
||||
data = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
void blend_cursor_monochrome(const cursor_t &cursor, img_t &img) {
|
||||
int height = cursor.shape_info.Height / 2;
|
||||
int width = cursor.shape_info.Width;
|
||||
int pitch = cursor.shape_info.Pitch;
|
||||
void
|
||||
blend_cursor_monochrome(const cursor_t &cursor, img_t &img) {
|
||||
int height = cursor.shape_info.Height / 2;
|
||||
int width = cursor.shape_info.Width;
|
||||
int pitch = cursor.shape_info.Pitch;
|
||||
|
||||
// img cursor.{x,y} < 0, skip parts of the cursor.img_data
|
||||
auto cursor_skip_y = -std::min(0, cursor.y);
|
||||
auto cursor_skip_x = -std::min(0, cursor.x);
|
||||
// img cursor.{x,y} < 0, skip parts of the cursor.img_data
|
||||
auto cursor_skip_y = -std::min(0, cursor.y);
|
||||
auto cursor_skip_x = -std::min(0, cursor.x);
|
||||
|
||||
// img cursor.{x,y} > img.{x,y}, truncate parts of the cursor.img_data
|
||||
auto cursor_truncate_y = std::max(0, cursor.y - img.height);
|
||||
auto cursor_truncate_x = std::max(0, cursor.x - img.width);
|
||||
// img cursor.{x,y} > img.{x,y}, truncate parts of the cursor.img_data
|
||||
auto cursor_truncate_y = std::max(0, cursor.y - img.height);
|
||||
auto cursor_truncate_x = std::max(0, cursor.x - img.width);
|
||||
|
||||
auto cursor_width = width - cursor_skip_x - cursor_truncate_x;
|
||||
auto cursor_height = height - cursor_skip_y - cursor_truncate_y;
|
||||
auto cursor_width = width - cursor_skip_x - cursor_truncate_x;
|
||||
auto cursor_height = height - cursor_skip_y - cursor_truncate_y;
|
||||
|
||||
if(cursor_height > height || cursor_width > width) {
|
||||
return;
|
||||
}
|
||||
if (cursor_height > height || cursor_width > width) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto img_skip_y = std::max(0, cursor.y);
|
||||
auto img_skip_x = std::max(0, cursor.x);
|
||||
auto img_skip_y = std::max(0, cursor.y);
|
||||
auto img_skip_x = std::max(0, cursor.x);
|
||||
|
||||
auto cursor_img_data = cursor.img_data.data() + cursor_skip_y * pitch;
|
||||
auto cursor_img_data = cursor.img_data.data() + cursor_skip_y * pitch;
|
||||
|
||||
int delta_height = std::min(cursor_height - cursor_truncate_y, std::max(0, img.height - img_skip_y));
|
||||
int delta_width = std::min(cursor_width - cursor_truncate_x, std::max(0, img.width - img_skip_x));
|
||||
int delta_height = std::min(cursor_height - cursor_truncate_y, std::max(0, img.height - img_skip_y));
|
||||
int delta_width = std::min(cursor_width - cursor_truncate_x, std::max(0, img.width - img_skip_x));
|
||||
|
||||
auto pixels_per_byte = width / pitch;
|
||||
auto bytes_per_row = delta_width / pixels_per_byte;
|
||||
auto pixels_per_byte = width / pitch;
|
||||
auto bytes_per_row = delta_width / pixels_per_byte;
|
||||
|
||||
auto img_data = (int *)img.data;
|
||||
for(int i = 0; i < delta_height; ++i) {
|
||||
auto and_mask = &cursor_img_data[i * pitch];
|
||||
auto xor_mask = &cursor_img_data[(i + height) * pitch];
|
||||
auto img_data = (int *) img.data;
|
||||
for (int i = 0; i < delta_height; ++i) {
|
||||
auto and_mask = &cursor_img_data[i * pitch];
|
||||
auto xor_mask = &cursor_img_data[(i + height) * pitch];
|
||||
|
||||
auto img_pixel_p = &img_data[(i + img_skip_y) * (img.row_pitch / img.pixel_pitch) + img_skip_x];
|
||||
auto img_pixel_p = &img_data[(i + img_skip_y) * (img.row_pitch / img.pixel_pitch) + img_skip_x];
|
||||
|
||||
auto skip_x = cursor_skip_x;
|
||||
for(int x = 0; x < bytes_per_row; ++x) {
|
||||
for(auto bit = 0u; bit < 8; ++bit) {
|
||||
if(skip_x > 0) {
|
||||
--skip_x;
|
||||
auto skip_x = cursor_skip_x;
|
||||
for (int x = 0; x < bytes_per_row; ++x) {
|
||||
for (auto bit = 0u; bit < 8; ++bit) {
|
||||
if (skip_x > 0) {
|
||||
--skip_x;
|
||||
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
int and_ = *and_mask & (1 << (7 - bit)) ? -1 : 0;
|
||||
int xor_ = *xor_mask & (1 << (7 - bit)) ? -1 : 0;
|
||||
|
||||
*img_pixel_p &= and_;
|
||||
*img_pixel_p ^= xor_;
|
||||
|
||||
++img_pixel_p;
|
||||
}
|
||||
|
||||
int and_ = *and_mask & (1 << (7 - bit)) ? -1 : 0;
|
||||
int xor_ = *xor_mask & (1 << (7 - bit)) ? -1 : 0;
|
||||
++and_mask;
|
||||
++xor_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*img_pixel_p &= and_;
|
||||
*img_pixel_p ^= xor_;
|
||||
void
|
||||
apply_color_alpha(int *img_pixel_p, int cursor_pixel) {
|
||||
auto colors_out = (std::uint8_t *) &cursor_pixel;
|
||||
auto colors_in = (std::uint8_t *) img_pixel_p;
|
||||
|
||||
//TODO: When use of IDXGIOutput5 is implemented, support different color formats
|
||||
auto alpha = colors_out[3];
|
||||
if (alpha == 255) {
|
||||
*img_pixel_p = cursor_pixel;
|
||||
}
|
||||
else {
|
||||
colors_in[0] = colors_out[0] + (colors_in[0] * (255 - alpha) + 255 / 2) / 255;
|
||||
colors_in[1] = colors_out[1] + (colors_in[1] * (255 - alpha) + 255 / 2) / 255;
|
||||
colors_in[2] = colors_out[2] + (colors_in[2] * (255 - alpha) + 255 / 2) / 255;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
apply_color_masked(int *img_pixel_p, int cursor_pixel) {
|
||||
//TODO: When use of IDXGIOutput5 is implemented, support different color formats
|
||||
auto alpha = ((std::uint8_t *) &cursor_pixel)[3];
|
||||
if (alpha == 0xFF) {
|
||||
*img_pixel_p ^= cursor_pixel;
|
||||
}
|
||||
else {
|
||||
*img_pixel_p = cursor_pixel;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
blend_cursor_color(const cursor_t &cursor, img_t &img, const bool masked) {
|
||||
int height = cursor.shape_info.Height;
|
||||
int width = cursor.shape_info.Width;
|
||||
int pitch = cursor.shape_info.Pitch;
|
||||
|
||||
// img cursor.y < 0, skip parts of the cursor.img_data
|
||||
auto cursor_skip_y = -std::min(0, cursor.y);
|
||||
auto cursor_skip_x = -std::min(0, cursor.x);
|
||||
|
||||
// img cursor.{x,y} > img.{x,y}, truncate parts of the cursor.img_data
|
||||
auto cursor_truncate_y = std::max(0, cursor.y - img.height);
|
||||
auto cursor_truncate_x = std::max(0, cursor.x - img.width);
|
||||
|
||||
auto img_skip_y = std::max(0, cursor.y);
|
||||
auto img_skip_x = std::max(0, cursor.x);
|
||||
|
||||
auto cursor_width = width - cursor_skip_x - cursor_truncate_x;
|
||||
auto cursor_height = height - cursor_skip_y - cursor_truncate_y;
|
||||
|
||||
if (cursor_height > height || cursor_width > width) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto cursor_img_data = (int *) &cursor.img_data[cursor_skip_y * pitch];
|
||||
|
||||
int delta_height = std::min(cursor_height - cursor_truncate_y, std::max(0, img.height - img_skip_y));
|
||||
int delta_width = std::min(cursor_width - cursor_truncate_x, std::max(0, img.width - img_skip_x));
|
||||
|
||||
auto img_data = (int *) img.data;
|
||||
|
||||
for (int i = 0; i < delta_height; ++i) {
|
||||
auto cursor_begin = &cursor_img_data[i * cursor.shape_info.Width + cursor_skip_x];
|
||||
auto cursor_end = &cursor_begin[delta_width];
|
||||
|
||||
auto img_pixel_p = &img_data[(i + img_skip_y) * (img.row_pitch / img.pixel_pitch) + img_skip_x];
|
||||
std::for_each(cursor_begin, cursor_end, [&](int cursor_pixel) {
|
||||
if (masked) {
|
||||
apply_color_masked(img_pixel_p, cursor_pixel);
|
||||
}
|
||||
else {
|
||||
apply_color_alpha(img_pixel_p, cursor_pixel);
|
||||
}
|
||||
++img_pixel_p;
|
||||
}
|
||||
|
||||
++and_mask;
|
||||
++xor_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void apply_color_alpha(int *img_pixel_p, int cursor_pixel) {
|
||||
auto colors_out = (std::uint8_t *)&cursor_pixel;
|
||||
auto colors_in = (std::uint8_t *)img_pixel_p;
|
||||
|
||||
//TODO: When use of IDXGIOutput5 is implemented, support different color formats
|
||||
auto alpha = colors_out[3];
|
||||
if(alpha == 255) {
|
||||
*img_pixel_p = cursor_pixel;
|
||||
}
|
||||
else {
|
||||
colors_in[0] = colors_out[0] + (colors_in[0] * (255 - alpha) + 255 / 2) / 255;
|
||||
colors_in[1] = colors_out[1] + (colors_in[1] * (255 - alpha) + 255 / 2) / 255;
|
||||
colors_in[2] = colors_out[2] + (colors_in[2] * (255 - alpha) + 255 / 2) / 255;
|
||||
}
|
||||
}
|
||||
|
||||
void apply_color_masked(int *img_pixel_p, int cursor_pixel) {
|
||||
//TODO: When use of IDXGIOutput5 is implemented, support different color formats
|
||||
auto alpha = ((std::uint8_t *)&cursor_pixel)[3];
|
||||
if(alpha == 0xFF) {
|
||||
*img_pixel_p ^= cursor_pixel;
|
||||
}
|
||||
else {
|
||||
*img_pixel_p = cursor_pixel;
|
||||
}
|
||||
}
|
||||
|
||||
void blend_cursor_color(const cursor_t &cursor, img_t &img, const bool masked) {
|
||||
int height = cursor.shape_info.Height;
|
||||
int width = cursor.shape_info.Width;
|
||||
int pitch = cursor.shape_info.Pitch;
|
||||
|
||||
// img cursor.y < 0, skip parts of the cursor.img_data
|
||||
auto cursor_skip_y = -std::min(0, cursor.y);
|
||||
auto cursor_skip_x = -std::min(0, cursor.x);
|
||||
|
||||
// img cursor.{x,y} > img.{x,y}, truncate parts of the cursor.img_data
|
||||
auto cursor_truncate_y = std::max(0, cursor.y - img.height);
|
||||
auto cursor_truncate_x = std::max(0, cursor.x - img.width);
|
||||
|
||||
auto img_skip_y = std::max(0, cursor.y);
|
||||
auto img_skip_x = std::max(0, cursor.x);
|
||||
|
||||
auto cursor_width = width - cursor_skip_x - cursor_truncate_x;
|
||||
auto cursor_height = height - cursor_skip_y - cursor_truncate_y;
|
||||
|
||||
if(cursor_height > height || cursor_width > width) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto cursor_img_data = (int *)&cursor.img_data[cursor_skip_y * pitch];
|
||||
|
||||
int delta_height = std::min(cursor_height - cursor_truncate_y, std::max(0, img.height - img_skip_y));
|
||||
int delta_width = std::min(cursor_width - cursor_truncate_x, std::max(0, img.width - img_skip_x));
|
||||
|
||||
auto img_data = (int *)img.data;
|
||||
|
||||
for(int i = 0; i < delta_height; ++i) {
|
||||
auto cursor_begin = &cursor_img_data[i * cursor.shape_info.Width + cursor_skip_x];
|
||||
auto cursor_end = &cursor_begin[delta_width];
|
||||
|
||||
auto img_pixel_p = &img_data[(i + img_skip_y) * (img.row_pitch / img.pixel_pitch) + img_skip_x];
|
||||
std::for_each(cursor_begin, cursor_end, [&](int cursor_pixel) {
|
||||
if(masked) {
|
||||
apply_color_masked(img_pixel_p, cursor_pixel);
|
||||
}
|
||||
else {
|
||||
apply_color_alpha(img_pixel_p, cursor_pixel);
|
||||
}
|
||||
++img_pixel_p;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void blend_cursor(const cursor_t &cursor, img_t &img) {
|
||||
switch(cursor.shape_info.Type) {
|
||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR:
|
||||
blend_cursor_color(cursor, img, false);
|
||||
break;
|
||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME:
|
||||
blend_cursor_monochrome(cursor, img);
|
||||
break;
|
||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR:
|
||||
blend_cursor_color(cursor, img, true);
|
||||
break;
|
||||
default:
|
||||
BOOST_LOG(warning) << "Unsupported cursor format ["sv << cursor.shape_info.Type << ']';
|
||||
}
|
||||
}
|
||||
|
||||
capture_e display_ram_t::snapshot(::platf::img_t *img_base, std::chrono::milliseconds timeout, bool cursor_visible) {
|
||||
auto img = (img_t *)img_base;
|
||||
|
||||
HRESULT status;
|
||||
|
||||
DXGI_OUTDUPL_FRAME_INFO frame_info;
|
||||
|
||||
resource_t::pointer res_p {};
|
||||
auto capture_status = dup.next_frame(frame_info, timeout, &res_p);
|
||||
resource_t res { res_p };
|
||||
|
||||
if(capture_status != capture_e::ok) {
|
||||
return capture_status;
|
||||
}
|
||||
|
||||
const bool mouse_update_flag = frame_info.LastMouseUpdateTime.QuadPart != 0 || frame_info.PointerShapeBufferSize > 0;
|
||||
const bool frame_update_flag = frame_info.AccumulatedFrames != 0 || frame_info.LastPresentTime.QuadPart != 0;
|
||||
const bool update_flag = mouse_update_flag || frame_update_flag;
|
||||
|
||||
if(!update_flag) {
|
||||
return capture_e::timeout;
|
||||
}
|
||||
|
||||
if(frame_info.PointerShapeBufferSize > 0) {
|
||||
auto &img_data = cursor.img_data;
|
||||
|
||||
img_data.resize(frame_info.PointerShapeBufferSize);
|
||||
|
||||
UINT dummy;
|
||||
status = dup.dup->GetFramePointerShape(img_data.size(), img_data.data(), &dummy, &cursor.shape_info);
|
||||
if(FAILED(status)) {
|
||||
BOOST_LOG(error) << "Failed to get new pointer shape [0x"sv << util::hex(status).to_string_view() << ']';
|
||||
|
||||
return capture_e::error;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if(frame_info.LastMouseUpdateTime.QuadPart) {
|
||||
cursor.x = frame_info.PointerPosition.Position.x;
|
||||
cursor.y = frame_info.PointerPosition.Position.y;
|
||||
cursor.visible = frame_info.PointerPosition.Visible;
|
||||
void
|
||||
blend_cursor(const cursor_t &cursor, img_t &img) {
|
||||
switch (cursor.shape_info.Type) {
|
||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR:
|
||||
blend_cursor_color(cursor, img, false);
|
||||
break;
|
||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME:
|
||||
blend_cursor_monochrome(cursor, img);
|
||||
break;
|
||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR:
|
||||
blend_cursor_color(cursor, img, true);
|
||||
break;
|
||||
default:
|
||||
BOOST_LOG(warning) << "Unsupported cursor format ["sv << cursor.shape_info.Type << ']';
|
||||
}
|
||||
}
|
||||
|
||||
if(frame_update_flag) {
|
||||
{
|
||||
texture2d_t src {};
|
||||
status = res->QueryInterface(IID_ID3D11Texture2D, (void **)&src);
|
||||
capture_e
|
||||
display_ram_t::snapshot(::platf::img_t *img_base, std::chrono::milliseconds timeout, bool cursor_visible) {
|
||||
auto img = (img_t *) img_base;
|
||||
|
||||
HRESULT status;
|
||||
|
||||
DXGI_OUTDUPL_FRAME_INFO frame_info;
|
||||
|
||||
resource_t::pointer res_p {};
|
||||
auto capture_status = dup.next_frame(frame_info, timeout, &res_p);
|
||||
resource_t res { res_p };
|
||||
|
||||
if (capture_status != capture_e::ok) {
|
||||
return capture_status;
|
||||
}
|
||||
|
||||
const bool mouse_update_flag = frame_info.LastMouseUpdateTime.QuadPart != 0 || frame_info.PointerShapeBufferSize > 0;
|
||||
const bool frame_update_flag = frame_info.AccumulatedFrames != 0 || frame_info.LastPresentTime.QuadPart != 0;
|
||||
const bool update_flag = mouse_update_flag || frame_update_flag;
|
||||
|
||||
if (!update_flag) {
|
||||
return capture_e::timeout;
|
||||
}
|
||||
|
||||
if (frame_info.PointerShapeBufferSize > 0) {
|
||||
auto &img_data = cursor.img_data;
|
||||
|
||||
img_data.resize(frame_info.PointerShapeBufferSize);
|
||||
|
||||
UINT dummy;
|
||||
status = dup.dup->GetFramePointerShape(img_data.size(), img_data.data(), &dummy, &cursor.shape_info);
|
||||
if (FAILED(status)) {
|
||||
BOOST_LOG(error) << "Failed to get new pointer shape [0x"sv << util::hex(status).to_string_view() << ']';
|
||||
|
||||
return capture_e::error;
|
||||
}
|
||||
}
|
||||
|
||||
if (frame_info.LastMouseUpdateTime.QuadPart) {
|
||||
cursor.x = frame_info.PointerPosition.Position.x;
|
||||
cursor.y = frame_info.PointerPosition.Position.y;
|
||||
cursor.visible = frame_info.PointerPosition.Visible;
|
||||
}
|
||||
|
||||
if (frame_update_flag) {
|
||||
{
|
||||
texture2d_t src {};
|
||||
status = res->QueryInterface(IID_ID3D11Texture2D, (void **) &src);
|
||||
|
||||
if (FAILED(status)) {
|
||||
BOOST_LOG(error) << "Couldn't query interface [0x"sv << util::hex(status).to_string_view() << ']';
|
||||
return capture_e::error;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
src->GetDesc(&desc);
|
||||
|
||||
// If we don't know the capture format yet, grab it from this texture and create the staging texture
|
||||
if (capture_format == DXGI_FORMAT_UNKNOWN) {
|
||||
capture_format = desc.Format;
|
||||
BOOST_LOG(info) << "Capture format ["sv << dxgi_format_to_string(capture_format) << ']';
|
||||
|
||||
D3D11_TEXTURE2D_DESC t {};
|
||||
t.Width = width;
|
||||
t.Height = height;
|
||||
t.MipLevels = 1;
|
||||
t.ArraySize = 1;
|
||||
t.SampleDesc.Count = 1;
|
||||
t.Usage = D3D11_USAGE_STAGING;
|
||||
t.Format = capture_format;
|
||||
t.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
|
||||
auto status = device->CreateTexture2D(&t, nullptr, &texture);
|
||||
|
||||
if (FAILED(status)) {
|
||||
BOOST_LOG(error) << "Failed to create staging texture [0x"sv << util::hex(status).to_string_view() << ']';
|
||||
return capture_e::error;
|
||||
}
|
||||
}
|
||||
|
||||
// It's possible for our display enumeration to race with mode changes and result in
|
||||
// mismatched image pool and desktop texture sizes. If this happens, just reinit again.
|
||||
if (desc.Width != width || desc.Height != height) {
|
||||
BOOST_LOG(info) << "Capture size changed ["sv << width << 'x' << height << " -> "sv << desc.Width << 'x' << desc.Height << ']';
|
||||
return capture_e::reinit;
|
||||
}
|
||||
|
||||
// It's also possible for the capture format to change on the fly. If that happens,
|
||||
// reinitialize capture to try format detection again and create new images.
|
||||
if (capture_format != desc.Format) {
|
||||
BOOST_LOG(info) << "Capture format changed ["sv << dxgi_format_to_string(capture_format) << " -> "sv << dxgi_format_to_string(desc.Format) << ']';
|
||||
return capture_e::reinit;
|
||||
}
|
||||
|
||||
//Copy from GPU to CPU
|
||||
device_ctx->CopyResource(texture.get(), src.get());
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't know the final capture format yet, encode a dummy image
|
||||
if (capture_format == DXGI_FORMAT_UNKNOWN) {
|
||||
BOOST_LOG(debug) << "Capture format is still unknown. Encoding a blank image"sv;
|
||||
|
||||
if (dummy_img(img)) {
|
||||
return capture_e::error;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Map the staging texture for CPU access (making it inaccessible for the GPU)
|
||||
status = device_ctx->Map(texture.get(), 0, D3D11_MAP_READ, 0, &img_info);
|
||||
if (FAILED(status)) {
|
||||
BOOST_LOG(error) << "Failed to map texture [0x"sv << util::hex(status).to_string_view() << ']';
|
||||
|
||||
if(FAILED(status)) {
|
||||
BOOST_LOG(error) << "Couldn't query interface [0x"sv << util::hex(status).to_string_view() << ']';
|
||||
return capture_e::error;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
src->GetDesc(&desc);
|
||||
|
||||
// If we don't know the capture format yet, grab it from this texture and create the staging texture
|
||||
if(capture_format == DXGI_FORMAT_UNKNOWN) {
|
||||
capture_format = desc.Format;
|
||||
BOOST_LOG(info) << "Capture format ["sv << dxgi_format_to_string(capture_format) << ']';
|
||||
|
||||
D3D11_TEXTURE2D_DESC t {};
|
||||
t.Width = width;
|
||||
t.Height = height;
|
||||
t.MipLevels = 1;
|
||||
t.ArraySize = 1;
|
||||
t.SampleDesc.Count = 1;
|
||||
t.Usage = D3D11_USAGE_STAGING;
|
||||
t.Format = capture_format;
|
||||
t.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
|
||||
auto status = device->CreateTexture2D(&t, nullptr, &texture);
|
||||
|
||||
if(FAILED(status)) {
|
||||
BOOST_LOG(error) << "Failed to create staging texture [0x"sv << util::hex(status).to_string_view() << ']';
|
||||
return capture_e::error;
|
||||
}
|
||||
// Now that we know the capture format, we can finish creating the image
|
||||
if (complete_img(img, false)) {
|
||||
device_ctx->Unmap(texture.get(), 0);
|
||||
img_info.pData = nullptr;
|
||||
return capture_e::error;
|
||||
}
|
||||
|
||||
// It's possible for our display enumeration to race with mode changes and result in
|
||||
// mismatched image pool and desktop texture sizes. If this happens, just reinit again.
|
||||
if(desc.Width != width || desc.Height != height) {
|
||||
BOOST_LOG(info) << "Capture size changed ["sv << width << 'x' << height << " -> "sv << desc.Width << 'x' << desc.Height << ']';
|
||||
return capture_e::reinit;
|
||||
}
|
||||
std::copy_n((std::uint8_t *) img_info.pData, height * img_info.RowPitch, (std::uint8_t *) img->data);
|
||||
|
||||
// It's also possible for the capture format to change on the fly. If that happens,
|
||||
// reinitialize capture to try format detection again and create new images.
|
||||
if(capture_format != desc.Format) {
|
||||
BOOST_LOG(info) << "Capture format changed ["sv << dxgi_format_to_string(capture_format) << " -> "sv << dxgi_format_to_string(desc.Format) << ']';
|
||||
return capture_e::reinit;
|
||||
}
|
||||
|
||||
//Copy from GPU to CPU
|
||||
device_ctx->CopyResource(texture.get(), src.get());
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't know the final capture format yet, encode a dummy image
|
||||
if(capture_format == DXGI_FORMAT_UNKNOWN) {
|
||||
BOOST_LOG(debug) << "Capture format is still unknown. Encoding a blank image"sv;
|
||||
|
||||
if(dummy_img(img)) {
|
||||
return capture_e::error;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Map the staging texture for CPU access (making it inaccessible for the GPU)
|
||||
status = device_ctx->Map(texture.get(), 0, D3D11_MAP_READ, 0, &img_info);
|
||||
if(FAILED(status)) {
|
||||
BOOST_LOG(error) << "Failed to map texture [0x"sv << util::hex(status).to_string_view() << ']';
|
||||
|
||||
return capture_e::error;
|
||||
}
|
||||
|
||||
// Now that we know the capture format, we can finish creating the image
|
||||
if(complete_img(img, false)) {
|
||||
// Unmap the staging texture to allow GPU access again
|
||||
device_ctx->Unmap(texture.get(), 0);
|
||||
img_info.pData = nullptr;
|
||||
return capture_e::error;
|
||||
}
|
||||
|
||||
std::copy_n((std::uint8_t *)img_info.pData, height * img_info.RowPitch, (std::uint8_t *)img->data);
|
||||
if (cursor_visible && cursor.visible) {
|
||||
blend_cursor(cursor, *img);
|
||||
}
|
||||
|
||||
// Unmap the staging texture to allow GPU access again
|
||||
device_ctx->Unmap(texture.get(), 0);
|
||||
img_info.pData = nullptr;
|
||||
return capture_e::ok;
|
||||
}
|
||||
|
||||
if(cursor_visible && cursor.visible) {
|
||||
blend_cursor(cursor, *img);
|
||||
std::shared_ptr<platf::img_t>
|
||||
display_ram_t::alloc_img() {
|
||||
auto img = std::make_shared<img_t>();
|
||||
|
||||
// Initialize fields that are format-independent
|
||||
img->width = width;
|
||||
img->height = height;
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
return capture_e::ok;
|
||||
}
|
||||
int
|
||||
display_ram_t::complete_img(platf::img_t *img, bool dummy) {
|
||||
// If this is not a dummy image, we must know the format by now
|
||||
if (!dummy && capture_format == DXGI_FORMAT_UNKNOWN) {
|
||||
BOOST_LOG(error) << "display_ram_t::complete_img() called with unknown capture format!";
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::shared_ptr<platf::img_t> display_ram_t::alloc_img() {
|
||||
auto img = std::make_shared<img_t>();
|
||||
img->pixel_pitch = get_pixel_pitch();
|
||||
|
||||
// Initialize fields that are format-independent
|
||||
img->width = width;
|
||||
img->height = height;
|
||||
if (dummy && !img->row_pitch) {
|
||||
// Assume our dummy image will have no padding
|
||||
img->row_pitch = img->pixel_pitch * img->width;
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
// Reallocate the image buffer if the pitch changes
|
||||
if (!dummy && img->row_pitch != img_info.RowPitch) {
|
||||
img->row_pitch = img_info.RowPitch;
|
||||
delete img->data;
|
||||
img->data = nullptr;
|
||||
}
|
||||
|
||||
int display_ram_t::complete_img(platf::img_t *img, bool dummy) {
|
||||
// If this is not a dummy image, we must know the format by now
|
||||
if(!dummy && capture_format == DXGI_FORMAT_UNKNOWN) {
|
||||
BOOST_LOG(error) << "display_ram_t::complete_img() called with unknown capture format!";
|
||||
return -1;
|
||||
if (!img->data) {
|
||||
img->data = new std::uint8_t[img->row_pitch * height];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
img->pixel_pitch = get_pixel_pitch();
|
||||
int
|
||||
display_ram_t::dummy_img(platf::img_t *img) {
|
||||
if (complete_img(img, true)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(dummy && !img->row_pitch) {
|
||||
// Assume our dummy image will have no padding
|
||||
img->row_pitch = img->pixel_pitch * img->width;
|
||||
std::fill_n((std::uint8_t *) img->data, height * img->row_pitch, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reallocate the image buffer if the pitch changes
|
||||
if(!dummy && img->row_pitch != img_info.RowPitch) {
|
||||
img->row_pitch = img_info.RowPitch;
|
||||
delete img->data;
|
||||
img->data = nullptr;
|
||||
std::vector<DXGI_FORMAT>
|
||||
display_ram_t::get_supported_sdr_capture_formats() {
|
||||
return { DXGI_FORMAT_B8G8R8A8_UNORM };
|
||||
}
|
||||
|
||||
if(!img->data) {
|
||||
img->data = new std::uint8_t[img->row_pitch * height];
|
||||
std::vector<DXGI_FORMAT>
|
||||
display_ram_t::get_supported_hdr_capture_formats() {
|
||||
// HDR is unsupported
|
||||
return {};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
display_ram_t::init(const ::video::config_t &config, const std::string &display_name) {
|
||||
if (display_base_t::init(config, display_name)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int display_ram_t::dummy_img(platf::img_t *img) {
|
||||
if(complete_img(img, true)) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::fill_n((std::uint8_t *)img->data, height * img->row_pitch, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<DXGI_FORMAT> display_ram_t::get_supported_sdr_capture_formats() {
|
||||
return { DXGI_FORMAT_B8G8R8A8_UNORM };
|
||||
}
|
||||
|
||||
std::vector<DXGI_FORMAT> display_ram_t::get_supported_hdr_capture_formats() {
|
||||
// HDR is unsupported
|
||||
return {};
|
||||
}
|
||||
|
||||
int display_ram_t::init(const ::video::config_t &config, const std::string &display_name) {
|
||||
if(display_base_t::init(config, display_name)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace platf::dxgi
|
||||
} // namespace platf::dxgi
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,10 @@
|
||||
#include <winnt.h>
|
||||
|
||||
namespace platf {
|
||||
void print_status(const std::string_view &prefix, HRESULT status);
|
||||
HDESK syncThreadDesktop();
|
||||
} // namespace platf
|
||||
void
|
||||
print_status(const std::string_view &prefix, HRESULT status);
|
||||
HDESK
|
||||
syncThreadDesktop();
|
||||
} // namespace platf
|
||||
|
||||
#endif
|
||||
@@ -35,7 +35,7 @@ constexpr auto DNS_QUERY_RESULTS_VERSION1 = 0x1;
|
||||
#define SERVICE_DOMAIN "local"
|
||||
|
||||
constexpr auto SERVICE_INSTANCE_NAME = SV(SERVICE_NAME "." SERVICE_TYPE "." SERVICE_DOMAIN);
|
||||
constexpr auto SERVICE_TYPE_DOMAIN = SV(SERVICE_TYPE "." SERVICE_DOMAIN);
|
||||
constexpr auto SERVICE_TYPE_DOMAIN = SV(SERVICE_TYPE "." SERVICE_DOMAIN);
|
||||
|
||||
#ifndef __MINGW32__
|
||||
typedef struct _DNS_SERVICE_INSTANCE {
|
||||
@@ -59,7 +59,8 @@ typedef struct _DNS_SERVICE_INSTANCE {
|
||||
} DNS_SERVICE_INSTANCE, *PDNS_SERVICE_INSTANCE;
|
||||
#endif
|
||||
|
||||
typedef VOID WINAPI DNS_SERVICE_REGISTER_COMPLETE(
|
||||
typedef VOID WINAPI
|
||||
DNS_SERVICE_REGISTER_COMPLETE(
|
||||
_In_ DWORD Status,
|
||||
_In_ PVOID pQueryContext,
|
||||
_In_ PDNS_SERVICE_INSTANCE pInstance);
|
||||
@@ -88,122 +89,127 @@ _FN(_DnsServiceRegister, DWORD, (_In_ PDNS_SERVICE_REGISTER_REQUEST pRequest, _I
|
||||
} /* extern "C" */
|
||||
|
||||
namespace platf::publish {
|
||||
VOID WINAPI register_cb(DWORD status, PVOID pQueryContext, PDNS_SERVICE_INSTANCE pInstance) {
|
||||
auto alarm = (safe::alarm_t<PDNS_SERVICE_INSTANCE>::element_type *)pQueryContext;
|
||||
VOID WINAPI
|
||||
register_cb(DWORD status, PVOID pQueryContext, PDNS_SERVICE_INSTANCE pInstance) {
|
||||
auto alarm = (safe::alarm_t<PDNS_SERVICE_INSTANCE>::element_type *) pQueryContext;
|
||||
|
||||
if(status) {
|
||||
print_status("register_cb()"sv, status);
|
||||
}
|
||||
|
||||
alarm->ring(pInstance);
|
||||
}
|
||||
|
||||
static int service(bool enable, PDNS_SERVICE_INSTANCE &existing_instance) {
|
||||
auto alarm = safe::make_alarm<PDNS_SERVICE_INSTANCE>();
|
||||
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter;
|
||||
|
||||
std::wstring name { SERVICE_INSTANCE_NAME.data(), SERVICE_INSTANCE_NAME.size() };
|
||||
std::wstring domain { SERVICE_TYPE_DOMAIN.data(), SERVICE_TYPE_DOMAIN.size() };
|
||||
|
||||
auto host = converter.from_bytes(boost::asio::ip::host_name() + ".local");
|
||||
|
||||
DNS_SERVICE_INSTANCE instance {};
|
||||
instance.pszInstanceName = name.data();
|
||||
instance.wPort = map_port(nvhttp::PORT_HTTP);
|
||||
instance.pszHostName = host.data();
|
||||
|
||||
DNS_SERVICE_REGISTER_REQUEST req {};
|
||||
req.Version = DNS_QUERY_REQUEST_VERSION1;
|
||||
req.pQueryContext = alarm.get();
|
||||
req.pServiceInstance = enable ? &instance : existing_instance;
|
||||
req.pRegisterCompletionCallback = register_cb;
|
||||
|
||||
DNS_STATUS status {};
|
||||
|
||||
if(enable) {
|
||||
status = _DnsServiceRegister(&req, nullptr);
|
||||
if(status != DNS_REQUEST_PENDING) {
|
||||
print_status("DnsServiceRegister()"sv, status);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
status = _DnsServiceDeRegister(&req, nullptr);
|
||||
if(status != DNS_REQUEST_PENDING) {
|
||||
print_status("DnsServiceDeRegister()"sv, status);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
alarm->wait();
|
||||
|
||||
auto registered_instance = alarm->status();
|
||||
if(enable) {
|
||||
// Store this instance for later deregistration
|
||||
existing_instance = registered_instance;
|
||||
}
|
||||
else if(registered_instance) {
|
||||
// Deregistration was successful
|
||||
_DnsServiceFreeInstance(registered_instance);
|
||||
existing_instance = nullptr;
|
||||
}
|
||||
|
||||
return registered_instance ? 0 : -1;
|
||||
}
|
||||
|
||||
class mdns_registration_t : public ::platf::deinit_t {
|
||||
public:
|
||||
mdns_registration_t() : existing_instance(nullptr) {
|
||||
if(service(true, existing_instance)) {
|
||||
BOOST_LOG(error) << "Unable to register Sunshine mDNS service"sv;
|
||||
return;
|
||||
if (status) {
|
||||
print_status("register_cb()"sv, status);
|
||||
}
|
||||
|
||||
BOOST_LOG(info) << "Registered Sunshine mDNS service"sv;
|
||||
alarm->ring(pInstance);
|
||||
}
|
||||
|
||||
~mdns_registration_t() override {
|
||||
if(existing_instance) {
|
||||
if(service(false, existing_instance)) {
|
||||
BOOST_LOG(error) << "Unable to unregister Sunshine mDNS service"sv;
|
||||
static int
|
||||
service(bool enable, PDNS_SERVICE_INSTANCE &existing_instance) {
|
||||
auto alarm = safe::make_alarm<PDNS_SERVICE_INSTANCE>();
|
||||
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter;
|
||||
|
||||
std::wstring name { SERVICE_INSTANCE_NAME.data(), SERVICE_INSTANCE_NAME.size() };
|
||||
std::wstring domain { SERVICE_TYPE_DOMAIN.data(), SERVICE_TYPE_DOMAIN.size() };
|
||||
|
||||
auto host = converter.from_bytes(boost::asio::ip::host_name() + ".local");
|
||||
|
||||
DNS_SERVICE_INSTANCE instance {};
|
||||
instance.pszInstanceName = name.data();
|
||||
instance.wPort = map_port(nvhttp::PORT_HTTP);
|
||||
instance.pszHostName = host.data();
|
||||
|
||||
DNS_SERVICE_REGISTER_REQUEST req {};
|
||||
req.Version = DNS_QUERY_REQUEST_VERSION1;
|
||||
req.pQueryContext = alarm.get();
|
||||
req.pServiceInstance = enable ? &instance : existing_instance;
|
||||
req.pRegisterCompletionCallback = register_cb;
|
||||
|
||||
DNS_STATUS status {};
|
||||
|
||||
if (enable) {
|
||||
status = _DnsServiceRegister(&req, nullptr);
|
||||
if (status != DNS_REQUEST_PENDING) {
|
||||
print_status("DnsServiceRegister()"sv, status);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
status = _DnsServiceDeRegister(&req, nullptr);
|
||||
if (status != DNS_REQUEST_PENDING) {
|
||||
print_status("DnsServiceDeRegister()"sv, status);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
alarm->wait();
|
||||
|
||||
auto registered_instance = alarm->status();
|
||||
if (enable) {
|
||||
// Store this instance for later deregistration
|
||||
existing_instance = registered_instance;
|
||||
}
|
||||
else if (registered_instance) {
|
||||
// Deregistration was successful
|
||||
_DnsServiceFreeInstance(registered_instance);
|
||||
existing_instance = nullptr;
|
||||
}
|
||||
|
||||
return registered_instance ? 0 : -1;
|
||||
}
|
||||
|
||||
class mdns_registration_t: public ::platf::deinit_t {
|
||||
public:
|
||||
mdns_registration_t():
|
||||
existing_instance(nullptr) {
|
||||
if (service(true, existing_instance)) {
|
||||
BOOST_LOG(error) << "Unable to register Sunshine mDNS service"sv;
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_LOG(info) << "Unregistered Sunshine mDNS service"sv;
|
||||
BOOST_LOG(info) << "Registered Sunshine mDNS service"sv;
|
||||
}
|
||||
|
||||
~mdns_registration_t() override {
|
||||
if (existing_instance) {
|
||||
if (service(false, existing_instance)) {
|
||||
BOOST_LOG(error) << "Unable to unregister Sunshine mDNS service"sv;
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_LOG(info) << "Unregistered Sunshine mDNS service"sv;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
PDNS_SERVICE_INSTANCE existing_instance;
|
||||
};
|
||||
|
||||
int
|
||||
load_funcs(HMODULE handle) {
|
||||
auto fg = util::fail_guard([handle]() {
|
||||
FreeLibrary(handle);
|
||||
});
|
||||
|
||||
_DnsServiceFreeInstance = (_DnsServiceFreeInstance_fn) GetProcAddress(handle, "DnsServiceFreeInstance");
|
||||
_DnsServiceDeRegister = (_DnsServiceDeRegister_fn) GetProcAddress(handle, "DnsServiceDeRegister");
|
||||
_DnsServiceRegister = (_DnsServiceRegister_fn) GetProcAddress(handle, "DnsServiceRegister");
|
||||
|
||||
if (!(_DnsServiceFreeInstance && _DnsServiceDeRegister && _DnsServiceRegister)) {
|
||||
BOOST_LOG(error) << "mDNS service not available in dnsapi.dll"sv;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fg.disable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
PDNS_SERVICE_INSTANCE existing_instance;
|
||||
};
|
||||
std::unique_ptr<::platf::deinit_t>
|
||||
start() {
|
||||
HMODULE handle = LoadLibrary("dnsapi.dll");
|
||||
|
||||
int load_funcs(HMODULE handle) {
|
||||
auto fg = util::fail_guard([handle]() {
|
||||
FreeLibrary(handle);
|
||||
});
|
||||
if (!handle || load_funcs(handle)) {
|
||||
BOOST_LOG(error) << "Couldn't load dnsapi.dll, You'll need to add PC manually from Moonlight"sv;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_DnsServiceFreeInstance = (_DnsServiceFreeInstance_fn)GetProcAddress(handle, "DnsServiceFreeInstance");
|
||||
_DnsServiceDeRegister = (_DnsServiceDeRegister_fn)GetProcAddress(handle, "DnsServiceDeRegister");
|
||||
_DnsServiceRegister = (_DnsServiceRegister_fn)GetProcAddress(handle, "DnsServiceRegister");
|
||||
|
||||
if(!(_DnsServiceFreeInstance && _DnsServiceDeRegister && _DnsServiceRegister)) {
|
||||
BOOST_LOG(error) << "mDNS service not available in dnsapi.dll"sv;
|
||||
return -1;
|
||||
return std::make_unique<mdns_registration_t>();
|
||||
}
|
||||
|
||||
fg.disable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<::platf::deinit_t> start() {
|
||||
HMODULE handle = LoadLibrary("dnsapi.dll");
|
||||
|
||||
if(!handle || load_funcs(handle)) {
|
||||
BOOST_LOG(error) << "Couldn't load dnsapi.dll, You'll need to add PC manually from Moonlight"sv;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<mdns_registration_t>();
|
||||
}
|
||||
} // namespace platf::publish
|
||||
} // namespace platf::publish
|
||||
|
||||
Reference in New Issue
Block a user