From e83f43d7fd3aae79522cb13cb158725243cf6319 Mon Sep 17 00:00:00 2001 From: hecomi Date: Tue, 15 Nov 2016 21:50:35 +0900 Subject: [PATCH] fix crash bugs and memory leaks. --- .../Examples/Scripts/Loupe.cs | 2 +- .../Scripts/MultipleMonitorCreator.cs | 2 +- .../Plugins/x86_64/uDesktopDuplication.dll | Bin 69120 -> 69632 bytes Assets/uDesktopDuplication/Scripts/Lib.cs | 2 + Assets/uDesktopDuplication/Scripts/Manager.cs | 74 +++++++++++------- Assets/uDesktopDuplication/Scripts/Monitor.cs | 55 ++++++++----- Assets/uDesktopDuplication/Scripts/Texture.cs | 5 ++ .../uDesktopDuplication/Cursor.cpp | 29 ++++--- .../uDesktopDuplication/Monitor.cpp | 6 +- .../uDesktopDuplication/MonitorManager.cpp | 27 +++---- .../uDesktopDuplication/MonitorManager.h | 2 +- .../uDesktopDuplication/main.cpp | 6 ++ 12 files changed, 129 insertions(+), 81 deletions(-) diff --git a/Assets/uDesktopDuplication/Examples/Scripts/Loupe.cs b/Assets/uDesktopDuplication/Examples/Scripts/Loupe.cs index 5b4eac8..741cfa9 100644 --- a/Assets/uDesktopDuplication/Examples/Scripts/Loupe.cs +++ b/Assets/uDesktopDuplication/Examples/Scripts/Loupe.cs @@ -21,7 +21,7 @@ public class Loupe : MonoBehaviour // To get other monitor textures, set dirty flag. foreach (var target in uDesktopDuplication.Manager.monitors) { - target.CreateTexture(); + target.CreateTextureIfNeeded(); target.shouldBeUpdated = true; } diff --git a/Assets/uDesktopDuplication/Examples/Scripts/MultipleMonitorCreator.cs b/Assets/uDesktopDuplication/Examples/Scripts/MultipleMonitorCreator.cs index 4f0db6b..43364c4 100644 --- a/Assets/uDesktopDuplication/Examples/Scripts/MultipleMonitorCreator.cs +++ b/Assets/uDesktopDuplication/Examples/Scripts/MultipleMonitorCreator.cs @@ -112,7 +112,7 @@ public class MultipleMonitorCreator : MonoBehaviour go.name = "Monitor " + i; // Expand AABB - var mesh = go.GetComponent().mesh; // clone + var mesh = go.GetComponent().sharedMesh; var aabbScale = mesh.bounds.size; aabbScale.y = Mathf.Max(aabbScale.y, aabbScale.x); aabbScale.z = Mathf.Max(aabbScale.z, aabbScale.x); diff --git a/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll b/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll index 3e587b8c5dfb505987d1c674a8b7a4f3ed913699..1a03337f5c8400f9db464d187f7e9454e232d170 100644 GIT binary patch delta 21094 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 ZSg{`7adz|{VAJlB-3LG0@dQ7S|35U`pp5_k diff --git a/Assets/uDesktopDuplication/Scripts/Lib.cs b/Assets/uDesktopDuplication/Scripts/Lib.cs index a6ef6e6..fb17848 100644 --- a/Assets/uDesktopDuplication/Scripts/Lib.cs +++ b/Assets/uDesktopDuplication/Scripts/Lib.cs @@ -78,6 +78,8 @@ public static class Lib [DllImport("uDesktopDuplication")] public static extern int GetMonitorCount(); [DllImport("uDesktopDuplication")] + public static extern bool HasMonitorCountChanged(); + [DllImport("uDesktopDuplication")] public static extern int GetCursorMonitorId(); [DllImport("uDesktopDuplication")] public static extern int GetTotalWidth(); diff --git a/Assets/uDesktopDuplication/Scripts/Manager.cs b/Assets/uDesktopDuplication/Scripts/Manager.cs index d350f54..c0ff113 100644 --- a/Assets/uDesktopDuplication/Scripts/Manager.cs +++ b/Assets/uDesktopDuplication/Scripts/Manager.cs @@ -13,6 +13,19 @@ public class Manager : MonoBehaviour get { return CreateInstance(); } } + public static Manager CreateInstance() + { + if (instance_) { + return instance_; + } + + var manager = FindObjectOfType(); + if (manager) return manager; + + var go = new GameObject("uDesktopDuplicationManager"); + return go.AddComponent(); + } + private List monitors_ = new List(); static public List monitors { @@ -48,22 +61,6 @@ public class Manager : MonoBehaviour public delegate void ReinitializeHandler(); public static event ReinitializeHandler onReinitialized; - public static Manager CreateInstance() - { - if (instance_) { - return instance_; - } - - var manager = FindObjectOfType(); - if (manager) { - manager.Awake(); - return manager; - } - - var go = new GameObject("uDesktopDuplicationManager"); - return go.AddComponent(); - } - public static Monitor GetMonitor(int id) { if (id < 0 || id >= Manager.monitors.Count) { @@ -77,18 +74,21 @@ public class Manager : MonoBehaviour { Lib.SetDebugMode(debugMode); Lib.InitializeUDD(); + Lib.SetTimeout(desktopDuplicationApiTimeout); - if (instance_ != null) return; + if (instance_ != null) { + Destroy(gameObject); + return; + } instance_ = this; CreateMonitors(); - - Lib.SetTimeout(desktopDuplicationApiTimeout); } void OnApplicationQuit() { Lib.FinalizeUDD(); + DestroyMonitors(); } void OnEnable() @@ -124,20 +124,30 @@ public class Manager : MonoBehaviour void ReinitializeIfNeeded() { + bool reinitializeNeeded = false; + for (int i = 0; i < monitors.Count; ++i) { var monitor = monitors[i]; - if (monitor.state == MonitorState.NotSet || + if ( + monitor.state == MonitorState.NotSet || monitor.state == MonitorState.AccessLost || monitor.state == MonitorState.AccessDenied || - monitor.state == MonitorState.SessionDisconnected) { - if (!shouldReinitialize_) { - shouldReinitialize_ = true; - reinitializationTimer_ = 0f; - break; - } + monitor.state == MonitorState.SessionDisconnected + ) { + reinitializeNeeded = true; + break; } } + if (Lib.HasMonitorCountChanged()) { + reinitializeNeeded = true; + } + + if (!shouldReinitialize_ && reinitializeNeeded) { + shouldReinitialize_ = true; + reinitializationTimer_ = 0f; + } + if (shouldReinitialize_) { if (reinitializationTimer_ > retryReinitializationDuration) { Reinitialize(); @@ -182,12 +192,20 @@ public class Manager : MonoBehaviour void CreateMonitors() { - monitors.Clear(); + DestroyMonitors(); for (int i = 0; i < monitorCount; ++i) { monitors.Add(new Monitor(i)); } } + void DestroyMonitors() + { + for (int i = 0; i < monitors.Count; ++i) { + monitors[i].DestroyTexture(); + } + monitors.Clear(); + } + void ReinitializeMonitors() { for (int i = 0; i < monitorCount; ++i) { @@ -202,7 +220,7 @@ public class Manager : MonoBehaviour void RecreateTextures() { for (int i = 0; i < monitorCount; ++i) { - monitors[i].CreateTexture(); + monitors[i].CreateTextureIfNeeded(); } } } diff --git a/Assets/uDesktopDuplication/Scripts/Monitor.cs b/Assets/uDesktopDuplication/Scripts/Monitor.cs index 04e8a07..4811bf7 100644 --- a/Assets/uDesktopDuplication/Scripts/Monitor.cs +++ b/Assets/uDesktopDuplication/Scripts/Monitor.cs @@ -38,6 +38,11 @@ public class Monitor } } + ~Monitor() + { + DestroyTexture(); + } + public int id { get; @@ -203,21 +208,24 @@ public class Monitor set; } - private static Texture2D errorTexture; + private static Texture2D errorTexture_; private static readonly string errorTexturePath = "uDesktopDuplication/Textures/NotAvailable"; + private Texture2D errorTexture + { + get + { + return errorTexture_ ?? + (errorTexture_ = Resources.Load(errorTexturePath)); + } + } private Texture2D texture_; public Texture2D texture { get { - if (!available) { - return errorTexture ?? - (errorTexture = Resources.Load(errorTexturePath)); - } - if (texture_ == null) { - CreateTexture(); - } + if (!available) return errorTexture; + if (texture_ == null) CreateTextureIfNeeded(); return texture_; } } @@ -235,7 +243,7 @@ public class Monitor Lib.GetCursorTexture(id, ptr); } - public void CreateTexture() + public void CreateTextureIfNeeded() { if (!available) return; @@ -243,13 +251,8 @@ public class Monitor var h = isHorizontal ? height : width; bool shouldCreate = true; - if (texture_) { - if (texture_.width != w || texture_.height != h) { - Object.DestroyImmediate(texture_); - texture_ = null; - } else { - shouldCreate = false; - } + if (texture_ && texture_.width == w && texture_.height == h) { + shouldCreate = false; } if (w <= 0 || h <= 0) { @@ -257,13 +260,29 @@ public class Monitor } if (shouldCreate) { - texture_ = new Texture2D(w, h, TextureFormat.BGRA32, false); + CreateTexture(); + } + } + + void CreateTexture() + { + DestroyTexture(); + var w = isHorizontal ? width : height; + var h = isHorizontal ? height : width; + texture_ = new Texture2D(w, h, TextureFormat.BGRA32, false); + } + + public void DestroyTexture() + { + if (texture_) { + Object.Destroy(texture_); + texture_ = null; } } public void Reinitialize() { - CreateTexture(); + CreateTextureIfNeeded(); } } diff --git a/Assets/uDesktopDuplication/Scripts/Texture.cs b/Assets/uDesktopDuplication/Scripts/Texture.cs index dfb3ac8..7860bec 100644 --- a/Assets/uDesktopDuplication/Scripts/Texture.cs +++ b/Assets/uDesktopDuplication/Scripts/Texture.cs @@ -118,6 +118,11 @@ public class Texture : MonoBehaviour } } + void OnDisable() + { + Destroy(material); + } + void Update() { monitor.shouldBeUpdated = true; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.cpp index 5c79d00..94b73d2 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.cpp @@ -53,16 +53,21 @@ void Cursor::UpdateBuffer(const DXGI_OUTDUPL_FRAME_INFO& frameInfo) apiBufferSize_ = frameInfo.PointerShapeBufferSize; apiBuffer_ = std::make_unique(apiBufferSize_); } - if (!apiBuffer_) return; + + if (!apiBuffer_) + { + return; + } // Get mouse pointer information UINT bufferSize; DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo; const auto hr = monitor_->GetDeskDupl()->GetFramePointerShape( apiBufferSize_, - reinterpret_cast(apiBuffer_.get()), + apiBuffer_.get(), &bufferSize, &shapeInfo); + if (FAILED(hr)) { Debug::Error("Cursor::UpdateBuffer() => GetFramePointerShape() failed."); @@ -149,13 +154,12 @@ void Cursor::UpdateTexture() desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.MiscFlags = 0; - ID3D11Texture2D* texture; + ComPtr texture; if (FAILED(GetDevice()->CreateTexture2D(&desc, nullptr, &texture))) { Debug::Error("Cursor::UpdateTexture() => GetDevice()->CreateTexture2D() failed."); return; } - const auto textureReleaser = MakeUniqueWithReleaser(texture); D3D11_BOX box; box.front = 0; @@ -171,18 +175,18 @@ void Cursor::UpdateTexture() return; } - ID3D11DeviceContext* context; - GetDevice()->GetImmediateContext(&context); - context->CopySubresourceRegion(texture, 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box); - context->Release(); + { + ComPtr context; + GetDevice()->GetImmediateContext(&context); + context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box); + } - IDXGISurface* surface; - if (FAILED(texture->QueryInterface(&surface))) + ComPtr surface; + if (FAILED(texture.As(&surface))) { Debug::Error("Cursor::UpdateTexture() => texture->QueryInterface() failed."); return; } - const auto surfaceReleaser = MakeUniqueWithReleaser(surface); DXGI_MAPPED_RECT mappedSurface; if (FAILED(surface->Map(&mappedSurface, DXGI_MAP_READ))) @@ -282,10 +286,9 @@ void Cursor::GetTexture(ID3D11Texture2D* texture) return; } - ID3D11DeviceContext* context; + ComPtr context; GetDevice()->GetImmediateContext(&context); context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_.get(), GetWidth() * 4, 0); - context->Release(); } diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp index 93c51aa..7b4e7d0 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp @@ -21,6 +21,7 @@ Monitor::~Monitor() if (deskDupl_) { deskDupl_->Release(); + deskDupl_ = nullptr; } } @@ -113,7 +114,7 @@ void Monitor::Render(UINT timeout) { if (!deskDupl_) return; - IDXGIResource* resource; + ComPtr resource; DXGI_OUTDUPL_FRAME_INFO frameInfo; const auto hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource); @@ -181,10 +182,9 @@ void Monitor::Render(UINT timeout) } else { - ID3D11DeviceContext* context; + ComPtr context; GetDevice()->GetImmediateContext(&context); context->CopyResource(unityTexture_, texture); - context->Release(); } } diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp index 729b33b..faa12a9 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.cpp @@ -33,11 +33,8 @@ void MonitorManager::Initialize() { Finalize(); - ComPtr factory; - ComPtr adapter; - ComPtr output; - // Get factory + ComPtr factory; if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&factory)))) { Debug::Error("MonitorManager::Initialize() => CreateDXGIFactory1() failed."); @@ -46,9 +43,11 @@ void MonitorManager::Initialize() // Check all display adapters int id = 0; + ComPtr adapter; for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i) { // Search the main monitor from all outputs + ComPtr output; for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j) { auto monitor = std::make_shared(id++); @@ -79,31 +78,27 @@ void MonitorManager::Reinitialize() } -void MonitorManager::CheckMonitorNumbers() +bool MonitorManager::HasMonitorCountChanged() const { ComPtr factory; - ComPtr adapter; - ComPtr output; - if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&factory)))) { - Debug::Error("MonitorManager::CheckMonitorNumbers() => CreateDXGIFactory1() failed."); - return; + Debug::Error("MonitorManager::CheckMonitorConnection() => CreateDXGIFactory1() failed."); + return false; } int id = 0; + ComPtr adapter; for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i) { + ComPtr output; for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j) { id++; } } - if (GetMonitorCount() != id) - { - RequireReinitilization(); - } + return monitors_.size() != id; } @@ -119,8 +114,6 @@ std::shared_ptr MonitorManager::GetMonitor(int id) const void MonitorManager::Update() { - CheckMonitorNumbers(); - if (isReinitializationRequired_) { Reinitialize(); @@ -146,6 +139,7 @@ int MonitorManager::GetMonitorCount() const return static_cast(monitors_.size()); } + int MonitorManager::GetTotalWidth() const { std::vector lefts, rights; @@ -159,6 +153,7 @@ int MonitorManager::GetTotalWidth() const return maxRight - minLeft; } + int MonitorManager::GetTotalHeight() const { std::vector tops, bottoms; diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h index e4bc07c..34692ee 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/MonitorManager.h @@ -16,7 +16,7 @@ public: explicit MonitorManager(); ~MonitorManager(); void Reinitialize(); - void CheckMonitorNumbers(); + bool HasMonitorCountChanged() const; void RequireReinitilization(); void SetCursorMonitorId(int id) { cursorMonitorId_ = id; } int GetCursorMonitorId() const { return cursorMonitorId_; } diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp index a6ee4fb..7d391df 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp @@ -115,6 +115,12 @@ extern "C" return g_manager->GetMonitorCount(); } + UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API HasMonitorCountChanged() + { + if (!g_manager) return false; + return g_manager->HasMonitorCountChanged(); + } + UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorMonitorId() { if (!g_manager) return -1;