diff --git a/Assets/uDesktopDuplication/Plugins/uDesktopDuplication.dll b/Assets/uDesktopDuplication/Plugins/uDesktopDuplication.dll index 5964779..2da96d2 100644 Binary files a/Assets/uDesktopDuplication/Plugins/uDesktopDuplication.dll and b/Assets/uDesktopDuplication/Plugins/uDesktopDuplication.dll differ diff --git a/Assets/uDesktopDuplication/Scripts/Lib.cs b/Assets/uDesktopDuplication/Scripts/Lib.cs index 2445604..21ef19d 100644 --- a/Assets/uDesktopDuplication/Scripts/Lib.cs +++ b/Assets/uDesktopDuplication/Scripts/Lib.cs @@ -5,6 +5,12 @@ using System.Runtime.InteropServices; namespace uDesktopDuplication { +public enum Message +{ + None = -1, + Reinitialized = 0, +} + public enum CursorShapeType { MonoChrome = 1, @@ -14,6 +20,16 @@ public enum CursorShapeType public static class Lib { + public delegate void MessageHandler(Message message); + + [DllImport("uDesktopDuplication")] + public static extern void Initialize(); + [DllImport("uDesktopDuplication")] + public static extern void Finalize(); + [DllImport("uDesktopDuplication")] + public static extern void Update(); + [DllImport("uDesktopDuplication")] + public static extern Message PopMessage(); [DllImport("uDesktopDuplication")] public static extern int GetMonitorCount(); [DllImport("uDesktopDuplication")] diff --git a/Assets/uDesktopDuplication/Scripts/Manager.cs b/Assets/uDesktopDuplication/Scripts/Manager.cs index 0220dde..968ce67 100644 --- a/Assets/uDesktopDuplication/Scripts/Manager.cs +++ b/Assets/uDesktopDuplication/Scripts/Manager.cs @@ -26,7 +26,7 @@ public class Manager : MonoBehaviour static public int monitorCount { - get { return instance.monitors_.Count; } + get { return Lib.GetMonitorCount(); } } static public Monitor primary @@ -41,19 +41,25 @@ public class Manager : MonoBehaviour int timeout = 0; private Coroutine renderCoroutine_ = null; + Message message_ = Message.None; void Awake() { + Lib.Initialize(); + if (instance_ != null) return; instance_ = this; - for (int i = 0; i < Lib.GetMonitorCount(); ++i) { - monitors.Add(new Monitor(i)); - } + CreateMonitors(); Lib.SetTimeout(timeout); } + void OnApplicationQuit() + { + Lib.Finalize(); + } + void OnEnable() { renderCoroutine_ = StartCoroutine(OnRender()); @@ -67,6 +73,26 @@ public class Manager : MonoBehaviour } } + void Update() + { + Lib.Update(); + + var message = Lib.PopMessage(); + while (message != Message.None) { + switch (message) { + case Message.Reinitialized: + Debug.Log("Reinitialize"); + Reinitialize(); + break; + default: + break; + } + message = Lib.PopMessage(); + } + + message_ = Message.None; + } + IEnumerator OnRender() { for (;;) { @@ -80,6 +106,28 @@ public class Manager : MonoBehaviour } } } + + void CreateMonitors() + { + for (int i = 0; i < monitorCount; ++i) { + monitors.Add(new Monitor(i)); + } + } + + void OnMessage(Message message) + { + message_ = message; + } + + void Reinitialize() + { + for (int i = 0; i < monitorCount; ++i) { + if (i == monitors.Count) { + monitors.Add(new Monitor(i)); + } + monitors[i].Reinitialize(); + } + } } } \ No newline at end of file diff --git a/Assets/uDesktopDuplication/Scripts/Monitor.cs b/Assets/uDesktopDuplication/Scripts/Monitor.cs index f886f6b..9ee82d4 100644 --- a/Assets/uDesktopDuplication/Scripts/Monitor.cs +++ b/Assets/uDesktopDuplication/Scripts/Monitor.cs @@ -16,6 +16,11 @@ public class Monitor private set; } + public bool exists + { + get { return id < Manager.monitorCount; } + } + public string name { get { return Lib.GetName(id); } @@ -93,10 +98,7 @@ public class Monitor get { if (texture_ == null) { - var w = isHorizontal ? width : height; - var h = isHorizontal ? height : width; - texture_ = new Texture2D(w, h, TextureFormat.BGRA32, false); - Lib.SetTexturePtr(id, texture_.GetNativeTexturePtr()); + CreateTexture(); } return texture_; } @@ -104,6 +106,7 @@ public class Monitor public void Render() { + Lib.SetTexturePtr(id, texture_.GetNativeTexturePtr()); GL.IssuePluginEvent(Lib.GetRenderEventFunc(), id); } @@ -111,6 +114,31 @@ public class Monitor { Lib.UpdateCursorTexture(id, ptr); } + + void CreateTexture() + { + var w = isHorizontal ? width : height; + var h = isHorizontal ? height : width; + bool shouldCreate = true; + + if (texture_) { + if (texture_.width != w || texture_.height != h) { + if (texture_) Object.DestroyImmediate(texture_); + shouldCreate = true; + } else { + shouldCreate = false; + } + } + + if (shouldCreate) { + texture_ = new Texture2D(w, h, TextureFormat.BGRA32, false); + } + } + + public void Reinitialize() + { + CreateTexture(); + } } } \ No newline at end of file diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Common.h b/Plugins/uDesktopDuplication/uDesktopDuplication/Common.h index ade96bf..5367cbe 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Common.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Common.h @@ -5,4 +5,11 @@ class MonitorManager; IUnityInterfaces* GetUnity(); ID3D11Device* GetDevice(); -const std::unique_ptr& GetMonitorManager(); \ No newline at end of file +const std::unique_ptr& GetMonitorManager(); + +enum class Message +{ + None = -1, + Reinitialized = 0, +}; +void SendMessageToUnity(Message message); \ No newline at end of file diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp index 5883d6b..bff7928 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp @@ -8,27 +8,64 @@ Monitor::Monitor(int id, IDXGIOutput* output) : id_(id) { - // MEMO: 'output' will be released automatically after this ctor. output->GetDesc(&outputDesc_); monitorInfo_.cbSize = sizeof(MONITORINFOEX); GetMonitorInfo(outputDesc_.Monitor, &monitorInfo_); auto output1 = reinterpret_cast(output); - output1->DuplicateOutput(GetDevice(), &deskDupl_); + const auto hr = output1->DuplicateOutput(GetDevice(), &deskDupl_); + + auto error = 0; + + // TODO: error check + switch (hr) + { + case S_OK: + break; + case E_INVALIDARG: + error = 1; + break; + case E_ACCESSDENIED: + error = 2; + // For example, when the user presses Ctrl + Alt + Delete and the screen + // switches to admin screen, this error occurs. + break; + case DXGI_ERROR_UNSUPPORTED: + error = 3; + break; + case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: + error = 4; + // Other application use Desktop Duplication API... + break; + case DXGI_ERROR_SESSION_DISCONNECTED: + error = 5; + break; + } cursor_ = std::make_unique(this); + + // MEMO: 'output' will be released automatically after this ctor. } Monitor::~Monitor() { - deskDupl_->Release(); + if (deskDupl_ != nullptr) + { + deskDupl_->Release(); + } } HRESULT Monitor::Render(UINT timeout) { - if (deskDupl_ == nullptr || unityTexture_ == nullptr) return 0; + if (deskDupl_ == nullptr) + { + GetMonitorManager()->RequireReinitilization(); + return 0; + } + + if (unityTexture_ == nullptr) return 0; IDXGIResource* resource = nullptr; DXGI_OUTDUPL_FRAME_INFO frameInfo; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp index 8f9b2dc..d4a4f5a 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp @@ -6,6 +6,7 @@ #include "IUnityInterface.h" #include "IUnityGraphicsD3D11.h" +#include "Common.h" #include "Monitor.h" #include "Cursor.h" #include "MonitorManager.h" @@ -56,6 +57,13 @@ void MonitorManager::Finalize() } +void MonitorManager::Reinitialize() +{ + Initialize(); + SendMessageToUnity(Message::Reinitialized); +} + + std::shared_ptr MonitorManager::GetMonitor(int id) const { if (id >= 0 && id < monitors_.size()) @@ -66,6 +74,16 @@ std::shared_ptr MonitorManager::GetMonitor(int id) const } +void MonitorManager::Update() +{ + if (isReinitializationRequired_) + { + Reinitialize(); + isReinitializationRequired_ = false; + } +} + + void MonitorManager::OnRender(int id) { if (auto monitor = GetMonitor(id)) @@ -75,7 +93,7 @@ void MonitorManager::OnRender(int id) const auto hr = monitor->Render(timeout_); if (hr == DXGI_ERROR_ACCESS_LOST) { - Initialize(); + isReinitializationRequired_ = true; } } } diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h index 08b9e9b..efa03ab 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h @@ -14,6 +14,8 @@ public: explicit MonitorManager(); ~MonitorManager(); + void RequireReinitilization() { isReinitializationRequired_ = true; } + void SetCursorMonitorId(int id) { cursorMonitorId_ = id; } int GetCursorMonitorId() const { return cursorMonitorId_; } std::shared_ptr GetMonitor(int id) const; @@ -21,10 +23,12 @@ public: private: void Initialize(); void Finalize(); + void Reinitialize(); // Setters from Unity public: void OnRender(int id); + void Update(); void UpdateCursorTexture(int id, ID3D11Texture2D* ptr); void SetTimeout(int timeout); void SetTexturePtr(int id, void* texture); @@ -49,4 +53,5 @@ private: std::vector> monitors_; std::shared_ptr cursor_; 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 03f5d78..ee035b1 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "IUnityInterface.h" #include "IUnityGraphics.h" @@ -18,6 +19,7 @@ namespace { IUnityInterfaces* g_unity = nullptr; std::unique_ptr g_manager; + std::queue g_messages; } @@ -32,27 +34,49 @@ ID3D11Device* GetDevice() return GetUnity()->Get()->GetDevice(); } + const std::unique_ptr& GetMonitorManager() { return g_manager; } +void SendMessageToUnity(Message message) +{ + g_messages.push(message); +} + + extern "C" { + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Initialize() + { + if (g_unity && !g_manager) + { + g_manager = std::make_unique(); + } + } + + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Finalize() + { + g_manager.reset(); + } + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces) { g_unity = unityInterfaces; - g_manager = std::make_unique(); + Initialize(); } UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginUnload() { - g_manager.reset(); + g_unity = nullptr; + Finalize(); } void UNITY_INTERFACE_API OnRenderEvent(int id) { + if (!g_manager) return; g_manager->OnRender(id); } @@ -61,78 +85,108 @@ extern "C" return OnRenderEvent; } + UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Update() + { + if (!g_manager) return; + g_manager->Update(); + } + + UNITY_INTERFACE_EXPORT Message PopMessage() + { + if (g_messages.empty()) return Message::None; + + const auto message = g_messages.front(); + g_messages.pop(); + return message; + } + UNITY_INTERFACE_EXPORT size_t UNITY_INTERFACE_API GetMonitorCount() { + if (!g_manager) return 0; return g_manager->GetMonitorCount(); } UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetTimeout(int timeout) { + if (!g_manager) return; g_manager->SetTimeout(timeout); } UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetName(int id, char* buf, int len) { + if (!g_manager) return; g_manager->GetName(id, buf, len); } UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API IsPrimary(int id) { + if (!g_manager) return false; return g_manager->IsPrimary(id); } UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetWidth(int id) { + if (!g_manager) return -1; return g_manager->GetWidth(id); } UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetHeight(int id) { + if (!g_manager) return -1; return g_manager->GetHeight(id); } - UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API IsCursorVisible(int id) + UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API IsCursorVisible(int id) { + if (!g_manager) return false; return g_manager->IsCursorVisible(id); } UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorX(int id) { + if (!g_manager) return -1; return g_manager->GetCursorX(id); } UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorY(int id) { + if (!g_manager) return -1; return g_manager->GetCursorY(id); } UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapeWidth(int id) { + if (!g_manager) return -1; return g_manager->GetCursorShapeWidth(id); } UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapeHeight(int id) { + if (!g_manager) return -1; return g_manager->GetCursorShapeHeight(id); } UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapePitch(int id) { + if (!g_manager) return -1; return g_manager->GetCursorShapePitch(id); } UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapeType(int id) { + if (!g_manager) return -1; return g_manager->GetCursorShapeType(id); } UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UpdateCursorTexture(int id, ID3D11Texture2D* ptr) { + if (!g_manager) return; g_manager->UpdateCursorTexture(id, ptr); } UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetTexturePtr(int id, void* texture) { + if (!g_manager) return; g_manager->SetTexturePtr(id, texture); } } \ No newline at end of file