diff --git a/Assets/uDesktopDuplication/Examples/Prefabs/Monitor Board.prefab b/Assets/uDesktopDuplication/Examples/Prefabs/Monitor Board.prefab index 8054f24..6fee757 100644 Binary files a/Assets/uDesktopDuplication/Examples/Prefabs/Monitor Board.prefab and b/Assets/uDesktopDuplication/Examples/Prefabs/Monitor Board.prefab differ diff --git a/Assets/uDesktopDuplication/Examples/Scenes/Meta Data.unity b/Assets/uDesktopDuplication/Examples/Scenes/Meta Data.unity new file mode 100644 index 0000000..c36b758 Binary files /dev/null and b/Assets/uDesktopDuplication/Examples/Scenes/Meta Data.unity differ diff --git a/Assets/uDesktopDuplication/Examples/Scenes/Meta Data.unity.meta b/Assets/uDesktopDuplication/Examples/Scenes/Meta Data.unity.meta new file mode 100644 index 0000000..116cee8 --- /dev/null +++ b/Assets/uDesktopDuplication/Examples/Scenes/Meta Data.unity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aac40d1b58f3f8940be815779d89b5a4 +timeCreated: 1479544409 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/uDesktopDuplication/Examples/Scripts/MetadataVisualizer.cs b/Assets/uDesktopDuplication/Examples/Scripts/MetadataVisualizer.cs new file mode 100644 index 0000000..5d4954f --- /dev/null +++ b/Assets/uDesktopDuplication/Examples/Scripts/MetadataVisualizer.cs @@ -0,0 +1,88 @@ +using UnityEngine; +using MeshForwardDirection = uDesktopDuplication.Texture.MeshForwardDirection; + +public class MetadataVisualizer : MonoBehaviour +{ + uDesktopDuplication.Texture uddTexture_; + + [SerializeField] bool drawMoveRectDest; + [SerializeField] bool drawMoveRectSource; + [SerializeField] bool drawDirtyRect; + + void Start() + { + uddTexture_ = GetComponent(); + } + + public Vector3 GetWorldPositionFromCoord(int u, int v) + { + var monitor = uddTexture_.monitor; + + // mesh & scale information + var mesh = GetComponent().sharedMesh; + var width = transform.localScale.x * (mesh.bounds.extents.x * 2f); + var height = transform.localScale.y * (mesh.bounds.extents.y * 2f); + + // local position (scale included). + var x = (float)(u - monitor.width / 2) / monitor.width; + var y = -(float)(v - monitor.height / 2) / monitor.height; + var localPos = new Vector3(width * x, height * y, 0f); + + // bend + if (uddTexture_.bend) { + var radius = uddTexture_.radius; + var angle = localPos.x / radius; + if (uddTexture_.meshForwardDirection == MeshForwardDirection.Y) { + localPos.y -= radius * (1f - Mathf.Cos(angle)); + } else { + localPos.z -= radius * (1f - Mathf.Cos(angle)); + } + localPos.x = radius * Mathf.Sin(angle); + } + + // to world position + return transform.position + (transform.rotation * localPos); + } + + void Update() + { + UpdateMoveRects(); + UpdateDirtyRects(); + } + + void DrawRect(uDesktopDuplication.RECT rect, Color color) + { + var p0 = GetWorldPositionFromCoord(rect.left, rect.top); + var p1 = GetWorldPositionFromCoord(rect.right, rect.top); + var p2 = GetWorldPositionFromCoord(rect.right, rect.bottom); + var p3 = GetWorldPositionFromCoord(rect.left, rect.bottom); + + Debug.DrawLine(p0, p1, color); + Debug.DrawLine(p1, p2, color); + Debug.DrawLine(p2, p3, color); + Debug.DrawLine(p3, p0, color); + } + + void UpdateMoveRects() + { + if (drawMoveRectSource) { + foreach (var rect in uddTexture_.monitor.moveRects) { + DrawRect(rect.source, Color.blue); + } + } + if (drawMoveRectDest) { + foreach (var rect in uddTexture_.monitor.moveRects) { + DrawRect(rect.destination, Color.green); + } + } + } + + void UpdateDirtyRects() + { + if (drawDirtyRect) { + foreach (var rect in uddTexture_.monitor.dirtyRects) { + DrawRect(rect, Color.red); + } + } + } +} diff --git a/Assets/uDesktopDuplication/Examples/Scripts/MetadataVisualizer.cs.meta b/Assets/uDesktopDuplication/Examples/Scripts/MetadataVisualizer.cs.meta new file mode 100644 index 0000000..686a09b --- /dev/null +++ b/Assets/uDesktopDuplication/Examples/Scripts/MetadataVisualizer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 52d402bdca823cc42925c9d65993ee59 +timeCreated: 1479546123 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/uDesktopDuplication/Examples/Scripts/MultipleMonitorRoundLayouter.cs b/Assets/uDesktopDuplication/Examples/Scripts/MultipleMonitorRoundLayouter.cs index 7abb214..29376b8 100644 --- a/Assets/uDesktopDuplication/Examples/Scripts/MultipleMonitorRoundLayouter.cs +++ b/Assets/uDesktopDuplication/Examples/Scripts/MultipleMonitorRoundLayouter.cs @@ -1,4 +1,5 @@ using UnityEngine; +using MeshForwardDirection = uDesktopDuplication.Texture.MeshForwardDirection; public class MultipleMonitorRoundLayouter : MultipleMonitorLayouter { @@ -20,7 +21,11 @@ public class MultipleMonitorRoundLayouter : MultipleMonitorLayouter // keep the local scale z of monitors as 1 to bend them correctly. foreach (var info in monitors) { var scale = info.gameObject.transform.localScale; - scale.z = 1f; + if (creator_.meshForwardDirection == MeshForwardDirection.Y) { + scale.y = 1f; + } else { + scale.z = 1f; + } info.gameObject.transform.localScale = scale; } diff --git a/Assets/uDesktopDuplication/Examples/Scripts/ToggleMonitors.cs b/Assets/uDesktopDuplication/Examples/Scripts/ToggleMonitors.cs index 9db2619..f262eed 100644 --- a/Assets/uDesktopDuplication/Examples/Scripts/ToggleMonitors.cs +++ b/Assets/uDesktopDuplication/Examples/Scripts/ToggleMonitors.cs @@ -6,10 +6,12 @@ public class ToggleMonitors : MonoBehaviour { if (Input.GetKeyDown(KeyCode.Tab)) { var texture = GetComponent(); + var id = texture.monitorId; + var n = uDesktopDuplication.Manager.monitorCount; if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { - texture.monitorId--; + texture.monitorId = (id - 1 < 0) ? 0 : (id - 1); } else { - texture.monitorId++; + texture.monitorId = (id + 1 >= n) ? (n - 1) : (id + 1); } } } diff --git a/Assets/uDesktopDuplication/Materials/uDD_Screen_Unlit.mat b/Assets/uDesktopDuplication/Materials/uDD_Screen_Unlit.mat index 79bce7a..71c7f59 100644 Binary files a/Assets/uDesktopDuplication/Materials/uDD_Screen_Unlit.mat and b/Assets/uDesktopDuplication/Materials/uDD_Screen_Unlit.mat differ diff --git a/Assets/uDesktopDuplication/Models/uDD_Board.fbx b/Assets/uDesktopDuplication/Models/uDD_Board.fbx index 035338a..db1cf0c 100644 Binary files a/Assets/uDesktopDuplication/Models/uDD_Board.fbx and b/Assets/uDesktopDuplication/Models/uDD_Board.fbx differ diff --git a/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll b/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll index ceee205..8ff08b9 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 6f5fa53..9ba5b9b 100644 --- a/Assets/uDesktopDuplication/Scripts/Lib.cs +++ b/Assets/uDesktopDuplication/Scripts/Lib.cs @@ -50,6 +50,26 @@ public enum DebugMode UnityLog = 2, /* currently has bug when app exits. */ } +[StructLayout(LayoutKind.Sequential)] +public struct RECT +{ + [MarshalAs(UnmanagedType.I4)] + public int left; + [MarshalAs(UnmanagedType.I4)] + public int top; + [MarshalAs(UnmanagedType.I4)] + public int right; + [MarshalAs(UnmanagedType.I4)] + public int bottom; +} + +[StructLayout(LayoutKind.Sequential)] +public struct DXGI_OUTDUPL_MOVE_RECT +{ + public RECT source; + public RECT destination; +} + public static class Lib { public delegate void MessageHandler(Message message); @@ -134,6 +154,14 @@ public static class Lib public static extern void GetCursorTexture(int id, System.IntPtr ptr); [DllImport("uDesktopDuplication")] public static extern int SetTexturePtr(int id, IntPtr ptr); + [DllImport("uDesktopDuplication")] + public static extern int GetMoveRectCount(int id); + [DllImport("uDesktopDuplication", EntryPoint = "GetMoveRects")] + private static extern IntPtr GetMoveRects_Internal(int id); + [DllImport("uDesktopDuplication")] + public static extern int GetDirtyRectCount(int id); + [DllImport("uDesktopDuplication", EntryPoint = "GetDirtyRects")] + private static extern IntPtr GetDirtyRects_Internal(int id); public static string GetName(int id) { @@ -141,6 +169,32 @@ public static class Lib GetName(id, buf, buf.Capacity); return buf.ToString(); } + + public static DXGI_OUTDUPL_MOVE_RECT[] GetMoveRects(int id) + { + var count = GetMoveRectCount(id); + var rects = new DXGI_OUTDUPL_MOVE_RECT[count]; + var ptr = GetMoveRects_Internal(id); + var size = Marshal.SizeOf(typeof(DXGI_OUTDUPL_MOVE_RECT)); + for (int i = 0; i < count; ++i) { + var data = new IntPtr(ptr.ToInt64() + size * i); + rects[i] = (DXGI_OUTDUPL_MOVE_RECT)Marshal.PtrToStructure(data, typeof(DXGI_OUTDUPL_MOVE_RECT)); + } + return rects; + } + + public static RECT[] GetDirtyRects(int id) + { + var count = GetDirtyRectCount(id); + var rects = new RECT[count]; + var ptr = GetDirtyRects_Internal(id); + var size = Marshal.SizeOf(typeof(RECT)); + for (int i = 0; i < count; ++i) { + var data = new IntPtr(ptr.ToInt64() + size * i); + rects[i] = (RECT)Marshal.PtrToStructure(data, typeof(RECT)); + } + return rects; + } } } \ No newline at end of file diff --git a/Assets/uDesktopDuplication/Scripts/Monitor.cs b/Assets/uDesktopDuplication/Scripts/Monitor.cs index 4811bf7..70fd618 100644 --- a/Assets/uDesktopDuplication/Scripts/Monitor.cs +++ b/Assets/uDesktopDuplication/Scripts/Monitor.cs @@ -202,6 +202,26 @@ public class Monitor get { return Lib.GetCursorShapeType(id); } } + public int moveRectCount + { + get { return Lib.GetMoveRectCount(id); } + } + + public DXGI_OUTDUPL_MOVE_RECT[] moveRects + { + get { return Lib.GetMoveRects(id); } + } + + public int dirtyRectCount + { + get { return Lib.GetDirtyRectCount(id); } + } + + public RECT[] dirtyRects + { + get { return Lib.GetDirtyRects(id); } + } + public bool shouldBeUpdated { get; diff --git a/Assets/uDesktopDuplication/Scripts/Texture.cs b/Assets/uDesktopDuplication/Scripts/Texture.cs index f7b94ae..597709d 100644 --- a/Assets/uDesktopDuplication/Scripts/Texture.cs +++ b/Assets/uDesktopDuplication/Scripts/Texture.cs @@ -69,13 +69,13 @@ public class Texture : MonoBehaviour switch (value) { case MeshForwardDirection.Y: material.SetInt("_Forward", 0); - material.EnableKeyword("_BEND_Y"); - material.DisableKeyword("_BEND_Z"); + material.EnableKeyword("_FORWARD_Y"); + material.DisableKeyword("_FORWARD_Z"); break; case MeshForwardDirection.Z: material.SetInt("_Forward", 1); - material.DisableKeyword("_BEND_Y"); - material.EnableKeyword("_BEND_Z"); + material.DisableKeyword("_FORWARD_Y"); + material.EnableKeyword("_FORWARD_Z"); break; } } diff --git a/Assets/uDesktopDuplication/Shaders/uDD_Common.cginc b/Assets/uDesktopDuplication/Shaders/uDD_Common.cginc index f5de721..b198817 100644 --- a/Assets/uDesktopDuplication/Shaders/uDD_Common.cginc +++ b/Assets/uDesktopDuplication/Shaders/uDD_Common.cginc @@ -97,13 +97,13 @@ inline void uddBendVertex(inout float4 v, half radius, half width, half thicknes #ifdef BEND_ON half angle = width * v.x / radius; #ifdef _FORWARD_Z + v.z *= thickness; + radius -= v.z; + v.z -= radius * (1 - cos(angle)); + #elif _FORWARD_Y v.y *= thickness; radius -= v.y; v.y += radius * (1 - cos(angle)); - #elif _FORWARD_Y - v.z *= thickness; - radius -= v.z; - v.z += radius * (1 - cos(angle)); #endif v.x = radius * sin(angle) / width; #else diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Common.h b/Plugins/uDesktopDuplication/uDesktopDuplication/Common.h index 8f78917..60bd24e 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Common.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Common.h @@ -33,50 +33,67 @@ template class Buffer { public: - Buffer() {} - ~Buffer() {} + Buffer() {} + ~Buffer() {} - void ExpandIfNeeded(UINT size) - { - if (size > size_) - { - size_ = size; - value_ = std::make_unique(size); - } - } + void ExpandIfNeeded(UINT size) + { + if (size > size_) + { + size_ = size; + value_ = std::make_unique(size); + } + } - void Reset() - { - value_.reset(); - size_ = 0; - } + void Reset() + { + value_.reset(); + size_ = 0; + } - UINT Size() const - { - return size_; - } + UINT Size() const + { + return size_; + } - T* Get() const - { - return value_.get(); - } + T* Get() const + { + return value_.get(); + } - operator bool() const - { - return value_ != nullptr; - } + T* Get(UINT offset) const + { + return (value_.get() + offset); + } - T operator [](UINT index) const - { - if (index >= size_) - { - Debug::Error("Array index out of range: ", index, size_); - return T(0); - } - return value_[index]; - } + template + U* As() const + { + return reinterpret_cast(Get()); + } + + template + U* As(UINT offset) const + { + return reinterpret_cast(Get(offset)); + } + + operator bool() const + { + return value_ != nullptr; + } + + T operator [](UINT index) const + { + if (index >= size_) + { + Debug::Error("Array index out of range: ", index, size_); + return T(0); + } + return value_[index]; + } private: - std::unique_ptr value_; - UINT size_ = 0; + std::unique_ptr value_; + UINT size_ = 0; }; \ No newline at end of file diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp index 496609b..26c0d47 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.cpp @@ -1,6 +1,5 @@ #include #include -#include "Common.h" #include "Debug.h" #include "Cursor.h" #include "MonitorManager.h" @@ -50,7 +49,7 @@ void Monitor::Initialize(IDXGIOutput* output) 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. + // DPI is set as -1, so the application has to use the appropriate value. } auto output1 = reinterpret_cast(output); @@ -156,7 +155,7 @@ void Monitor::Render(UINT timeout) return; } - // Get texture + // Get texture if (unityTexture_) { ID3D11Texture2D* texture; @@ -189,8 +188,8 @@ void Monitor::Render(UINT timeout) } } - cursor_->UpdateBuffer(frameInfo); - cursor_->UpdateTexture(); + UpdateMetadata(frameInfo); + UpdateCursor(frameInfo); if (FAILED(deskDupl_->ReleaseFrame())) { @@ -199,6 +198,109 @@ void Monitor::Render(UINT timeout) } +void Monitor::UpdateCursor(const DXGI_OUTDUPL_FRAME_INFO& frameInfo) +{ + cursor_->UpdateBuffer(frameInfo); + cursor_->UpdateTexture(); +} + + +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; + } +} + + int Monitor::GetId() const { return id_; @@ -304,4 +406,28 @@ int Monitor::GetWidth() const int Monitor::GetHeight() const { return height_; +} + + +int Monitor::GetMoveRectCount() const +{ + return moveRectSize_ / sizeof(DXGI_OUTDUPL_MOVE_RECT); +} + + +DXGI_OUTDUPL_MOVE_RECT* Monitor::GetMoveRects() const +{ + return metaData_.As(); +} + + +int Monitor::GetDirtyRectCount() const +{ + return dirtyRectSize_ / sizeof(RECT); +} + + +RECT* Monitor::GetDirtyRects() const +{ + return metaData_.As(moveRectSize_); } \ No newline at end of file diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h index 159de5f..e1bc4d0 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Monitor.h @@ -4,6 +4,7 @@ #include #include #include +#include "Common.h" class Cursor; @@ -50,8 +51,17 @@ public: int GetDpiY() const; IDXGIOutputDuplication* GetDeskDupl(); const std::unique_ptr& GetCursor(); + int GetMoveRectCount() const; + DXGI_OUTDUPL_MOVE_RECT* GetMoveRects() const; + int GetDirtyRectCount() const; + RECT* GetDirtyRects() const; 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); + int id_ = -1; UINT dpiX_ = -1, dpiY_ = -1; int width_ = -1, height_ = -1; @@ -61,4 +71,7 @@ private: ID3D11Texture2D* unityTexture_ = nullptr; DXGI_OUTPUT_DESC outputDesc_; MONITORINFOEX monitorInfo_; + Buffer metaData_; + UINT moveRectSize_ = 0; + UINT dirtyRectSize_ = 0;; }; \ No newline at end of file diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp index 0252a6d..d039fbb 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/main.cpp @@ -383,4 +383,40 @@ extern "C" monitor->SetUnityTexture(d3d11Texture); } } + + UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetMoveRectCount(int id) + { + if (!g_manager) return -1; + if (auto monitor = g_manager->GetMonitor(id)) + { + return monitor->GetMoveRectCount(); + } + } + + UNITY_INTERFACE_EXPORT void* UNITY_INTERFACE_API GetMoveRects(int id) + { + if (!g_manager) return nullptr; + if (auto monitor = g_manager->GetMonitor(id)) + { + return monitor->GetMoveRects(); + } + } + + UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetDirtyRectCount(int id) + { + if (!g_manager) return -1; + if (auto monitor = g_manager->GetMonitor(id)) + { + return monitor->GetDirtyRectCount(); + } + } + + UNITY_INTERFACE_EXPORT void* UNITY_INTERFACE_API GetDirtyRects(int id) + { + if (!g_manager) return nullptr; + if (auto monitor = g_manager->GetMonitor(id)) + { + return monitor->GetDirtyRects(); + } + } } \ No newline at end of file