fix crash bugs and memory leaks.

This commit is contained in:
hecomi
2016-11-15 21:50:35 +09:00
parent 58e14d76d8
commit e83f43d7fd
12 changed files with 129 additions and 81 deletions
@@ -21,7 +21,7 @@ public class Loupe : MonoBehaviour
// To get other monitor textures, set dirty flag. // To get other monitor textures, set dirty flag.
foreach (var target in uDesktopDuplication.Manager.monitors) { foreach (var target in uDesktopDuplication.Manager.monitors) {
target.CreateTexture(); target.CreateTextureIfNeeded();
target.shouldBeUpdated = true; target.shouldBeUpdated = true;
} }
@@ -112,7 +112,7 @@ public class MultipleMonitorCreator : MonoBehaviour
go.name = "Monitor " + i; go.name = "Monitor " + i;
// Expand AABB // Expand AABB
var mesh = go.GetComponent<MeshFilter>().mesh; // clone var mesh = go.GetComponent<MeshFilter>().sharedMesh;
var aabbScale = mesh.bounds.size; var aabbScale = mesh.bounds.size;
aabbScale.y = Mathf.Max(aabbScale.y, aabbScale.x); aabbScale.y = Mathf.Max(aabbScale.y, aabbScale.x);
aabbScale.z = Mathf.Max(aabbScale.z, aabbScale.x); aabbScale.z = Mathf.Max(aabbScale.z, aabbScale.x);
@@ -78,6 +78,8 @@ public static class Lib
[DllImport("uDesktopDuplication")] [DllImport("uDesktopDuplication")]
public static extern int GetMonitorCount(); public static extern int GetMonitorCount();
[DllImport("uDesktopDuplication")] [DllImport("uDesktopDuplication")]
public static extern bool HasMonitorCountChanged();
[DllImport("uDesktopDuplication")]
public static extern int GetCursorMonitorId(); public static extern int GetCursorMonitorId();
[DllImport("uDesktopDuplication")] [DllImport("uDesktopDuplication")]
public static extern int GetTotalWidth(); public static extern int GetTotalWidth();
+46 -28
View File
@@ -13,6 +13,19 @@ public class Manager : MonoBehaviour
get { return CreateInstance(); } get { return CreateInstance(); }
} }
public static Manager CreateInstance()
{
if (instance_) {
return instance_;
}
var manager = FindObjectOfType<Manager>();
if (manager) return manager;
var go = new GameObject("uDesktopDuplicationManager");
return go.AddComponent<Manager>();
}
private List<Monitor> monitors_ = new List<Monitor>(); private List<Monitor> monitors_ = new List<Monitor>();
static public List<Monitor> monitors static public List<Monitor> monitors
{ {
@@ -48,22 +61,6 @@ public class Manager : MonoBehaviour
public delegate void ReinitializeHandler(); public delegate void ReinitializeHandler();
public static event ReinitializeHandler onReinitialized; public static event ReinitializeHandler onReinitialized;
public static Manager CreateInstance()
{
if (instance_) {
return instance_;
}
var manager = FindObjectOfType<Manager>();
if (manager) {
manager.Awake();
return manager;
}
var go = new GameObject("uDesktopDuplicationManager");
return go.AddComponent<Manager>();
}
public static Monitor GetMonitor(int id) public static Monitor GetMonitor(int id)
{ {
if (id < 0 || id >= Manager.monitors.Count) { if (id < 0 || id >= Manager.monitors.Count) {
@@ -77,18 +74,21 @@ public class Manager : MonoBehaviour
{ {
Lib.SetDebugMode(debugMode); Lib.SetDebugMode(debugMode);
Lib.InitializeUDD(); Lib.InitializeUDD();
Lib.SetTimeout(desktopDuplicationApiTimeout);
if (instance_ != null) return; if (instance_ != null) {
Destroy(gameObject);
return;
}
instance_ = this; instance_ = this;
CreateMonitors(); CreateMonitors();
Lib.SetTimeout(desktopDuplicationApiTimeout);
} }
void OnApplicationQuit() void OnApplicationQuit()
{ {
Lib.FinalizeUDD(); Lib.FinalizeUDD();
DestroyMonitors();
} }
void OnEnable() void OnEnable()
@@ -124,20 +124,30 @@ public class Manager : MonoBehaviour
void ReinitializeIfNeeded() void ReinitializeIfNeeded()
{ {
bool reinitializeNeeded = false;
for (int i = 0; i < monitors.Count; ++i) { for (int i = 0; i < monitors.Count; ++i) {
var monitor = monitors[i]; var monitor = monitors[i];
if (monitor.state == MonitorState.NotSet || if (
monitor.state == MonitorState.NotSet ||
monitor.state == MonitorState.AccessLost || monitor.state == MonitorState.AccessLost ||
monitor.state == MonitorState.AccessDenied || monitor.state == MonitorState.AccessDenied ||
monitor.state == MonitorState.SessionDisconnected) { monitor.state == MonitorState.SessionDisconnected
if (!shouldReinitialize_) { ) {
shouldReinitialize_ = true; reinitializeNeeded = true;
reinitializationTimer_ = 0f; break;
break;
}
} }
} }
if (Lib.HasMonitorCountChanged()) {
reinitializeNeeded = true;
}
if (!shouldReinitialize_ && reinitializeNeeded) {
shouldReinitialize_ = true;
reinitializationTimer_ = 0f;
}
if (shouldReinitialize_) { if (shouldReinitialize_) {
if (reinitializationTimer_ > retryReinitializationDuration) { if (reinitializationTimer_ > retryReinitializationDuration) {
Reinitialize(); Reinitialize();
@@ -182,12 +192,20 @@ public class Manager : MonoBehaviour
void CreateMonitors() void CreateMonitors()
{ {
monitors.Clear(); DestroyMonitors();
for (int i = 0; i < monitorCount; ++i) { for (int i = 0; i < monitorCount; ++i) {
monitors.Add(new Monitor(i)); monitors.Add(new Monitor(i));
} }
} }
void DestroyMonitors()
{
for (int i = 0; i < monitors.Count; ++i) {
monitors[i].DestroyTexture();
}
monitors.Clear();
}
void ReinitializeMonitors() void ReinitializeMonitors()
{ {
for (int i = 0; i < monitorCount; ++i) { for (int i = 0; i < monitorCount; ++i) {
@@ -202,7 +220,7 @@ public class Manager : MonoBehaviour
void RecreateTextures() void RecreateTextures()
{ {
for (int i = 0; i < monitorCount; ++i) { for (int i = 0; i < monitorCount; ++i) {
monitors[i].CreateTexture(); monitors[i].CreateTextureIfNeeded();
} }
} }
} }
+37 -18
View File
@@ -38,6 +38,11 @@ public class Monitor
} }
} }
~Monitor()
{
DestroyTexture();
}
public int id public int id
{ {
get; get;
@@ -203,21 +208,24 @@ public class Monitor
set; set;
} }
private static Texture2D errorTexture; private static Texture2D errorTexture_;
private static readonly string errorTexturePath = "uDesktopDuplication/Textures/NotAvailable"; private static readonly string errorTexturePath = "uDesktopDuplication/Textures/NotAvailable";
private Texture2D errorTexture
{
get
{
return errorTexture_ ??
(errorTexture_ = Resources.Load<Texture2D>(errorTexturePath));
}
}
private Texture2D texture_; private Texture2D texture_;
public Texture2D texture public Texture2D texture
{ {
get get
{ {
if (!available) { if (!available) return errorTexture;
return errorTexture ?? if (texture_ == null) CreateTextureIfNeeded();
(errorTexture = Resources.Load<Texture2D>(errorTexturePath));
}
if (texture_ == null) {
CreateTexture();
}
return texture_; return texture_;
} }
} }
@@ -235,7 +243,7 @@ public class Monitor
Lib.GetCursorTexture(id, ptr); Lib.GetCursorTexture(id, ptr);
} }
public void CreateTexture() public void CreateTextureIfNeeded()
{ {
if (!available) return; if (!available) return;
@@ -243,13 +251,8 @@ public class Monitor
var h = isHorizontal ? height : width; var h = isHorizontal ? height : width;
bool shouldCreate = true; bool shouldCreate = true;
if (texture_) { if (texture_ && texture_.width == w && texture_.height == h) {
if (texture_.width != w || texture_.height != h) { shouldCreate = false;
Object.DestroyImmediate(texture_);
texture_ = null;
} else {
shouldCreate = false;
}
} }
if (w <= 0 || h <= 0) { if (w <= 0 || h <= 0) {
@@ -257,13 +260,29 @@ public class Monitor
} }
if (shouldCreate) { 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() public void Reinitialize()
{ {
CreateTexture(); CreateTextureIfNeeded();
} }
} }
@@ -118,6 +118,11 @@ public class Texture : MonoBehaviour
} }
} }
void OnDisable()
{
Destroy(material);
}
void Update() void Update()
{ {
monitor.shouldBeUpdated = true; monitor.shouldBeUpdated = true;
@@ -53,16 +53,21 @@ void Cursor::UpdateBuffer(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
apiBufferSize_ = frameInfo.PointerShapeBufferSize; apiBufferSize_ = frameInfo.PointerShapeBufferSize;
apiBuffer_ = std::make_unique<BYTE[]>(apiBufferSize_); apiBuffer_ = std::make_unique<BYTE[]>(apiBufferSize_);
} }
if (!apiBuffer_) return;
if (!apiBuffer_)
{
return;
}
// Get mouse pointer information // Get mouse pointer information
UINT bufferSize; UINT bufferSize;
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo; DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
const auto hr = monitor_->GetDeskDupl()->GetFramePointerShape( const auto hr = monitor_->GetDeskDupl()->GetFramePointerShape(
apiBufferSize_, apiBufferSize_,
reinterpret_cast<void*>(apiBuffer_.get()), apiBuffer_.get(),
&bufferSize, &bufferSize,
&shapeInfo); &shapeInfo);
if (FAILED(hr)) if (FAILED(hr))
{ {
Debug::Error("Cursor::UpdateBuffer() => GetFramePointerShape() failed."); Debug::Error("Cursor::UpdateBuffer() => GetFramePointerShape() failed.");
@@ -149,13 +154,12 @@ void Cursor::UpdateTexture()
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0; desc.MiscFlags = 0;
ID3D11Texture2D* texture; ComPtr<ID3D11Texture2D> texture;
if (FAILED(GetDevice()->CreateTexture2D(&desc, nullptr, &texture))) if (FAILED(GetDevice()->CreateTexture2D(&desc, nullptr, &texture)))
{ {
Debug::Error("Cursor::UpdateTexture() => GetDevice()->CreateTexture2D() failed."); Debug::Error("Cursor::UpdateTexture() => GetDevice()->CreateTexture2D() failed.");
return; return;
} }
const auto textureReleaser = MakeUniqueWithReleaser(texture);
D3D11_BOX box; D3D11_BOX box;
box.front = 0; box.front = 0;
@@ -171,18 +175,18 @@ void Cursor::UpdateTexture()
return; return;
} }
ID3D11DeviceContext* context; {
GetDevice()->GetImmediateContext(&context); ComPtr<ID3D11DeviceContext> context;
context->CopySubresourceRegion(texture, 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box); GetDevice()->GetImmediateContext(&context);
context->Release(); context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box);
}
IDXGISurface* surface; ComPtr<IDXGISurface> surface;
if (FAILED(texture->QueryInterface<IDXGISurface>(&surface))) if (FAILED(texture.As(&surface)))
{ {
Debug::Error("Cursor::UpdateTexture() => texture->QueryInterface() failed."); Debug::Error("Cursor::UpdateTexture() => texture->QueryInterface() failed.");
return; return;
} }
const auto surfaceReleaser = MakeUniqueWithReleaser(surface);
DXGI_MAPPED_RECT mappedSurface; DXGI_MAPPED_RECT mappedSurface;
if (FAILED(surface->Map(&mappedSurface, DXGI_MAP_READ))) if (FAILED(surface->Map(&mappedSurface, DXGI_MAP_READ)))
@@ -282,10 +286,9 @@ void Cursor::GetTexture(ID3D11Texture2D* texture)
return; return;
} }
ID3D11DeviceContext* context; ComPtr<ID3D11DeviceContext> context;
GetDevice()->GetImmediateContext(&context); GetDevice()->GetImmediateContext(&context);
context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_.get(), GetWidth() * 4, 0); context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_.get(), GetWidth() * 4, 0);
context->Release();
} }
@@ -21,6 +21,7 @@ Monitor::~Monitor()
if (deskDupl_) if (deskDupl_)
{ {
deskDupl_->Release(); deskDupl_->Release();
deskDupl_ = nullptr;
} }
} }
@@ -113,7 +114,7 @@ void Monitor::Render(UINT timeout)
{ {
if (!deskDupl_) return; if (!deskDupl_) return;
IDXGIResource* resource; ComPtr<IDXGIResource> resource;
DXGI_OUTDUPL_FRAME_INFO frameInfo; DXGI_OUTDUPL_FRAME_INFO frameInfo;
const auto hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource); const auto hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource);
@@ -181,10 +182,9 @@ void Monitor::Render(UINT timeout)
} }
else else
{ {
ID3D11DeviceContext* context; ComPtr<ID3D11DeviceContext> context;
GetDevice()->GetImmediateContext(&context); GetDevice()->GetImmediateContext(&context);
context->CopyResource(unityTexture_, texture); context->CopyResource(unityTexture_, texture);
context->Release();
} }
} }
@@ -33,11 +33,8 @@ void MonitorManager::Initialize()
{ {
Finalize(); Finalize();
ComPtr<IDXGIFactory1> factory;
ComPtr<IDXGIAdapter1> adapter;
ComPtr<IDXGIOutput> output;
// Get factory // Get factory
ComPtr<IDXGIFactory1> factory;
if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&factory)))) if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&factory))))
{ {
Debug::Error("MonitorManager::Initialize() => CreateDXGIFactory1() failed."); Debug::Error("MonitorManager::Initialize() => CreateDXGIFactory1() failed.");
@@ -46,9 +43,11 @@ void MonitorManager::Initialize()
// Check all display adapters // Check all display adapters
int id = 0; int id = 0;
ComPtr<IDXGIAdapter1> adapter;
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i) for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
{ {
// Search the main monitor from all outputs // Search the main monitor from all outputs
ComPtr<IDXGIOutput> output;
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j) for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
{ {
auto monitor = std::make_shared<Monitor>(id++); auto monitor = std::make_shared<Monitor>(id++);
@@ -79,31 +78,27 @@ void MonitorManager::Reinitialize()
} }
void MonitorManager::CheckMonitorNumbers() bool MonitorManager::HasMonitorCountChanged() const
{ {
ComPtr<IDXGIFactory1> factory; ComPtr<IDXGIFactory1> factory;
ComPtr<IDXGIAdapter1> adapter;
ComPtr<IDXGIOutput> output;
if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&factory)))) if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&factory))))
{ {
Debug::Error("MonitorManager::CheckMonitorNumbers() => CreateDXGIFactory1() failed."); Debug::Error("MonitorManager::CheckMonitorConnection() => CreateDXGIFactory1() failed.");
return; return false;
} }
int id = 0; int id = 0;
ComPtr<IDXGIAdapter1> adapter;
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i) for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
{ {
ComPtr<IDXGIOutput> output;
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j) for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
{ {
id++; id++;
} }
} }
if (GetMonitorCount() != id) return monitors_.size() != id;
{
RequireReinitilization();
}
} }
@@ -119,8 +114,6 @@ std::shared_ptr<Monitor> MonitorManager::GetMonitor(int id) const
void MonitorManager::Update() void MonitorManager::Update()
{ {
CheckMonitorNumbers();
if (isReinitializationRequired_) if (isReinitializationRequired_)
{ {
Reinitialize(); Reinitialize();
@@ -146,6 +139,7 @@ int MonitorManager::GetMonitorCount() const
return static_cast<int>(monitors_.size()); return static_cast<int>(monitors_.size());
} }
int MonitorManager::GetTotalWidth() const int MonitorManager::GetTotalWidth() const
{ {
std::vector<int> lefts, rights; std::vector<int> lefts, rights;
@@ -159,6 +153,7 @@ int MonitorManager::GetTotalWidth() const
return maxRight - minLeft; return maxRight - minLeft;
} }
int MonitorManager::GetTotalHeight() const int MonitorManager::GetTotalHeight() const
{ {
std::vector<int> tops, bottoms; std::vector<int> tops, bottoms;
@@ -16,7 +16,7 @@ public:
explicit MonitorManager(); explicit MonitorManager();
~MonitorManager(); ~MonitorManager();
void Reinitialize(); void Reinitialize();
void CheckMonitorNumbers(); bool HasMonitorCountChanged() const;
void RequireReinitilization(); void RequireReinitilization();
void SetCursorMonitorId(int id) { cursorMonitorId_ = id; } void SetCursorMonitorId(int id) { cursorMonitorId_ = id; }
int GetCursorMonitorId() const { return cursorMonitorId_; } int GetCursorMonitorId() const { return cursorMonitorId_; }
@@ -115,6 +115,12 @@ extern "C"
return g_manager->GetMonitorCount(); 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() UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorMonitorId()
{ {
if (!g_manager) return -1; if (!g_manager) return -1;