Compare commits

..

52 Commits

Author SHA1 Message Date
hecomi
70cfad90a9 fix bug that caused darker screen #22. 2018-08-05 00:20:03 +09:00
hecomi
c926127e49 update Unity version to 2018.1. 2018-08-05 00:19:07 +09:00
hecomi
03469ce429 remove unnecessary line break. 2018-08-05 00:18:42 +09:00
hecomi
f63e573f04 remove unnecessary logs. 2018-05-20 15:53:30 +09:00
hecomi
682553a5a2 tweak code. 2018-05-20 02:08:18 +09:00
hecomi
b5fd483d6a call ReleaseFrame() just before AcquireNextFrame() #18. 2018-05-20 01:11:03 +09:00
hecomi
0d2c0e02f0 update Visual Studio version to 2017. 2018-05-20 00:53:36 +09:00
hecomi
6f876f65ed update Unity version to 2017.4. 2018-05-19 21:49:24 +09:00
hecomi
8434d803bb remove build status. 2017-08-24 01:38:00 +09:00
hecomi
1c332ebca7 fix bugs that caused x86 build problem. 2017-08-24 01:34:53 +09:00
hecomi
340e2d5194 remove unnecessary shared flag from cursor texture. 2017-01-09 17:07:26 +09:00
hecomi
e397f5eb84 fix typo. 2017-01-08 01:01:05 +09:00
hecomi
c20c09e275 fix bug that drew cursor on all monitors. 2017-01-08 00:38:01 +09:00
hecomi
a0ca46630e fix perf macro bug. 2017-01-08 00:32:14 +09:00
hecomi
5b5995d7d0 remove unnecessary perf. 2017-01-08 00:29:04 +09:00
hecomi
808a71ed6d remove unnecessary codes. 2017-01-08 00:09:24 +09:00
hecomi
da072aa9f3 draw cursor texture to unity texture instead of cached texture. 2017-01-08 00:02:41 +09:00
hecomi
7237d283ef add error messages. 2017-01-07 23:10:13 +09:00
hecomi
4a28b5f341 tweak shared texture. 2017-01-07 23:02:48 +09:00
hecomi
10091be4b3 lock shared texture. 2017-01-07 15:28:13 +09:00
hecomi
c41fe42aa3 check frame id. 2017-01-07 13:48:38 +09:00
hecomi
c0e1967e2e modify duplicator state handling. 2017-01-07 13:26:28 +09:00
hecomi
f5a8a83c7e change member name. 2017-01-07 13:18:11 +09:00
hecomi
c251de3a30 add debug timer macro. 2017-01-07 01:15:33 +09:00
hecomi
b0877a49ed tweak code. 2017-01-07 00:53:37 +09:00
hecomi
68d9e30816 allow buffer copy. 2017-01-06 18:44:43 +09:00
hecomi
b8ae1d6c4a remove unused code. 2017-01-06 18:11:18 +09:00
hecomi
15624dc0f4 add frame rate setter and calc more accurate sleep duration. 2017-01-06 18:07:35 +09:00
hecomi
06d4edbcb0 add timeout to avoid unnecessarily high cpu usage. 2017-01-06 17:53:16 +09:00
hecomi
9ee2d35175 replace code to copy texture with old one #11 2017-01-06 17:32:10 +09:00
hecomi
0634993bb0 prepare multiple texture buffer for each device to avoid flickering cursor #11 2017-01-06 17:29:09 +09:00
hecomi
6bd892bc4b remove unused code. 2017-01-06 16:34:02 +09:00
hecomi
2a631a0a89 add mutex for debug logs. 2017-01-06 16:17:08 +09:00
hecomi
0833b965e9 rename GetFrame() to GetLastFrame(). 2017-01-06 16:14:10 +09:00
hecomi
12726d85dc fix cursor bugs #11 2017-01-06 13:52:23 +09:00
hecomi
29920b6b94 fix bug that blocked stopping scene #12 2017-01-06 04:02:24 +09:00
hecomi
4de8f0ba51 remove unused code. 2017-01-06 03:47:48 +09:00
hecomi
476be8243a remove unused code. 2017-01-06 03:42:48 +09:00
hecomi
c681e43d65 Merge branch 'ousttrue-AcquireNextFrame_on_thread' 2017-01-05 21:21:32 +09:00
hecomi
ed24ca2fb2 add x86 dll and remove pdb file #10 2017-01-05 21:20:35 +09:00
hecomi
791fa42478 fix crash bug when stopping scene #10 2017-01-05 21:13:25 +09:00
hecomi
11dbb7be57 update cursor in each thread #10 2017-01-05 19:38:30 +09:00
hecomi
9ed24dd3b1 modify timing to fetch metadata and add it to frame data #10 2017-01-05 19:03:29 +09:00
hecomi
cfbd218374 fix styles. 2017-01-05 19:03:28 +09:00
hecomi
bf7174f406 initialize at first #10 2017-01-05 19:03:28 +09:00
hecomi
4a761a06f3 remove const_cast #10 2017-01-05 19:03:28 +09:00
hecomi
1effd65aeb add Duplicator class to modularize duplication function #10 2017-01-05 19:03:28 +09:00
hecomi
46cc789be5 spearate IsolatedD3D11Device into different files #10 2017-01-05 19:03:28 +09:00
hecomi
1053b30d7e remove ThreadedDesktopDuplicator.cpp #10 2017-01-05 19:03:28 +09:00
hecomi
d58855ff8a check ReleaseFrame result #10 2017-01-05 19:03:18 +09:00
hecomi
741e2c0bc1 remove useThread flag #10 2017-01-05 12:14:03 +09:00
ousttrue
f6ce875463 call AcquireNextFrame on isolated thread 2016-12-28 02:12:03 +09:00
73 changed files with 1523 additions and 607 deletions

3
.gitignore vendored
View File

@@ -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

View File

@@ -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;
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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:

View File

@@ -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:

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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"

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -0,0 +1,5 @@
LIBRARY
EXPORTS
UnityPluginLoad
UnityPluginUnload

View File

@@ -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);
}

View File

@@ -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)
{

View File

@@ -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_)

View File

@@ -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_;
};

View File

@@ -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()

View File

@@ -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

View 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_;
}

View 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_;
};

View 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;
}
}

View 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_;
};

View File

@@ -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];

View File

@@ -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;;
};
};

View File

@@ -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_;
}

View File

@@ -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;
};
};

View File

@@ -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);
}
}

View File

@@ -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" />

View File

@@ -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.

View File

@@ -0,0 +1,6 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1386491679 &1
PresetManager:
m_ObjectHideFlags: 0
m_DefaultList: []

View File

@@ -1,2 +1 @@
m_EditorVersion: 5.4.2f2
m_StandardAssetsVersion: 0
m_EditorVersion: 2018.1.9f1

Binary file not shown.

Binary file not shown.

View File

@@ -2,7 +2,6 @@ uDesktopDuplication
===================
![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)
![Build Status](http://unitybuildbadge.azurewebsites.net/api/status/7566d616-2916-4c99-bb14-e7ab9501cf7e)
**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)