implement dirty rects and move rects.

This commit is contained in:
hecomi
2016-11-19 21:45:32 +09:00
parent a10d5aa5c1
commit 72376b9e91
18 changed files with 435 additions and 54 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: aac40d1b58f3f8940be815779d89b5a4
timeCreated: 1479544409
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
@@ -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<uDesktopDuplication.Texture>();
}
public Vector3 GetWorldPositionFromCoord(int u, int v)
{
var monitor = uddTexture_.monitor;
// mesh & scale information
var mesh = GetComponent<MeshFilter>().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);
}
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 52d402bdca823cc42925c9d65993ee59
timeCreated: 1479546123
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,4 +1,5 @@
using UnityEngine; using UnityEngine;
using MeshForwardDirection = uDesktopDuplication.Texture.MeshForwardDirection;
public class MultipleMonitorRoundLayouter : MultipleMonitorLayouter 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. // keep the local scale z of monitors as 1 to bend them correctly.
foreach (var info in monitors) { foreach (var info in monitors) {
var scale = info.gameObject.transform.localScale; 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; info.gameObject.transform.localScale = scale;
} }
@@ -6,10 +6,12 @@ public class ToggleMonitors : MonoBehaviour
{ {
if (Input.GetKeyDown(KeyCode.Tab)) { if (Input.GetKeyDown(KeyCode.Tab)) {
var texture = GetComponent<uDesktopDuplication.Texture>(); var texture = GetComponent<uDesktopDuplication.Texture>();
var id = texture.monitorId;
var n = uDesktopDuplication.Manager.monitorCount;
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) {
texture.monitorId--; texture.monitorId = (id - 1 < 0) ? 0 : (id - 1);
} else { } else {
texture.monitorId++; texture.monitorId = (id + 1 >= n) ? (n - 1) : (id + 1);
} }
} }
} }
Binary file not shown.
+54
View File
@@ -50,6 +50,26 @@ public enum DebugMode
UnityLog = 2, /* currently has bug when app exits. */ 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 static class Lib
{ {
public delegate void MessageHandler(Message message); public delegate void MessageHandler(Message message);
@@ -134,6 +154,14 @@ public static class Lib
public static extern void GetCursorTexture(int id, System.IntPtr ptr); public static extern void GetCursorTexture(int id, System.IntPtr ptr);
[DllImport("uDesktopDuplication")] [DllImport("uDesktopDuplication")]
public static extern int SetTexturePtr(int id, IntPtr ptr); 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) public static string GetName(int id)
{ {
@@ -141,6 +169,32 @@ public static class Lib
GetName(id, buf, buf.Capacity); GetName(id, buf, buf.Capacity);
return buf.ToString(); 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;
}
} }
} }
@@ -202,6 +202,26 @@ public class Monitor
get { return Lib.GetCursorShapeType(id); } 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 public bool shouldBeUpdated
{ {
get; get;
@@ -69,13 +69,13 @@ public class Texture : MonoBehaviour
switch (value) { switch (value) {
case MeshForwardDirection.Y: case MeshForwardDirection.Y:
material.SetInt("_Forward", 0); material.SetInt("_Forward", 0);
material.EnableKeyword("_BEND_Y"); material.EnableKeyword("_FORWARD_Y");
material.DisableKeyword("_BEND_Z"); material.DisableKeyword("_FORWARD_Z");
break; break;
case MeshForwardDirection.Z: case MeshForwardDirection.Z:
material.SetInt("_Forward", 1); material.SetInt("_Forward", 1);
material.DisableKeyword("_BEND_Y"); material.DisableKeyword("_FORWARD_Y");
material.EnableKeyword("_BEND_Z"); material.EnableKeyword("_FORWARD_Z");
break; break;
} }
} }
@@ -97,13 +97,13 @@ inline void uddBendVertex(inout float4 v, half radius, half width, half thicknes
#ifdef BEND_ON #ifdef BEND_ON
half angle = width * v.x / radius; half angle = width * v.x / radius;
#ifdef _FORWARD_Z #ifdef _FORWARD_Z
v.z *= thickness;
radius -= v.z;
v.z -= radius * (1 - cos(angle));
#elif _FORWARD_Y
v.y *= thickness; v.y *= thickness;
radius -= v.y; radius -= v.y;
v.y += radius * (1 - cos(angle)); v.y += radius * (1 - cos(angle));
#elif _FORWARD_Y
v.z *= thickness;
radius -= v.z;
v.z += radius * (1 - cos(angle));
#endif #endif
v.x = radius * sin(angle) / width; v.x = radius * sin(angle) / width;
#else #else
@@ -33,50 +33,67 @@ template <class T>
class Buffer class Buffer
{ {
public: public:
Buffer() {} Buffer() {}
~Buffer() {} ~Buffer() {}
void ExpandIfNeeded(UINT size) void ExpandIfNeeded(UINT size)
{ {
if (size > size_) if (size > size_)
{ {
size_ = size; size_ = size;
value_ = std::make_unique<T[]>(size); value_ = std::make_unique<T[]>(size);
} }
} }
void Reset() void Reset()
{ {
value_.reset(); value_.reset();
size_ = 0; size_ = 0;
} }
UINT Size() const UINT Size() const
{ {
return size_; return size_;
} }
T* Get() const T* Get() const
{ {
return value_.get(); return value_.get();
} }
operator bool() const T* Get(UINT offset) const
{ {
return value_ != nullptr; return (value_.get() + offset);
} }
T operator [](UINT index) const template <class U>
{ U* As() const
if (index >= size_) {
{ return reinterpret_cast<U*>(Get());
Debug::Error("Array index out of range: ", index, size_); }
return T(0);
} template <class U>
return value_[index]; U* As(UINT offset) const
} {
return reinterpret_cast<U*>(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: private:
std::unique_ptr<T[]> value_; std::unique_ptr<T[]> value_;
UINT size_ = 0; UINT size_ = 0;
}; };
@@ -1,6 +1,5 @@
#include <d3d11.h> #include <d3d11.h>
#include <ShellScalingAPI.h> #include <ShellScalingAPI.h>
#include "Common.h"
#include "Debug.h" #include "Debug.h"
#include "Cursor.h" #include "Cursor.h"
#include "MonitorManager.h" #include "MonitorManager.h"
@@ -50,7 +49,7 @@ void Monitor::Initialize(IDXGIOutput* output)
if (FAILED(GetDpiForMonitor(outputDesc_.Monitor, MDT_RAW_DPI, &dpiX_, &dpiY_))) if (FAILED(GetDpiForMonitor(outputDesc_.Monitor, MDT_RAW_DPI, &dpiX_, &dpiY_)))
{ {
Debug::Error("Monitor::Initialize() => GetDpiForMonitor() failed."); 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<IDXGIOutput1*>(output); auto output1 = reinterpret_cast<IDXGIOutput1*>(output);
@@ -156,7 +155,7 @@ void Monitor::Render(UINT timeout)
return; return;
} }
// Get texture // Get texture
if (unityTexture_) if (unityTexture_)
{ {
ID3D11Texture2D* texture; ID3D11Texture2D* texture;
@@ -189,8 +188,8 @@ void Monitor::Render(UINT timeout)
} }
} }
cursor_->UpdateBuffer(frameInfo); UpdateMetadata(frameInfo);
cursor_->UpdateTexture(); UpdateCursor(frameInfo);
if (FAILED(deskDupl_->ReleaseFrame())) 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<DXGI_OUTDUPL_MOVE_RECT>(),
&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<RECT>(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 int Monitor::GetId() const
{ {
return id_; return id_;
@@ -304,4 +406,28 @@ int Monitor::GetWidth() const
int Monitor::GetHeight() const int Monitor::GetHeight() const
{ {
return height_; return height_;
}
int Monitor::GetMoveRectCount() const
{
return moveRectSize_ / sizeof(DXGI_OUTDUPL_MOVE_RECT);
}
DXGI_OUTDUPL_MOVE_RECT* Monitor::GetMoveRects() const
{
return metaData_.As<DXGI_OUTDUPL_MOVE_RECT>();
}
int Monitor::GetDirtyRectCount() const
{
return dirtyRectSize_ / sizeof(RECT);
}
RECT* Monitor::GetDirtyRects() const
{
return metaData_.As<RECT>(moveRectSize_);
} }
@@ -4,6 +4,7 @@
#include <dxgi1_2.h> #include <dxgi1_2.h>
#include <wrl/client.h> #include <wrl/client.h>
#include <memory> #include <memory>
#include "Common.h"
class Cursor; class Cursor;
@@ -50,8 +51,17 @@ public:
int GetDpiY() const; int GetDpiY() const;
IDXGIOutputDuplication* GetDeskDupl(); IDXGIOutputDuplication* GetDeskDupl();
const std::unique_ptr<Cursor>& GetCursor(); const std::unique_ptr<Cursor>& GetCursor();
int GetMoveRectCount() const;
DXGI_OUTDUPL_MOVE_RECT* GetMoveRects() const;
int GetDirtyRectCount() const;
RECT* GetDirtyRects() const;
private: 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; int id_ = -1;
UINT dpiX_ = -1, dpiY_ = -1; UINT dpiX_ = -1, dpiY_ = -1;
int width_ = -1, height_ = -1; int width_ = -1, height_ = -1;
@@ -61,4 +71,7 @@ private:
ID3D11Texture2D* unityTexture_ = nullptr; ID3D11Texture2D* unityTexture_ = nullptr;
DXGI_OUTPUT_DESC outputDesc_; DXGI_OUTPUT_DESC outputDesc_;
MONITORINFOEX monitorInfo_; MONITORINFOEX monitorInfo_;
Buffer<BYTE> metaData_;
UINT moveRectSize_ = 0;
UINT dirtyRectSize_ = 0;;
}; };
@@ -383,4 +383,40 @@ extern "C"
monitor->SetUnityTexture(d3d11Texture); 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();
}
}
} }