diff --git a/Assets/uDesktopDuplication/Examples/Scripts/DisplacementMapping.cs b/Assets/uDesktopDuplication/Examples/Scripts/DisplacementMapping.cs index bccdc27..8eebc34 100644 --- a/Assets/uDesktopDuplication/Examples/Scripts/DisplacementMapping.cs +++ b/Assets/uDesktopDuplication/Examples/Scripts/DisplacementMapping.cs @@ -45,6 +45,10 @@ public class DisplacementMapping : MonoBehaviour case TargetMonitor.Next: ++id; break; case TargetMonitor.Prev: --id; break; } + if (uDesktopDuplication.Manager.monitorCount == 0) + { + return; + } id = Mathf.Clamp(id, 0, uDesktopDuplication.Manager.monitorCount - 1); var monitor = uDesktopDuplication.Manager.GetMonitor(id); monitor.shouldBeUpdated = true; diff --git a/Assets/uDesktopDuplication/Examples/Scripts/MultipleMonitorCreator.cs b/Assets/uDesktopDuplication/Examples/Scripts/MultipleMonitorCreator.cs index 4a87916..e56d363 100644 --- a/Assets/uDesktopDuplication/Examples/Scripts/MultipleMonitorCreator.cs +++ b/Assets/uDesktopDuplication/Examples/Scripts/MultipleMonitorCreator.cs @@ -2,7 +2,7 @@ using UnityEngine.Assertions; using System.Collections.Generic; using MeshForwardDirection = uDesktopDuplication.Texture.MeshForwardDirection; -using MonitorState = uDesktopDuplication.MonitorState; +using DuplicatorState = uDesktopDuplication.DuplicatorState; public class MultipleMonitorCreator : MonoBehaviour { @@ -92,11 +92,11 @@ public class MultipleMonitorCreator : MonoBehaviour if (removeWaitTimer_ > removeWaitDuration) { hasMonitorUnsupportStateChecked_ = true; foreach (var info in monitors) { - if (info.uddTexture.monitor.state == MonitorState.Unsupported) { + if (info.uddTexture.monitor.state == DuplicatorState.Unsupported) { Destroy(info.gameObject); } } - monitors.RemoveAll(info => info.uddTexture.monitor.state == MonitorState.Unsupported); + monitors.RemoveAll(info => info.uddTexture.monitor.state == DuplicatorState.Unsupported); } } } diff --git a/Assets/uDesktopDuplication/Plugins/x86/uDesktopDuplication.dll b/Assets/uDesktopDuplication/Plugins/x86/uDesktopDuplication.dll index 5517899..352629c 100644 Binary files a/Assets/uDesktopDuplication/Plugins/x86/uDesktopDuplication.dll and b/Assets/uDesktopDuplication/Plugins/x86/uDesktopDuplication.dll differ diff --git a/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll b/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll index c9cbd12..917c8b9 100644 Binary files a/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll and b/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll differ diff --git a/Assets/uDesktopDuplication/Scripts/Lib.cs b/Assets/uDesktopDuplication/Scripts/Lib.cs index 8163559..d20dbaf 100644 --- a/Assets/uDesktopDuplication/Scripts/Lib.cs +++ b/Assets/uDesktopDuplication/Scripts/Lib.cs @@ -32,17 +32,18 @@ public enum MonitorRotation Rotate270 = 4 } -public enum MonitorState +public enum DuplicatorState { NotSet = -1, - Available = 0, - InvalidArg = 1, - AccessDenied = 2, - Unsupported = 3, - CurrentlyNotAvailable = 4, - SessionDisconnected = 5, - AccessLost = 6, - TextureSizeInconsistent = 7, + Ready = 0, + Running = 1, + InvalidArg = 2, + AccessDenied = 3, + Unsupported = 4, + CurrentlyNotAvailable = 5, + SessionDisconnected = 6, + AccessLost = 7, + TextureSizeInconsistent = 8, Unknown = 999, } @@ -86,7 +87,7 @@ public static class Lib [DllImport("uDesktopDuplication")] public static extern void Finalize(); [DllImport("uDesktopDuplication")] - public static extern void Reinitialize(); + public static extern void Reinitialize(bool useThread); [DllImport("uDesktopDuplication")] public static extern void Update(); [DllImport("uDesktopDuplication")] @@ -118,7 +119,7 @@ public static class Lib [DllImport("uDesktopDuplication")] public static extern int GetId(int id); [DllImport("uDesktopDuplication")] - public static extern MonitorState GetState(int id); + public static extern DuplicatorState GetState(int id); [DllImport("uDesktopDuplication")] public static extern void GetName(int id, StringBuilder buf, int len); [DllImport("uDesktopDuplication")] diff --git a/Assets/uDesktopDuplication/Scripts/Manager.cs b/Assets/uDesktopDuplication/Scripts/Manager.cs index aee4e7b..b3253b8 100644 --- a/Assets/uDesktopDuplication/Scripts/Manager.cs +++ b/Assets/uDesktopDuplication/Scripts/Manager.cs @@ -57,6 +57,8 @@ public class Manager : MonoBehaviour [SerializeField] int desktopDuplicationApiTimeout = 0; [SerializeField] float retryReinitializationDuration = 1f; + [SerializeField] + bool useThread = false; private Coroutine renderCoroutine_ = null; private bool shouldReinitialize_ = false; @@ -143,7 +145,7 @@ public class Manager : MonoBehaviour public void Reinitialize() { Debug.Log("[uDD] Reinitialize"); - Lib.Reinitialize(); + Lib.Reinitialize(useThread); CreateMonitors(); if (onReinitialized != null) { onReinitialized(); @@ -158,11 +160,11 @@ public class Manager : MonoBehaviour var monitor = monitors[i]; var state = monitor.state; if ( - state == MonitorState.NotSet || - state == MonitorState.AccessLost || - state == MonitorState.AccessDenied || - state == MonitorState.SessionDisconnected || - state == MonitorState.Unknown + state == DuplicatorState.NotSet || + state == DuplicatorState.AccessLost || + state == DuplicatorState.AccessDenied || + state == DuplicatorState.SessionDisconnected || + state == DuplicatorState.Unknown ) { reinitializeNeeded = true; break; diff --git a/Assets/uDesktopDuplication/Scripts/Monitor.cs b/Assets/uDesktopDuplication/Scripts/Monitor.cs index 19409d4..588907b 100644 --- a/Assets/uDesktopDuplication/Scripts/Monitor.cs +++ b/Assets/uDesktopDuplication/Scripts/Monitor.cs @@ -11,21 +11,23 @@ public class Monitor switch (state) { - case MonitorState.Available: + case DuplicatorState.Ready: break; - case MonitorState.InvalidArg: + case DuplicatorState.Running: + break; + case DuplicatorState.InvalidArg: Debug.LogErrorFormat("[uDD] {0}:{1} => Invalid.", id, name); break; - case MonitorState.AccessDenied: + case DuplicatorState.AccessDenied: Debug.LogWarningFormat("[uDD] {0}:{1} => Access Denied.", id, name); break; - case MonitorState.Unsupported: + case DuplicatorState.Unsupported: Debug.LogWarningFormat("[uDD] {0}:{1} => Unsupported.", id, name); break; - case MonitorState.SessionDisconnected: + case DuplicatorState.SessionDisconnected: Debug.LogWarningFormat("[uDD] {0}:{1} => Disconnected.", id, name); break; - case MonitorState.NotSet: + case DuplicatorState.NotSet: Debug.LogErrorFormat("[uDD] {0}:{1} => Something wrong.", id, name); break; default: @@ -53,14 +55,19 @@ public class Monitor get { return id < Manager.monitorCount; } } - public MonitorState state + public DuplicatorState state { get { return Lib.GetState(id); } } public bool available { - get { return state == MonitorState.Available; } + get + { + return + state == DuplicatorState.Ready || + state == DuplicatorState.Running; + } } public string name diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Common.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Common.cpp index 3c59f5d..9e90e85 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Common.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Common.cpp @@ -6,10 +6,12 @@ #include "IUnityInterface.h" #include "IUnityGraphicsD3D11.h" #include "Common.h" +#include "Debug.h" using namespace Microsoft::WRL; + extern IUnityInterfaces* g_unity; extern std::unique_ptr g_manager; extern std::queue g_messages; @@ -33,6 +35,29 @@ const std::unique_ptr& GetMonitorManager() } +LUID GetUnityAdapterLuid() +{ + const auto device = GetUnity()->Get()->GetDevice(); + + Microsoft::WRL::ComPtr dxgiDevice; + if (FAILED(device->QueryInterface(IID_PPV_ARGS(&dxgiDevice)))){ + Debug::Error("QueryInterface from IUnityGraphicsD3D11 to IDXGIDevice1 failed."); + return LUID(); + } + + Microsoft::WRL::ComPtr dxgiAdapter; + if (FAILED(dxgiDevice->GetAdapter(&dxgiAdapter))) { + Debug::Error("QueryInterface from IDXGIDevice1 to IDXGIAdapter failed."); + return LUID(); + } + + DXGI_ADAPTER_DESC adapterDesc; + dxgiAdapter->GetDesc(&adapterDesc); + + return adapterDesc.AdapterLuid; +} + + void SendMessageToUnity(Message message) { g_messages.push(message); diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Common.h b/Plugins/uDesktopDuplication/uDesktopDuplication/Common.h index 31a8c13..7f04629 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Common.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Common.h @@ -1,21 +1,41 @@ #pragma once +#include #include #include -// Unity interface and ID3D11Device getters + +// Unity interface getter struct IUnityInterfaces; IUnityInterfaces* GetUnity(); +// ID3D11Device (in Unity) getter struct ID3D11Device; Microsoft::WRL::ComPtr GetDevice(); - // Manager getter class MonitorManager; const std::unique_ptr& GetMonitorManager(); +// Get adapter LUID to check the adapter of the monitor is same as Unity one. +LUID GetUnityAdapterLuid(); + + + +// Releaser +class ScopedReleaser +{ +public: + using ReleaseFuncType = std::function; + ScopedReleaser(ReleaseFuncType&& func) : func_(func) {} + ~ScopedReleaser() { func_(); } + +private: + ReleaseFuncType func_; +}; + + // Message is pooled and fetch from Unity. enum class Message @@ -28,13 +48,36 @@ enum class Message void SendMessageToUnity(Message message); + // Buffer template class Buffer { public: - Buffer() {} - ~Buffer() {} + Buffer() + { + } + + Buffer& operator=(const Buffer& other) + { + if (&other == this) return *this; + + value_.reset(); + size_ = 0; + ExpandIfNeeded(other.size_); + memcpy_s(value_.get(), size_, other.value_.get(), other.size_); + + return *this; + } + + ~Buffer() + { + } + + bool Empty() const + { + return !value_; + } void ExpandIfNeeded(UINT size) { diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.cpp index 31ac461..1ac6054 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.cpp @@ -1,13 +1,15 @@ #include #include -#include "Debug.h" -#include "MonitorManager.h" -#include "Monitor.h" + #include "Cursor.h" +#include "Debug.h" +#include "Monitor.h" +#include "Duplicator.h" using namespace Microsoft::WRL; + Cursor::Cursor() { } @@ -18,19 +20,17 @@ Cursor::~Cursor() } -void Cursor::UpdateBuffer(Monitor* monitor, const DXGI_OUTDUPL_FRAME_INFO& frameInfo) +void Cursor::UpdateBuffer(Duplicator* duplicator) { + auto monitor = duplicator->GetMonitor(); + const auto& frameInfo = duplicator->GetFrame().info; + if (frameInfo.LastMouseUpdateTime.QuadPart == 0) { return; } isVisible_ = frameInfo.PointerPosition.Visible != 0; - if (isVisible_) - { - GetMonitorManager()->SetCursorMonitorId(monitor->GetId()); - } - x_ = frameInfo.PointerPosition.Position.x; y_ = frameInfo.PointerPosition.Position.y; timestamp_ = frameInfo.LastMouseUpdateTime; @@ -49,7 +49,7 @@ void Cursor::UpdateBuffer(Monitor* monitor, const DXGI_OUTDUPL_FRAME_INFO& frame // Get mouse pointer information UINT bufferSize; DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo; - const auto hr = monitor->GetDeskDupl()->GetFramePointerShape( + const auto hr = duplicator->GetDuplication()->GetFramePointerShape( buffer_.Size(), buffer_.Get(), &bufferSize, @@ -66,12 +66,15 @@ void Cursor::UpdateBuffer(Monitor* monitor, const DXGI_OUTDUPL_FRAME_INFO& frame } -void Cursor::Draw(Monitor* monitor) +void Cursor::Draw(Duplicator* duplicator) { + auto monitor = duplicator->GetMonitor(); + const auto& frame = duplicator->GetFrame(); + // Check desktop texure - if (monitor->GetUnityTexture() == nullptr) + if (frame.texture == nullptr) { - Debug::Error("Cursor::UpdateTexture() => Monitor::GetUnityTexture() is null."); + Debug::Error("Cursor::UpdateTexture() => texture is null."); return; } @@ -219,7 +222,7 @@ void Cursor::Draw(Monitor* monitor) desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.MiscFlags = 0; - if (FAILED(GetDevice()->CreateTexture2D(&desc, nullptr, &texture))) + if (FAILED(duplicator->GetDevice()->CreateTexture2D(&desc, nullptr, &texture))) { Debug::Error("Cursor::UpdateTexture() => GetDevice()->CreateTexture2D() failed."); return; @@ -229,8 +232,8 @@ void Cursor::Draw(Monitor* monitor) // Copy desktop image to the texture { ComPtr context; - GetDevice()->GetImmediateContext(&context); - context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, monitor->GetUnityTexture(), 0, &capturedImageArea); + duplicator->GetDevice()->GetImmediateContext(&context); + context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, frame.texture.Get(), 0, &capturedImageArea); } // Get mapped surface to access pixels in CPU @@ -360,8 +363,8 @@ void Cursor::Draw(Monitor* monitor) { ComPtr context; - GetDevice()->GetImmediateContext(&context); - context->UpdateSubresource(monitor->GetUnityTexture(), 0, &capturedImageArea, bgraBuffer_.Get(), capturedImageWidth * 4, 0); + duplicator->GetDevice()->GetImmediateContext(&context); + context->UpdateSubresource(frame.texture.Get(), 0, &capturedImageArea, bgraBuffer_.Get(), capturedImageWidth * 4, 0); } if (FAILED(surface->Unmap())) diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.h b/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.h index efc7f8b..0f994fe 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.h @@ -5,15 +5,15 @@ #include #include "Common.h" -class Monitor; +class Duplicator; class Cursor { public: explicit Cursor(); ~Cursor(); - void UpdateBuffer(Monitor* monitor, const DXGI_OUTDUPL_FRAME_INFO& frameInfo); - void Draw(Monitor* monitor); + void UpdateBuffer(Duplicator* duplicator); + void Draw(Duplicator* duplicator); void GetTexture(ID3D11Texture2D* texture); bool IsVisible() const; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Debug.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Debug.cpp index 1dc2b36..f25bdc8 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Debug.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Debug.cpp @@ -4,6 +4,7 @@ #include "Debug.h" + decltype(Debug::isInitialized_) Debug::isInitialized_ = false; decltype(Debug::mode_) Debug::mode_ = Debug::Mode::File; decltype(Debug::logFunc_) Debug::logFunc_ = nullptr; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Device.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Device.cpp new file mode 100644 index 0000000..87c2847 --- /dev/null +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Device.cpp @@ -0,0 +1,96 @@ +#pragma once + +#include +#include + +#include "IUnityInterface.h" +#include "IUnityGraphicsD3D11.h" +#include "Device.h" +#include "Debug.h" + +#pragma comment(lib, "d3d11.lib") + +using namespace Microsoft::WRL; + + + +IsolatedD3D11Device::IsolatedD3D11Device() +{ +} + + +IsolatedD3D11Device::~IsolatedD3D11Device() +{ +} + + +HRESULT IsolatedD3D11Device::Create(const ComPtr& adapter) +{ + const auto driverType = adapter ? + D3D_DRIVER_TYPE_UNKNOWN : + D3D_DRIVER_TYPE_HARDWARE; + const auto flags = + D3D11_CREATE_DEVICE_BGRA_SUPPORT; // D2D Compatible + // | D3D11_CREATE_DEVICE_VIDEO_SUPPORT // MediaFoundation + const D3D_FEATURE_LEVEL featureLevelsRequested[] = + { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1 + }; + const UINT numLevelsRequested = sizeof(featureLevelsRequested) / sizeof(D3D_FEATURE_LEVEL); + D3D_FEATURE_LEVEL featureLevelsSupported; + + return D3D11CreateDevice( + adapter.Get(), + driverType, + nullptr, + flags, + featureLevelsRequested, + numLevelsRequested, + D3D11_SDK_VERSION, + &device_, + &featureLevelsSupported, + nullptr); +} + + +ComPtr IsolatedD3D11Device::GetDevice() +{ + return device_; +} + + +ComPtr IsolatedD3D11Device::GetCompatibleSharedTexture(const ComPtr& src) +{ + D3D11_TEXTURE2D_DESC srcDesc; + src->GetDesc(&srcDesc); + + // check if the format and size of the current texture are same as the source one + if (cachedTexture_) + { + D3D11_TEXTURE2D_DESC targetDesc; + cachedTexture_->GetDesc(&targetDesc); + if (targetDesc.Format == srcDesc.Format && + targetDesc.Width == srcDesc.Width && + targetDesc.Height == srcDesc.Height) + { + return cachedTexture_; + } + cachedTexture_ = nullptr; + } + + // for sharing this texture with unity device + srcDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; + + if (FAILED(device_->CreateTexture2D(&srcDesc, nullptr, &cachedTexture_))) + { + Debug::Error("IsolatedD3D11Device::GetCompatibleSharedTexture() => Creating shared texture failed."); + return nullptr; + } + + return cachedTexture_; +} \ No newline at end of file diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Device.h b/Plugins/uDesktopDuplication/uDesktopDuplication/Device.h new file mode 100644 index 0000000..4b6af1e --- /dev/null +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Device.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + + +// Thraed safe self created ID3D11Device from specified adapter +class IsolatedD3D11Device +{ +public: + IsolatedD3D11Device(); + ~IsolatedD3D11Device(); + + HRESULT Create(const Microsoft::WRL::ComPtr& adapter); + Microsoft::WRL::ComPtr GetDevice(); + Microsoft::WRL::ComPtr GetCompatibleSharedTexture( + const Microsoft::WRL::ComPtr& src); + +private: + Microsoft::WRL::ComPtr device_; + Microsoft::WRL::ComPtr cachedTexture_; +}; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.cpp new file mode 100644 index 0000000..85bec14 --- /dev/null +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.cpp @@ -0,0 +1,436 @@ +#pragma once + +#include "Duplicator.h" +#include "Monitor.h" +#include "MonitorManager.h" +#include "Cursor.h" +#include "Device.h" +#include "Debug.h" + +#include "IUnityInterface.h" +#include "IUnityGraphicsD3D11.h" + +using namespace Microsoft::WRL; + + + +Duplicator::Duplicator(Monitor* monitor) + : monitor_(monitor) +{ + InitializeDevice(); + InitializeDuplication(); + CheckUnityAdapter(); +} + + +Duplicator::~Duplicator() +{ + Stop(); +} + + +void Duplicator::InitializeDevice() +{ + device_ = std::make_shared(); + + if (FAILED(device_->Create(monitor_->GetAdapter()))) + { + Debug::Error("Monitor::Initialize() => IsolatedD3D11Device::Create() failed."); + state_ = State::Unknown; + } +} + + +void Duplicator::InitializeDuplication() +{ + ComPtr output1; + if (FAILED(monitor_->GetOutput().As(&output1))) { + return; + } + + auto hr = output1->DuplicateOutput(device_->GetDevice().Get(), &dupl_); + switch (hr) + { + case S_OK: + { + state_ = State::Ready; + const auto rot = static_cast(monitor_->GetRotation()); + Debug::Log("Duplicator::Initialize() => OK."); + Debug::Log(" ID : ", monitor_->GetId()); + Debug::Log(" Size : (", monitor_->GetWidth(), ", ", monitor_->GetHeight(), ")"); + Debug::Log(" DPI : (", monitor_->GetDpiX(), ", ", monitor_->GetDpiY(), ")"); + Debug::Log(" Rot : ", + rot == DXGI_MODE_ROTATION_IDENTITY ? "Landscape" : + rot == DXGI_MODE_ROTATION_ROTATE90 ? "Portrait" : + rot == DXGI_MODE_ROTATION_ROTATE180 ? "Landscape (flipped)" : + rot == DXGI_MODE_ROTATION_ROTATE270 ? "Portrait (flipped)" : + "Unspecified"); + break; + } + case E_INVALIDARG: + { + state_ = State::InvalidArg; + Debug::Error("Duplicator::Initialize() => Invalid arguments."); + break; + } + case E_ACCESSDENIED: + { + // For example, when the user presses Ctrl + Alt + Delete and the screen + // switches to admin screen, this error occurs. + state_ = State::AccessDenied; + Debug::Error("Duplicator::Initialize() => Access denied."); + break; + } + case DXGI_ERROR_UNSUPPORTED: + { + // If the display adapter on the computer is running under the Microsoft Hybrid system, + // this error occurs. + state_ = State::Unsupported; + Debug::Error("Duplicator::Initialize() => Unsupported display."); + break; + } + case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: + { + // When other application use Desktop Duplication API, this error occurs. + state_ = State::CurrentlyNotAvailable; + Debug::Error("Duplicator::Initialize() => Currently not available."); + break; + } + case DXGI_ERROR_SESSION_DISCONNECTED: + { + state_ = State::SessionDisconnected; + Debug::Error("Duplicator::Initialize() => Session disconnected."); + break; + } + default: + { + state_ = State::Unknown; + Debug::Error("Duplicator::Render() => Unknown Error."); + break; + } + } +} + + +void Duplicator::CheckUnityAdapter() +{ + DXGI_ADAPTER_DESC desc; + monitor_->GetAdapter()->GetDesc(&desc); + + const auto unityAdapterLuid = GetUnityAdapterLuid(); + const auto isUnityAdapter = + (desc.AdapterLuid.LowPart == unityAdapterLuid.LowPart) && + (desc.AdapterLuid.HighPart == unityAdapterLuid.HighPart); + + if (!isUnityAdapter) + { + Debug::Error("Duplicator::CheckUnityAdapter() => The adapter is not same as Unity, and now this case is not supported."); + state_ = State::Unsupported; + } +} + + +void Duplicator::Start() +{ + if (state_ != State::Ready) return; + + Stop(); + + thread_ = std::thread([this] + { + state_ = State::Running; + + shouldRun_ = true; + while (shouldRun_) + { + if (!Duplicate()) break; + } + + if (state_ == State::Running) + { + state_ = State::Ready; + } + }); +} + + +void Duplicator::Stop() +{ + shouldRun_ = false; + + if (thread_.joinable()) + { + thread_.join(); + } +} + + +bool Duplicator::IsRunning() const +{ + return state_ == State::Running; +} + + +bool Duplicator::IsError() const +{ + return + state_ != State::Ready && + state_ != State::Running; +} + + +Duplicator::State Duplicator::GetState() const +{ + return state_; +} + + +Monitor* Duplicator::GetMonitor() const +{ + return monitor_; +} + + +Microsoft::WRL::ComPtr Duplicator::GetDevice() +{ + return device_->GetDevice(); +} + + +ComPtr Duplicator::GetDuplication() +{ + return dupl_; +} + + +const Duplicator::Frame& Duplicator::GetFrame() const +{ + std::lock_guard lock(mutex_); + return lastFrame_; +} + + +bool Duplicator::Duplicate() +{ + if (!dupl_ || !device_) return false; + + ComPtr resource; + DXGI_OUTDUPL_FRAME_INFO frameInfo; + const auto hr = dupl_->AcquireNextFrame(INFINITE, &frameInfo, &resource); + + if (FAILED(hr)) + { + switch (hr) + { + case DXGI_ERROR_ACCESS_LOST: + { + // If any monitor setting has changed (e.g. monitor size has changed), + // it is necessary to re-initialize monitors. + Debug::Log("Duplicator::Duplicate() => DXGI_ERROR_ACCESS_LOST."); + state_ = State::AccessLost; + break; + } + case DXGI_ERROR_WAIT_TIMEOUT: + { + // This often occurs when timeout value is small and it is not problem. + // Debug::Log("Duplicator::Duplicate() => DXGI_ERROR_WAIT_TIMEOUT."); + break; + } + case DXGI_ERROR_INVALID_CALL: + { + Debug::Error("Duplicator::Duplicate() => DXGI_ERROR_INVALID_CALL."); + break; + } + case E_INVALIDARG: + { + Debug::Error("Duplicator::Duplicate() => E_INVALIDARG."); + break; + } + default: + { + state_ = State::Unknown; + Debug::Error("Duplicator::Duplicate() => Unknown Error."); + break; + } + } + return false; + } + + ScopedReleaser releaser([this] + { + const auto hr = dupl_->ReleaseFrame(); + if (FAILED(hr)) + { + switch (hr) + { + case DXGI_ERROR_ACCESS_LOST: + { + Debug::Log("Duplicator::Duplicate() => DXGI_ERROR_ACCESS_LOST."); + state_ = State::AccessLost; + break; + } + case DXGI_ERROR_INVALID_CALL: + { + Debug::Error("Duplicator::Duplicate() => DXGI_ERROR_INVALID_CALL."); + break; + } + default: + { + state_ = State::Unknown; + Debug::Error("Duplicator::Duplicate() => Unknown Error."); + break; + } + } + } + }); + + ComPtr texture; + if (FAILED(resource.As(&texture))) + { + return false; + } + + auto copyTarget = device_->GetCompatibleSharedTexture(texture); + if (!copyTarget) + { + return false; + } + + ComPtr context; + device_->GetDevice()->GetImmediateContext(&context); + context->CopyResource(copyTarget.Get(), texture.Get()); + + { + std::lock_guard lock(mutex_); + lastFrame_.texture = copyTarget; + lastFrame_.info = frameInfo; + } + + UpdateMetadata(); + UpdateCursor(); + + return true; +} + + +void Duplicator::UpdateCursor() +{ + auto& manager = GetMonitorManager(); + if (!manager) return; + + if (lastFrame_.info.PointerPosition.Visible) + { + manager->SetCursorMonitorId(monitor_->GetId()); + } + + if (monitor_->GetId() == manager->GetCursorMonitorId()) + { + auto cursor = GetMonitorManager()->GetCursor(); + cursor->UpdateBuffer(this); + cursor->Draw(this); + } +} + + +void Duplicator::UpdateMetadata() +{ + metaData_.buffer.ExpandIfNeeded(lastFrame_.info.TotalMetadataBufferSize); + if (!metaData_.buffer.Empty()) + { + UpdateMoveRects(); + UpdateDirtyRects(); + } + + { + std::lock_guard lock(mutex_); + lastFrame_.metaData = metaData_; + } +} + + +void Duplicator::UpdateMoveRects() +{ + metaData_.moveRectSize = metaData_.buffer.Size(); + + const auto hr = dupl_->GetFrameMoveRects( + metaData_.moveRectSize, + metaData_.buffer.As(), + &metaData_.moveRectSize); + + if (FAILED(hr)) + { + switch (hr) + { + case DXGI_ERROR_ACCESS_LOST: + { + Debug::Log("Duplicator::UpdateMoveRects() => DXGI_ERROR_ACCESS_LOST."); + break; + } + case DXGI_ERROR_MORE_DATA: + { + Debug::Error("Duplicator::UpdateMoveRects() => DXGI_ERROR_MORE_DATA."); + break; + } + case DXGI_ERROR_INVALID_CALL: + { + Debug::Error("Duplicator::UpdateMoveRects() => DXGI_ERROR_INVALID_CALL."); + break; + } + case E_INVALIDARG: + { + Debug::Error("Duplicator::UpdateMoveRects() => E_INVALIDARG."); + break; + } + default: + { + Debug::Error("Duplicator::UpdateMoveRects() => Unknown Error."); + break; + } + } + return; + } +} + + +void Duplicator::UpdateDirtyRects() +{ + metaData_.dirtyRectSize = metaData_.buffer.Size() - metaData_.moveRectSize; + + const auto hr = dupl_->GetFrameDirtyRects( + metaData_.dirtyRectSize, + metaData_.buffer.As(metaData_.moveRectSize /* offset */), + &metaData_.dirtyRectSize); + + if (FAILED(hr)) + { + switch (hr) + { + case DXGI_ERROR_ACCESS_LOST: + { + Debug::Log("Duplicator::UpdateDirtyRects() => DXGI_ERROR_ACCESS_LOST."); + break; + } + case DXGI_ERROR_MORE_DATA: + { + Debug::Error("Duplicator::UpdateDirtyRects() => DXGI_ERROR_MORE_DATA."); + break; + } + case DXGI_ERROR_INVALID_CALL: + { + Debug::Error("Duplicator::UpdateDirtyRects() => DXGI_ERROR_INVALID_CALL."); + break; + } + case E_INVALIDARG: + { + Debug::Error("Duplicator::UpdateDirtyRects() => E_INVALIDARG."); + break; + } + default: + { + Debug::Error("Duplicator::UpdateDirtyRects() => Unknown Error."); + break; + } + } + return; + } +} \ No newline at end of file diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.h b/Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.h new file mode 100644 index 0000000..a048377 --- /dev/null +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.h @@ -0,0 +1,87 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "Common.h" + + +class Monitor; + + +enum class DuplicatorState +{ + NotSet = -1, + Ready = 0, + Running = 1, + InvalidArg = 2, + AccessDenied = 3, + Unsupported = 4, + CurrentlyNotAvailable = 5, + SessionDisconnected = 6, + AccessLost = 7, + TextureSizeInconsistent = 8, + Unknown = 999, +}; + + +class Duplicator +{ +public: + using State = DuplicatorState; + + struct Metadata + { + Buffer buffer; + UINT moveRectSize = 0; + UINT dirtyRectSize = 0; + }; + + struct Frame + { + Microsoft::WRL::ComPtr texture; + DXGI_OUTDUPL_FRAME_INFO info; + Metadata metaData; + }; + + explicit Duplicator(Monitor* monitor); + ~Duplicator(); + void Start(); + void Stop(); + bool IsRunning() const; + bool IsError() const; + State GetState() const; + Monitor* GetMonitor() const; + Microsoft::WRL::ComPtr GetDevice(); + Microsoft::WRL::ComPtr GetDuplication(); + const Frame& GetFrame() const; + +private: + void InitializeDevice(); + void InitializeDuplication(); + void CheckUnityAdapter(); + + bool Duplicate(); + + void UpdateCursor(); + void UpdateMetadata(); + void UpdateMoveRects(); + void UpdateDirtyRects(); + + Monitor* monitor_ = nullptr; + State state_ = State::Ready; + + std::shared_ptr device_; + Microsoft::WRL::ComPtr dupl_; + Frame lastFrame_; + + volatile bool shouldRun_ = false; + std::thread thread_; + mutable std::mutex mutex_; + + Metadata metaData_; +}; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp index 95fa7ee..bf6bf5b 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp @@ -1,348 +1,118 @@ #include #include +#include +#include "Monitor.h" +#include "Duplicator.h" #include "Debug.h" #include "Cursor.h" #include "MonitorManager.h" -#include "Monitor.h" +#include "Device.h" using namespace Microsoft::WRL; + Monitor::Monitor(int id) : id_(id) { + ZeroMemory(&monitorInfo_, sizeof(monitorInfo_)); } Monitor::~Monitor() { - if (deskDupl_) + duplicator_->Stop(); +} + + +void Monitor::Initialize( + const ComPtr &adapter, + const ComPtr &output +) +{ + adapter_ = adapter; + output_ = output; + + if (FAILED(output->GetDesc(&outputDesc_))) + { + Debug::Error("Monitor::Initialize() => IDXGIOutput::GetDesc() failed."); + return; + } + + monitorInfo_.cbSize = sizeof(MONITORINFOEX); + if (!GetMonitorInfo(outputDesc_.Monitor, &monitorInfo_)) + { + Debug::Error("Monitor::Initialize() => GetMonitorInfo() failed."); + return; + } + else + { + const auto rect = monitorInfo_.rcMonitor; + width_ = rect.right - rect.left; + height_ = rect.bottom - rect.top; + } + + if (FAILED(GetDpiForMonitor(outputDesc_.Monitor, MDT_RAW_DPI, &dpiX_, &dpiY_))) + { + Debug::Error("Monitor::Initialize() => GetDpiForMonitor() failed."); + // DPI is set as -1, so the application has to use the appropriate value. + } + + duplicator_ = std::make_shared(this); + if (duplicator_->GetState() == DuplicatorState::Ready) { - deskDupl_->Release(); - deskDupl_ = nullptr; + duplicator_->Start(); } } -void Monitor::Initialize(IDXGIOutput* output) +void Monitor::Finalize() { - if (FAILED(output->GetDesc(&outputDesc_))) - { - Debug::Error("Monitor::Initialize() => IDXGIOutput::GetDesc() failed."); - return; - } - - monitorInfo_.cbSize = sizeof(MONITORINFOEX); - if (!GetMonitorInfo(outputDesc_.Monitor, &monitorInfo_)) - { - Debug::Error("Monitor::Initialize() => GetMonitorInfo() failed."); - return; - } - else - { - const auto rect = monitorInfo_.rcMonitor; - width_ = rect.right - rect.left; - height_ = rect.bottom - rect.top; - } - - if (FAILED(GetDpiForMonitor(outputDesc_.Monitor, MDT_RAW_DPI, &dpiX_, &dpiY_))) - { - Debug::Error("Monitor::Initialize() => GetDpiForMonitor() failed."); - // DPI is set as -1, so the application has to use the appropriate value. - } - - auto output1 = reinterpret_cast(output); - switch (output1->DuplicateOutput(GetDevice().Get(), &deskDupl_)) - { - case S_OK: - { - state_ = State::Available; - const auto rot = static_cast(GetRotation()); - Debug::Log("Monitor::Initialize() => OK."); - Debug::Log(" ID : ", GetId()); - Debug::Log(" Size : (", GetWidth(), ", ", GetHeight(), ")"); - Debug::Log(" DPI : (", GetDpiX(), ", ", GetDpiY(), ")"); - Debug::Log(" Rot : ", - rot == DXGI_MODE_ROTATION_IDENTITY ? "Landscape" : - rot == DXGI_MODE_ROTATION_ROTATE90 ? "Portrait" : - rot == DXGI_MODE_ROTATION_ROTATE180 ? "Landscape (flipped)" : - rot == DXGI_MODE_ROTATION_ROTATE270 ? "Portrait (flipped)" : - "Unspecified"); - break; - } - case E_INVALIDARG: - { - state_ = State::InvalidArg; - Debug::Error("Monitor::Initialize() => Invalid arguments."); - break; - } - case E_ACCESSDENIED: - { - // For example, when the user presses Ctrl + Alt + Delete and the screen - // switches to admin screen, this error occurs. - state_ = State::AccessDenied; - Debug::Error("Monitor::Initialize() => Access denied."); - break; - } - case DXGI_ERROR_UNSUPPORTED: - { - // If the display adapter on the computer is running under the Microsoft Hybrid system, - // this error occurs. - state_ = State::Unsupported; - Debug::Error("Monitor::Initialize() => Unsupported display."); - break; - } - case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: - { - // When other application use Desktop Duplication API, this error occurs. - state_ = State::CurrentlyNotAvailable; - Debug::Error("Monitor::Initialize() => Currently not available."); - break; - } - case DXGI_ERROR_SESSION_DISCONNECTED: - { - state_ = State::SessionDisconnected; - Debug::Error("Monitor::Initialize() => Session disconnected."); - break; - } - default: - { - state_ = State::Unknown; - Debug::Error("Monitor::Render() => Unknown Error."); - break; - } - } + duplicator_->Stop(); } -void Monitor::Render(UINT timeout) +void Monitor::Render() { - if (!deskDupl_) return; + const auto& frame = duplicator_->GetFrame(); + const auto texture = frame.texture; + const auto& frameInfo = frame.info; - HRESULT hr; - ComPtr resource; - DXGI_OUTDUPL_FRAME_INFO frameInfo; + if (!texture) return; - hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource); - if (FAILED(hr)) - { - switch (hr) - { - case DXGI_ERROR_ACCESS_LOST: - { - // If any monitor setting has changed (e.g. monitor size has changed), - // it is necessary to re-initialize monitors. - Debug::Log("Monitor::Render() => DXGI_ERROR_ACCESS_LOST."); - state_ = State::AccessLost; - break; - } - case DXGI_ERROR_WAIT_TIMEOUT: - { - // This often occurs when timeout value is small and it is not problem. - // Debug::Log("Monitor::Render() => DXGI_ERROR_WAIT_TIMEOUT."); - break; - } - case DXGI_ERROR_INVALID_CALL: - { - Debug::Error("Monitor::Render() => DXGI_ERROR_INVALID_CALL."); - break; - } - case E_INVALIDARG: - { - Debug::Error("Monitor::Render() => E_INVALIDARG."); - break; - } - default: - { - state_ = State::Unknown; - Debug::Error("Monitor::Render() => Unknown Error."); - break; - } - } - return; - } + // Get texture + if (unityTexture_) + { + D3D11_TEXTURE2D_DESC srcDesc, dstDesc; + texture->GetDesc(&srcDesc); + unityTexture_->GetDesc(&dstDesc); + if (srcDesc.Width != dstDesc.Width || + srcDesc.Height != dstDesc.Height) + { + Debug::Error("Monitor::Render() => Texture sizes are defferent."); + Debug::Error(" Source : (", srcDesc.Width, ", ", srcDesc.Height, ")"); + Debug::Error(" Dest : (", dstDesc.Width, ", ", dstDesc.Height, ")"); + //Debug::Log(" => Try modifying width/height using reported value from DDA."); + //width_ = srcDesc.Width; + //height_ = srcDesc.Height; + //state_ = MonitorState::TextureSizeInconsistent; + //SendMessageToUnity(Message::TextureSizeChanged); + return; + } + else + { + ComPtr context; + GetDevice()->GetImmediateContext(&context); + context->CopyResource(unityTexture_, texture.Get()); + } + } - ID3D11Texture2D* texture; - if (FAILED(resource.CopyTo(&texture))) - { - Debug::Error("Monitor::Render() => resource.As() failed."); - return; - } + if (UseGetPixels()) + { + CopyTextureFromGpuToCpu(unityTexture_); + } - // Get texture - if (unityTexture_) - { - D3D11_TEXTURE2D_DESC srcDesc, dstDesc; - texture->GetDesc(&srcDesc); - unityTexture_->GetDesc(&dstDesc); - if (srcDesc.Width != dstDesc.Width || - srcDesc.Height != dstDesc.Height) - { - Debug::Error("Monitor::Render() => Texture sizes are defferent."); - Debug::Error(" Source : (", srcDesc.Width, ", ", srcDesc.Height, ")"); - Debug::Error(" Dest : (", dstDesc.Width, ", ", dstDesc.Height, ")"); - //Debug::Log(" => Try modifying width/height using reported value from DDA."); - //width_ = srcDesc.Width; - //height_ = srcDesc.Height; - state_ = MonitorState::TextureSizeInconsistent; - //SendMessageToUnity(Message::TextureSizeChanged); - } - else - { - ComPtr context; - GetDevice()->GetImmediateContext(&context); - context->CopyResource(unityTexture_, texture); - } - } - - UpdateMetadata(frameInfo); - - if (frameInfo.PointerPosition.Visible) - { - GetMonitorManager()->SetCursorMonitorId(id_); - } - - if (GetMonitorManager()->GetCursorMonitorId() == id_) - { - UpdateCursor(frameInfo); - } - - if (UseGetPixels()) - { - CopyTextureFromGpuToCpu(texture); - } - - hr = deskDupl_->ReleaseFrame(); - if (FAILED(hr)) - { - switch (hr) - { - case DXGI_ERROR_ACCESS_LOST: - { - Debug::Log("Monitor::Render() => DXGI_ERROR_ACCESS_LOST."); - state_ = State::AccessLost; - break; - } - case DXGI_ERROR_INVALID_CALL: - { - Debug::Error("Monitor::Render() => DXGI_ERROR_INVALID_CALL."); - break; - } - default: - { - state_ = State::Unknown; - Debug::Error("Monitor::Render() => Unknown Error."); - break; - } - } - return; - } - - hasBeenUpdated_ = true; -} - - -void Monitor::UpdateCursor(const DXGI_OUTDUPL_FRAME_INFO& frameInfo) -{ - auto cursor_ = GetMonitorManager()->GetCursor(); - cursor_->UpdateBuffer(this, frameInfo); - cursor_->Draw(this); -} - - -void Monitor::UpdateMetadata(const DXGI_OUTDUPL_FRAME_INFO& frameInfo) -{ - metaData_.ExpandIfNeeded(frameInfo.TotalMetadataBufferSize); - UpdateMoveRects(frameInfo); - UpdateDirtyRects(frameInfo); -} - - -void Monitor::UpdateMoveRects(const DXGI_OUTDUPL_FRAME_INFO& frameInfo) -{ - moveRectSize_ = metaData_.Size(); - - const auto hr = deskDupl_->GetFrameMoveRects( - moveRectSize_, - metaData_.As(), - &moveRectSize_); - - if (FAILED(hr)) - { - switch (hr) - { - case DXGI_ERROR_ACCESS_LOST: - { - Debug::Log("Monitor::Render() => DXGI_ERROR_ACCESS_LOST (GetFrameMoveRects())."); - break; - } - case DXGI_ERROR_MORE_DATA: - { - Debug::Error("Monitor::Render() => DXGI_ERROR_MORE_DATA (GetFrameMoveRects())."); - break; - } - case DXGI_ERROR_INVALID_CALL: - { - Debug::Error("Monitor::Render() => DXGI_ERROR_INVALID_CALL (GetFrameMoveRects())."); - break; - } - case E_INVALIDARG: - { - Debug::Error("Monitor::Render() => E_INVALIDARG (GetFrameMoveRects())."); - break; - } - default: - { - Debug::Error("Monitor::Render() => Unknown Error (GetFrameMoveRects())."); - break; - } - } - return; - } -} - - -void Monitor::UpdateDirtyRects(const DXGI_OUTDUPL_FRAME_INFO& frameInfo) -{ - dirtyRectSize_ = metaData_.Size() - moveRectSize_; - - const auto hr = deskDupl_->GetFrameDirtyRects( - dirtyRectSize_, - metaData_.As(moveRectSize_ /* offset */), - &dirtyRectSize_); - - if (FAILED(hr)) - { - switch (hr) - { - case DXGI_ERROR_ACCESS_LOST: - { - Debug::Log("Monitor::Render() => DXGI_ERROR_ACCESS_LOST (GetFrameDirtyRects())."); - break; - } - case DXGI_ERROR_MORE_DATA: - { - Debug::Error("Monitor::Render() => DXGI_ERROR_MORE_DATA (GetFrameDirtyRects())."); - break; - } - case DXGI_ERROR_INVALID_CALL: - { - Debug::Error("Monitor::Render() => DXGI_ERROR_INVALID_CALL (GetFrameDirtyRects())."); - break; - } - case E_INVALIDARG: - { - Debug::Error("Monitor::Render() => E_INVALIDARG (GetFrameDirtyRects())."); - break; - } - default: - { - Debug::Error("Monitor::Render() => Unknown Error (GetFrameDirtyRects())."); - break; - } - } - return; - } + hasBeenUpdated_ = true; } @@ -352,9 +122,21 @@ int Monitor::GetId() const } -MonitorState Monitor::GetState() const +ComPtr Monitor::GetAdapter() { - return state_; + return adapter_; +} + + +ComPtr Monitor::GetOutput() +{ + return output_; +} + + +DuplicatorState Monitor::GetDuplicatorState() const +{ + return duplicator_->GetState(); } @@ -370,9 +152,9 @@ ID3D11Texture2D* Monitor::GetUnityTexture() const } -IDXGIOutputDuplication* Monitor::GetDeskDupl() +ComPtr Monitor::GetDeskDupl() { - return deskDupl_; + return duplicator_->GetDuplication(); } @@ -450,25 +232,29 @@ int Monitor::GetHeight() const int Monitor::GetMoveRectCount() const { - return moveRectSize_ / sizeof(DXGI_OUTDUPL_MOVE_RECT); + const auto& metaData = duplicator_->GetFrame().metaData; + return metaData.moveRectSize / sizeof(DXGI_OUTDUPL_MOVE_RECT); } DXGI_OUTDUPL_MOVE_RECT* Monitor::GetMoveRects() const { - return metaData_.As(); + const auto& metaData = duplicator_->GetFrame().metaData; + return metaData.buffer.As(); } int Monitor::GetDirtyRectCount() const { - return dirtyRectSize_ / sizeof(RECT); + const auto& metaData = duplicator_->GetFrame().metaData; + return metaData.dirtyRectSize / sizeof(RECT); } RECT* Monitor::GetDirtyRects() const { - return metaData_.As(moveRectSize_); + const auto& metaData = duplicator_->GetFrame().metaData; + return metaData.buffer.As(metaData.moveRectSize); } diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h index bb06519..003022d 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h @@ -5,35 +5,31 @@ #include #include #include +#include #include "Common.h" -enum class MonitorState -{ - NotSet = -1, - Available = 0, - InvalidArg = 1, - AccessDenied = 2, - Unsupported = 3, - CurrentlyNotAvailable = 4, - SessionDisconnected = 5, - AccessLost = 6, - TextureSizeInconsistent = 7, - Unknown = 999, -}; + +enum class DuplicatorState; + class Monitor { -public: - using State = MonitorState; + class ThreadedDesktopDuplicator *m_threaded = nullptr; +public: explicit Monitor(int id); ~Monitor(); - void Initialize(IDXGIOutput* output); - void Render(UINT timeout = 0); + void Initialize( + const Microsoft::WRL::ComPtr &adapter, + const Microsoft::WRL::ComPtr &output); + void Finalize(); + void Render(); public: int GetId() const; - State GetState() const; + Microsoft::WRL::ComPtr GetAdapter(); + Microsoft::WRL::ComPtr GetOutput(); + DuplicatorState GetDuplicatorState() const; void SetUnityTexture(ID3D11Texture2D* texture); ID3D11Texture2D* GetUnityTexture() const; void GetName(char* buf, int len) const; @@ -48,7 +44,7 @@ public: int GetRotation() const; int GetDpiX() const; int GetDpiY() const; - IDXGIOutputDuplication* GetDeskDupl(); + Microsoft::WRL::ComPtr GetDeskDupl(); int GetMoveRectCount() const; DXGI_OUTDUPL_MOVE_RECT* GetMoveRects() const; int GetDirtyRectCount() const; @@ -58,25 +54,24 @@ public: bool GetPixels(BYTE* output, int x, int y, int width, int height); private: - void UpdateCursor(const DXGI_OUTDUPL_FRAME_INFO& frameInfo); - void UpdateMetadata(const DXGI_OUTDUPL_FRAME_INFO& frameInfo); - void UpdateMoveRects(const DXGI_OUTDUPL_FRAME_INFO& frameInfo); - void UpdateDirtyRects(const DXGI_OUTDUPL_FRAME_INFO& frameInfo); void CopyTextureFromGpuToCpu(ID3D11Texture2D* texture); int id_ = -1; + UINT dpiX_ = -1, dpiY_ = -1; int width_ = -1, height_ = -1; + bool hasBeenUpdated_ = false; bool useGetPixels_ = false; - State state_ = State::NotSet; - IDXGIOutputDuplication* deskDupl_ = nullptr; - ID3D11Texture2D* unityTexture_ = nullptr; + + Microsoft::WRL::ComPtr output_; + Microsoft::WRL::ComPtr adapter_; DXGI_OUTPUT_DESC outputDesc_; MONITORINFOEX monitorInfo_; - Buffer metaData_; + + std::shared_ptr duplicator_; + + ID3D11Texture2D* unityTexture_ = nullptr; Microsoft::WRL::ComPtr textureForGetPixels_; Buffer bufferForGetPixels_; - UINT moveRectSize_ = 0; - UINT dirtyRectSize_ = 0;; -}; \ No newline at end of file +}; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp index 16439b6..ae35287 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp @@ -17,7 +17,9 @@ using namespace Microsoft::WRL; -MonitorManager::MonitorManager() + +MonitorManager::MonitorManager(LUID unityAdapterLuid) + : unityAdapterLuid_(unityAdapterLuid) { Initialize(); } @@ -51,7 +53,8 @@ void MonitorManager::Initialize() for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j) { auto monitor = std::make_shared(id++); - monitor->Initialize(output.Get()); + const auto unityAdapterLuid = GetUnityAdapterLuid(); + monitor->Initialize(adapter, output); monitors_.push_back(monitor); } } @@ -60,6 +63,11 @@ void MonitorManager::Initialize() void MonitorManager::Finalize() { + for (const auto& monitor : monitors_) + { + monitor->Finalize(); + } + monitors_.clear(); } @@ -171,4 +179,4 @@ int MonitorManager::GetTotalHeight() const const auto minTop = *std::min_element(tops.begin(), tops.end()); const auto maxBottom = *std::max_element(bottoms.begin(), bottoms.end()); return maxBottom - minTop; -} \ No newline at end of file +} diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h index 4c2f383..24d6204 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h @@ -13,7 +13,7 @@ class Cursor; class MonitorManager { public: - explicit MonitorManager(); + explicit MonitorManager(LUID unityAdapterLuid_); ~MonitorManager(); void Reinitialize(); bool HasMonitorCountChanged() const; @@ -24,7 +24,7 @@ public: std::shared_ptr GetCursor() const; private: - void Initialize(); + void Initialize(); void Finalize(); // Setters from Unity @@ -40,10 +40,12 @@ public: int GetTotalHeight() const; private: + LUID unityAdapterLuid_; + int timeout_ = 10; bool enableTextureCopyFromGpuToCpu_ = false; std::vector> monitors_; std::shared_ptr cursor_ = std::make_shared(); int cursorMonitorId_ = -1; bool isReinitializationRequired_ = false; -}; \ No newline at end of file +}; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp index f686d25..c6fdf44 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp @@ -7,10 +7,12 @@ #include "IUnityInterface.h" #include "IUnityGraphics.h" +#include "include/IUnityGraphicsD3D11.h" #include "Common.h" #include "Debug.h" #include "Monitor.h" +#include "Duplicator.h" #include "Cursor.h" #include "MonitorManager.h" @@ -36,7 +38,25 @@ extern "C" if (g_unity && !g_manager) { Debug::Initialize(); - g_manager = std::make_unique(); + + auto device = g_unity->Get()->GetDevice(); + + Microsoft::WRL::ComPtr dxgiDevice; + if (FAILED(device->QueryInterface(IID_PPV_ARGS(&dxgiDevice)))){ + Debug::Error("fatal"); + return; + } + + Microsoft::WRL::ComPtr dxgiAdapter; + if (FAILED(dxgiDevice->GetAdapter(&dxgiAdapter))) { + Debug::Error("fatal"); + return; + } + + DXGI_ADAPTER_DESC desc; + dxgiAdapter->GetDesc(&desc); + + g_manager = std::make_unique(desc.AdapterLuid); } } @@ -87,7 +107,7 @@ extern "C" if (!g_manager) return; if (auto monitor = g_manager->GetMonitor(id)) { - monitor->Render(g_manager->GetTimeout()); + monitor->Render(); } } @@ -177,14 +197,14 @@ extern "C" } } - UNITY_INTERFACE_EXPORT MonitorState UNITY_INTERFACE_API GetState(int id) + UNITY_INTERFACE_EXPORT DuplicatorState UNITY_INTERFACE_API GetState(int id) { - if (!g_manager) return MonitorState::NotSet; + if (!g_manager) return DuplicatorState::NotSet; if (auto monitor = g_manager->GetMonitor(id)) { - return monitor->GetState(); + return monitor->GetDuplicatorState(); } - return MonitorState::NotSet; + return DuplicatorState::NotSet; } UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetName(int id, char* buf, int len) diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj b/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj index 63a01f2..687c7e8 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj @@ -140,6 +140,8 @@ + + @@ -148,6 +150,8 @@ + + diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj.filters b/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj.filters index 48179e2..e0646f0 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj.filters +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj.filters @@ -20,6 +20,8 @@ + + @@ -28,5 +30,7 @@ + + \ No newline at end of file diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset index 417940f..5bbdb35 100644 Binary files a/ProjectSettings/GraphicsSettings.asset and b/ProjectSettings/GraphicsSettings.asset differ diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index ae41cb6..66e05aa 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1 @@ -m_EditorVersion: 5.4.2f2 -m_StandardAssetsVersion: 0 +m_EditorVersion: 5.5.0f3