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_64/uDesktopDuplication.dll b/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll index 488f3e6..96f78f1 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 eac0169..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, } @@ -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 624bc8a..b3253b8 100644 --- a/Assets/uDesktopDuplication/Scripts/Manager.cs +++ b/Assets/uDesktopDuplication/Scripts/Manager.cs @@ -160,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/Duplicator.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.cpp new file mode 100644 index 0000000..852efc6 --- /dev/null +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.cpp @@ -0,0 +1,296 @@ +#pragma once + +#include "Duplicator.h" +#include "Monitor.h" +#include "Device.h" +#include "Common.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_; +} + + +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("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 false; + } + + ScopedReleaser releaser([this] + { + const auto hr = dupl_->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; + } + } + } + }); + + 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_ = Frame { copyTarget, frameInfo }; + } + + return true; +} \ 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..86673a2 --- /dev/null +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + + +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 Frame + { + Microsoft::WRL::ComPtr texture; + DXGI_OUTDUPL_FRAME_INFO info; + }; + + explicit Duplicator(Monitor* monitor); + ~Duplicator(); + void Start(); + void Stop(); + bool IsRunning() const; + bool IsError() const; + State GetState() const; + Microsoft::WRL::ComPtr GetDuplication(); + const Frame& GetFrame() const; + +private: + void InitializeDevice(); + void InitializeDuplication(); + void CheckUnityAdapter(); + bool Duplicate(); + + 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_; +}; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp index 99763e4..bdad7be 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp @@ -2,6 +2,7 @@ #include #include #include "Monitor.h" +#include "Duplicator.h" #include "Debug.h" #include "Cursor.h" #include "MonitorManager.h" @@ -11,45 +12,6 @@ using namespace Microsoft::WRL; -struct QueueItem -{ - ComPtr Texture; - DXGI_OUTDUPL_FRAME_INFO Info; - - QueueItem() - {} - - QueueItem(const ComPtr &texture - , const DXGI_OUTDUPL_FRAME_INFO &info - ) - : Texture(texture), Info(info) - {} -}; -class TextureQueue -{ - std::queue m_queue; - std::mutex m_mutex; - -public: - void Enqueue(const QueueItem &item) - { - std::lock_guard lk(m_mutex); - m_queue.push(item); - } - - QueueItem Dequeue() - { - std::lock_guard lk(m_mutex); - if (m_queue.empty()) { - return QueueItem(); - } - auto front = m_queue.front(); - m_queue.pop(); - return front; - } -}; - - Monitor::Monitor(int id) : id_(id) { @@ -59,17 +21,6 @@ Monitor::Monitor(int id) Monitor::~Monitor() { - m_stopLoop = true; - - if (deskDupl_) - { - deskDupl_->Release(); - deskDupl_ = nullptr; - } - - if (m_desktopDuplicationThread.joinable()) { - m_desktopDuplicationThread.join(); - } } @@ -78,14 +29,8 @@ void Monitor::Initialize( const ComPtr &output ) { - m_pIsolated = std::make_shared(); - m_textureQueue = std::make_shared(); - - if (FAILED(m_pIsolated->Create(adapter))) - { - Debug::Error("Monitor::Initialize() => IsolatedD3D11Device::Create() failed."); - return; - } + adapter_ = adapter; + output_ = output; if (FAILED(output->GetDesc(&outputDesc_))) { @@ -112,231 +57,21 @@ void Monitor::Initialize( // DPI is set as -1, so the application has to use the appropriate value. } - ComPtr output1; - if (FAILED(output.As(&output1))) { - return; - } - - // use self created device - auto hr = output1->DuplicateOutput(m_pIsolated->GetDevice().Get(), &deskDupl_); - switch (hr) - { - 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; - } - } - - // check adapter - DXGI_ADAPTER_DESC adapterDesc; - adapter->GetDesc(&adapterDesc); - const auto unityAdapterLuid = GetUnityAdapterLuid(); - const auto isUnityAdapter = - adapterDesc.AdapterLuid.HighPart == unityAdapterLuid.HighPart && - adapterDesc.AdapterLuid.LowPart == unityAdapterLuid.LowPart; - - // start desktop duplication thread - m_stopLoop = false; - if (isUnityAdapter) { - m_desktopDuplicationThread = std::thread(std::bind(&Monitor::DuplicateAndCopyLoop, this)); - } - else { - m_desktopDuplicationThread = std::thread(std::bind(&Monitor::DuplicateAndMapLoop, this)); - } + duplicator_ = std::make_shared(this); + if (duplicator_->GetState() == DuplicatorState::Ready) + { + duplicator_->Start(); + } } -void Monitor::Render(UINT timeout) +void Monitor::Render() { - if (!deskDupl_) return; + const auto frame = duplicator_->GetFrame(); // copy + const auto texture = frame.texture; + const auto frameInfo = frame.info; - HRESULT hr; - ComPtr resource; - DXGI_OUTDUPL_FRAME_INFO frameInfo; - - 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; - } - - ID3D11Texture2D* texture; - if (FAILED(resource.CopyTo(&texture))) - { - Debug::Error("Monitor::Render() => resource.As() failed."); - 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); - } - 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::CopyTextureFromThread() -{ - QueueItem item; - if (m_textureQueue) { - item=m_textureQueue->Dequeue(); - } - auto texture = item.Texture; - if (!texture) { - return; - } - auto &frameInfo = item.Info; + if (!texture) return; // Get texture if (unityTexture_) @@ -344,7 +79,7 @@ void Monitor::CopyTextureFromThread() D3D11_TEXTURE2D_DESC srcDesc, dstDesc; texture->GetDesc(&srcDesc); unityTexture_->GetDesc(&dstDesc); - if (srcDesc.Width != dstDesc.Width || + if (srcDesc.Width != dstDesc.Width || srcDesc.Height != dstDesc.Height) { Debug::Error("Monitor::Render() => Texture sizes are defferent."); @@ -353,8 +88,9 @@ void Monitor::CopyTextureFromThread() //Debug::Log(" => Try modifying width/height using reported value from DDA."); //width_ = srcDesc.Width; //height_ = srcDesc.Height; - state_ = MonitorState::TextureSizeInconsistent; + //state_ = MonitorState::TextureSizeInconsistent; //SendMessageToUnity(Message::TextureSizeChanged); + return; } else { @@ -385,109 +121,6 @@ void Monitor::CopyTextureFromThread() } -void Monitor::DuplicateAndCopyLoop() -{ - if (!deskDupl_) return; - - while (!m_stopLoop) - { - ComPtr resource; - DXGI_OUTDUPL_FRAME_INFO frameInfo; - - const auto hr = deskDupl_->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("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; - } - } - continue; - } - - ScopedReleaser releaser([this] - { - const auto 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; - } - } - } - }); - - ComPtr texture; - if (FAILED(resource.As(&texture))) { - return; - } - - // copy target - auto copyTarget = m_pIsolated->GetCompatibleSharedTexture(texture); - if (!copyTarget) { - return; - } - - // copy - ComPtr context; - m_pIsolated->GetDevice()->GetImmediateContext(&context); - context->CopyResource(copyTarget.Get(), texture.Get()); - - m_textureQueue->Enqueue(QueueItem(copyTarget, frameInfo)); - } -} - - -void Monitor::DuplicateAndMapLoop() -{ - // not implemented; -} - - void Monitor::UpdateCursor(const DXGI_OUTDUPL_FRAME_INFO& frameInfo) { auto cursor_ = GetMonitorManager()->GetCursor(); @@ -508,7 +141,7 @@ void Monitor::UpdateMoveRects(const DXGI_OUTDUPL_FRAME_INFO& frameInfo) { moveRectSize_ = metaData_.Size(); - const auto hr = deskDupl_->GetFrameMoveRects( + const auto hr = GetDeskDupl()->GetFrameMoveRects( moveRectSize_, metaData_.As(), &moveRectSize_); @@ -552,7 +185,7 @@ void Monitor::UpdateDirtyRects(const DXGI_OUTDUPL_FRAME_INFO& frameInfo) { dirtyRectSize_ = metaData_.Size() - moveRectSize_; - const auto hr = deskDupl_->GetFrameDirtyRects( + const auto hr = GetDeskDupl()->GetFrameDirtyRects( dirtyRectSize_, metaData_.As(moveRectSize_ /* offset */), &dirtyRectSize_); @@ -598,9 +231,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(); } @@ -616,9 +261,9 @@ ID3D11Texture2D* Monitor::GetUnityTexture() const } -IDXGIOutputDuplication* Monitor::GetDeskDupl() +ComPtr Monitor::GetDeskDupl() { - return deskDupl_; + return duplicator_->GetDuplication(); } diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h index f46ee56..5346f0c 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h @@ -8,38 +8,27 @@ #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 { class ThreadedDesktopDuplicator *m_threaded = nullptr; public: - using State = MonitorState; - explicit Monitor(int id); ~Monitor(); void Initialize( const Microsoft::WRL::ComPtr &adapter, const Microsoft::WRL::ComPtr &output); - void CopyTextureFromThread(); - void Render(UINT timeout = 0); + 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; @@ -54,7 +43,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; @@ -63,14 +52,6 @@ public: bool UseGetPixels() const; bool GetPixels(BYTE* output, int x, int y, int width, int height); -private: - void DuplicateAndCopyLoop(); - void DuplicateAndMapLoop(); - std::shared_ptr m_pIsolated; - std::thread m_desktopDuplicationThread; - volatile bool m_stopLoop = false; - std::shared_ptr m_textureQueue; - private: void UpdateCursor(const DXGI_OUTDUPL_FRAME_INFO& frameInfo); void UpdateMetadata(const DXGI_OUTDUPL_FRAME_INFO& frameInfo); @@ -79,18 +60,25 @@ private: 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_; + + Buffer metaData_; UINT moveRectSize_ = 0; - UINT dirtyRectSize_ = 0;; + UINT dirtyRectSize_ = 0; }; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp index 3a0e8ee..c6fdf44 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp @@ -12,6 +12,7 @@ #include "Common.h" #include "Debug.h" #include "Monitor.h" +#include "Duplicator.h" #include "Cursor.h" #include "MonitorManager.h" @@ -106,7 +107,7 @@ extern "C" if (!g_manager) return; if (auto monitor = g_manager->GetMonitor(id)) { - monitor->CopyTextureFromThread(); + monitor->Render(); } } @@ -196,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 df33c95..75c6e21 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj @@ -142,6 +142,7 @@ copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetName).pdb" "$(Soluti + @@ -151,6 +152,7 @@ copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetName).pdb" "$(Soluti + diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj.filters b/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj.filters index eb8cef5..e0646f0 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj.filters +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/uDesktopDuplication.vcxproj.filters @@ -21,6 +21,7 @@ + @@ -30,5 +31,6 @@ + \ No newline at end of file