2024-06-10 14:40:55 +00:00
|
|
|
/* GStreamer
|
|
|
|
* Copyright (C) 2024 Seungha Yang <seungha@centricular.com>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "gstd3d12window-win32.h"
|
|
|
|
|
|
|
|
GST_DEBUG_CATEGORY_EXTERN (gst_d3d12_window_debug);
|
|
|
|
#define GST_CAT_DEFAULT gst_d3d12_window_debug
|
|
|
|
|
|
|
|
#define WS_GST_D3D12 (WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW)
|
|
|
|
|
|
|
|
#define WM_GST_D3D12_FULLSCREEN (WM_USER + 1)
|
|
|
|
#define WM_GST_D3D12_ATTACH_INTERNAL_WINDOW (WM_USER + 2)
|
2024-06-16 12:21:44 +00:00
|
|
|
#define WM_GST_D3D12_CREATE_PROXY (WM_USER + 3)
|
2024-06-10 14:40:55 +00:00
|
|
|
#define WM_GST_D3D12_DESTROY_INTERNAL_WINDOW (WM_USER + 4)
|
|
|
|
#define WM_GST_D3D12_UPDATE_RENDER_RECT (WM_USER + 5)
|
|
|
|
#define WM_GST_D3D12_PARENT_SIZE (WM_USER + 6)
|
|
|
|
#define WM_GST_D3D12_SWAPCHAIN_CREATED (WM_USER + 7)
|
|
|
|
|
|
|
|
#ifndef GET_X_LPARAM
|
|
|
|
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef GET_Y_LPARAM
|
|
|
|
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* *INDENT-OFF* */
|
|
|
|
SwapChainProxy::SwapChainProxy (GstD3D12Window * window, SIZE_T id)
|
|
|
|
{
|
|
|
|
g_assert (GST_IS_D3D12_WINDOW (window));
|
|
|
|
window_ = (GstD3D12Window *) gst_object_ref (window);
|
|
|
|
id_ = id;
|
|
|
|
|
2024-10-23 21:10:13 +00:00
|
|
|
GST_DEBUG_OBJECT (window_, "Creating proxy %u", (guint) id_);
|
2024-06-10 14:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SwapChainProxy::~SwapChainProxy ()
|
|
|
|
{
|
2024-10-23 21:10:13 +00:00
|
|
|
GST_DEBUG_OBJECT (window_, "Destroying proxy %u", (guint) id_);
|
2024-06-10 14:40:55 +00:00
|
|
|
|
|
|
|
swapchain_ = nullptr;
|
2024-06-16 12:21:44 +00:00
|
|
|
if (window_thread_ && hwnd_ && hwnd_ != parent_hwnd_) {
|
2024-06-10 14:40:55 +00:00
|
|
|
if (window_thread_ == g_thread_self ())
|
|
|
|
DestroyWindow (hwnd_);
|
|
|
|
else
|
|
|
|
PostMessageW (hwnd_, WM_GST_D3D12_DESTROY_INTERNAL_WINDOW, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
gst_object_unref (window_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SwapChainProxy::set_window_handles (HWND parent_hwnd, HWND child_hwnd)
|
|
|
|
{
|
|
|
|
parent_hwnd_ = parent_hwnd;
|
|
|
|
hwnd_ = child_hwnd;
|
|
|
|
window_thread_ = g_thread_self ();
|
|
|
|
}
|
|
|
|
|
|
|
|
HWND
|
|
|
|
SwapChainProxy::get_window_handle ()
|
|
|
|
{
|
|
|
|
return hwnd_;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIZE_T
|
|
|
|
SwapChainProxy::get_id ()
|
|
|
|
{
|
|
|
|
return id_;
|
|
|
|
}
|
|
|
|
|
2024-06-16 12:21:44 +00:00
|
|
|
GstD3D12Window *
|
|
|
|
SwapChainProxy::get_window ()
|
|
|
|
{
|
|
|
|
return window_;
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:40:55 +00:00
|
|
|
bool
|
|
|
|
SwapChainProxy::has_parent ()
|
|
|
|
{
|
|
|
|
return parent_hwnd_ ? true : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SwapChainProxy::on_destroy ()
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
hwnd_ = nullptr;
|
|
|
|
swapchain_ = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SwapChainProxy::set_fullscreen_on_alt_enter (bool enable)
|
|
|
|
{
|
|
|
|
fstate_.fullscreen_on_alt_enter = enable;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SwapChainProxy::toggle_fullscreen (bool enable)
|
|
|
|
{
|
|
|
|
bool send_msg = false;
|
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
|
|
|
|
/* fullscreen toggle is supported only for internal hwnd */
|
|
|
|
if (parent_hwnd_ || !hwnd_)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (window_thread_ == g_thread_self ())
|
|
|
|
send_msg = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (send_msg)
|
|
|
|
SendMessageW (hwnd_, WM_GST_D3D12_FULLSCREEN, 0, (LPARAM) enable);
|
|
|
|
else
|
|
|
|
PostMessageW (hwnd_, WM_GST_D3D12_FULLSCREEN, 0, (LPARAM) enable);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SwapChainProxy::update_render_rect ()
|
|
|
|
{
|
|
|
|
bool send_msg = false;
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
2024-06-16 12:21:44 +00:00
|
|
|
if (!hwnd_ || hwnd_ == parent_hwnd_)
|
2024-06-10 14:40:55 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (window_thread_ == g_thread_self ())
|
|
|
|
send_msg = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (send_msg)
|
|
|
|
SendMessageW (hwnd_, WM_GST_D3D12_UPDATE_RENDER_RECT, 0, 0);
|
|
|
|
else
|
|
|
|
PostMessageW (hwnd_, WM_GST_D3D12_UPDATE_RENDER_RECT, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SwapChainProxy::handle_update_render_rect ()
|
|
|
|
{
|
|
|
|
GstVideoRectangle rect;
|
|
|
|
gst_d3d12_window_get_render_rect (window_, &rect);
|
|
|
|
|
|
|
|
if (rect.w == -1 && rect.h == -1 && parent_hwnd_) {
|
|
|
|
GST_DEBUG_OBJECT (window_, "Back to parent size");
|
|
|
|
|
|
|
|
RECT parent_rect;
|
|
|
|
GetClientRect (parent_hwnd_, &parent_rect);
|
|
|
|
MoveWindow (hwnd_, parent_rect.left, parent_rect.top,
|
|
|
|
parent_rect.right - parent_rect.left,
|
|
|
|
parent_rect.bottom - parent_rect.top, FALSE);
|
|
|
|
} else if (rect.w > 0 && rect.h > 0) {
|
|
|
|
GST_DEBUG_OBJECT (window_, "Applying render rect");
|
|
|
|
MoveWindow (hwnd_, rect.x, rect.y, rect.w, rect.h, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SwapChainProxy::handle_fullscreen_change (bool is_fullscreen)
|
|
|
|
{
|
|
|
|
if (is_fullscreen == fstate_.applied_fullscreen)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (is_fullscreen) {
|
|
|
|
GST_DEBUG_OBJECT (window_, "Enable fullscreen");
|
|
|
|
GetWindowPlacement (hwnd_, &fstate_.restore_placement);
|
|
|
|
|
|
|
|
ShowWindow (hwnd_, SW_SHOW);
|
|
|
|
|
|
|
|
fstate_.restore_style = GetWindowLong (hwnd_, GWL_STYLE);
|
|
|
|
|
|
|
|
SetWindowLongA (hwnd_, GWL_STYLE,
|
|
|
|
fstate_.restore_style &
|
|
|
|
~(WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU |
|
|
|
|
WS_THICKFRAME | WS_MAXIMIZE));
|
|
|
|
|
|
|
|
HMONITOR monitor = MonitorFromWindow (hwnd_, MONITOR_DEFAULTTONEAREST);
|
|
|
|
MONITORINFO minfo = { };
|
|
|
|
minfo.cbSize = sizeof (minfo);
|
|
|
|
if (!GetMonitorInfo (monitor, &minfo)) {
|
|
|
|
GST_WARNING_OBJECT (window_, "Couldn't get monitor info");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetWindowPos (hwnd_, HWND_TOP, minfo.rcMonitor.left, minfo.rcMonitor.top,
|
|
|
|
minfo.rcMonitor.right - minfo.rcMonitor.left,
|
|
|
|
minfo.rcMonitor.bottom - minfo.rcMonitor.top,
|
|
|
|
SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
|
|
|
ShowWindow (hwnd_, SW_MAXIMIZE);
|
|
|
|
} else {
|
|
|
|
GST_DEBUG_OBJECT (window_, "Back to window mode");
|
|
|
|
|
|
|
|
SetWindowLongW (hwnd_, GWL_STYLE, fstate_.restore_style);
|
|
|
|
SetWindowPlacement (hwnd_, &fstate_.restore_placement);
|
|
|
|
}
|
|
|
|
|
|
|
|
fstate_.applied_fullscreen = is_fullscreen;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SwapChainProxy::handle_syskey_down ()
|
|
|
|
{
|
|
|
|
if (!fstate_.fullscreen_on_alt_enter)
|
|
|
|
return;
|
|
|
|
|
|
|
|
WORD state = GetKeyState (VK_RETURN);
|
|
|
|
BYTE high = HIBYTE (state);
|
|
|
|
if (high & 0x1) {
|
|
|
|
LPARAM param = 1;
|
|
|
|
if (fstate_.applied_fullscreen)
|
|
|
|
param = 0;
|
|
|
|
|
|
|
|
SendMessageW (hwnd_, WM_GST_D3D12_FULLSCREEN, 0, param);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SwapChainProxy::handle_key_event (UINT msg, WPARAM wparam, LPARAM lparam)
|
|
|
|
{
|
|
|
|
if (!gst_d3d12_window_get_navigation_events_enabled (window_))
|
|
|
|
return;
|
|
|
|
|
|
|
|
gunichar2 keyname[128];
|
|
|
|
const gchar *event;
|
|
|
|
|
|
|
|
if (!GetKeyNameTextW (lparam, (LPWSTR) keyname, 128))
|
|
|
|
return;
|
|
|
|
|
|
|
|
gchar *name = g_utf16_to_utf8 (keyname, 128, nullptr, nullptr, nullptr);
|
|
|
|
if (!name)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (msg == WM_KEYDOWN)
|
|
|
|
event = "key-press";
|
|
|
|
else
|
|
|
|
event = "key-release";
|
|
|
|
|
|
|
|
gst_d3d12_window_on_key_event (window_, event, name);
|
|
|
|
g_free (name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SwapChainProxy::handle_mouse_event (UINT msg, WPARAM wparam, LPARAM lparam)
|
|
|
|
{
|
|
|
|
if (!gst_d3d12_window_get_navigation_events_enabled (window_))
|
|
|
|
return;
|
|
|
|
|
|
|
|
gint button = 0;
|
|
|
|
const gchar *event = nullptr;
|
|
|
|
guint modifier = 0;
|
2024-10-26 19:26:46 +00:00
|
|
|
gint delta_x = 0;
|
|
|
|
gint delta_y = 0;
|
2024-06-10 14:40:55 +00:00
|
|
|
|
|
|
|
auto xpos = GET_X_LPARAM (lparam);
|
|
|
|
auto ypos = GET_Y_LPARAM (lparam);
|
|
|
|
|
2024-10-26 19:26:46 +00:00
|
|
|
if (msg == WM_MOUSEHWHEEL || msg == WM_MOUSEWHEEL) {
|
|
|
|
/* wheel events coordinates are relative to screen */
|
|
|
|
POINT updated_pos;
|
|
|
|
updated_pos.x = xpos;
|
|
|
|
updated_pos.y = ypos;
|
|
|
|
|
|
|
|
if (!ScreenToClient (hwnd_, &updated_pos)) {
|
|
|
|
GST_WARNING_OBJECT (window_, "Couldn't convert screen position to client");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xpos = updated_pos.x;
|
|
|
|
ypos = updated_pos.y;
|
|
|
|
} else if (parent_hwnd_ && parent_hwnd_ != hwnd_) {
|
2024-06-10 14:40:55 +00:00
|
|
|
POINT updated_pos;
|
|
|
|
updated_pos.x = xpos;
|
|
|
|
updated_pos.y = ypos;
|
|
|
|
|
|
|
|
if (!ClientToScreen (parent_hwnd_, &updated_pos)) {
|
|
|
|
GST_WARNING_OBJECT (window_, "Couldn't convert parent position to screen");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ScreenToClient (hwnd_, &updated_pos)) {
|
|
|
|
GST_WARNING_OBJECT (window_, "Couldn't convert screen position to client");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xpos = updated_pos.x;
|
|
|
|
ypos = updated_pos.y;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (msg) {
|
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
button = 0;
|
|
|
|
event = "mouse-move";
|
|
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
button = 1;
|
|
|
|
event = "mouse-button-press";
|
|
|
|
break;
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
button = 1;
|
|
|
|
event = "mouse-button-release";
|
|
|
|
break;
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
|
|
button = 1;
|
|
|
|
event = "mouse-double-click";
|
|
|
|
break;
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
button = 2;
|
|
|
|
event = "mouse-button-press";
|
|
|
|
break;
|
|
|
|
case WM_RBUTTONUP:
|
|
|
|
button = 2;
|
|
|
|
event = "mouse-button-release";
|
|
|
|
break;
|
|
|
|
case WM_RBUTTONDBLCLK:
|
|
|
|
button = 2;
|
|
|
|
event = "mouse-double-click";
|
|
|
|
break;
|
|
|
|
case WM_MBUTTONDOWN:
|
|
|
|
button = 3;
|
|
|
|
event = "mouse-button-press";
|
|
|
|
break;
|
|
|
|
case WM_MBUTTONUP:
|
|
|
|
button = 3;
|
|
|
|
event = "mouse-button-release";
|
|
|
|
break;
|
|
|
|
case WM_MBUTTONDBLCLK:
|
|
|
|
button = 3;
|
|
|
|
event = "mouse-double-click";
|
|
|
|
break;
|
2024-10-26 19:26:46 +00:00
|
|
|
case WM_MOUSEHWHEEL:
|
|
|
|
delta_x = GET_WHEEL_DELTA_WPARAM (wparam);
|
|
|
|
break;
|
|
|
|
case WM_MOUSEWHEEL:
|
|
|
|
delta_y = GET_WHEEL_DELTA_WPARAM (wparam);
|
|
|
|
break;
|
2024-06-10 14:40:55 +00:00
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((wparam & MK_CONTROL) != 0)
|
|
|
|
modifier |= GST_NAVIGATION_MODIFIER_CONTROL_MASK;
|
|
|
|
if ((wparam & MK_LBUTTON) != 0)
|
|
|
|
modifier |= GST_NAVIGATION_MODIFIER_BUTTON1_MASK;
|
|
|
|
if ((wparam & MK_RBUTTON) != 0)
|
|
|
|
modifier |= GST_NAVIGATION_MODIFIER_BUTTON2_MASK;
|
|
|
|
if ((wparam & MK_MBUTTON) != 0)
|
|
|
|
modifier |= GST_NAVIGATION_MODIFIER_BUTTON3_MASK;
|
|
|
|
if ((wparam & MK_SHIFT) != 0)
|
|
|
|
modifier |= GST_NAVIGATION_MODIFIER_SHIFT_MASK;
|
|
|
|
|
|
|
|
GstVideoRectangle output_rect = { };
|
|
|
|
GstVideoOrientationMethod orientation;
|
|
|
|
gint in_w, in_h;
|
|
|
|
gst_d3d12_window_get_mouse_pos_info (window_, &output_rect,
|
|
|
|
in_w, in_h, orientation);
|
|
|
|
|
|
|
|
if (in_w <= 0 || in_h <= 0 || xpos < output_rect.x ||
|
|
|
|
xpos >= output_rect.x + output_rect.w || ypos < output_rect.y ||
|
|
|
|
ypos >= output_rect.y + output_rect.h) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gint src_w, src_h;
|
|
|
|
switch (orientation) {
|
|
|
|
case GST_VIDEO_ORIENTATION_90R:
|
|
|
|
case GST_VIDEO_ORIENTATION_90L:
|
|
|
|
case GST_VIDEO_ORIENTATION_UL_LR:
|
|
|
|
case GST_VIDEO_ORIENTATION_UR_LL:
|
|
|
|
src_w = in_h;
|
|
|
|
src_h = in_w;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
src_w = in_w;
|
|
|
|
src_h = in_h;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
xpos = ((xpos - output_rect.x) / (double) output_rect.w) * src_w;
|
|
|
|
ypos = ((ypos - output_rect.y) / (double) output_rect.h) * src_h;
|
|
|
|
|
|
|
|
xpos = CLAMP (xpos, 0, (LONG) (src_w - 1));
|
|
|
|
ypos = CLAMP (ypos, 0, (LONG) (src_h - 1));
|
|
|
|
|
|
|
|
double final_x = 0;
|
|
|
|
double final_y = 0;
|
|
|
|
|
|
|
|
switch (orientation) {
|
|
|
|
case GST_VIDEO_ORIENTATION_90R:
|
|
|
|
final_x = ypos;
|
|
|
|
final_y = src_w - xpos;
|
|
|
|
break;
|
|
|
|
case GST_VIDEO_ORIENTATION_90L:
|
|
|
|
final_x = src_h - ypos;
|
|
|
|
final_y = xpos;
|
|
|
|
break;
|
|
|
|
case GST_VIDEO_ORIENTATION_UR_LL:
|
|
|
|
final_x = src_h - ypos;
|
|
|
|
final_y = src_w - xpos;
|
|
|
|
break;
|
|
|
|
case GST_VIDEO_ORIENTATION_UL_LR:
|
|
|
|
final_x = ypos;
|
|
|
|
final_y = xpos;
|
|
|
|
break;
|
|
|
|
case GST_VIDEO_ORIENTATION_180:
|
|
|
|
final_x = src_w - xpos;
|
|
|
|
final_y = src_h - ypos;
|
|
|
|
break;
|
|
|
|
case GST_VIDEO_ORIENTATION_HORIZ:
|
|
|
|
final_x = src_w - xpos;
|
|
|
|
final_y = ypos;
|
|
|
|
break;
|
|
|
|
case GST_VIDEO_ORIENTATION_VERT:
|
|
|
|
final_x = xpos;
|
|
|
|
final_y = src_h - ypos;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
final_x = xpos;
|
|
|
|
final_y = ypos;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-10-26 19:26:46 +00:00
|
|
|
if (msg == WM_MOUSEHWHEEL || msg == WM_MOUSEWHEEL) {
|
|
|
|
gst_d3d12_window_on_scroll_event (window_, delta_x, delta_y, final_x,
|
|
|
|
final_y, modifier);
|
|
|
|
} else {
|
|
|
|
gst_d3d12_window_on_mouse_event (window_,
|
|
|
|
event, button, final_x, final_y, modifier);
|
|
|
|
}
|
2024-06-10 14:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GstFlowReturn
|
|
|
|
SwapChainProxy::setup_swapchain (GstD3D12Device * device,
|
|
|
|
DXGI_FORMAT format, const GstVideoInfo * in_info,
|
|
|
|
const GstVideoInfo * out_info, GstStructure * conv_config)
|
|
|
|
{
|
|
|
|
std::shared_ptr<SwapChain> sc;
|
|
|
|
HWND hwnd = nullptr;
|
|
|
|
bool is_new_swapchain = false;
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
if (!hwnd_) {
|
|
|
|
GST_WARNING_OBJECT (window_, "Window was closed");
|
|
|
|
return GST_D3D12_WINDOW_FLOW_CLOSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!swapchain_)
|
|
|
|
swapchain_ = std::make_shared<SwapChain> (device);
|
|
|
|
|
|
|
|
sc = swapchain_;
|
|
|
|
hwnd = hwnd_;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ret = sc->setup_swapchain (window_, device,
|
|
|
|
hwnd, format, in_info, out_info, conv_config, is_new_swapchain);
|
|
|
|
if (ret != GST_FLOW_OK)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (is_new_swapchain)
|
|
|
|
PostMessageW (hwnd, WM_GST_D3D12_SWAPCHAIN_CREATED, 0, 0);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<SwapChain>
|
|
|
|
SwapChainProxy::get_swapchain ()
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
if (!hwnd_) {
|
|
|
|
GST_DEBUG_OBJECT (window_, "Window handle is not configured");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!swapchain_) {
|
|
|
|
GST_DEBUG_OBJECT (window_, "Swapchain is not configured");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return swapchain_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SwapChainProxy::handle_swapchain_created ()
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
if (!hwnd_ || !swapchain_)
|
|
|
|
return;
|
|
|
|
|
|
|
|
swapchain_->disable_alt_enter (hwnd_);
|
|
|
|
}
|
|
|
|
|
2024-06-16 12:21:44 +00:00
|
|
|
void
|
|
|
|
SwapChainProxy::handle_position_changed (INT width, INT height)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
if (!hwnd_ || !swapchain_)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (width != width_ || height != height_) {
|
|
|
|
width_ = width;
|
|
|
|
height_ = height;
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto sc = get_swapchain ();
|
|
|
|
if (sc)
|
|
|
|
sc->resize_buffer (window_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SwapChainProxy::release_swapchin ()
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
swapchain_ = nullptr;
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:40:55 +00:00
|
|
|
GstFlowReturn
|
2024-06-16 12:21:44 +00:00
|
|
|
SwapChainProxy::resize_buffer (INT width, INT height)
|
2024-06-10 14:40:55 +00:00
|
|
|
{
|
|
|
|
auto sc = get_swapchain ();
|
|
|
|
if (!sc)
|
|
|
|
return GST_FLOW_OK;
|
|
|
|
|
2024-06-16 12:21:44 +00:00
|
|
|
if (width > 0 && height > 0) {
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
width_ = width;
|
|
|
|
height_ = height;
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:40:55 +00:00
|
|
|
return sc->resize_buffer (window_);
|
|
|
|
}
|
|
|
|
|
|
|
|
GstFlowReturn
|
|
|
|
SwapChainProxy::set_buffer (GstBuffer * buffer)
|
|
|
|
{
|
|
|
|
auto sc = get_swapchain ();
|
|
|
|
if (!sc)
|
|
|
|
return GST_D3D12_WINDOW_FLOW_CLOSED;
|
|
|
|
|
|
|
|
return sc->set_buffer (window_, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
GstFlowReturn
|
|
|
|
SwapChainProxy::present ()
|
|
|
|
{
|
|
|
|
auto sc = get_swapchain ();
|
|
|
|
if (!sc)
|
|
|
|
return GST_D3D12_WINDOW_FLOW_CLOSED;
|
|
|
|
|
|
|
|
return sc->present ();
|
|
|
|
}
|
|
|
|
|
2024-06-21 09:38:04 +00:00
|
|
|
void
|
|
|
|
SwapChainProxy::expose ()
|
|
|
|
{
|
|
|
|
auto sc = get_swapchain ();
|
|
|
|
if (sc)
|
|
|
|
sc->expose (window_);
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:40:55 +00:00
|
|
|
void
|
|
|
|
HwndServer::register_window (GstD3D12Window * window)
|
|
|
|
{
|
|
|
|
std::lock_guard<std::recursive_mutex> lk (lock_);
|
|
|
|
GST_DEBUG_OBJECT (window, "Register");
|
|
|
|
state_.insert ({window, std::make_shared<State> ()});
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HwndServer::unregister_window (GstD3D12Window * window)
|
|
|
|
{
|
|
|
|
std::lock_guard<std::recursive_mutex> lk (lock_);
|
|
|
|
GST_DEBUG_OBJECT (window, "Unregister");
|
|
|
|
state_.erase (window);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HwndServer::unlock_window (GstD3D12Window * window)
|
|
|
|
{
|
|
|
|
std::lock_guard<std::recursive_mutex> lk (lock_);
|
|
|
|
auto it = state_.find (window);
|
|
|
|
|
|
|
|
if (it != state_.end ()) {
|
|
|
|
std::lock_guard<std::mutex> lk (it->second->create_lock);
|
|
|
|
it->second->flushing = true;
|
|
|
|
it->second->create_cond.notify_all ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HwndServer::unlock_stop_window (GstD3D12Window * window)
|
|
|
|
{
|
|
|
|
std::lock_guard<std::recursive_mutex> lk (lock_);
|
|
|
|
auto it = state_.find (window);
|
|
|
|
|
|
|
|
if (it != state_.end ()) {
|
|
|
|
std::lock_guard<std::mutex> lk (it->second->create_lock);
|
|
|
|
it->second->flushing = false;
|
|
|
|
it->second->create_cond.notify_all ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define EXTERNAL_PROC_PROP_NAME L"gst-d3d12-hwnd-external-proc"
|
|
|
|
#define D3D12_WINDOW_PROP_NAME L"gst-d3d12-hwnd-obj"
|
|
|
|
#define D3D12_WINDOW_ID_PROP_NAME L"gst-d3d12-hwnd-obj-id"
|
|
|
|
|
|
|
|
static LRESULT CALLBACK
|
|
|
|
parent_wnd_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
|
|
|
{
|
|
|
|
auto external_window_proc =
|
|
|
|
(WNDPROC) GetPropW (hwnd, EXTERNAL_PROC_PROP_NAME);
|
|
|
|
|
|
|
|
if (!external_window_proc) {
|
|
|
|
GST_WARNING ("null external proc");
|
|
|
|
return DefWindowProcW (hwnd, msg, wparam, lparam);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto server = HwndServer::get_instance ();
|
|
|
|
if (msg == WM_GST_D3D12_ATTACH_INTERNAL_WINDOW) {
|
|
|
|
GST_DEBUG ("Attach internal window");
|
|
|
|
server->create_child_hwnd_finish ((GstD3D12Window *) lparam, hwnd,
|
|
|
|
(SIZE_T) wparam);
|
|
|
|
return 0;
|
2024-06-16 12:21:44 +00:00
|
|
|
} else if (msg == WM_GST_D3D12_CREATE_PROXY) {
|
|
|
|
server->create_proxy_finish ((GstD3D12Window *) lparam, hwnd,
|
|
|
|
(SIZE_T) wparam);
|
|
|
|
return 0;
|
2024-06-10 14:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
server->forward_parent_message (hwnd, msg, wparam, lparam);
|
|
|
|
|
2024-06-16 12:21:44 +00:00
|
|
|
auto direct_proxy = server->get_direct_proxy (hwnd);
|
|
|
|
switch (msg) {
|
|
|
|
case WM_SIZE:
|
|
|
|
{
|
|
|
|
auto dproxy = server->get_direct_proxy (hwnd);
|
|
|
|
if (dproxy)
|
|
|
|
dproxy->resize_buffer (LOWORD (lparam), HIWORD (lparam));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_WINDOWPOSCHANGED:
|
|
|
|
{
|
|
|
|
WINDOWPOS *pos = (WINDOWPOS *) lparam;
|
|
|
|
if ((pos->flags & SWP_HIDEWINDOW) == 0) {
|
|
|
|
INT width = pos->cx;
|
|
|
|
INT height = pos->cy;
|
|
|
|
if ((pos->flags & SWP_NOSIZE) != 0) {
|
|
|
|
RECT rect = { };
|
|
|
|
GetClientRect (hwnd, &rect);
|
|
|
|
width = rect.right - rect.left;
|
|
|
|
height = rect.bottom - rect.top;
|
|
|
|
}
|
|
|
|
auto dproxy = server->get_direct_proxy (hwnd);
|
|
|
|
if (dproxy)
|
|
|
|
dproxy->handle_position_changed (width, height);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_KEYDOWN:
|
|
|
|
case WM_KEYUP:
|
|
|
|
{
|
|
|
|
auto dproxy = server->get_direct_proxy (hwnd);
|
|
|
|
if (dproxy)
|
|
|
|
dproxy->handle_key_event (msg, wparam, lparam);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
case WM_RBUTTONUP:
|
|
|
|
case WM_MBUTTONDOWN:
|
|
|
|
case WM_MBUTTONUP:
|
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
|
|
case WM_RBUTTONDBLCLK:
|
|
|
|
case WM_MBUTTONDBLCLK:
|
2024-10-26 19:26:46 +00:00
|
|
|
case WM_MOUSEHWHEEL:
|
|
|
|
case WM_MOUSEWHEEL:
|
2024-06-16 12:21:44 +00:00
|
|
|
{
|
|
|
|
auto proxy = server->get_direct_proxy (hwnd);
|
|
|
|
if (proxy)
|
|
|
|
proxy->handle_mouse_event (msg, wparam, lparam);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:40:55 +00:00
|
|
|
if (msg == WM_DESTROY) {
|
|
|
|
GST_INFO ("Parent HWND %p is being destroyed", hwnd);
|
|
|
|
server->on_parent_destroy (hwnd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return CallWindowProcW (external_window_proc, hwnd, msg, wparam, lparam);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct WindowCreateParams
|
|
|
|
{
|
|
|
|
GstD3D12Window *window;
|
|
|
|
SIZE_T id;
|
|
|
|
};
|
|
|
|
|
|
|
|
static LRESULT CALLBACK
|
|
|
|
internal_wnd_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
|
|
|
{
|
|
|
|
auto server = HwndServer::get_instance ();
|
|
|
|
|
|
|
|
if (msg == WM_NCCREATE) {
|
|
|
|
LPCREATESTRUCTW lpcs = (LPCREATESTRUCTW) lparam;
|
|
|
|
auto params = (WindowCreateParams *) lpcs->lpCreateParams;
|
|
|
|
SetPropW (hwnd, D3D12_WINDOW_PROP_NAME, (HANDLE) params->window);
|
|
|
|
SetPropW (hwnd, D3D12_WINDOW_ID_PROP_NAME, (HANDLE) params->id);
|
|
|
|
|
|
|
|
gst_object_ref (params->window);
|
|
|
|
|
|
|
|
return DefWindowProcW (hwnd, msg, wparam, lparam);
|
|
|
|
} else if (msg == WM_GST_D3D12_DESTROY_INTERNAL_WINDOW) {
|
|
|
|
GST_INFO ("%p, Got custom destroy window event", hwnd);
|
|
|
|
DestroyWindow (hwnd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto window = (GstD3D12Window *) GetPropW (hwnd, D3D12_WINDOW_PROP_NAME);
|
|
|
|
auto id = (SIZE_T) GetPropW (hwnd, D3D12_WINDOW_ID_PROP_NAME);
|
|
|
|
|
|
|
|
if (!window)
|
|
|
|
return DefWindowProcW (hwnd, msg, wparam, lparam);
|
|
|
|
|
|
|
|
/* Custom event handler */
|
|
|
|
if (msg == WM_GST_D3D12_PARENT_SIZE) {
|
|
|
|
auto proxy = server->get_proxy (window, id);
|
|
|
|
if (!proxy)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
WORD width, height;
|
|
|
|
|
|
|
|
width = LOWORD (lparam);
|
|
|
|
height = HIWORD (lparam);
|
|
|
|
|
|
|
|
GST_LOG_OBJECT (window, "Parent resize %dx%d", width, height);
|
|
|
|
|
|
|
|
GstVideoRectangle rect;
|
|
|
|
gst_d3d12_window_get_render_rect (window, &rect);
|
|
|
|
if (rect.w > 0 && rect.h > 0)
|
|
|
|
MoveWindow (hwnd, rect.x, rect.y, rect.w, rect.h, FALSE);
|
|
|
|
else
|
|
|
|
MoveWindow (hwnd, 0, 0, width, height, FALSE);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
} else if (msg == WM_GST_D3D12_UPDATE_RENDER_RECT) {
|
|
|
|
auto proxy = server->get_proxy (window, id);
|
|
|
|
if (!proxy)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
proxy->handle_update_render_rect ();
|
|
|
|
return 0;
|
|
|
|
} else if (msg == WM_GST_D3D12_FULLSCREEN) {
|
|
|
|
auto proxy = server->get_proxy (window, id);
|
|
|
|
if (!proxy)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
proxy->handle_fullscreen_change (lparam ? true : false);
|
|
|
|
return 0;
|
|
|
|
} else if (msg == WM_GST_D3D12_SWAPCHAIN_CREATED) {
|
|
|
|
auto proxy = server->get_proxy (window, id);
|
|
|
|
if (!proxy)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
proxy->handle_swapchain_created ();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (msg) {
|
|
|
|
case WM_KEYDOWN:
|
|
|
|
case WM_KEYUP:
|
|
|
|
{
|
|
|
|
auto proxy = server->get_proxy (window, id);
|
|
|
|
if (proxy)
|
|
|
|
proxy->handle_key_event (msg, wparam, lparam);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
case WM_RBUTTONUP:
|
|
|
|
case WM_MBUTTONDOWN:
|
|
|
|
case WM_MBUTTONUP:
|
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
|
|
case WM_RBUTTONDBLCLK:
|
|
|
|
case WM_MBUTTONDBLCLK:
|
2024-10-26 19:26:46 +00:00
|
|
|
case WM_MOUSEHWHEEL:
|
|
|
|
case WM_MOUSEWHEEL:
|
2024-06-10 14:40:55 +00:00
|
|
|
{
|
|
|
|
auto proxy = server->get_proxy (window, id);
|
|
|
|
if (proxy)
|
|
|
|
proxy->handle_mouse_event (msg, wparam, lparam);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_NCHITTEST:
|
|
|
|
{
|
|
|
|
auto proxy = server->get_proxy (window, id);
|
|
|
|
if (proxy && proxy->has_parent ()) {
|
|
|
|
/* To passthrough mouse event if external window is used.
|
|
|
|
* Only hit-test succeeded window can receive/handle some mouse events
|
|
|
|
* and we want such events to be handled by parent (application) window
|
|
|
|
*/
|
|
|
|
return (LRESULT) HTTRANSPARENT;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_SIZE:
|
|
|
|
{
|
|
|
|
auto proxy = server->get_proxy (window, id);
|
|
|
|
if (proxy)
|
2024-06-16 12:21:44 +00:00
|
|
|
proxy->resize_buffer (0, 0);
|
2024-06-10 14:40:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_SYSKEYDOWN:
|
|
|
|
{
|
|
|
|
auto proxy = server->get_proxy (window, id);
|
|
|
|
if (proxy)
|
|
|
|
proxy->handle_syskey_down ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
|
|
{
|
|
|
|
GST_DEBUG ("%p, WM_DESTROY", hwnd);
|
|
|
|
RemovePropW (hwnd, D3D12_WINDOW_PROP_NAME);
|
|
|
|
RemovePropW (hwnd, D3D12_WINDOW_ID_PROP_NAME);
|
|
|
|
|
|
|
|
auto proxy = server->get_proxy (window, id);
|
|
|
|
if (proxy) {
|
|
|
|
proxy->on_destroy ();
|
|
|
|
server->on_proxy_destroy (window, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
gst_object_unref (window);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return DefWindowProcW (hwnd, msg, wparam, lparam);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
register_window_class ()
|
|
|
|
{
|
|
|
|
GST_D3D12_CALL_ONCE_BEGIN {
|
|
|
|
auto inst = GetModuleHandle (nullptr);
|
|
|
|
WNDCLASSEXW wc = { };
|
|
|
|
|
|
|
|
wc.cbSize = sizeof (WNDCLASSEXW);
|
|
|
|
wc.lpfnWndProc = internal_wnd_proc;
|
|
|
|
wc.hInstance = inst;
|
|
|
|
wc.hIcon = LoadIcon (nullptr, IDI_WINLOGO);
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
|
|
|
|
wc.hCursor = LoadCursor (nullptr, IDC_ARROW);
|
|
|
|
wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
|
|
|
|
wc.lpszClassName = L"GstD3D12Hwnd";
|
|
|
|
|
|
|
|
RegisterClassExW (&wc);
|
|
|
|
} GST_D3D12_CALL_ONCE_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
GstFlowReturn
|
|
|
|
HwndServer::create_child_hwnd (GstD3D12Window * window, HWND parent_hwnd,
|
2024-06-16 12:21:44 +00:00
|
|
|
gboolean direct_swapchain, SIZE_T & proxy_id)
|
2024-06-10 14:40:55 +00:00
|
|
|
{
|
|
|
|
proxy_id = 0;
|
|
|
|
if (!IsWindow (parent_hwnd)) {
|
|
|
|
GST_WARNING_OBJECT (window, "%p is not window handle", parent_hwnd);
|
|
|
|
return GST_D3D12_WINDOW_FLOW_CLOSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<State> state;
|
|
|
|
{
|
|
|
|
std::lock_guard<std::recursive_mutex> lk (lock_);
|
|
|
|
auto external_proc = (WNDPROC)
|
|
|
|
GetWindowLongPtrW (parent_hwnd, GWLP_WNDPROC);
|
|
|
|
if (external_proc != (WNDPROC) parent_wnd_proc) {
|
|
|
|
if (!SetPropW (parent_hwnd, EXTERNAL_PROC_PROP_NAME,
|
|
|
|
(HANDLE) external_proc)) {
|
|
|
|
GST_WARNING_OBJECT (window,
|
|
|
|
"Couldn't store original procedure function");
|
|
|
|
return GST_D3D12_WINDOW_FLOW_CLOSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetWindowLongPtrW (parent_hwnd, GWLP_WNDPROC,
|
|
|
|
(LONG_PTR) parent_wnd_proc);
|
|
|
|
|
|
|
|
GST_DEBUG_OBJECT (window,
|
|
|
|
"subclass proc installed for hwnd %p", parent_hwnd);
|
|
|
|
}
|
|
|
|
|
2024-06-16 12:21:44 +00:00
|
|
|
/* Cannot attach multiple swapchain to a single HWND.
|
|
|
|
* release swapchain if needed */
|
|
|
|
if (direct_swapchain) {
|
|
|
|
for (auto it : state_) {
|
|
|
|
auto state = it.second;
|
|
|
|
if (state) {
|
|
|
|
auto proxy = state->proxy;
|
|
|
|
if (proxy && proxy->get_window_handle () == parent_hwnd) {
|
|
|
|
proxy->release_swapchin ();
|
|
|
|
std::unique_lock<std::mutex> lk (state->create_lock);
|
|
|
|
state->proxy = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto it = direct_proxy_map_.find (parent_hwnd);
|
|
|
|
if (it != direct_proxy_map_.end ()) {
|
|
|
|
auto proxy = it->second.lock ();
|
|
|
|
if (proxy)
|
|
|
|
proxy->release_swapchin ();
|
|
|
|
}
|
|
|
|
|
|
|
|
direct_proxy_map_.erase (parent_hwnd);
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:40:55 +00:00
|
|
|
auto it = state_.find (window);
|
|
|
|
state = it->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_lock<std::mutex> lk (state->create_lock);
|
|
|
|
state->id++;
|
|
|
|
if (state->id == 0)
|
|
|
|
state->id++;
|
|
|
|
|
|
|
|
SIZE_T id = state->id;
|
|
|
|
state->proxy = std::make_shared<SwapChainProxy> (window, id);
|
|
|
|
|
|
|
|
if (state->flushing) {
|
|
|
|
GST_INFO_OBJECT (window, "Window is flushing");
|
|
|
|
state->proxy = nullptr;
|
|
|
|
return GST_FLOW_FLUSHING;
|
|
|
|
}
|
|
|
|
|
|
|
|
state->create_state = CreateState::Waiting;
|
2024-06-16 12:21:44 +00:00
|
|
|
if (!PostMessageW (parent_hwnd, direct_swapchain ?
|
|
|
|
WM_GST_D3D12_CREATE_PROXY: WM_GST_D3D12_ATTACH_INTERNAL_WINDOW,
|
2024-06-10 14:40:55 +00:00
|
|
|
(WPARAM) id, (LPARAM) window)) {
|
|
|
|
GST_WARNING_OBJECT (window, "Couldn't post message");
|
|
|
|
state->create_state = CreateState::None;
|
|
|
|
state->proxy = nullptr;
|
|
|
|
return GST_D3D12_WINDOW_FLOW_CLOSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!state->flushing && state->create_state == CreateState::Waiting)
|
|
|
|
state->create_cond.wait(lk);
|
|
|
|
|
|
|
|
GstFlowReturn ret = GST_D3D12_WINDOW_FLOW_CLOSED;
|
|
|
|
if (state->create_state == CreateState::Opened) {
|
|
|
|
ret = GST_FLOW_OK;
|
|
|
|
proxy_id = id;
|
|
|
|
} else {
|
|
|
|
state->proxy = nullptr;
|
|
|
|
if (state->flushing)
|
|
|
|
ret = GST_FLOW_FLUSHING;
|
|
|
|
}
|
|
|
|
|
|
|
|
state->create_state = CreateState::None;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HwndServer::create_child_hwnd_finish (GstD3D12Window * window,
|
|
|
|
HWND parent_hwnd, SIZE_T proxy_id)
|
|
|
|
{
|
|
|
|
std::shared_ptr<State> state;
|
|
|
|
std::shared_ptr<SwapChainProxy> proxy;
|
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard<std::recursive_mutex> lk (lock_);
|
|
|
|
auto it = state_.find (window);
|
|
|
|
if (it == state_.end ()) {
|
|
|
|
GST_WARNING ("Window is not registered");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
state = it->second;
|
|
|
|
proxy = state->proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!proxy) {
|
|
|
|
GST_INFO ("Proxy was released");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (proxy->get_id () != proxy_id) {
|
|
|
|
GST_INFO ("Different proxy id");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
register_window_class ();
|
|
|
|
|
|
|
|
WindowCreateParams params;
|
|
|
|
params.window = window;
|
|
|
|
params.id = proxy_id;
|
|
|
|
|
|
|
|
auto child = CreateWindowExW (0,
|
|
|
|
L"GstD3D12Hwnd", L"GstD3D12Hwnd",
|
|
|
|
WS_GST_D3D12, 0, 0, 0, 0, (HWND) nullptr, (HMENU) nullptr,
|
|
|
|
GetModuleHandle (nullptr), ¶ms);
|
|
|
|
SetWindowLongPtrW (child, GWL_STYLE, WS_CHILD | WS_MAXIMIZE);
|
|
|
|
SetParent (child, parent_hwnd);
|
|
|
|
|
|
|
|
RECT rect;
|
|
|
|
GetClientRect (parent_hwnd, &rect);
|
|
|
|
|
|
|
|
GstVideoRectangle user_rect = { };
|
|
|
|
gst_d3d12_window_get_render_rect (window, &user_rect);
|
|
|
|
|
|
|
|
if (user_rect.w > 0 && user_rect.h > 0) {
|
|
|
|
rect.left = user_rect.x;
|
|
|
|
rect.top = user_rect.y;
|
|
|
|
rect.right = user_rect.x + user_rect.w;
|
|
|
|
rect.bottom = user_rect.y + user_rect.h;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetWindowPos (child, HWND_TOP, rect.left, rect.top,
|
|
|
|
rect.right - rect.left, rect.bottom - rect.top,
|
|
|
|
SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
|
|
|
|
SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
|
|
|
MoveWindow (child, rect.left, rect.top,
|
|
|
|
rect.right - rect.left, rect.bottom - rect.top, FALSE);
|
|
|
|
ShowWindow (child, SW_SHOW);
|
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard<std::recursive_mutex> lk (lock_);
|
|
|
|
auto it = parent_hwnd_map_.find (parent_hwnd);
|
|
|
|
if (it == parent_hwnd_map_.end ()) {
|
|
|
|
GST_DEBUG ("Register parent hwnd %p with child %p", parent_hwnd, child);
|
|
|
|
std::vector<HWND> hwnd_list;
|
|
|
|
hwnd_list.push_back (child);
|
|
|
|
parent_hwnd_map_.insert ({parent_hwnd, hwnd_list});
|
|
|
|
} else {
|
|
|
|
it->second.push_back (child);
|
|
|
|
GST_DEBUG ("New child hwnd %p is added for parent %p, num child %" G_GSIZE_FORMAT,
|
|
|
|
parent_hwnd, child, it->second.size ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard <std::mutex> lk (state->create_lock);
|
|
|
|
proxy->set_window_handles (parent_hwnd, child);
|
|
|
|
state->create_state = CreateState::Opened;
|
|
|
|
state->create_cond.notify_all ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-16 12:21:44 +00:00
|
|
|
void
|
|
|
|
HwndServer::create_proxy_finish (GstD3D12Window * window,
|
|
|
|
HWND parent_hwnd, SIZE_T proxy_id)
|
|
|
|
{
|
|
|
|
std::shared_ptr<State> state;
|
|
|
|
std::shared_ptr<SwapChainProxy> proxy;
|
|
|
|
|
|
|
|
std::lock_guard<std::recursive_mutex> lk (lock_);
|
|
|
|
auto it = state_.find (window);
|
|
|
|
if (it == state_.end ()) {
|
|
|
|
GST_WARNING ("Window is not registered");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
state = it->second;
|
|
|
|
proxy = state->proxy;
|
|
|
|
|
|
|
|
if (!proxy) {
|
|
|
|
GST_INFO ("Proxy was released");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (proxy->get_id () != proxy_id) {
|
|
|
|
GST_INFO ("Different proxy id");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
direct_proxy_map_.insert ({parent_hwnd, proxy});
|
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard <std::mutex> lk (state->create_lock);
|
|
|
|
proxy->set_window_handles (parent_hwnd, parent_hwnd);
|
|
|
|
state->create_state = CreateState::Opened;
|
|
|
|
state->create_cond.notify_all ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:40:55 +00:00
|
|
|
SIZE_T
|
|
|
|
HwndServer::create_internal_window (GstD3D12Window * window)
|
|
|
|
{
|
|
|
|
std::wstring title;
|
|
|
|
GstVideoRectangle rect;
|
|
|
|
GstVideoOrientationMethod orientation;
|
|
|
|
int x = CW_USEDEFAULT;
|
|
|
|
int y = CW_USEDEFAULT;
|
|
|
|
int w, h;
|
|
|
|
|
|
|
|
gst_d3d12_window_get_create_params (window, title, &rect, w, h, orientation);
|
|
|
|
|
|
|
|
std::shared_ptr<State> state;
|
|
|
|
{
|
|
|
|
std::lock_guard<std::recursive_mutex> lk (lock_);
|
|
|
|
auto it = state_.find (window);
|
|
|
|
state = it->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lk (state->create_lock);
|
|
|
|
state->id++;
|
|
|
|
if (state->id == 0)
|
|
|
|
state->id++;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIZE_T id = state->id;
|
|
|
|
auto proxy = std::make_shared<SwapChainProxy> (window, id);
|
|
|
|
|
|
|
|
DWORD style = WS_GST_D3D12 | WS_VISIBLE;
|
|
|
|
if (rect.w > 0 && rect.h > 0) {
|
|
|
|
x = rect.x;
|
|
|
|
y = rect.y;
|
|
|
|
w = rect.w;
|
|
|
|
h = rect.h;
|
|
|
|
} else {
|
|
|
|
RECT rect = { };
|
|
|
|
switch (orientation) {
|
|
|
|
case GST_VIDEO_ORIENTATION_90R:
|
|
|
|
case GST_VIDEO_ORIENTATION_90L:
|
|
|
|
case GST_VIDEO_ORIENTATION_UL_LR:
|
|
|
|
case GST_VIDEO_ORIENTATION_UR_LL:
|
|
|
|
rect.right = h;
|
|
|
|
rect.bottom = w;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rect.right = w;
|
|
|
|
rect.bottom = h;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
AdjustWindowRect (&rect, WS_GST_D3D12, FALSE);
|
|
|
|
|
|
|
|
w = rect.right - rect.left;
|
|
|
|
h = rect.bottom - rect.top;
|
|
|
|
}
|
|
|
|
|
|
|
|
register_window_class ();
|
|
|
|
|
|
|
|
WindowCreateParams params;
|
|
|
|
params.window = window;
|
|
|
|
params.id = id;
|
|
|
|
auto hwnd = CreateWindowExW (0, L"GstD3D12Hwnd", title.c_str (),
|
|
|
|
style, x, y, w, h, (HWND) nullptr, (HMENU) nullptr,
|
|
|
|
GetModuleHandle (nullptr), ¶ms);
|
|
|
|
proxy->set_window_handles (nullptr, hwnd);
|
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard <std::mutex> slk (state->create_lock);
|
|
|
|
state->proxy = std::move (proxy);
|
|
|
|
}
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HwndServer::release_proxy (GstD3D12Window * window, SIZE_T proxy_id)
|
|
|
|
{
|
|
|
|
std::shared_ptr<SwapChainProxy> proxy;
|
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard<std::recursive_mutex> lk (lock_);
|
|
|
|
auto it = state_.find (window);
|
|
|
|
if (it == state_.end ())
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto state = it->second;
|
|
|
|
{
|
|
|
|
std::lock_guard <std::mutex> slk (state->create_lock);
|
|
|
|
if (state->proxy && state->proxy->get_id () == proxy_id) {
|
|
|
|
proxy = state->proxy;
|
|
|
|
state->proxy = nullptr;
|
|
|
|
}
|
|
|
|
}
|
2024-06-16 12:21:44 +00:00
|
|
|
|
|
|
|
auto dit = direct_proxy_map_.begin ();
|
|
|
|
while (dit != direct_proxy_map_.end ()) {
|
|
|
|
auto proxy = dit->second.lock ();
|
|
|
|
if (!proxy || proxy->get_window () == window)
|
|
|
|
dit = direct_proxy_map_.erase (dit);
|
|
|
|
else
|
|
|
|
dit++;
|
|
|
|
}
|
2024-06-10 14:40:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
translate_message (UINT & msg, WPARAM & wparam, LPARAM & lparam)
|
|
|
|
{
|
|
|
|
switch (msg) {
|
|
|
|
case WM_SIZE:
|
|
|
|
msg = WM_GST_D3D12_PARENT_SIZE;
|
|
|
|
return true;
|
|
|
|
case WM_KEYDOWN:
|
|
|
|
case WM_KEYUP:
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
case WM_RBUTTONUP:
|
|
|
|
case WM_MBUTTONDOWN:
|
|
|
|
case WM_MBUTTONUP:
|
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
|
|
case WM_RBUTTONDBLCLK:
|
|
|
|
case WM_MBUTTONDBLCLK:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HwndServer::forward_parent_message (HWND parent, UINT msg, WPARAM wparam, LPARAM lparam)
|
|
|
|
{
|
|
|
|
if (translate_message (msg, wparam, lparam)) {
|
|
|
|
std::vector<HWND> child_hwnds;
|
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
auto it = parent_hwnd_map_.find (parent);
|
|
|
|
if (it == parent_hwnd_map_.end ())
|
|
|
|
return;
|
|
|
|
|
|
|
|
child_hwnds = it->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto child : child_hwnds)
|
|
|
|
SendMessageW (child, msg, wparam, lparam);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HwndServer::on_parent_destroy (HWND parent_hwnd)
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
parent_hwnd_map_.erase (parent_hwnd);
|
2024-06-16 12:21:44 +00:00
|
|
|
direct_proxy_map_.erase (parent_hwnd);
|
|
|
|
for (auto it : state_) {
|
|
|
|
auto state = it.second;
|
|
|
|
if (state) {
|
|
|
|
auto proxy = state->proxy;
|
|
|
|
if (proxy && proxy->get_window_handle () == parent_hwnd) {
|
|
|
|
proxy->release_swapchin ();
|
|
|
|
std::unique_lock<std::mutex> lk (state->create_lock);
|
|
|
|
state->proxy = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-06-10 14:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HwndServer::on_proxy_destroy (GstD3D12Window * window,
|
|
|
|
SIZE_T proxy_id)
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
auto it = state_.find (window);
|
|
|
|
if (it != state_.end ()) {
|
|
|
|
auto state = it->second;
|
|
|
|
std::lock_guard <std::mutex> slk (state->create_lock);
|
|
|
|
if (state->proxy && state->proxy->get_id () == proxy_id) {
|
|
|
|
state->proxy = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<SwapChainProxy>
|
|
|
|
HwndServer::get_proxy (GstD3D12Window * window, SIZE_T proxy_id)
|
|
|
|
{
|
|
|
|
std::shared_ptr<SwapChainProxy> ret;
|
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
auto it = state_.find (window);
|
|
|
|
if (it == state_.end ())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard <std::mutex> slk (it->second->create_lock);
|
|
|
|
ret = it->second->proxy;
|
|
|
|
if (ret && ret->get_id () != proxy_id)
|
|
|
|
ret = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2024-06-16 12:21:44 +00:00
|
|
|
|
|
|
|
std::shared_ptr<SwapChainProxy>
|
|
|
|
HwndServer::get_direct_proxy (HWND parent_hwnd)
|
|
|
|
{
|
|
|
|
std::lock_guard <std::recursive_mutex> lk (lock_);
|
|
|
|
auto it = direct_proxy_map_.find (parent_hwnd);
|
|
|
|
if (it == direct_proxy_map_.end ())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return it->second.lock ();
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:40:55 +00:00
|
|
|
/* *INDENT-ON* */
|