Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70cfad90a9 | ||
|
|
c926127e49 | ||
|
|
03469ce429 | ||
|
|
f63e573f04 | ||
|
|
682553a5a2 | ||
|
|
b5fd483d6a | ||
|
|
0d2c0e02f0 | ||
|
|
6f876f65ed | ||
|
|
8434d803bb | ||
|
|
1c332ebca7 | ||
|
|
340e2d5194 | ||
|
|
e397f5eb84 | ||
|
|
c20c09e275 | ||
|
|
a0ca46630e | ||
|
|
5b5995d7d0 | ||
|
|
808a71ed6d | ||
|
|
da072aa9f3 | ||
|
|
7237d283ef | ||
|
|
4a28b5f341 | ||
|
|
10091be4b3 | ||
|
|
c41fe42aa3 | ||
|
|
c0e1967e2e | ||
|
|
f5a8a83c7e | ||
|
|
c251de3a30 | ||
|
|
b0877a49ed | ||
|
|
68d9e30816 | ||
|
|
b8ae1d6c4a | ||
|
|
15624dc0f4 | ||
|
|
06d4edbcb0 | ||
|
|
9ee2d35175 | ||
|
|
0634993bb0 | ||
|
|
6bd892bc4b | ||
|
|
2a631a0a89 | ||
|
|
0833b965e9 | ||
|
|
12726d85dc | ||
|
|
29920b6b94 | ||
|
|
4de8f0ba51 | ||
|
|
476be8243a | ||
|
|
c681e43d65 | ||
|
|
ed24ca2fb2 | ||
|
|
791fa42478 | ||
|
|
11dbb7be57 | ||
|
|
9ed24dd3b1 | ||
|
|
cfbd218374 | ||
|
|
bf7174f406 | ||
|
|
4a761a06f3 | ||
|
|
1effd65aeb | ||
|
|
46cc789be5 | ||
|
|
1053b30d7e | ||
|
|
d58855ff8a | ||
|
|
741e2c0bc1 | ||
|
|
f6ce875463 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,6 +5,8 @@
|
||||
/[Bb]uild/
|
||||
/[Ww]iki/
|
||||
/[Mm]isc/
|
||||
/UnityPackageManager
|
||||
/Packages
|
||||
|
||||
# Autogenerated VS/MD solution and project files
|
||||
*.csproj
|
||||
@@ -28,3 +30,4 @@ sysinfo.txt
|
||||
/Assets/AssetStoreTools*
|
||||
/Assets/Extensions*
|
||||
/uDesktopDuplication.log
|
||||
.vs
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,41 +1,41 @@
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(MultipleMonitorCreator))]
|
||||
public class MultipleMonitorAnalyzer : MonoBehaviour
|
||||
{
|
||||
MultipleMonitorCreator creator_;
|
||||
Vector3 gazePoint_ = Vector3.zero;
|
||||
public Vector3 gazePoint
|
||||
{
|
||||
get { return gazePoint_; }
|
||||
private set
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(MultipleMonitorCreator))]
|
||||
public class MultipleMonitorAnalyzer : MonoBehaviour
|
||||
{
|
||||
MultipleMonitorCreator creator_;
|
||||
Vector3 gazePoint_ = Vector3.zero;
|
||||
public Vector3 gazePoint
|
||||
{
|
||||
get { return gazePoint_; }
|
||||
private set
|
||||
{
|
||||
gazePoint_ += (value - gazePoint) * (gazePointFilter / (1f / 60 / Time.deltaTime));
|
||||
}
|
||||
}
|
||||
|
||||
[Header("Filters")]
|
||||
[Range(0f, 1f)] public float gazePointFilter = 0.1f;
|
||||
[Range(0f, 1f)] public float moveRectFilter = 0.05f;
|
||||
[Range(0f, 1f)] public float mouseFilter = 0.05f;
|
||||
[Range(0f, 1f)] public float dirtyRectFilter = 0.01f;
|
||||
[Range(0f, 1f)] public float noEventFilter = 0.01f;
|
||||
[Range(0f, 1f)] public float velocityFilter = 0.1f;
|
||||
|
||||
[Header("Debug")]
|
||||
[SerializeField] bool drawGazePoint;
|
||||
[SerializeField] bool drawAveragePos;
|
||||
[SerializeField] bool drawMoveRects;
|
||||
[SerializeField] bool drawDirtyRects;
|
||||
|
||||
void Start()
|
||||
}
|
||||
}
|
||||
|
||||
[Header("Filters")]
|
||||
[Range(0f, 1f)] public float gazePointFilter = 0.1f;
|
||||
[Range(0f, 1f)] public float moveRectFilter = 0.05f;
|
||||
[Range(0f, 1f)] public float mouseFilter = 0.05f;
|
||||
[Range(0f, 1f)] public float dirtyRectFilter = 0.01f;
|
||||
[Range(0f, 1f)] public float noEventFilter = 0.01f;
|
||||
[Range(0f, 1f)] public float velocityFilter = 0.1f;
|
||||
|
||||
[Header("Debug")]
|
||||
[SerializeField] bool drawGazePoint;
|
||||
[SerializeField] bool drawAveragePos;
|
||||
[SerializeField] bool drawMoveRects;
|
||||
[SerializeField] bool drawDirtyRects;
|
||||
|
||||
void Start()
|
||||
{
|
||||
creator_ = GetComponent<MultipleMonitorCreator>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
var cursorMonitorId = uDesktopDuplication.Manager.cursorMonitorId;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
var cursorMonitorId = uDesktopDuplication.Manager.cursorMonitorId;
|
||||
for (int i = 0; i < creator_.monitors.Count; ++i) {
|
||||
var info = creator_.monitors[i];
|
||||
var analyzer =
|
||||
@@ -44,18 +44,18 @@ public class MultipleMonitorAnalyzer : MonoBehaviour
|
||||
UpdateAnalyzer(analyzer);
|
||||
if (info.uddTexture.monitorId == cursorMonitorId) {
|
||||
gazePoint = analyzer.averagePos;
|
||||
}
|
||||
}
|
||||
|
||||
if (drawGazePoint) DrawGazePoint();
|
||||
}
|
||||
|
||||
void DrawGazePoint()
|
||||
}
|
||||
}
|
||||
|
||||
if (drawGazePoint) DrawGazePoint();
|
||||
}
|
||||
|
||||
void DrawGazePoint()
|
||||
{
|
||||
Debug.DrawLine(transform.position, gazePoint, Color.magenta);
|
||||
}
|
||||
|
||||
void UpdateAnalyzer(GazePointAnalyzer analyzer)
|
||||
}
|
||||
|
||||
void UpdateAnalyzer(GazePointAnalyzer analyzer)
|
||||
{
|
||||
analyzer.moveRectFilter = moveRectFilter;
|
||||
analyzer.mouseFilter = mouseFilter;
|
||||
@@ -65,5 +65,5 @@ public class MultipleMonitorAnalyzer : MonoBehaviour
|
||||
analyzer.drawAveragePos = drawAveragePos;
|
||||
analyzer.drawMoveRects = drawMoveRects;
|
||||
analyzer.drawDirtyRects = drawDirtyRects;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using UnityEngine.Assertions;
|
||||
using System.Collections.Generic;
|
||||
using MeshForwardDirection = uDesktopDuplication.Texture.MeshForwardDirection;
|
||||
using MonitorState = uDesktopDuplication.MonitorState;
|
||||
using DuplicatorState = uDesktopDuplication.DuplicatorState;
|
||||
|
||||
public class MultipleMonitorCreator : MonoBehaviour
|
||||
{
|
||||
@@ -92,11 +92,11 @@ public class MultipleMonitorCreator : MonoBehaviour
|
||||
if (removeWaitTimer_ > removeWaitDuration) {
|
||||
hasMonitorUnsupportStateChecked_ = true;
|
||||
foreach (var info in monitors) {
|
||||
if (info.uddTexture.monitor.state == MonitorState.Unsupported) {
|
||||
if (info.uddTexture.monitor.state == DuplicatorState.Unsupported) {
|
||||
Destroy(info.gameObject);
|
||||
}
|
||||
}
|
||||
monitors.RemoveAll(info => info.uddTexture.monitor.state == MonitorState.Unsupported);
|
||||
monitors.RemoveAll(info => info.uddTexture.monitor.state == DuplicatorState.Unsupported);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,53 +1,150 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19d4c78204afead44b6de11427d7f2f6
|
||||
timeCreated: 1480693943
|
||||
guid: d3ab0ac3a3d6bb643af0a464a93be957
|
||||
timeCreated: 1503496900
|
||||
licenseType: Pro
|
||||
PluginImporter:
|
||||
serializedVersion: 1
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
Any:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
Editor:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: x86
|
||||
DefaultValueInitialized: true
|
||||
Linux:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: x86
|
||||
Linux64:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
LinuxUniversal:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: x86
|
||||
OSXIntel:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
OSXIntel64:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
OSXUniversal:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: x86
|
||||
Win:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
Win64:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
data:
|
||||
first:
|
||||
'': Any
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
Exclude Android: 0
|
||||
Exclude Editor: 0
|
||||
Exclude Linux: 0
|
||||
Exclude Linux64: 0
|
||||
Exclude LinuxUniversal: 0
|
||||
Exclude OSXIntel: 0
|
||||
Exclude OSXIntel64: 0
|
||||
Exclude OSXUniversal: 0
|
||||
Exclude Win: 0
|
||||
Exclude Win64: 1
|
||||
data:
|
||||
first:
|
||||
'': data
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
data:
|
||||
first:
|
||||
Android: Android
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: ARMv7
|
||||
data:
|
||||
first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
Exclude Editor: 0
|
||||
Exclude Linux: 0
|
||||
Exclude Linux64: 0
|
||||
Exclude LinuxUniversal: 0
|
||||
Exclude OSXIntel: 0
|
||||
Exclude OSXIntel64: 0
|
||||
Exclude OSXUniversal: 0
|
||||
Exclude WebGL: 0
|
||||
Exclude Win: 0
|
||||
Exclude Win64: 1
|
||||
data:
|
||||
first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: x86
|
||||
DefaultValueInitialized: true
|
||||
OS: AnyOS
|
||||
data:
|
||||
first:
|
||||
Facebook: WebGL
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
data:
|
||||
first:
|
||||
Facebook: Win
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
data:
|
||||
first:
|
||||
Facebook: Win64
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
data:
|
||||
first:
|
||||
Standalone: Linux
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: x86
|
||||
data:
|
||||
first:
|
||||
Standalone: Linux64
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: None
|
||||
data:
|
||||
first:
|
||||
Standalone: LinuxUniversal
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
data:
|
||||
first:
|
||||
Standalone: OSXIntel
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
data:
|
||||
first:
|
||||
Standalone: OSXIntel64
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: None
|
||||
data:
|
||||
first:
|
||||
Standalone: OSXUniversal
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
data:
|
||||
first:
|
||||
Standalone: Win
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
data:
|
||||
first:
|
||||
Standalone: Win64
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
data:
|
||||
first:
|
||||
WebGL: WebGL
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
Binary file not shown.
@@ -1,54 +1,150 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02fc121822cf2ea4e82e16c4a28bf711
|
||||
timeCreated: 1477546714
|
||||
guid: 7cb91c9ae744dc5429005b20e11f4f37
|
||||
timeCreated: 1503505907
|
||||
licenseType: Pro
|
||||
PluginImporter:
|
||||
serializedVersion: 1
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
Any:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
Editor:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
DefaultValueInitialized: true
|
||||
OS: AnyOS
|
||||
Linux:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: x86
|
||||
Linux64:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: x86_64
|
||||
LinuxUniversal:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
OSXIntel:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
OSXIntel64:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
OSXUniversal:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
Win:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
Win64:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
data:
|
||||
first:
|
||||
'': Any
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
Exclude Android: 0
|
||||
Exclude Editor: 0
|
||||
Exclude Linux: 0
|
||||
Exclude Linux64: 0
|
||||
Exclude LinuxUniversal: 0
|
||||
Exclude OSXIntel: 0
|
||||
Exclude OSXIntel64: 0
|
||||
Exclude OSXUniversal: 0
|
||||
Exclude Win: 1
|
||||
Exclude Win64: 0
|
||||
data:
|
||||
first:
|
||||
'': data
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
data:
|
||||
first:
|
||||
Android: Android
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: ARMv7
|
||||
data:
|
||||
first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
Exclude Editor: 0
|
||||
Exclude Linux: 0
|
||||
Exclude Linux64: 0
|
||||
Exclude LinuxUniversal: 0
|
||||
Exclude OSXIntel: 0
|
||||
Exclude OSXIntel64: 0
|
||||
Exclude OSXUniversal: 0
|
||||
Exclude WebGL: 0
|
||||
Exclude Win: 1
|
||||
Exclude Win64: 0
|
||||
data:
|
||||
first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: x86_64
|
||||
DefaultValueInitialized: true
|
||||
OS: AnyOS
|
||||
data:
|
||||
first:
|
||||
Facebook: WebGL
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
data:
|
||||
first:
|
||||
Facebook: Win
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
data:
|
||||
first:
|
||||
Facebook: Win64
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
data:
|
||||
first:
|
||||
Standalone: Linux
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: None
|
||||
data:
|
||||
first:
|
||||
Standalone: Linux64
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: x86_64
|
||||
data:
|
||||
first:
|
||||
Standalone: LinuxUniversal
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
data:
|
||||
first:
|
||||
Standalone: OSXIntel
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: None
|
||||
data:
|
||||
first:
|
||||
Standalone: OSXIntel64
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
data:
|
||||
first:
|
||||
Standalone: OSXUniversal
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
data:
|
||||
first:
|
||||
Standalone: Win
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: None
|
||||
data:
|
||||
first:
|
||||
Standalone: Win64
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
data:
|
||||
first:
|
||||
WebGL: WebGL
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
@@ -32,17 +32,18 @@ public enum MonitorRotation
|
||||
Rotate270 = 4
|
||||
}
|
||||
|
||||
public enum MonitorState
|
||||
public enum DuplicatorState
|
||||
{
|
||||
NotSet = -1,
|
||||
Available = 0,
|
||||
InvalidArg = 1,
|
||||
AccessDenied = 2,
|
||||
Unsupported = 3,
|
||||
CurrentlyNotAvailable = 4,
|
||||
SessionDisconnected = 5,
|
||||
AccessLost = 6,
|
||||
TextureSizeInconsistent = 7,
|
||||
Ready = 0,
|
||||
Running = 1,
|
||||
InvalidArg = 2,
|
||||
AccessDenied = 3,
|
||||
Unsupported = 4,
|
||||
CurrentlyNotAvailable = 5,
|
||||
SessionDisconnected = 6,
|
||||
AccessLost = 7,
|
||||
TextureSizeInconsistent = 8,
|
||||
Unknown = 999,
|
||||
}
|
||||
|
||||
@@ -112,13 +113,11 @@ public static class Lib
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern int GetTotalHeight();
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern void SetTimeout(int timeout);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern IntPtr GetRenderEventFunc();
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern int GetId(int id);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern MonitorState GetState(int id);
|
||||
public static extern DuplicatorState GetState(int id);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern void GetName(int id, StringBuilder buf, int len);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
@@ -173,6 +172,8 @@ public static class Lib
|
||||
public static extern bool HasBeenUpdated(int id);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern bool UseGetPixels(int id, bool use);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern void SetFrameRate(uint frameRate);
|
||||
|
||||
public static string GetName(int id)
|
||||
{
|
||||
|
||||
@@ -55,7 +55,6 @@ public class Manager : MonoBehaviour
|
||||
[Tooltip("Debug mode is not applied while running.")]
|
||||
[SerializeField] DebugMode debugMode = DebugMode.File;
|
||||
|
||||
[SerializeField] int desktopDuplicationApiTimeout = 0;
|
||||
[SerializeField] float retryReinitializationDuration = 1f;
|
||||
|
||||
private Coroutine renderCoroutine_ = null;
|
||||
@@ -97,10 +96,15 @@ public class Manager : MonoBehaviour
|
||||
Lib.SetLogFunc(onDebugLog);
|
||||
Lib.SetErrorFunc(onDebugErr);
|
||||
|
||||
Lib.SetTimeout(desktopDuplicationApiTimeout);
|
||||
Lib.Initialize();
|
||||
|
||||
CreateMonitors();
|
||||
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
Shader.DisableKeyword("USE_GAMMA_TO_LINEAR_SPACE");
|
||||
#else
|
||||
Shader.EnableKeyword("USE_GAMMA_TO_LINEAR_SPACE");
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
@@ -158,11 +162,11 @@ public class Manager : MonoBehaviour
|
||||
var monitor = monitors[i];
|
||||
var state = monitor.state;
|
||||
if (
|
||||
state == MonitorState.NotSet ||
|
||||
state == MonitorState.AccessLost ||
|
||||
state == MonitorState.AccessDenied ||
|
||||
state == MonitorState.SessionDisconnected ||
|
||||
state == MonitorState.Unknown
|
||||
state == DuplicatorState.NotSet ||
|
||||
state == DuplicatorState.AccessLost ||
|
||||
state == DuplicatorState.AccessDenied ||
|
||||
state == DuplicatorState.SessionDisconnected ||
|
||||
state == DuplicatorState.Unknown
|
||||
) {
|
||||
reinitializeNeeded = true;
|
||||
break;
|
||||
|
||||
@@ -11,21 +11,23 @@ public class Monitor
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case MonitorState.Available:
|
||||
case DuplicatorState.Ready:
|
||||
break;
|
||||
case MonitorState.InvalidArg:
|
||||
case DuplicatorState.Running:
|
||||
break;
|
||||
case DuplicatorState.InvalidArg:
|
||||
Debug.LogErrorFormat("[uDD] {0}:{1} => Invalid.", id, name);
|
||||
break;
|
||||
case MonitorState.AccessDenied:
|
||||
case DuplicatorState.AccessDenied:
|
||||
Debug.LogWarningFormat("[uDD] {0}:{1} => Access Denied.", id, name);
|
||||
break;
|
||||
case MonitorState.Unsupported:
|
||||
case DuplicatorState.Unsupported:
|
||||
Debug.LogWarningFormat("[uDD] {0}:{1} => Unsupported.", id, name);
|
||||
break;
|
||||
case MonitorState.SessionDisconnected:
|
||||
case DuplicatorState.SessionDisconnected:
|
||||
Debug.LogWarningFormat("[uDD] {0}:{1} => Disconnected.", id, name);
|
||||
break;
|
||||
case MonitorState.NotSet:
|
||||
case DuplicatorState.NotSet:
|
||||
Debug.LogErrorFormat("[uDD] {0}:{1} => Something wrong.", id, name);
|
||||
break;
|
||||
default:
|
||||
@@ -53,14 +55,19 @@ public class Monitor
|
||||
get { return id < Manager.monitorCount; }
|
||||
}
|
||||
|
||||
public MonitorState state
|
||||
public DuplicatorState state
|
||||
{
|
||||
get { return Lib.GetState(id); }
|
||||
}
|
||||
|
||||
public bool available
|
||||
{
|
||||
get { return state == MonitorState.Available; }
|
||||
get
|
||||
{
|
||||
return
|
||||
state == DuplicatorState.Ready ||
|
||||
state == DuplicatorState.Running;
|
||||
}
|
||||
}
|
||||
|
||||
public string name
|
||||
|
||||
@@ -271,7 +271,10 @@ public class Texture : MonoBehaviour
|
||||
|
||||
void RequireUpdate()
|
||||
{
|
||||
monitor.shouldBeUpdated = true;
|
||||
if (monitor != null)
|
||||
{
|
||||
monitor.shouldBeUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Reinitialize()
|
||||
@@ -280,11 +283,16 @@ public class Texture : MonoBehaviour
|
||||
monitor = Manager.GetMonitor(lastMonitorId_);
|
||||
}
|
||||
|
||||
int clipPositionScaleKey_ = Shader.PropertyToID("_ClipPositionScale");
|
||||
void UpdateMaterial()
|
||||
{
|
||||
width = transform.localScale.x;
|
||||
rotation = monitor.rotation;
|
||||
material.SetVector("_ClipPositionScale", new Vector4(clipPos.x, clipPos.y, clipScale.x, clipScale.y));
|
||||
|
||||
if (monitor != null) {
|
||||
rotation = monitor.rotation;
|
||||
}
|
||||
|
||||
material.SetVector(clipPositionScaleKey_, new Vector4(clipPos.x, clipPos.y, clipScale.x, clipScale.y));
|
||||
}
|
||||
|
||||
public Vector3 GetWorldPositionFromCoord(Vector2 coord)
|
||||
|
||||
@@ -58,9 +58,11 @@ inline float2 uddClipUV(float2 uv)
|
||||
|
||||
inline void uddConvertToLinearIfNeeded(inout fixed3 rgb)
|
||||
{
|
||||
#ifdef USE_GAMMA_TO_LINEAR_SPACE
|
||||
if (!IsGammaSpace()) {
|
||||
rgb = GammaToLinearSpace(rgb);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline fixed4 uddGetTexture(sampler2D tex, float2 uv)
|
||||
|
||||
@@ -31,6 +31,7 @@ SubShader
|
||||
#pragma multi_compile ___ USE_CLIP
|
||||
#pragma multi_compile ___ BEND_ON
|
||||
#pragma multi_compile _FORWARD_Y _FORWARD_Z
|
||||
#pragma multi_compile ___ USE_GAMMA_TO_LINEAR_SPACE
|
||||
|
||||
#define SURFACE_SHADER
|
||||
#include "./uDD_Common.cginc"
|
||||
|
||||
@@ -55,6 +55,7 @@ Pass
|
||||
#pragma multi_compile ___ USE_CLIP
|
||||
#pragma multi_compile ___ BEND_ON
|
||||
#pragma multi_compile _FORWARD_Y _FORWARD_Z
|
||||
#pragma multi_compile ___ USE_GAMMA_TO_LINEAR_SPACE
|
||||
ENDCG
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ Pass
|
||||
#pragma multi_compile ___ USE_CLIP
|
||||
#pragma multi_compile ___ BEND_ON
|
||||
#pragma multi_compile _FORWARD_Y _FORWARD_Z
|
||||
#pragma multi_compile ___ USE_GAMMA_TO_LINEAR_SPACE
|
||||
ENDCG
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ DsOutput domain(
|
||||
float disp = length(_DispTex.SampleLevel(sampler_DispTex, o.f2TexCoord, 0)) * _DispFactor;
|
||||
f3Position.xyz += f3Normal * disp;
|
||||
|
||||
o.f4Position = mul(UNITY_MATRIX_MVP, float4(f3Position.xyz, 1.0));
|
||||
o.f4Position = UnityObjectToClipPos(float4(f3Position.xyz, 1.0));
|
||||
|
||||
return o;
|
||||
}
|
||||
@@ -168,6 +168,7 @@ Pass
|
||||
#pragma multi_compile ___ USE_CLIP
|
||||
#pragma multi_compile ___ BEND_ON
|
||||
#pragma multi_compile _FORWARD_Y _FORWARD_Z
|
||||
#pragma multi_compile ___ USE_GAMMA_TO_LINEAR_SPACE
|
||||
ENDCG
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ Pass
|
||||
#pragma multi_compile ___ USE_CLIP
|
||||
#pragma multi_compile ___ BEND_ON
|
||||
#pragma multi_compile _FORWARD_Y _FORWARD_Z
|
||||
#pragma multi_compile ___ USE_GAMMA_TO_LINEAR_SPACE
|
||||
ENDCG
|
||||
}
|
||||
|
||||
|
||||
5
Plugins/uDesktopDuplication/uDesktopDuplication.def
Normal file
5
Plugins/uDesktopDuplication/uDesktopDuplication.def
Normal file
@@ -0,0 +1,5 @@
|
||||
LIBRARY
|
||||
|
||||
EXPORTS
|
||||
UnityPluginLoad
|
||||
UnityPluginUnload
|
||||
@@ -6,10 +6,12 @@
|
||||
#include "IUnityInterface.h"
|
||||
#include "IUnityGraphicsD3D11.h"
|
||||
#include "Common.h"
|
||||
#include "Debug.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
|
||||
|
||||
extern IUnityInterfaces* g_unity;
|
||||
extern std::unique_ptr<MonitorManager> g_manager;
|
||||
extern std::queue<Message> g_messages;
|
||||
@@ -33,7 +35,45 @@ const std::unique_ptr<MonitorManager>& GetMonitorManager()
|
||||
}
|
||||
|
||||
|
||||
LUID GetUnityAdapterLuid()
|
||||
{
|
||||
const auto device = GetUnity()->Get<IUnityGraphicsD3D11>()->GetDevice();
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIDevice1> dxgiDevice;
|
||||
if (FAILED(device->QueryInterface(IID_PPV_ARGS(&dxgiDevice)))){
|
||||
Debug::Error("QueryInterface from IUnityGraphicsD3D11 to IDXGIDevice1 failed.");
|
||||
return LUID();
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIAdapter> dxgiAdapter;
|
||||
if (FAILED(dxgiDevice->GetAdapter(&dxgiAdapter))) {
|
||||
Debug::Error("QueryInterface from IDXGIDevice1 to IDXGIAdapter failed.");
|
||||
return LUID();
|
||||
}
|
||||
|
||||
DXGI_ADAPTER_DESC adapterDesc;
|
||||
dxgiAdapter->GetDesc(&adapterDesc);
|
||||
|
||||
return adapterDesc.AdapterLuid;
|
||||
}
|
||||
|
||||
|
||||
void SendMessageToUnity(Message message)
|
||||
{
|
||||
g_messages.push(message);
|
||||
}
|
||||
|
||||
|
||||
ScopedTimer::ScopedTimer(TimerFuncType&& func)
|
||||
: func_(func)
|
||||
, start_(std::chrono::high_resolution_clock::now())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ScopedTimer::~ScopedTimer()
|
||||
{
|
||||
const auto end = std::chrono::high_resolution_clock::now();
|
||||
const auto time = std::chrono::duration_cast<microseconds>(end - start_);
|
||||
func_(time);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include <wrl/client.h>
|
||||
|
||||
|
||||
// Unity interface and ID3D11Device getters
|
||||
|
||||
// Unity interface getter
|
||||
struct IUnityInterfaces;
|
||||
IUnityInterfaces* GetUnity();
|
||||
|
||||
// ID3D11Device (in Unity) getter
|
||||
struct ID3D11Device;
|
||||
Microsoft::WRL::ComPtr<ID3D11Device> GetDevice();
|
||||
|
||||
|
||||
// Manager getter
|
||||
class MonitorManager;
|
||||
const std::unique_ptr<MonitorManager>& GetMonitorManager();
|
||||
|
||||
// Get adapter LUID to check the adapter of the monitor is same as Unity one.
|
||||
LUID GetUnityAdapterLuid();
|
||||
|
||||
|
||||
|
||||
// Releaser
|
||||
class ScopedReleaser
|
||||
{
|
||||
public:
|
||||
using ReleaseFuncType = std::function<void()>;
|
||||
ScopedReleaser(ReleaseFuncType&& func) : func_(func) {}
|
||||
~ScopedReleaser() { func_(); }
|
||||
|
||||
private:
|
||||
const ReleaseFuncType func_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Timer
|
||||
class ScopedTimer
|
||||
{
|
||||
public:
|
||||
using microseconds = std::chrono::microseconds;
|
||||
using TimerFuncType = std::function<void(microseconds)>;
|
||||
ScopedTimer(TimerFuncType&& func);
|
||||
~ScopedTimer();
|
||||
|
||||
private:
|
||||
const TimerFuncType func_;
|
||||
const std::chrono::time_point<std::chrono::steady_clock> start_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Message is pooled and fetch from Unity.
|
||||
enum class Message
|
||||
@@ -28,13 +65,44 @@ enum class Message
|
||||
void SendMessageToUnity(Message message);
|
||||
|
||||
|
||||
|
||||
// Buffer
|
||||
template <class T>
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
Buffer() {}
|
||||
~Buffer() {}
|
||||
Buffer()
|
||||
{
|
||||
}
|
||||
|
||||
Buffer(const Buffer& other)
|
||||
{
|
||||
value_.reset();
|
||||
size_ = 0;
|
||||
ExpandIfNeeded(other.size_);
|
||||
memcpy_s(value_.get(), size_, other.value_.get(), other.size_);
|
||||
}
|
||||
|
||||
Buffer<T>& operator=(const Buffer& other)
|
||||
{
|
||||
if (&other == this) return *this;
|
||||
|
||||
value_.reset();
|
||||
size_ = 0;
|
||||
ExpandIfNeeded(other.size_);
|
||||
memcpy_s(value_.get(), size_, other.value_.get(), other.size_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Buffer()
|
||||
{
|
||||
}
|
||||
|
||||
bool Empty() const
|
||||
{
|
||||
return !value_;
|
||||
}
|
||||
|
||||
void ExpandIfNeeded(UINT size)
|
||||
{
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#include <d3d11.h>
|
||||
#include <wrl/client.h>
|
||||
#include "Debug.h"
|
||||
#include "MonitorManager.h"
|
||||
#include "Monitor.h"
|
||||
|
||||
#include "Cursor.h"
|
||||
#include "Debug.h"
|
||||
#include "Monitor.h"
|
||||
#include "Duplicator.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
|
||||
|
||||
Cursor::Cursor()
|
||||
{
|
||||
}
|
||||
@@ -18,7 +19,7 @@ Cursor::~Cursor()
|
||||
}
|
||||
|
||||
|
||||
void Cursor::UpdateBuffer(Monitor* monitor, const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
|
||||
void Cursor::UpdateBuffer(Duplicator* duplicator, const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
|
||||
{
|
||||
if (frameInfo.LastMouseUpdateTime.QuadPart == 0)
|
||||
{
|
||||
@@ -26,11 +27,6 @@ void Cursor::UpdateBuffer(Monitor* monitor, const DXGI_OUTDUPL_FRAME_INFO& frame
|
||||
}
|
||||
|
||||
isVisible_ = frameInfo.PointerPosition.Visible != 0;
|
||||
if (isVisible_)
|
||||
{
|
||||
GetMonitorManager()->SetCursorMonitorId(monitor->GetId());
|
||||
}
|
||||
|
||||
x_ = frameInfo.PointerPosition.Position.x;
|
||||
y_ = frameInfo.PointerPosition.Position.y;
|
||||
timestamp_ = frameInfo.LastMouseUpdateTime;
|
||||
@@ -49,7 +45,7 @@ void Cursor::UpdateBuffer(Monitor* monitor, const DXGI_OUTDUPL_FRAME_INFO& frame
|
||||
// Get mouse pointer information
|
||||
UINT bufferSize;
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
|
||||
const auto hr = monitor->GetDeskDupl()->GetFramePointerShape(
|
||||
const auto hr = duplicator->GetDuplication()->GetFramePointerShape(
|
||||
buffer_.Size(),
|
||||
buffer_.Get(),
|
||||
&bufferSize,
|
||||
@@ -66,12 +62,16 @@ void Cursor::UpdateBuffer(Monitor* monitor, const DXGI_OUTDUPL_FRAME_INFO& frame
|
||||
}
|
||||
|
||||
|
||||
void Cursor::Draw(Monitor* monitor)
|
||||
void Cursor::UpdateTexture(
|
||||
Duplicator* duplicator,
|
||||
const ComPtr<ID3D11Texture2D>& desktopTexture)
|
||||
{
|
||||
auto monitor = duplicator->GetMonitor();
|
||||
|
||||
// Check desktop texure
|
||||
if (monitor->GetUnityTexture() == nullptr)
|
||||
if (desktopTexture == nullptr)
|
||||
{
|
||||
Debug::Error("Cursor::UpdateTexture() => Monitor::GetUnityTexture() is null.");
|
||||
Debug::Error("Cursor::UpdateTexture() => Desktop texture is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ void Cursor::Draw(Monitor* monitor)
|
||||
// Check buffers
|
||||
if (!bgraBuffer_ || !buffer_)
|
||||
{
|
||||
Debug::Error("Cursor::UpdateTexture() => no buffer.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -193,7 +194,7 @@ void Cursor::Draw(Monitor* monitor)
|
||||
return;
|
||||
}
|
||||
|
||||
D3D11_BOX capturedImageArea
|
||||
capturedImageArea_ = D3D11_BOX
|
||||
{
|
||||
static_cast<UINT>(capturedImageLeft),
|
||||
static_cast<UINT>(capturedImageTop),
|
||||
@@ -219,7 +220,7 @@ void Cursor::Draw(Monitor* monitor)
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
if (FAILED(GetDevice()->CreateTexture2D(&desc, nullptr, &texture)))
|
||||
if (FAILED(duplicator->GetDevice()->CreateTexture2D(&desc, nullptr, &texture)))
|
||||
{
|
||||
Debug::Error("Cursor::UpdateTexture() => GetDevice()->CreateTexture2D() failed.");
|
||||
return;
|
||||
@@ -229,8 +230,8 @@ void Cursor::Draw(Monitor* monitor)
|
||||
// Copy desktop image to the texture
|
||||
{
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, monitor->GetUnityTexture(), 0, &capturedImageArea);
|
||||
duplicator->GetDevice()->GetImmediateContext(&context);
|
||||
context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, desktopTexture.Get(), 0, &capturedImageArea_);
|
||||
}
|
||||
|
||||
// Get mapped surface to access pixels in CPU
|
||||
@@ -358,12 +359,6 @@ void Cursor::Draw(Monitor* monitor)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->UpdateSubresource(monitor->GetUnityTexture(), 0, &capturedImageArea, bgraBuffer_.Get(), capturedImageWidth * 4, 0);
|
||||
}
|
||||
|
||||
if (FAILED(surface->Unmap()))
|
||||
{
|
||||
Debug::Error("Cursor::UpdateTexture() => surface->Unmap() failed.");
|
||||
@@ -372,6 +367,21 @@ void Cursor::Draw(Monitor* monitor)
|
||||
}
|
||||
|
||||
|
||||
void Cursor::Draw(const Microsoft::WRL::ComPtr<ID3D11Texture2D>& texture)
|
||||
{
|
||||
if (texture == nullptr)
|
||||
{
|
||||
Debug::Error("Cursor::UpdateTexture() => Desktop texture is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto capturedImageWidth = capturedImageArea_.right - capturedImageArea_.left;
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->UpdateSubresource(texture.Get(), 0, &capturedImageArea_, bgraBuffer_.Get(), capturedImageWidth * 4, 0);
|
||||
}
|
||||
|
||||
|
||||
void Cursor::GetTexture(ID3D11Texture2D* texture)
|
||||
{
|
||||
if (!bgraBuffer_)
|
||||
|
||||
@@ -2,18 +2,25 @@
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <wrl/client.h>
|
||||
#include <memory>
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
class Monitor;
|
||||
class Duplicator;
|
||||
|
||||
class Cursor
|
||||
{
|
||||
public:
|
||||
explicit Cursor();
|
||||
~Cursor();
|
||||
void UpdateBuffer(Monitor* monitor, const DXGI_OUTDUPL_FRAME_INFO& frameInfo);
|
||||
void Draw(Monitor* monitor);
|
||||
void UpdateBuffer(
|
||||
Duplicator* duplicator,
|
||||
const DXGI_OUTDUPL_FRAME_INFO& frameInfo);
|
||||
void UpdateTexture(
|
||||
Duplicator* duplicator,
|
||||
const Microsoft::WRL::ComPtr<ID3D11Texture2D>& desktopTexture);
|
||||
void Draw(const Microsoft::WRL::ComPtr<ID3D11Texture2D>& texture);
|
||||
void GetTexture(ID3D11Texture2D* texture);
|
||||
|
||||
bool IsVisible() const;
|
||||
@@ -32,4 +39,5 @@ private:
|
||||
Buffer<BYTE> bgraBuffer_;
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo_;
|
||||
LARGE_INTEGER timestamp_;
|
||||
D3D11_BOX capturedImageArea_;
|
||||
};
|
||||
@@ -4,12 +4,14 @@
|
||||
#include "Debug.h"
|
||||
|
||||
|
||||
|
||||
decltype(Debug::isInitialized_) Debug::isInitialized_ = false;
|
||||
decltype(Debug::mode_) Debug::mode_ = Debug::Mode::File;
|
||||
decltype(Debug::logFunc_) Debug::logFunc_ = nullptr;
|
||||
decltype(Debug::errFunc_) Debug::errFunc_ = nullptr;
|
||||
decltype(Debug::fs_) Debug::fs_;
|
||||
decltype(Debug::ss_) Debug::ss_;
|
||||
decltype(Debug::mutex_) Debug::mutex_;
|
||||
|
||||
|
||||
void Debug::Initialize()
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <mutex>
|
||||
|
||||
#include "Common.h"
|
||||
#include "IUnityInterface.h"
|
||||
|
||||
|
||||
// Debug flag
|
||||
#define UDD_DEBUG_ON
|
||||
|
||||
|
||||
// Logging
|
||||
class Debug
|
||||
{
|
||||
@@ -107,6 +116,7 @@ public:
|
||||
template <class Arg, class... RestArgs>
|
||||
static void Log(Arg&& arg, RestArgs&&... restArgs)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
Output("[uDD::Log]");
|
||||
OutputTime();
|
||||
Output(" ");
|
||||
@@ -116,6 +126,7 @@ public:
|
||||
template <class Arg, class... RestArgs>
|
||||
static void Error(Arg&& arg, RestArgs&&... restArgs)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
Output("[uDD::Err]");
|
||||
OutputTime();
|
||||
Output(" ");
|
||||
@@ -129,4 +140,22 @@ private:
|
||||
static std::ostringstream ss_;
|
||||
static DebugLogFuncPtr logFunc_;
|
||||
static DebugLogFuncPtr errFunc_;
|
||||
};
|
||||
static std::mutex mutex_;
|
||||
};
|
||||
|
||||
|
||||
#ifdef UDD_DEBUG_ON
|
||||
#define UDD_FUNCTION_SCOPE_TIMER \
|
||||
ScopedTimer _timer_##__COUNTER__([](std::chrono::microseconds us) \
|
||||
{ \
|
||||
Debug::Log(__FUNCTION__, "@", __FILE__, ":", __LINE__, " => ", us.count(), " [us]"); \
|
||||
});
|
||||
#define UDD_SCOPE_TIMER(Name) \
|
||||
ScopedTimer _timer_##__COUNTER__([](std::chrono::microseconds us) \
|
||||
{ \
|
||||
Debug::Log(#Name, " => ", us.count(), " [us]"); \
|
||||
});
|
||||
#else
|
||||
#define UDD_FUNCTION_SCOPE_TIMER
|
||||
#define UDD_SCOPE_TIMER(Name)
|
||||
#endif
|
||||
97
Plugins/uDesktopDuplication/uDesktopDuplication/Device.cpp
Normal file
97
Plugins/uDesktopDuplication/uDesktopDuplication/Device.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include <d3d11.h>
|
||||
|
||||
#include "IUnityInterface.h"
|
||||
#include "IUnityGraphicsD3D11.h"
|
||||
#include "Device.h"
|
||||
#include "Debug.h"
|
||||
#include "Common.h"
|
||||
|
||||
#pragma comment(lib, "d3d11.lib")
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
|
||||
|
||||
IsolatedD3D11Device::IsolatedD3D11Device()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
IsolatedD3D11Device::~IsolatedD3D11Device()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
HRESULT IsolatedD3D11Device::Create(const ComPtr<IDXGIAdapter>& adapter)
|
||||
{
|
||||
const auto driverType = adapter ?
|
||||
D3D_DRIVER_TYPE_UNKNOWN :
|
||||
D3D_DRIVER_TYPE_HARDWARE;
|
||||
const auto flags =
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT; // D2D Compatible
|
||||
// | D3D11_CREATE_DEVICE_VIDEO_SUPPORT // MediaFoundation
|
||||
const D3D_FEATURE_LEVEL featureLevelsRequested[] =
|
||||
{
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
D3D_FEATURE_LEVEL_10_1,
|
||||
D3D_FEATURE_LEVEL_10_0,
|
||||
D3D_FEATURE_LEVEL_9_3,
|
||||
D3D_FEATURE_LEVEL_9_2,
|
||||
D3D_FEATURE_LEVEL_9_1
|
||||
};
|
||||
const UINT numLevelsRequested = sizeof(featureLevelsRequested) / sizeof(D3D_FEATURE_LEVEL);
|
||||
D3D_FEATURE_LEVEL featureLevelsSupported;
|
||||
|
||||
return D3D11CreateDevice(
|
||||
adapter.Get(),
|
||||
driverType,
|
||||
nullptr,
|
||||
flags,
|
||||
featureLevelsRequested,
|
||||
numLevelsRequested,
|
||||
D3D11_SDK_VERSION,
|
||||
&device_,
|
||||
&featureLevelsSupported,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
|
||||
ComPtr<ID3D11Device> IsolatedD3D11Device::GetDevice()
|
||||
{
|
||||
return device_;
|
||||
}
|
||||
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> IsolatedD3D11Device::GetCompatibleSharedTexture(
|
||||
const ComPtr<ID3D11Texture2D>& src)
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC srcDesc;
|
||||
src->GetDesc(&srcDesc);
|
||||
|
||||
// check if the format and size of the current texture are same as the source one
|
||||
if (cachedSharedTexture_)
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC targetDesc;
|
||||
cachedSharedTexture_->GetDesc(&targetDesc);
|
||||
if (targetDesc.Format == srcDesc.Format &&
|
||||
targetDesc.Width == srcDesc.Width &&
|
||||
targetDesc.Height == srcDesc.Height)
|
||||
{
|
||||
return cachedSharedTexture_;
|
||||
}
|
||||
}
|
||||
|
||||
// for sharing this texture with unity device
|
||||
srcDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
|
||||
|
||||
if (FAILED(device_->CreateTexture2D(&srcDesc, nullptr, &cachedSharedTexture_)))
|
||||
{
|
||||
Debug::Error("IsolatedD3D11Device::GetCompatibleSharedTexture() => Creating shared texture failed.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return cachedSharedTexture_;
|
||||
}
|
||||
25
Plugins/uDesktopDuplication/uDesktopDuplication/Device.h
Normal file
25
Plugins/uDesktopDuplication/uDesktopDuplication/Device.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <d3d11.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
|
||||
// Thraed safe self created ID3D11Device from specified adapter
|
||||
class IsolatedD3D11Device
|
||||
{
|
||||
public:
|
||||
IsolatedD3D11Device();
|
||||
~IsolatedD3D11Device();
|
||||
|
||||
HRESULT Create(const Microsoft::WRL::ComPtr<IDXGIAdapter>& adapter);
|
||||
Microsoft::WRL::ComPtr<ID3D11Device> GetDevice();
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> GetCompatibleSharedTexture(
|
||||
const Microsoft::WRL::ComPtr<ID3D11Texture2D>& src);
|
||||
|
||||
private:
|
||||
Microsoft::WRL::ComPtr<ID3D11Device> device_;
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> cachedSharedTexture_;
|
||||
};
|
||||
468
Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.cpp
Normal file
468
Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.cpp
Normal file
@@ -0,0 +1,468 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "Duplicator.h"
|
||||
#include "Monitor.h"
|
||||
#include "MonitorManager.h"
|
||||
#include "Cursor.h"
|
||||
#include "Device.h"
|
||||
#include "Debug.h"
|
||||
|
||||
#include "IUnityInterface.h"
|
||||
#include "IUnityGraphicsD3D11.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
|
||||
|
||||
Duplicator::Duplicator(Monitor* monitor)
|
||||
: monitor_(monitor)
|
||||
{
|
||||
InitializeDevice();
|
||||
InitializeDuplication();
|
||||
CheckUnityAdapter();
|
||||
}
|
||||
|
||||
|
||||
Duplicator::~Duplicator()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
|
||||
void Duplicator::InitializeDevice()
|
||||
{
|
||||
device_ = std::make_shared<IsolatedD3D11Device>();
|
||||
|
||||
if (FAILED(device_->Create(monitor_->GetAdapter())))
|
||||
{
|
||||
Debug::Error("Monitor::Initialize() => IsolatedD3D11Device::Create() failed.");
|
||||
state_ = State::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Duplicator::InitializeDuplication()
|
||||
{
|
||||
ComPtr<IDXGIOutput1> output1;
|
||||
if (FAILED(monitor_->GetOutput().As(&output1)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto hr = output1->DuplicateOutput(device_->GetDevice().Get(), &dupl_);
|
||||
switch (hr)
|
||||
{
|
||||
case S_OK:
|
||||
{
|
||||
state_ = State::Ready;
|
||||
const auto rot = static_cast<DXGI_MODE_ROTATION>(monitor_->GetRotation());
|
||||
Debug::Log("Duplicator::Initialize() => OK.");
|
||||
Debug::Log(" ID : ", monitor_->GetId());
|
||||
Debug::Log(" Size : (", monitor_->GetWidth(), ", ", monitor_->GetHeight(), ")");
|
||||
Debug::Log(" DPI : (", monitor_->GetDpiX(), ", ", monitor_->GetDpiY(), ")");
|
||||
Debug::Log(" Rot : ",
|
||||
rot == DXGI_MODE_ROTATION_IDENTITY ? "Landscape" :
|
||||
rot == DXGI_MODE_ROTATION_ROTATE90 ? "Portrait" :
|
||||
rot == DXGI_MODE_ROTATION_ROTATE180 ? "Landscape (flipped)" :
|
||||
rot == DXGI_MODE_ROTATION_ROTATE270 ? "Portrait (flipped)" :
|
||||
"Unspecified");
|
||||
break;
|
||||
}
|
||||
case E_INVALIDARG:
|
||||
{
|
||||
state_ = State::InvalidArg;
|
||||
Debug::Error("Duplicator::Initialize() => Invalid arguments.");
|
||||
break;
|
||||
}
|
||||
case E_ACCESSDENIED:
|
||||
{
|
||||
// For example, when the user presses Ctrl + Alt + Delete and the screen
|
||||
// switches to admin screen, this error occurs.
|
||||
state_ = State::AccessDenied;
|
||||
Debug::Error("Duplicator::Initialize() => Access denied.");
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_UNSUPPORTED:
|
||||
{
|
||||
// If the display adapter on the computer is running under the Microsoft Hybrid system,
|
||||
// this error occurs.
|
||||
state_ = State::Unsupported;
|
||||
Debug::Error("Duplicator::Initialize() => Unsupported display.");
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
|
||||
{
|
||||
// When other application use Desktop Duplication API, this error occurs.
|
||||
state_ = State::CurrentlyNotAvailable;
|
||||
Debug::Error("Duplicator::Initialize() => Currently not available.");
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_SESSION_DISCONNECTED:
|
||||
{
|
||||
state_ = State::SessionDisconnected;
|
||||
Debug::Error("Duplicator::Initialize() => Session disconnected.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
state_ = State::Unknown;
|
||||
Debug::Error("Duplicator::Render() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Duplicator::CheckUnityAdapter()
|
||||
{
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
monitor_->GetAdapter()->GetDesc(&desc);
|
||||
|
||||
const auto unityAdapterLuid = GetUnityAdapterLuid();
|
||||
const auto isUnityAdapter =
|
||||
(desc.AdapterLuid.LowPart == unityAdapterLuid.LowPart) &&
|
||||
(desc.AdapterLuid.HighPart == unityAdapterLuid.HighPart);
|
||||
|
||||
if (!isUnityAdapter)
|
||||
{
|
||||
Debug::Error("Duplicator::CheckUnityAdapter() => The adapter is not same as Unity, and now this case is not supported.");
|
||||
state_ = State::Unsupported;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Duplicator::Start()
|
||||
{
|
||||
if (state_ != State::Ready) return;
|
||||
|
||||
Stop();
|
||||
|
||||
thread_ = std::thread([this]
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
state_ = State::Running;
|
||||
|
||||
shouldRun_ = true;
|
||||
while (shouldRun_)
|
||||
{
|
||||
const auto frameRate = GetMonitorManager()->GetFrameRate();
|
||||
const UINT frameMicroSeconds = 1000000 / frameRate;
|
||||
const UINT frameMilliSeconds = 1000 / frameRate;
|
||||
|
||||
ScopedTimer timer([frameMicroSeconds] (microseconds us)
|
||||
{
|
||||
const auto waitTime = microseconds(frameMicroSeconds) - us;
|
||||
if (waitTime > microseconds::zero())
|
||||
{
|
||||
std::this_thread::sleep_for(waitTime);
|
||||
}
|
||||
});
|
||||
|
||||
const auto timeout = static_cast<UINT>(frameMilliSeconds);
|
||||
Duplicate(timeout);
|
||||
|
||||
if (state_ != State::Running)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state_ == State::Running)
|
||||
{
|
||||
state_ = State::Ready;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Duplicator::Stop()
|
||||
{
|
||||
shouldRun_ = false;
|
||||
|
||||
if (thread_.joinable())
|
||||
{
|
||||
thread_.join();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Duplicator::IsRunning() const
|
||||
{
|
||||
return state_ == State::Running;
|
||||
}
|
||||
|
||||
|
||||
bool Duplicator::IsError() const
|
||||
{
|
||||
return
|
||||
state_ != State::Ready &&
|
||||
state_ != State::Running;
|
||||
}
|
||||
|
||||
|
||||
Duplicator::State Duplicator::GetState() const
|
||||
{
|
||||
return state_;
|
||||
}
|
||||
|
||||
|
||||
Monitor* Duplicator::GetMonitor() const
|
||||
{
|
||||
return monitor_;
|
||||
}
|
||||
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11Device> Duplicator::GetDevice()
|
||||
{
|
||||
return device_->GetDevice();
|
||||
}
|
||||
|
||||
|
||||
ComPtr<IDXGIOutputDuplication> Duplicator::GetDuplication()
|
||||
{
|
||||
return dupl_;
|
||||
}
|
||||
|
||||
|
||||
const Duplicator::Frame& Duplicator::GetLastFrame() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return lastFrame_;
|
||||
}
|
||||
|
||||
|
||||
void Duplicator::Duplicate(UINT timeout)
|
||||
{
|
||||
if (!dupl_ || !device_) return;
|
||||
|
||||
Release();
|
||||
|
||||
ComPtr<IDXGIResource> resource;
|
||||
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
||||
const auto hr = dupl_->AcquireNextFrame(timeout, &frameInfo, &resource);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
switch (hr)
|
||||
{
|
||||
case DXGI_ERROR_ACCESS_LOST:
|
||||
{
|
||||
// If any monitor setting has changed (e.g. monitor size has changed),
|
||||
// it is necessary to re-initialize monitors.
|
||||
Debug::Log("Duplicator::Duplicate() => DXGI_ERROR_ACCESS_LOST.");
|
||||
state_ = State::AccessLost;
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_WAIT_TIMEOUT:
|
||||
{
|
||||
// This often occurs when timeout value is small and it is not problem.
|
||||
// Debug::Log("Duplicator::Duplicate() => DXGI_ERROR_WAIT_TIMEOUT.");
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_INVALID_CALL:
|
||||
{
|
||||
Debug::Error("Duplicator::Duplicate() => DXGI_ERROR_INVALID_CALL.");
|
||||
break;
|
||||
}
|
||||
case E_INVALIDARG:
|
||||
{
|
||||
Debug::Error("Duplicator::Duplicate() => E_INVALIDARG.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
state_ = State::Unknown;
|
||||
Debug::Error("Duplicator::Duplicate() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
isFrameAcquired_ = true;
|
||||
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
if (FAILED(resource.As(&texture)))
|
||||
{
|
||||
Debug::Error("Duplicator::Duplicate() => IDXGIResource could not be converted to ID3D11Texture2D.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto sharedTexture = device_->GetCompatibleSharedTexture(texture);
|
||||
if (!sharedTexture)
|
||||
{
|
||||
Debug::Error("Duplicator::Duplicate() => Shared texture is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
device_->GetDevice()->GetImmediateContext(&context);
|
||||
context->CopyResource(sharedTexture.Get(), texture.Get());
|
||||
}
|
||||
|
||||
UpdateCursor(sharedTexture, frameInfo);
|
||||
UpdateMetadata(frameInfo.TotalMetadataBufferSize);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
lastFrame_ = Frame
|
||||
{
|
||||
lastFrameId_++,
|
||||
sharedTexture,
|
||||
frameInfo,
|
||||
metaData_
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Duplicator::Release()
|
||||
{
|
||||
if (!isFrameAcquired_) return;
|
||||
|
||||
const auto hr = dupl_->ReleaseFrame();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
switch (hr)
|
||||
{
|
||||
case DXGI_ERROR_ACCESS_LOST:
|
||||
{
|
||||
Debug::Log("Duplicator::Duplicate() => DXGI_ERROR_ACCESS_LOST.");
|
||||
state_ = State::AccessLost;
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_INVALID_CALL:
|
||||
{
|
||||
Debug::Error("Duplicator::Duplicate() => DXGI_ERROR_INVALID_CALL.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
state_ = State::Unknown;
|
||||
Debug::Error("Duplicator::Duplicate() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isFrameAcquired_ = false;
|
||||
}
|
||||
|
||||
|
||||
void Duplicator::UpdateCursor(
|
||||
const ComPtr<ID3D11Texture2D>& texture,
|
||||
const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
|
||||
{
|
||||
auto& manager = GetMonitorManager();
|
||||
|
||||
if (frameInfo.PointerPosition.Visible)
|
||||
{
|
||||
manager->SetCursorMonitorId(monitor_->GetId());
|
||||
}
|
||||
|
||||
if (monitor_->GetId() == manager->GetCursorMonitorId())
|
||||
{
|
||||
auto cursor = manager->GetCursor();
|
||||
cursor->UpdateBuffer(this, frameInfo);
|
||||
cursor->UpdateTexture(this, texture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Duplicator::UpdateMetadata(UINT totalBufferSize)
|
||||
{
|
||||
metaData_.buffer.ExpandIfNeeded(totalBufferSize);
|
||||
if (!metaData_.buffer.Empty())
|
||||
{
|
||||
UpdateMoveRects();
|
||||
UpdateDirtyRects();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Duplicator::UpdateMoveRects()
|
||||
{
|
||||
const auto hr = dupl_->GetFrameMoveRects(
|
||||
metaData_.buffer.Size(),
|
||||
metaData_.buffer.As<DXGI_OUTDUPL_MOVE_RECT>(),
|
||||
&metaData_.moveRectSize);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
switch (hr)
|
||||
{
|
||||
case DXGI_ERROR_ACCESS_LOST:
|
||||
{
|
||||
Debug::Log("Duplicator::UpdateMoveRects() => DXGI_ERROR_ACCESS_LOST.");
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_MORE_DATA:
|
||||
{
|
||||
Debug::Error("Duplicator::UpdateMoveRects() => DXGI_ERROR_MORE_DATA.");
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_INVALID_CALL:
|
||||
{
|
||||
Debug::Error("Duplicator::UpdateMoveRects() => DXGI_ERROR_INVALID_CALL.");
|
||||
break;
|
||||
}
|
||||
case E_INVALIDARG:
|
||||
{
|
||||
Debug::Error("Duplicator::UpdateMoveRects() => E_INVALIDARG.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Debug::Error("Duplicator::UpdateMoveRects() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Duplicator::UpdateDirtyRects()
|
||||
{
|
||||
const auto hr = dupl_->GetFrameDirtyRects(
|
||||
metaData_.buffer.Size() - metaData_.moveRectSize,
|
||||
metaData_.buffer.As<RECT>(metaData_.moveRectSize /* offset */),
|
||||
&metaData_.dirtyRectSize);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
switch (hr)
|
||||
{
|
||||
case DXGI_ERROR_ACCESS_LOST:
|
||||
{
|
||||
Debug::Log("Duplicator::UpdateDirtyRects() => DXGI_ERROR_ACCESS_LOST.");
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_MORE_DATA:
|
||||
{
|
||||
Debug::Error("Duplicator::UpdateDirtyRects() => DXGI_ERROR_MORE_DATA.");
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_INVALID_CALL:
|
||||
{
|
||||
Debug::Error("Duplicator::UpdateDirtyRects() => DXGI_ERROR_INVALID_CALL.");
|
||||
break;
|
||||
}
|
||||
case E_INVALIDARG:
|
||||
{
|
||||
Debug::Error("Duplicator::UpdateDirtyRects() => E_INVALIDARG.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Debug::Error("Duplicator::UpdateDirtyRects() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
94
Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.h
Normal file
94
Plugins/uDesktopDuplication/uDesktopDuplication/Duplicator.h
Normal file
@@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <wrl/client.h>
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
|
||||
class Monitor;
|
||||
|
||||
|
||||
enum class DuplicatorState
|
||||
{
|
||||
NotSet = -1,
|
||||
Ready = 0,
|
||||
Running = 1,
|
||||
InvalidArg = 2,
|
||||
AccessDenied = 3,
|
||||
Unsupported = 4,
|
||||
CurrentlyNotAvailable = 5,
|
||||
SessionDisconnected = 6,
|
||||
AccessLost = 7,
|
||||
TextureSizeInconsistent = 8,
|
||||
Unknown = 999,
|
||||
};
|
||||
|
||||
|
||||
class Duplicator
|
||||
{
|
||||
public:
|
||||
using State = DuplicatorState;
|
||||
|
||||
struct Metadata
|
||||
{
|
||||
Buffer<BYTE> buffer;
|
||||
UINT moveRectSize = 0;
|
||||
UINT dirtyRectSize = 0;
|
||||
};
|
||||
|
||||
struct Frame
|
||||
{
|
||||
UINT id;
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture;
|
||||
DXGI_OUTDUPL_FRAME_INFO info;
|
||||
Metadata metaData;
|
||||
};
|
||||
|
||||
explicit Duplicator(Monitor* monitor);
|
||||
~Duplicator();
|
||||
void Start();
|
||||
void Stop();
|
||||
bool IsRunning() const;
|
||||
bool IsError() const;
|
||||
State GetState() const;
|
||||
Monitor* GetMonitor() const;
|
||||
Microsoft::WRL::ComPtr<ID3D11Device> GetDevice();
|
||||
Microsoft::WRL::ComPtr<IDXGIOutputDuplication> GetDuplication();
|
||||
const Frame& GetLastFrame() const;
|
||||
|
||||
private:
|
||||
void InitializeDevice();
|
||||
void InitializeDuplication();
|
||||
void CheckUnityAdapter();
|
||||
|
||||
void Duplicate(UINT timeout);
|
||||
void Release();
|
||||
|
||||
void UpdateCursor(
|
||||
const Microsoft::WRL::ComPtr<ID3D11Texture2D>& texture,
|
||||
const DXGI_OUTDUPL_FRAME_INFO& frameInfo);
|
||||
void UpdateMetadata(UINT totalBufferSize);
|
||||
void UpdateMoveRects();
|
||||
void UpdateDirtyRects();
|
||||
|
||||
Monitor* monitor_ = nullptr;
|
||||
std::atomic<State> state_ = State::Ready;
|
||||
|
||||
std::shared_ptr<class IsolatedD3D11Device> device_;
|
||||
Microsoft::WRL::ComPtr<IDXGIOutputDuplication> dupl_;
|
||||
Frame lastFrame_;
|
||||
UINT lastFrameId_ = 0;
|
||||
bool isFrameAcquired_ = false;
|
||||
|
||||
volatile bool shouldRun_ = false;
|
||||
std::thread thread_;
|
||||
mutable std::mutex mutex_;
|
||||
|
||||
Metadata metaData_;
|
||||
};
|
||||
@@ -1,348 +1,131 @@
|
||||
#include <d3d11.h>
|
||||
#include <ShellScalingAPI.h>
|
||||
#include <queue>
|
||||
#include "Monitor.h"
|
||||
#include "Duplicator.h"
|
||||
#include "Debug.h"
|
||||
#include "Cursor.h"
|
||||
#include "MonitorManager.h"
|
||||
#include "Monitor.h"
|
||||
#include "Device.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
|
||||
|
||||
Monitor::Monitor(int id)
|
||||
: id_(id)
|
||||
{
|
||||
ZeroMemory(&monitorInfo_, sizeof(monitorInfo_));
|
||||
}
|
||||
|
||||
|
||||
Monitor::~Monitor()
|
||||
{
|
||||
if (deskDupl_)
|
||||
{
|
||||
deskDupl_->Release();
|
||||
deskDupl_ = nullptr;
|
||||
}
|
||||
duplicator_->Stop();
|
||||
}
|
||||
|
||||
|
||||
void Monitor::Initialize(IDXGIOutput* output)
|
||||
void Monitor::Initialize(
|
||||
const ComPtr<IDXGIAdapter> &adapter,
|
||||
const ComPtr<IDXGIOutput> &output
|
||||
)
|
||||
{
|
||||
if (FAILED(output->GetDesc(&outputDesc_)))
|
||||
adapter_ = adapter;
|
||||
output_ = output;
|
||||
|
||||
if (FAILED(output->GetDesc(&outputDesc_)))
|
||||
{
|
||||
Debug::Error("Monitor::Initialize() => IDXGIOutput::GetDesc() failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
monitorInfo_.cbSize = sizeof(MONITORINFOEX);
|
||||
if (!GetMonitorInfo(outputDesc_.Monitor, &monitorInfo_))
|
||||
{
|
||||
Debug::Error("Monitor::Initialize() => GetMonitorInfo() failed.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto rect = monitorInfo_.rcMonitor;
|
||||
width_ = rect.right - rect.left;
|
||||
height_ = rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
duplicator_ = std::make_shared<Duplicator>(this);
|
||||
}
|
||||
|
||||
|
||||
void Monitor::Finalize()
|
||||
{
|
||||
StopCapture();
|
||||
}
|
||||
|
||||
|
||||
void Monitor::Render()
|
||||
{
|
||||
const auto& frame = duplicator_->GetLastFrame();
|
||||
|
||||
if (frame.id == lastFrameId_) return;
|
||||
lastFrameId_ = frame.id;
|
||||
|
||||
if (unityTexture_ == nullptr)
|
||||
{
|
||||
Debug::Error("Monitor::Initialize() => IDXGIOutput::GetDesc() failed.");
|
||||
Debug::Error("Monitor::Render() => Target texture has not been set yet..");
|
||||
return;
|
||||
}
|
||||
|
||||
monitorInfo_.cbSize = sizeof(MONITORINFOEX);
|
||||
if (!GetMonitorInfo(outputDesc_.Monitor, &monitorInfo_))
|
||||
D3D11_TEXTURE2D_DESC srcDesc, dstDesc;
|
||||
frame.texture->GetDesc(&srcDesc);
|
||||
unityTexture_->GetDesc(&dstDesc);
|
||||
if (srcDesc.Width != dstDesc.Width ||
|
||||
srcDesc.Height != dstDesc.Height)
|
||||
{
|
||||
Debug::Error("Monitor::Initialize() => GetMonitorInfo() failed.");
|
||||
Debug::Error("Monitor::Render() => Texture sizes are defferent.");
|
||||
Debug::Error(" Source : (", srcDesc.Width, ", ", srcDesc.Height, ")");
|
||||
Debug::Error(" Dest : (", dstDesc.Width, ", ", dstDesc.Height, ")");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto rect = monitorInfo_.rcMonitor;
|
||||
width_ = rect.right - rect.left;
|
||||
height_ = rect.bottom - rect.top;
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopyResource(unityTexture_, frame.texture.Get());
|
||||
|
||||
auto& manager = GetMonitorManager();
|
||||
if (id_ == manager->GetCursorMonitorId())
|
||||
{
|
||||
manager->GetCursor()->Draw(unityTexture_);
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
if (UseGetPixels())
|
||||
{
|
||||
CopyTextureFromGpuToCpu(unityTexture_);
|
||||
}
|
||||
|
||||
auto output1 = reinterpret_cast<IDXGIOutput1*>(output);
|
||||
switch (output1->DuplicateOutput(GetDevice().Get(), &deskDupl_))
|
||||
hasBeenUpdated_ = true;
|
||||
}
|
||||
|
||||
|
||||
void Monitor::StartCapture()
|
||||
{
|
||||
if (duplicator_->GetState() == DuplicatorState::Ready)
|
||||
{
|
||||
case S_OK:
|
||||
{
|
||||
state_ = State::Available;
|
||||
const auto rot = static_cast<DXGI_MODE_ROTATION>(GetRotation());
|
||||
Debug::Log("Monitor::Initialize() => OK.");
|
||||
Debug::Log(" ID : ", GetId());
|
||||
Debug::Log(" Size : (", GetWidth(), ", ", GetHeight(), ")");
|
||||
Debug::Log(" DPI : (", GetDpiX(), ", ", GetDpiY(), ")");
|
||||
Debug::Log(" Rot : ",
|
||||
rot == DXGI_MODE_ROTATION_IDENTITY ? "Landscape" :
|
||||
rot == DXGI_MODE_ROTATION_ROTATE90 ? "Portrait" :
|
||||
rot == DXGI_MODE_ROTATION_ROTATE180 ? "Landscape (flipped)" :
|
||||
rot == DXGI_MODE_ROTATION_ROTATE270 ? "Portrait (flipped)" :
|
||||
"Unspecified");
|
||||
break;
|
||||
}
|
||||
case E_INVALIDARG:
|
||||
{
|
||||
state_ = State::InvalidArg;
|
||||
Debug::Error("Monitor::Initialize() => Invalid arguments.");
|
||||
break;
|
||||
}
|
||||
case E_ACCESSDENIED:
|
||||
{
|
||||
// For example, when the user presses Ctrl + Alt + Delete and the screen
|
||||
// switches to admin screen, this error occurs.
|
||||
state_ = State::AccessDenied;
|
||||
Debug::Error("Monitor::Initialize() => Access denied.");
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_UNSUPPORTED:
|
||||
{
|
||||
// If the display adapter on the computer is running under the Microsoft Hybrid system,
|
||||
// this error occurs.
|
||||
state_ = State::Unsupported;
|
||||
Debug::Error("Monitor::Initialize() => Unsupported display.");
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
|
||||
{
|
||||
// When other application use Desktop Duplication API, this error occurs.
|
||||
state_ = State::CurrentlyNotAvailable;
|
||||
Debug::Error("Monitor::Initialize() => Currently not available.");
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_SESSION_DISCONNECTED:
|
||||
{
|
||||
state_ = State::SessionDisconnected;
|
||||
Debug::Error("Monitor::Initialize() => Session disconnected.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
state_ = State::Unknown;
|
||||
Debug::Error("Monitor::Render() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
duplicator_->Start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Monitor::Render(UINT timeout)
|
||||
void Monitor::StopCapture()
|
||||
{
|
||||
if (!deskDupl_) return;
|
||||
|
||||
HRESULT hr;
|
||||
ComPtr<IDXGIResource> resource;
|
||||
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
||||
|
||||
hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
switch (hr)
|
||||
{
|
||||
case DXGI_ERROR_ACCESS_LOST:
|
||||
{
|
||||
// If any monitor setting has changed (e.g. monitor size has changed),
|
||||
// it is necessary to re-initialize monitors.
|
||||
Debug::Log("Monitor::Render() => DXGI_ERROR_ACCESS_LOST.");
|
||||
state_ = State::AccessLost;
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_WAIT_TIMEOUT:
|
||||
{
|
||||
// This often occurs when timeout value is small and it is not problem.
|
||||
// Debug::Log("Monitor::Render() => DXGI_ERROR_WAIT_TIMEOUT.");
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_INVALID_CALL:
|
||||
{
|
||||
Debug::Error("Monitor::Render() => DXGI_ERROR_INVALID_CALL.");
|
||||
break;
|
||||
}
|
||||
case E_INVALIDARG:
|
||||
{
|
||||
Debug::Error("Monitor::Render() => E_INVALIDARG.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
state_ = State::Unknown;
|
||||
Debug::Error("Monitor::Render() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ID3D11Texture2D* texture;
|
||||
if (FAILED(resource.CopyTo(&texture)))
|
||||
{
|
||||
Debug::Error("Monitor::Render() => resource.As() failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get texture
|
||||
if (unityTexture_)
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC srcDesc, dstDesc;
|
||||
texture->GetDesc(&srcDesc);
|
||||
unityTexture_->GetDesc(&dstDesc);
|
||||
if (srcDesc.Width != dstDesc.Width ||
|
||||
srcDesc.Height != dstDesc.Height)
|
||||
{
|
||||
Debug::Error("Monitor::Render() => Texture sizes are defferent.");
|
||||
Debug::Error(" Source : (", srcDesc.Width, ", ", srcDesc.Height, ")");
|
||||
Debug::Error(" Dest : (", dstDesc.Width, ", ", dstDesc.Height, ")");
|
||||
//Debug::Log(" => Try modifying width/height using reported value from DDA.");
|
||||
//width_ = srcDesc.Width;
|
||||
//height_ = srcDesc.Height;
|
||||
state_ = MonitorState::TextureSizeInconsistent;
|
||||
//SendMessageToUnity(Message::TextureSizeChanged);
|
||||
}
|
||||
else
|
||||
{
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopyResource(unityTexture_, texture);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateMetadata(frameInfo);
|
||||
|
||||
if (frameInfo.PointerPosition.Visible)
|
||||
{
|
||||
GetMonitorManager()->SetCursorMonitorId(id_);
|
||||
}
|
||||
|
||||
if (GetMonitorManager()->GetCursorMonitorId() == id_)
|
||||
{
|
||||
UpdateCursor(frameInfo);
|
||||
}
|
||||
|
||||
if (UseGetPixels())
|
||||
{
|
||||
CopyTextureFromGpuToCpu(texture);
|
||||
}
|
||||
|
||||
hr = deskDupl_->ReleaseFrame();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
switch (hr)
|
||||
{
|
||||
case DXGI_ERROR_ACCESS_LOST:
|
||||
{
|
||||
Debug::Log("Monitor::Render() => DXGI_ERROR_ACCESS_LOST.");
|
||||
state_ = State::AccessLost;
|
||||
break;
|
||||
}
|
||||
case DXGI_ERROR_INVALID_CALL:
|
||||
{
|
||||
Debug::Error("Monitor::Render() => DXGI_ERROR_INVALID_CALL.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
state_ = State::Unknown;
|
||||
Debug::Error("Monitor::Render() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
hasBeenUpdated_ = true;
|
||||
}
|
||||
|
||||
|
||||
void Monitor::UpdateCursor(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
|
||||
{
|
||||
auto cursor_ = GetMonitorManager()->GetCursor();
|
||||
cursor_->UpdateBuffer(this, frameInfo);
|
||||
cursor_->Draw(this);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
duplicator_->Stop();
|
||||
}
|
||||
|
||||
|
||||
@@ -352,9 +135,21 @@ int Monitor::GetId() const
|
||||
}
|
||||
|
||||
|
||||
MonitorState Monitor::GetState() const
|
||||
ComPtr<struct IDXGIAdapter> Monitor::GetAdapter()
|
||||
{
|
||||
return state_;
|
||||
return adapter_;
|
||||
}
|
||||
|
||||
|
||||
ComPtr<struct IDXGIOutput> Monitor::GetOutput()
|
||||
{
|
||||
return output_;
|
||||
}
|
||||
|
||||
|
||||
DuplicatorState Monitor::GetDuplicatorState() const
|
||||
{
|
||||
return duplicator_->GetState();
|
||||
}
|
||||
|
||||
|
||||
@@ -370,9 +165,9 @@ ID3D11Texture2D* Monitor::GetUnityTexture() const
|
||||
}
|
||||
|
||||
|
||||
IDXGIOutputDuplication* Monitor::GetDeskDupl()
|
||||
ComPtr<IDXGIOutputDuplication> Monitor::GetDeskDupl()
|
||||
{
|
||||
return deskDupl_;
|
||||
return duplicator_->GetDuplication();
|
||||
}
|
||||
|
||||
|
||||
@@ -450,25 +245,29 @@ int Monitor::GetHeight() const
|
||||
|
||||
int Monitor::GetMoveRectCount() const
|
||||
{
|
||||
return moveRectSize_ / sizeof(DXGI_OUTDUPL_MOVE_RECT);
|
||||
const auto& metaData = duplicator_->GetLastFrame().metaData;
|
||||
return metaData.moveRectSize / sizeof(DXGI_OUTDUPL_MOVE_RECT);
|
||||
}
|
||||
|
||||
|
||||
DXGI_OUTDUPL_MOVE_RECT* Monitor::GetMoveRects() const
|
||||
{
|
||||
return metaData_.As<DXGI_OUTDUPL_MOVE_RECT>();
|
||||
const auto& metaData = duplicator_->GetLastFrame().metaData;
|
||||
return metaData.buffer.As<DXGI_OUTDUPL_MOVE_RECT>();
|
||||
}
|
||||
|
||||
|
||||
int Monitor::GetDirtyRectCount() const
|
||||
{
|
||||
return dirtyRectSize_ / sizeof(RECT);
|
||||
const auto& metaData = duplicator_->GetLastFrame().metaData;
|
||||
return metaData.dirtyRectSize / sizeof(RECT);
|
||||
}
|
||||
|
||||
|
||||
RECT* Monitor::GetDirtyRects() const
|
||||
{
|
||||
return metaData_.As<RECT>(moveRectSize_);
|
||||
const auto& metaData = duplicator_->GetLastFrame().metaData;
|
||||
return metaData.buffer.As<RECT>(metaData.moveRectSize);
|
||||
}
|
||||
|
||||
|
||||
@@ -659,7 +458,6 @@ bool Monitor::GetPixels(BYTE* output, int x, int y, int width, int height)
|
||||
const auto outCol = col;
|
||||
const auto outIndex = 4 * (outRow * width + outCol);
|
||||
|
||||
|
||||
// BGRA -> RGBA
|
||||
output[outIndex + 0] = bufferForGetPixels_[inIndex + 2];
|
||||
output[outIndex + 1] = bufferForGetPixels_[inIndex + 1];
|
||||
|
||||
@@ -5,35 +5,31 @@
|
||||
#include <wrl/client.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include "Common.h"
|
||||
|
||||
enum class MonitorState
|
||||
{
|
||||
NotSet = -1,
|
||||
Available = 0,
|
||||
InvalidArg = 1,
|
||||
AccessDenied = 2,
|
||||
Unsupported = 3,
|
||||
CurrentlyNotAvailable = 4,
|
||||
SessionDisconnected = 5,
|
||||
AccessLost = 6,
|
||||
TextureSizeInconsistent = 7,
|
||||
Unknown = 999,
|
||||
};
|
||||
|
||||
enum class DuplicatorState;
|
||||
|
||||
|
||||
class Monitor
|
||||
{
|
||||
public:
|
||||
using State = MonitorState;
|
||||
|
||||
explicit Monitor(int id);
|
||||
~Monitor();
|
||||
void Initialize(IDXGIOutput* output);
|
||||
void Render(UINT timeout = 0);
|
||||
void Initialize(
|
||||
const Microsoft::WRL::ComPtr<struct IDXGIAdapter> &adapter,
|
||||
const Microsoft::WRL::ComPtr<struct IDXGIOutput> &output);
|
||||
void Finalize();
|
||||
void Render();
|
||||
void StartCapture();
|
||||
void StopCapture();
|
||||
|
||||
public:
|
||||
int GetId() const;
|
||||
State GetState() const;
|
||||
Microsoft::WRL::ComPtr<struct IDXGIAdapter> GetAdapter();
|
||||
Microsoft::WRL::ComPtr<struct IDXGIOutput> GetOutput();
|
||||
DuplicatorState GetDuplicatorState() const;
|
||||
void SetUnityTexture(ID3D11Texture2D* texture);
|
||||
ID3D11Texture2D* GetUnityTexture() const;
|
||||
void GetName(char* buf, int len) const;
|
||||
@@ -48,7 +44,7 @@ public:
|
||||
int GetRotation() const;
|
||||
int GetDpiX() const;
|
||||
int GetDpiY() const;
|
||||
IDXGIOutputDuplication* GetDeskDupl();
|
||||
Microsoft::WRL::ComPtr<IDXGIOutputDuplication> GetDeskDupl();
|
||||
int GetMoveRectCount() const;
|
||||
DXGI_OUTDUPL_MOVE_RECT* GetMoveRects() const;
|
||||
int GetDirtyRectCount() const;
|
||||
@@ -58,25 +54,25 @@ public:
|
||||
bool GetPixels(BYTE* output, int x, int y, int width, int height);
|
||||
|
||||
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);
|
||||
void CopyTextureFromGpuToCpu(ID3D11Texture2D* texture);
|
||||
|
||||
int id_ = -1;
|
||||
|
||||
UINT dpiX_ = -1, dpiY_ = -1;
|
||||
int width_ = -1, height_ = -1;
|
||||
|
||||
bool hasBeenUpdated_ = false;
|
||||
bool useGetPixels_ = false;
|
||||
State state_ = State::NotSet;
|
||||
IDXGIOutputDuplication* deskDupl_ = nullptr;
|
||||
ID3D11Texture2D* unityTexture_ = nullptr;
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIOutput> output_;
|
||||
Microsoft::WRL::ComPtr<IDXGIAdapter> adapter_;
|
||||
DXGI_OUTPUT_DESC outputDesc_;
|
||||
MONITORINFOEX monitorInfo_;
|
||||
Buffer<BYTE> metaData_;
|
||||
|
||||
std::shared_ptr<class Duplicator> duplicator_;
|
||||
UINT lastFrameId_ = -1;
|
||||
|
||||
ID3D11Texture2D* unityTexture_ = nullptr;
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> textureForGetPixels_;
|
||||
Buffer<BYTE> bufferForGetPixels_;
|
||||
UINT moveRectSize_ = 0;
|
||||
UINT dirtyRectSize_ = 0;;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
|
||||
MonitorManager::MonitorManager()
|
||||
|
||||
MonitorManager::MonitorManager(LUID unityAdapterLuid)
|
||||
: unityAdapterLuid_(unityAdapterLuid)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +52,9 @@ void MonitorManager::Initialize()
|
||||
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
|
||||
{
|
||||
auto monitor = std::make_shared<Monitor>(id++);
|
||||
monitor->Initialize(output.Get());
|
||||
const auto unityAdapterLuid = GetUnityAdapterLuid();
|
||||
monitor->Initialize(adapter, output);
|
||||
monitor->StartCapture();
|
||||
monitors_.push_back(monitor);
|
||||
}
|
||||
}
|
||||
@@ -60,12 +63,28 @@ void MonitorManager::Initialize()
|
||||
|
||||
void MonitorManager::Finalize()
|
||||
{
|
||||
for (const auto& monitor : monitors_)
|
||||
{
|
||||
monitor->Finalize();
|
||||
}
|
||||
|
||||
monitors_.clear();
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::Update()
|
||||
{
|
||||
if (isReinitializationRequired_)
|
||||
{
|
||||
Reinitialize();
|
||||
isReinitializationRequired_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::RequireReinitilization()
|
||||
{
|
||||
Debug::Log("MonitorManager::Reinitialize() was required.");
|
||||
isReinitializationRequired_ = true;
|
||||
}
|
||||
|
||||
@@ -118,28 +137,6 @@ std::shared_ptr<Cursor> MonitorManager::GetCursor() const
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::Update()
|
||||
{
|
||||
if (isReinitializationRequired_)
|
||||
{
|
||||
Reinitialize();
|
||||
isReinitializationRequired_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::SetTimeout(int timeout)
|
||||
{
|
||||
timeout_ = timeout;
|
||||
}
|
||||
|
||||
|
||||
int MonitorManager::GetTimeout() const
|
||||
{
|
||||
return timeout_;
|
||||
}
|
||||
|
||||
|
||||
int MonitorManager::GetMonitorCount() const
|
||||
{
|
||||
return static_cast<int>(monitors_.size());
|
||||
@@ -171,4 +168,16 @@ int MonitorManager::GetTotalHeight() const
|
||||
const auto minTop = *std::min_element(tops.begin(), tops.end());
|
||||
const auto maxBottom = *std::max_element(bottoms.begin(), bottoms.end());
|
||||
return maxBottom - minTop;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::SetFrameRate(UINT frameRate)
|
||||
{
|
||||
frameRate_ = frameRate;
|
||||
}
|
||||
|
||||
|
||||
UINT MonitorManager::GetFrameRate() const
|
||||
{
|
||||
return frameRate_;
|
||||
}
|
||||
|
||||
@@ -13,37 +13,32 @@ class Cursor;
|
||||
class MonitorManager
|
||||
{
|
||||
public:
|
||||
explicit MonitorManager();
|
||||
explicit MonitorManager(LUID unityAdapterLuid_);
|
||||
~MonitorManager();
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
void Reinitialize();
|
||||
void Update();
|
||||
bool HasMonitorCountChanged() const;
|
||||
void RequireReinitilization();
|
||||
void SetCursorMonitorId(int id) { cursorMonitorId_ = id; }
|
||||
int GetCursorMonitorId() const { return cursorMonitorId_; }
|
||||
std::shared_ptr<Monitor> GetMonitor(int id) const;
|
||||
std::shared_ptr<Cursor> GetCursor() const;
|
||||
void SetFrameRate(UINT frameRate);
|
||||
UINT GetFrameRate() const;
|
||||
|
||||
private:
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
// Setters from Unity
|
||||
public:
|
||||
void Update();
|
||||
void SetTimeout(int timeout);
|
||||
int GetTimeout() const;
|
||||
|
||||
// Getters from Unity
|
||||
public:
|
||||
int GetMonitorCount() const;
|
||||
int GetTotalWidth() const;
|
||||
int GetTotalHeight() const;
|
||||
|
||||
private:
|
||||
int timeout_ = 10;
|
||||
LUID unityAdapterLuid_;
|
||||
UINT frameRate_ = 60;
|
||||
bool enableTextureCopyFromGpuToCpu_ = false;
|
||||
std::vector<std::shared_ptr<Monitor>> monitors_;
|
||||
std::shared_ptr<Cursor> cursor_ = std::make_shared<Cursor>();
|
||||
int cursorMonitorId_ = -1;
|
||||
bool isReinitializationRequired_ = false;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
|
||||
#include "IUnityInterface.h"
|
||||
#include "IUnityGraphics.h"
|
||||
#include "include/IUnityGraphicsD3D11.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "Debug.h"
|
||||
#include "Monitor.h"
|
||||
#include "Duplicator.h"
|
||||
#include "Cursor.h"
|
||||
#include "MonitorManager.h"
|
||||
|
||||
@@ -36,13 +38,36 @@ extern "C"
|
||||
if (g_unity && !g_manager)
|
||||
{
|
||||
Debug::Initialize();
|
||||
g_manager = std::make_unique<MonitorManager>();
|
||||
|
||||
auto device = g_unity->Get<IUnityGraphicsD3D11>()->GetDevice();
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIDevice1> dxgiDevice;
|
||||
if (FAILED(device->QueryInterface(IID_PPV_ARGS(&dxgiDevice))))
|
||||
{
|
||||
Debug::Error("Initialize() => device->QueryInterface() failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIAdapter> dxgiAdapter;
|
||||
if (FAILED(dxgiDevice->GetAdapter(&dxgiAdapter)))
|
||||
{
|
||||
Debug::Error("Initialize() => dxgiDevice->GetAdapter() failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
dxgiAdapter->GetDesc(&desc);
|
||||
|
||||
g_manager = std::make_unique<MonitorManager>(desc.AdapterLuid);
|
||||
g_manager->Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Finalize()
|
||||
{
|
||||
if (!g_manager) return;
|
||||
|
||||
g_manager->Finalize();
|
||||
g_manager.reset();
|
||||
|
||||
std::queue<Message> empty;
|
||||
@@ -87,7 +112,7 @@ extern "C"
|
||||
if (!g_manager) return;
|
||||
if (auto monitor = g_manager->GetMonitor(id))
|
||||
{
|
||||
monitor->Render(g_manager->GetTimeout());
|
||||
monitor->Render();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,12 +187,6 @@ extern "C"
|
||||
return g_manager->GetTotalHeight();
|
||||
}
|
||||
|
||||
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 GetId(int id)
|
||||
{
|
||||
if (!g_manager) return;
|
||||
@@ -177,14 +196,14 @@ extern "C"
|
||||
}
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT MonitorState UNITY_INTERFACE_API GetState(int id)
|
||||
UNITY_INTERFACE_EXPORT DuplicatorState UNITY_INTERFACE_API GetState(int id)
|
||||
{
|
||||
if (!g_manager) return MonitorState::NotSet;
|
||||
if (!g_manager) return DuplicatorState::NotSet;
|
||||
if (auto monitor = g_manager->GetMonitor(id))
|
||||
{
|
||||
return monitor->GetState();
|
||||
return monitor->GetDuplicatorState();
|
||||
}
|
||||
return MonitorState::NotSet;
|
||||
return DuplicatorState::NotSet;
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetName(int id, char* buf, int len)
|
||||
@@ -422,4 +441,10 @@ extern "C"
|
||||
return monitor->UseGetPixels(use);
|
||||
}
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetFrameRate(UINT frameRate)
|
||||
{
|
||||
if (!g_manager) return;
|
||||
g_manager->SetFrameRate(frameRate);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
@@ -21,33 +21,33 @@
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{BC5DE2F9-BDCC-4449-A017-E5642E04BB56}</ProjectGuid>
|
||||
<RootNamespace>uDesktopDuplication</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>uDesktopDuplication</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
@@ -82,6 +82,8 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);include</IncludePath>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
@@ -92,6 +94,10 @@
|
||||
<PostBuildEvent>
|
||||
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86_64"</Command>
|
||||
</PostBuildEvent>
|
||||
<Link>
|
||||
<ModuleDefinitionFile>
|
||||
</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
@@ -100,8 +106,11 @@
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86_64"</Command>
|
||||
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86"</Command>
|
||||
</PostBuildEvent>
|
||||
<Link>
|
||||
<ModuleDefinitionFile>$(SolutionDir)$(ProjectName).def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
@@ -115,6 +124,8 @@
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<ModuleDefinitionFile>
|
||||
</ModuleDefinitionFile>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86_64"</Command>
|
||||
@@ -132,6 +143,7 @@
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<ModuleDefinitionFile>$(SolutionDir)$(ProjectName).def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86"</Command>
|
||||
@@ -140,6 +152,8 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Common.cpp" />
|
||||
<ClCompile Include="Debug.cpp" />
|
||||
<ClCompile Include="Device.cpp" />
|
||||
<ClCompile Include="Duplicator.cpp" />
|
||||
<ClCompile Include="MonitorManager.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="Monitor.cpp" />
|
||||
@@ -148,6 +162,8 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Common.h" />
|
||||
<ClInclude Include="Debug.h" />
|
||||
<ClInclude Include="Device.h" />
|
||||
<ClInclude Include="Duplicator.h" />
|
||||
<ClInclude Include="MonitorManager.h" />
|
||||
<ClInclude Include="include\IUnityGraphics.h" />
|
||||
<ClInclude Include="include\IUnityGraphicsD3D11.h" />
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
<ClInclude Include="Common.h" />
|
||||
<ClInclude Include="MonitorManager.h" />
|
||||
<ClInclude Include="Debug.h" />
|
||||
<ClInclude Include="Device.h" />
|
||||
<ClInclude Include="Duplicator.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Monitor.cpp" />
|
||||
@@ -28,5 +30,7 @@
|
||||
<ClCompile Include="MonitorManager.cpp" />
|
||||
<ClCompile Include="Common.cpp" />
|
||||
<ClCompile Include="Debug.cpp" />
|
||||
<ClCompile Include="Device.cpp" />
|
||||
<ClCompile Include="Duplicator.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
6
ProjectSettings/PresetManager.asset
Normal file
6
ProjectSettings/PresetManager.asset
Normal file
@@ -0,0 +1,6 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1386491679 &1
|
||||
PresetManager:
|
||||
m_ObjectHideFlags: 0
|
||||
m_DefaultList: []
|
||||
Binary file not shown.
@@ -1,2 +1 @@
|
||||
m_EditorVersion: 5.4.2f2
|
||||
m_StandardAssetsVersion: 0
|
||||
m_EditorVersion: 2018.1.9f1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,7 +2,6 @@ uDesktopDuplication
|
||||
===================
|
||||
|
||||

|
||||

|
||||
|
||||
**uDesktopDuplication** is an Unity asset to use the realtime screen capture as `Texture2D` using Desktop Duplication API.
|
||||
|
||||
@@ -28,7 +27,7 @@ Usage
|
||||
Attach `uDesktopDuplication/Texture` component to the target object, then its main texture will be replaced with the captured screen. Please see example scenes for more details.
|
||||
|
||||
|
||||
Lisence
|
||||
License
|
||||
-------
|
||||
The MIT License (MIT)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user