Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63d8f6936d | ||
|
|
e4e4917bcb | ||
|
|
0e205ecef7 | ||
|
|
cda8024b17 | ||
|
|
05085f7d24 | ||
|
|
52eafbe919 | ||
|
|
be1e0c25bb | ||
|
|
372e44d8c1 | ||
|
|
d79eb91333 | ||
|
|
f654df7f5b | ||
|
|
620762dba7 | ||
|
|
43ba445623 | ||
|
|
c7c12de730 | ||
|
|
1086595d6b | ||
|
|
f69fb6a7bb | ||
|
|
b661b4a93f | ||
|
|
8d9ef71829 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,3 +27,4 @@ sysinfo.txt
|
||||
.DS_Store
|
||||
/Assets/AssetStoreTools*
|
||||
/Assets/Extensions*
|
||||
/uDesktopDuplication.log
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,21 +7,19 @@ public class Loupe : MonoBehaviour
|
||||
public float aspect = 1f;
|
||||
|
||||
void Start()
|
||||
{
|
||||
uddTexture_ = GetComponent<uDesktopDuplication.Texture>();
|
||||
{
|
||||
uddTexture_ = GetComponent<uDesktopDuplication.Texture>();
|
||||
uddTexture_.useClip = true;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// To get other monitor textures, set dirty flag.
|
||||
foreach (var monitor in uDesktopDuplication.Manager.monitors) {
|
||||
monitor.CreateTexture();
|
||||
monitor.shouldBeUpdated = true;
|
||||
}
|
||||
uddTexture_.monitorId = uDesktopDuplication.Manager.cursorMonitorId;
|
||||
|
||||
if (!uddTexture_.monitor.isCursorVisible) {
|
||||
uddTexture_.monitorId = uDesktopDuplication.Manager.cursorMonitorId;
|
||||
// To get other monitor textures, set dirty flag.
|
||||
foreach (var monitor in uDesktopDuplication.Manager.monitors) {
|
||||
monitor.CreateTexture();
|
||||
monitor.shouldBeUpdated = true;
|
||||
}
|
||||
|
||||
var x = (float)uddTexture_.monitor.cursorX / uddTexture_.monitor.width;
|
||||
|
||||
@@ -4,23 +4,35 @@ using System.Collections.Generic;
|
||||
public class MultipleMonitorCreator : MonoBehaviour
|
||||
{
|
||||
[SerializeField] GameObject monitorPrefab;
|
||||
[SerializeField] bool removeIfUnsupported = true;
|
||||
[SerializeField] float removeWaitDuration = 5f;
|
||||
bool hasMonitorUnsupportStateChecked = false;
|
||||
float removeWaitTimer_ = 0f;
|
||||
|
||||
public class MonitorInfo
|
||||
{
|
||||
public GameObject gameObject { get; set; }
|
||||
public Quaternion originalRotation { get; set; }
|
||||
public uDesktopDuplication.Texture uddTexture { get; set; }
|
||||
public Vector3 meshBounds;
|
||||
public Mesh mesh { get; set; }
|
||||
}
|
||||
|
||||
private List<MonitorInfo> monitors_ = new List<MonitorInfo>();
|
||||
public List<MonitorInfo> monitors { get { return monitors_; } }
|
||||
private List<MonitorInfo> monitors_ = new List<MonitorInfo>();
|
||||
public List<MonitorInfo> monitors { get { return monitors_; } }
|
||||
|
||||
void Start()
|
||||
{
|
||||
uDesktopDuplication.Manager.CreateInstance();
|
||||
Create();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (removeIfUnsupported) {
|
||||
RemoveUnsupportedDisplayAfterRemoveTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
uDesktopDuplication.Manager.onReinitialized += Recreate;
|
||||
@@ -31,18 +43,45 @@ public class MultipleMonitorCreator : MonoBehaviour
|
||||
uDesktopDuplication.Manager.onReinitialized -= Recreate;
|
||||
}
|
||||
|
||||
void RemoveUnsupportedDisplayAfterRemoveTimer()
|
||||
{
|
||||
if (!hasMonitorUnsupportStateChecked) {
|
||||
removeWaitTimer_ += Time.deltaTime;
|
||||
if (removeWaitTimer_ > removeWaitDuration) {
|
||||
hasMonitorUnsupportStateChecked = true;
|
||||
foreach (var info in monitors_) {
|
||||
if (info.uddTexture.monitor.state == uDesktopDuplication.MonitorState.Unsupported) {
|
||||
Destroy(info.gameObject);
|
||||
}
|
||||
}
|
||||
monitors_.RemoveAll(info => info.uddTexture.monitor.state == uDesktopDuplication.MonitorState.Unsupported);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResetRemoveTimer()
|
||||
{
|
||||
hasMonitorUnsupportStateChecked = false;
|
||||
removeWaitTimer_ = 0f;
|
||||
}
|
||||
|
||||
void Create()
|
||||
{
|
||||
// Sort monitors in coordinate order
|
||||
var monitors = uDesktopDuplication.Manager.monitors;
|
||||
monitors.Sort((a, b) => a.left - b.left);
|
||||
ResetRemoveTimer();
|
||||
|
||||
// Create monitors
|
||||
for (int i = 0 ; i < uDesktopDuplication.Manager.monitorCount; ++i) {
|
||||
for (int i = 0; i < uDesktopDuplication.Manager.monitorCount; ++i) {
|
||||
// Create monitor obeject
|
||||
var go = Instantiate(monitorPrefab);
|
||||
go.name = "Monitor " + i;
|
||||
|
||||
// Expand AABB
|
||||
var mesh = go.GetComponent<MeshFilter>().mesh; // clone
|
||||
var aabbScale = mesh.bounds.size;
|
||||
aabbScale.y = Mathf.Max(aabbScale.y, aabbScale.x);
|
||||
aabbScale.z = Mathf.Max(aabbScale.z, aabbScale.x);
|
||||
mesh.bounds = new Bounds(mesh.bounds.center, aabbScale);
|
||||
|
||||
// Assign monitor
|
||||
var texture = go.GetComponent<uDesktopDuplication.Texture>();
|
||||
texture.monitorId = i;
|
||||
@@ -54,17 +93,17 @@ public class MultipleMonitorCreator : MonoBehaviour
|
||||
// Set parent as this object
|
||||
go.transform.SetParent(transform);
|
||||
|
||||
// Calc actual size considering mesh size
|
||||
var bounds = go.GetComponent<MeshFilter>().sharedMesh.bounds.extents * 2f;
|
||||
|
||||
// Save
|
||||
var info = new MonitorInfo();
|
||||
info.gameObject = go;
|
||||
info.originalRotation = go.transform.rotation;
|
||||
info.uddTexture = texture;
|
||||
info.meshBounds = bounds;
|
||||
info.mesh = mesh;
|
||||
monitors_.Add(info);
|
||||
}
|
||||
|
||||
// Sort monitors in coordinate order
|
||||
monitors_.Sort((a, b) => a.uddTexture.monitor.left - b.uddTexture.monitor.left);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
|
||||
@@ -15,13 +15,13 @@ public class MultipleMonitorLayouter : MonoBehaviour
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
if (updateEveryFrame) {
|
||||
Layout();
|
||||
if (updateEveryFrame) {
|
||||
Layout();
|
||||
}
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
{
|
||||
margin = Mathf.Max(margin, 0f);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public class MultipleMonitorLayouter : MonoBehaviour
|
||||
|
||||
var totalWidth = 0f;
|
||||
foreach (var info in monitors) {
|
||||
var width = info.uddTexture.monitor.widthMeter * info.meshBounds.x;
|
||||
var width = info.uddTexture.monitor.widthMeter * (info.mesh.bounds.extents.x * 2f);
|
||||
totalWidth += width;
|
||||
}
|
||||
totalWidth += margin * (n - 1);
|
||||
@@ -41,10 +41,10 @@ public class MultipleMonitorLayouter : MonoBehaviour
|
||||
|
||||
foreach (var info in creator_.monitors) {
|
||||
var monitor = info.uddTexture.monitor;
|
||||
x += (monitor.widthMeter * info.meshBounds.x) / 2;
|
||||
x += (monitor.widthMeter * info.mesh.bounds.extents.x);
|
||||
info.gameObject.transform.localPosition = new Vector3(x, 0f, 0f);
|
||||
info.gameObject.transform.localRotation = info.originalRotation;
|
||||
x += (monitor.widthMeter * info.meshBounds.x) / 2 + margin;
|
||||
x += (monitor.widthMeter * info.mesh.bounds.extents.x) + margin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ public class MultipleMonitorRoundLayouter : MultipleMonitorLayouter
|
||||
|
||||
var totalWidth = 0f;
|
||||
foreach (var info in monitors) {
|
||||
var width = info.uddTexture.monitor.widthMeter * info.meshBounds.x;
|
||||
var width = info.uddTexture.monitor.widthMeter * (info.mesh.bounds.extents.x * 2f);
|
||||
totalWidth += width;
|
||||
}
|
||||
totalWidth += margin * (n - 1);
|
||||
@@ -29,7 +29,7 @@ public class MultipleMonitorRoundLayouter : MultipleMonitorLayouter
|
||||
float angle = -totalAngle / 2;
|
||||
foreach (var info in monitors) {
|
||||
var uddTex = info.uddTexture;
|
||||
var width = uddTex.monitor.widthMeter * info.meshBounds.x;
|
||||
var width = uddTex.monitor.widthMeter * (info.mesh.bounds.extents.x * 2f);
|
||||
|
||||
angle += (width / radius) * 0.5f;
|
||||
uddTex.transform.localPosition = radius * new Vector3(Mathf.Sin(angle), 0f, Mathf.Cos(angle) - 1f);
|
||||
|
||||
Binary file not shown.
9
Assets/uDesktopDuplication/Plugins/x86_64.meta
Normal file
9
Assets/uDesktopDuplication/Plugins/x86_64.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99257566ccd0582439a44abad90e65d4
|
||||
folderAsset: yes
|
||||
timeCreated: 1478626361
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 37 KiB |
@@ -1,4 +1,5 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace uDesktopDuplication
|
||||
@@ -53,6 +54,7 @@ public class Cursor : MonoBehaviour
|
||||
}
|
||||
|
||||
var cursorTexture = textures_[key];
|
||||
Assert.IsNotNull(cursorTexture);
|
||||
monitor.GetCursorTexture(cursorTexture.GetNativeTexturePtr());
|
||||
uddTexture_.material.SetTexture("_CursorTex", cursorTexture);
|
||||
}
|
||||
|
||||
@@ -39,9 +39,18 @@ public enum MonitorState
|
||||
AccessLost = 6,
|
||||
}
|
||||
|
||||
public enum DebugMode
|
||||
{
|
||||
None = 0,
|
||||
File = 1,
|
||||
UnityLog = 2, /* currently has bug when app exits. */
|
||||
}
|
||||
|
||||
public static class Lib
|
||||
{
|
||||
public delegate void MessageHandler(Message message);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void DebugLogDelegate(string str);
|
||||
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern void InitializeUDD();
|
||||
@@ -54,6 +63,16 @@ public static class Lib
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern Message PopMessage();
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern void EnableDebug();
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern void DisableDebug();
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern void SetDebugMode(DebugMode mode);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern void SetLogFunc(IntPtr func);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern void SetErrorFunc(IntPtr func);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern int GetMonitorCount();
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern int GetCursorMonitorId();
|
||||
@@ -66,6 +85,8 @@ public static class Lib
|
||||
[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);
|
||||
[DllImport("uDesktopDuplication")]
|
||||
public static extern void GetName(int id, StringBuilder buf, int len);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace uDesktopDuplication
|
||||
{
|
||||
@@ -10,21 +11,7 @@ public class Manager : MonoBehaviour
|
||||
private static Manager instance_;
|
||||
public static Manager instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance_) {
|
||||
return instance_;
|
||||
}
|
||||
|
||||
var manager = FindObjectOfType<Manager>();
|
||||
if (manager) {
|
||||
manager.Awake();
|
||||
return manager;
|
||||
}
|
||||
|
||||
var go = new GameObject("uDesktopDuplicationManager");
|
||||
return go.AddComponent<Manager>();
|
||||
}
|
||||
get { return CreateInstance(); }
|
||||
}
|
||||
|
||||
private List<Monitor> monitors_ = new List<Monitor>();
|
||||
@@ -51,18 +38,36 @@ public class Manager : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] DebugMode debugMode = DebugMode.File;
|
||||
[SerializeField] int desktopDuplicationApiTimeout = 0;
|
||||
[SerializeField] float retryReinitializationDuration = 1f;
|
||||
|
||||
private Coroutine renderCoroutine_ = null;
|
||||
private bool shouldReinitialize = false;
|
||||
private float reinitializationTimer = 0f;
|
||||
private bool shouldReinitialize_ = false;
|
||||
private float reinitializationTimer_ = 0f;
|
||||
|
||||
public delegate void ReinitializeHandler();
|
||||
public static event ReinitializeHandler onReinitialized;
|
||||
|
||||
public static Manager CreateInstance()
|
||||
{
|
||||
if (instance_) {
|
||||
return instance_;
|
||||
}
|
||||
|
||||
var manager = FindObjectOfType<Manager>();
|
||||
if (manager) {
|
||||
manager.Awake();
|
||||
return manager;
|
||||
}
|
||||
|
||||
var go = new GameObject("uDesktopDuplicationManager");
|
||||
return go.AddComponent<Manager>();
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
Lib.SetDebugMode(debugMode);
|
||||
Lib.InitializeUDD();
|
||||
|
||||
if (instance_ != null) return;
|
||||
@@ -96,12 +101,6 @@ public class Manager : MonoBehaviour
|
||||
Lib.Update();
|
||||
ReinitializeIfNeeded();
|
||||
UpdateMessage();
|
||||
|
||||
/*
|
||||
foreach (var monitor in monitors_) {
|
||||
Debug.LogFormat("[{0}] {1}", monitor.id, monitor.state);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
[ContextMenu("Reinitialize")]
|
||||
@@ -120,20 +119,20 @@ public class Manager : MonoBehaviour
|
||||
monitor.state == MonitorState.AccessLost ||
|
||||
monitor.state == MonitorState.AccessDenied ||
|
||||
monitor.state == MonitorState.SessionDisconnected) {
|
||||
if (!shouldReinitialize) {
|
||||
shouldReinitialize = true;
|
||||
reinitializationTimer = 0f;
|
||||
if (!shouldReinitialize_) {
|
||||
shouldReinitialize_ = true;
|
||||
reinitializationTimer_ = 0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldReinitialize) {
|
||||
if (reinitializationTimer > retryReinitializationDuration) {
|
||||
if (shouldReinitialize_) {
|
||||
if (reinitializationTimer_ > retryReinitializationDuration) {
|
||||
Reinitialize();
|
||||
shouldReinitialize = false;
|
||||
shouldReinitialize_ = false;
|
||||
}
|
||||
reinitializationTimer += Time.deltaTime;
|
||||
reinitializationTimer_ += Time.deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +167,7 @@ public class Manager : MonoBehaviour
|
||||
|
||||
void CreateMonitors()
|
||||
{
|
||||
monitors.Clear();
|
||||
for (int i = 0; i < monitorCount; ++i) {
|
||||
monitors.Add(new Monitor(i));
|
||||
}
|
||||
|
||||
39
Plugins/uDesktopDuplication/uDesktopDuplication/Common.cpp
Normal file
39
Plugins/uDesktopDuplication/uDesktopDuplication/Common.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <iostream>
|
||||
#include <d3d11.h>
|
||||
|
||||
#include "IUnityInterface.h"
|
||||
#include "IUnityGraphicsD3D11.h"
|
||||
#include "Common.h"
|
||||
|
||||
|
||||
extern IUnityInterfaces* g_unity;
|
||||
extern std::unique_ptr<MonitorManager> g_manager;
|
||||
extern std::queue<Message> g_messages;
|
||||
|
||||
|
||||
IUnityInterfaces* GetUnity()
|
||||
{
|
||||
return g_unity;
|
||||
}
|
||||
|
||||
|
||||
ID3D11Device* GetDevice()
|
||||
{
|
||||
return GetUnity()->Get<IUnityGraphicsD3D11>()->GetDevice();
|
||||
}
|
||||
|
||||
|
||||
const std::unique_ptr<MonitorManager>& GetMonitorManager()
|
||||
{
|
||||
return g_manager;
|
||||
}
|
||||
|
||||
|
||||
void SendMessageToUnity(Message message)
|
||||
{
|
||||
g_messages.push(message);
|
||||
}
|
||||
@@ -1,15 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "IUnityInterface.h"
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
class MonitorManager;
|
||||
|
||||
// Unity interface and ID3D11Device getters
|
||||
struct IUnityInterfaces;
|
||||
IUnityInterfaces* GetUnity();
|
||||
|
||||
struct ID3D11Device;
|
||||
ID3D11Device* GetDevice();
|
||||
|
||||
|
||||
// Manager getter
|
||||
class MonitorManager;
|
||||
const std::unique_ptr<MonitorManager>& GetMonitorManager();
|
||||
|
||||
|
||||
// Message is pooled and fetch from Unity.
|
||||
enum class Message
|
||||
{
|
||||
None = -1,
|
||||
Reinitialized = 0,
|
||||
};
|
||||
|
||||
void SendMessageToUnity(Message message);
|
||||
@@ -1,9 +1,13 @@
|
||||
#include <d3d11.h>
|
||||
#include <wrl/client.h>
|
||||
#include "Common.h"
|
||||
#include "Debug.h"
|
||||
#include "MonitorManager.h"
|
||||
#include "Monitor.h"
|
||||
#include "Cursor.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
|
||||
Cursor::Cursor(Monitor* monitor)
|
||||
: monitor_(monitor)
|
||||
@@ -13,16 +17,6 @@ Cursor::Cursor(Monitor* monitor)
|
||||
|
||||
Cursor::~Cursor()
|
||||
{
|
||||
if (apiBuffer_ != nullptr)
|
||||
{
|
||||
delete[] apiBuffer_;
|
||||
apiBuffer_ = nullptr;
|
||||
}
|
||||
if (bgra32Buffer_ != nullptr)
|
||||
{
|
||||
delete[] bgra32Buffer_;
|
||||
bgra32Buffer_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,16 +27,21 @@ void Cursor::UpdateBuffer(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
|
||||
return;
|
||||
}
|
||||
|
||||
x_ = frameInfo.PointerPosition.Position.x;
|
||||
y_ = frameInfo.PointerPosition.Position.y;
|
||||
isVisible_ = frameInfo.PointerPosition.Visible != 0;
|
||||
timestamp_ = frameInfo.LastMouseUpdateTime;
|
||||
|
||||
if (isVisible_)
|
||||
{
|
||||
GetMonitorManager()->SetCursorMonitorId(monitor_->GetId());
|
||||
}
|
||||
|
||||
x_ = frameInfo.PointerPosition.Position.x;
|
||||
y_ = frameInfo.PointerPosition.Position.y;
|
||||
timestamp_ = frameInfo.LastMouseUpdateTime;
|
||||
|
||||
if (!IsCursorOnParentMonitor())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (frameInfo.PointerShapeBufferSize == 0)
|
||||
{
|
||||
return;
|
||||
@@ -51,54 +50,95 @@ void Cursor::UpdateBuffer(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
|
||||
// Increase the buffer size if needed
|
||||
if (frameInfo.PointerShapeBufferSize > apiBufferSize_)
|
||||
{
|
||||
if (apiBuffer_) delete[] apiBuffer_;
|
||||
apiBuffer_ = new BYTE[frameInfo.PointerShapeBufferSize];
|
||||
apiBufferSize_ = frameInfo.PointerShapeBufferSize;
|
||||
apiBuffer_ = std::make_unique<BYTE[]>(apiBufferSize_);
|
||||
}
|
||||
if (apiBuffer_ == nullptr) return;
|
||||
if (!apiBuffer_) return;
|
||||
|
||||
// Get mouse pointer information
|
||||
UINT bufferSize;
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
|
||||
const auto hr = monitor_->GetDeskDupl()->GetFramePointerShape(
|
||||
frameInfo.PointerShapeBufferSize,
|
||||
reinterpret_cast<void*>(apiBuffer_),
|
||||
apiBufferSize_,
|
||||
reinterpret_cast<void*>(apiBuffer_.get()),
|
||||
&bufferSize,
|
||||
&shapeInfo_);
|
||||
&shapeInfo);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
delete[] apiBuffer_;
|
||||
apiBuffer_ = nullptr;
|
||||
Debug::Error("Cursor::UpdateBuffer() => GetFramePointerShape() failed.");
|
||||
apiBuffer_.reset();
|
||||
apiBufferSize_ = 0;
|
||||
}
|
||||
|
||||
shapeInfo_ = shapeInfo;
|
||||
}
|
||||
|
||||
|
||||
void Cursor::UpdateTexture()
|
||||
{
|
||||
if (!IsCursorOnParentMonitor())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// cursor type
|
||||
const bool isMono = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME;
|
||||
const bool isColorMask = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR;
|
||||
|
||||
// Size
|
||||
const auto w = GetWidth();
|
||||
const auto h = GetHeight();
|
||||
const auto w0 = GetWidth();
|
||||
const auto h0 = GetHeight();
|
||||
const auto p = GetPitch();
|
||||
auto w = w0;
|
||||
auto h = h0;
|
||||
|
||||
// Convert the buffer given by API into BGRA32
|
||||
const UINT bgraBufferSize = w * h * 4;
|
||||
const UINT bgraBufferSize = w0 * h0 * 4;
|
||||
if (bgraBufferSize > bgra32BufferSize_)
|
||||
{
|
||||
if (bgra32Buffer_) delete[] bgra32Buffer_;
|
||||
bgra32Buffer_ = new BYTE[bgraBufferSize];
|
||||
bgra32BufferSize_ = bgraBufferSize;
|
||||
bgra32Buffer_ = std::make_unique<BYTE[]>(bgra32BufferSize_);
|
||||
}
|
||||
if (bgra32Buffer_ == nullptr) return;
|
||||
if (!bgra32Buffer_) return;
|
||||
|
||||
// If masked, copy the desktop image and merge it with masked image.
|
||||
if (isMono || isColorMask)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
const auto mw = monitor_->GetWidth();
|
||||
const auto mh = monitor_->GetHeight();
|
||||
auto x = x_;
|
||||
auto y = y_;
|
||||
auto colMin = 0;
|
||||
auto colMax = w0;
|
||||
auto rowMin = 0;
|
||||
auto rowMax = h0;
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
x = 0;
|
||||
w = w0 + x_;
|
||||
colMin = w0 - w;
|
||||
}
|
||||
if (x + w >= mw)
|
||||
{
|
||||
w = mw - x_;
|
||||
colMax = w;
|
||||
}
|
||||
if (y < 0)
|
||||
{
|
||||
y = 0;
|
||||
h = h0 + y_;
|
||||
rowMin = h0 - h;
|
||||
}
|
||||
if (y + h >= mh)
|
||||
{
|
||||
h = mh - y_;
|
||||
rowMax = h;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
desc.Width = w;
|
||||
desc.Height = h;
|
||||
@@ -112,31 +152,39 @@ void Cursor::UpdateTexture()
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
ID3D11Texture2D* texture = nullptr;
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
hr = GetDevice()->CreateTexture2D(&desc, nullptr, &texture);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Debug::Error("Cursor::UpdateTexture() => GetDevice()->CreateTexture2D() failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
D3D11_BOX box;
|
||||
box.front = 0;
|
||||
box.back = 1;
|
||||
box.left = x_;
|
||||
box.top = y_;
|
||||
box.right = x_ + w;
|
||||
box.bottom = y_ + h;
|
||||
box.left = x;
|
||||
box.top = y;
|
||||
box.right = x + w;
|
||||
box.bottom = y + h;
|
||||
|
||||
ID3D11DeviceContext* context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopySubresourceRegion(texture, 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box);
|
||||
context->Release();
|
||||
if (monitor_->GetUnityTexture() == nullptr)
|
||||
{
|
||||
Debug::Error("Cursor::UpdateTexture() => Monitor::GetUnityTexture() is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
IDXGISurface* surface = nullptr;
|
||||
hr = texture->QueryInterface(__uuidof(IDXGISurface), (void**)&surface);
|
||||
texture->Release();
|
||||
{
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box);
|
||||
}
|
||||
|
||||
ComPtr<IDXGISurface> surface;
|
||||
hr = texture.As<IDXGISurface>(&surface);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Debug::Error("Cursor::UpdateTexture() => texture->QueryInterface() failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -144,7 +192,7 @@ void Cursor::UpdateTexture()
|
||||
hr = surface->Map(&mappedSurface, DXGI_MAP_READ);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
surface->Release();
|
||||
Debug::Error("Cursor::UpdateTexture() => surface->Map() failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -153,40 +201,39 @@ void Cursor::UpdateTexture()
|
||||
const UINT desktopPitch = mappedSurface.Pitch / sizeof(UINT);
|
||||
|
||||
// Access RGBA values at the same time
|
||||
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_);
|
||||
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.get());
|
||||
|
||||
if (isMono)
|
||||
{
|
||||
for (int row = 0; row < h; ++row)
|
||||
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
|
||||
{
|
||||
BYTE mask = 0x80;
|
||||
for (int col = 0; col < w; ++col)
|
||||
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
|
||||
{
|
||||
const int i = row * w + col;
|
||||
BYTE mask = 0b10000000 >> (col % 8);
|
||||
const int i = row * w0 + col;
|
||||
const BYTE andMask = apiBuffer_[col / 8 + row * p] & mask;
|
||||
const BYTE xorMask = apiBuffer_[col / 8 + (row + h) * p] & mask;
|
||||
const UINT andMask32 = andMask ? 0xFFFFFFFF : 0x00000000;
|
||||
const UINT xorMask32 = xorMask ? 0xFFFFFFFF : 0x00000000;
|
||||
output32[i] = (desktop32[row * desktopPitch + col] & andMask32) ^ xorMask32;
|
||||
mask = (mask == 0x01) ? 0x80 : (mask >> 1);
|
||||
output32[i] = (desktop32[y * desktopPitch + x] & andMask32) ^ xorMask32;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR
|
||||
{
|
||||
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_);
|
||||
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_.get());
|
||||
|
||||
for (int row = 0; row < h; ++row)
|
||||
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
|
||||
{
|
||||
for (int col = 0; col < w; ++col)
|
||||
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
|
||||
{
|
||||
const int i = row * w + col;
|
||||
const int j = row * p / sizeof(UINT) + col;
|
||||
const int i = col + row * w0;
|
||||
const int j = col + row * p / sizeof(UINT);
|
||||
|
||||
UINT mask = 0xFF000000 & buffer32[j];
|
||||
if (mask)
|
||||
{
|
||||
output32[i] = (desktop32[row * desktopPitch + col] ^ buffer32[j]) | 0xFF000000;
|
||||
output32[i] = (desktop32[y * desktopPitch + x] ^ buffer32[j]) | 0xFF000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -197,7 +244,6 @@ void Cursor::UpdateTexture()
|
||||
}
|
||||
|
||||
hr = surface->Unmap();
|
||||
surface->Release();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return;
|
||||
@@ -205,25 +251,46 @@ void Cursor::UpdateTexture()
|
||||
}
|
||||
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR
|
||||
{
|
||||
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_);
|
||||
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_);
|
||||
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.get());
|
||||
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_.get());
|
||||
for (int i = 0; i < w * h; ++i)
|
||||
{
|
||||
output32[i] = buffer32[i];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void Cursor::GetTexture(ID3D11Texture2D* texture)
|
||||
{
|
||||
if (bgra32Buffer_ == nullptr || texture == nullptr) return;
|
||||
ID3D11DeviceContext* context;
|
||||
if (bgra32Buffer_ == nullptr)
|
||||
{
|
||||
Debug::Error("Cursor::GetTexture() => bgra32Buffer is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (texture == nullptr)
|
||||
{
|
||||
Debug::Error("Cursor::GetTexture() => The given texture is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
texture->GetDesc(&desc);
|
||||
if ((int)desc.Width < GetWidth() || (int)desc.Height < GetHeight())
|
||||
{
|
||||
char buf[256];
|
||||
sprintf_s(buf, 256,
|
||||
"Cursor::GetTexture() => The given texture has smaller width / height.\n"
|
||||
"Given => (%d, %d) Buffer => (%d, %d)",
|
||||
desc.Width, desc.Height, GetWidth(), GetHeight());
|
||||
Debug::Error(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_, shapeInfo_.Width * 4, 0);
|
||||
context->Release();
|
||||
context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_.get(), GetWidth() * 4, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -269,3 +336,9 @@ int Cursor::GetType() const
|
||||
{
|
||||
return shapeInfo_.Type;
|
||||
}
|
||||
|
||||
|
||||
bool Cursor::IsCursorOnParentMonitor() const
|
||||
{
|
||||
return GetMonitorManager()->GetCursorMonitorId() == monitor_->GetId();
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <memory>
|
||||
@@ -22,13 +24,15 @@ public:
|
||||
int GetType() const;
|
||||
|
||||
private:
|
||||
bool IsCursorOnParentMonitor() const;
|
||||
|
||||
Monitor* monitor_;
|
||||
bool isVisible_ = false;
|
||||
int x_ = -1;
|
||||
int y_ = -1;
|
||||
BYTE* apiBuffer_ = nullptr;
|
||||
std::unique_ptr<BYTE[]> apiBuffer_ = nullptr;
|
||||
UINT apiBufferSize_ = 0;
|
||||
BYTE* bgra32Buffer_ = nullptr;
|
||||
std::unique_ptr<BYTE[]> bgra32Buffer_ = nullptr;
|
||||
UINT bgra32BufferSize_ = 0;
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo_;
|
||||
LARGE_INTEGER timestamp_;
|
||||
|
||||
84
Plugins/uDesktopDuplication/uDesktopDuplication/Debug.cpp
Normal file
84
Plugins/uDesktopDuplication/uDesktopDuplication/Debug.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include "Debug.h"
|
||||
|
||||
|
||||
decltype(Debug::mode_) Debug::mode_ = Debug::Mode::kFile;
|
||||
decltype(Debug::logFunc_) Debug::logFunc_ = nullptr;
|
||||
decltype(Debug::errFunc_) Debug::errFunc_ = nullptr;
|
||||
decltype(Debug::fs_) Debug::fs_;
|
||||
|
||||
|
||||
void Debug::Initialize()
|
||||
{
|
||||
if (mode_ == Mode::kFile)
|
||||
{
|
||||
fs_.open("uDesktopDuplication.log");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Debug::Finalize()
|
||||
{
|
||||
fs_.close();
|
||||
}
|
||||
|
||||
|
||||
void Debug::Log(const char* msg)
|
||||
{
|
||||
switch (mode_)
|
||||
{
|
||||
case Mode::kNone:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Mode::kFile:
|
||||
{
|
||||
if (fs_.good())
|
||||
{
|
||||
fs_ << "[uDD::Log] " << msg << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::kUnityLog:
|
||||
{
|
||||
if (logFunc_ == nullptr)
|
||||
{
|
||||
char buf[256];
|
||||
sprintf_s(buf, 256, "[uDD::Log] %s", msg);
|
||||
logFunc_(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Debug::Error(const char* msg)
|
||||
{
|
||||
switch (mode_)
|
||||
{
|
||||
case Mode::kNone:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Mode::kFile:
|
||||
{
|
||||
if (fs_.good())
|
||||
{
|
||||
fs_ << "[uDD::Err] " << msg << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::kUnityLog:
|
||||
{
|
||||
if (logFunc_ == nullptr)
|
||||
{
|
||||
char buf[256];
|
||||
sprintf_s(buf, 256, "[uDD::Err] %s", msg);
|
||||
errFunc_(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Plugins/uDesktopDuplication/uDesktopDuplication/Debug.h
Normal file
33
Plugins/uDesktopDuplication/uDesktopDuplication/Debug.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include <fstream>
|
||||
#include "IUnityInterface.h"
|
||||
|
||||
// Logging
|
||||
class Debug
|
||||
{
|
||||
public:
|
||||
enum class Mode
|
||||
{
|
||||
kNone = 0,
|
||||
kFile = 1,
|
||||
kUnityLog = 2,
|
||||
};
|
||||
|
||||
using DebugLogFuncPtr = void(UNITY_INTERFACE_API *)(const char*);
|
||||
|
||||
static void SetMode(Mode mode) { mode_ = mode; }
|
||||
static void Initialize();
|
||||
static void Finalize();
|
||||
static void SetLogFunc(DebugLogFuncPtr func) { logFunc_ = func; }
|
||||
static void SetErrorFunc(DebugLogFuncPtr func) { errFunc_ = func; }
|
||||
|
||||
public:
|
||||
static void Log(const char* msg);
|
||||
static void Error(const char* msg);
|
||||
|
||||
private:
|
||||
static Mode mode_;
|
||||
static std::ofstream fs_;
|
||||
static DebugLogFuncPtr logFunc_;
|
||||
static DebugLogFuncPtr errFunc_;
|
||||
};
|
||||
@@ -1,10 +1,13 @@
|
||||
#include <d3d11.h>
|
||||
#include <ShellScalingAPI.h>
|
||||
#include "Common.h"
|
||||
#include "Debug.h"
|
||||
#include "Cursor.h"
|
||||
#include "MonitorManager.h"
|
||||
#include "Monitor.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
|
||||
Monitor::Monitor(int id)
|
||||
: id_(id)
|
||||
@@ -13,7 +16,12 @@ Monitor::Monitor(int id)
|
||||
}
|
||||
|
||||
|
||||
HRESULT Monitor::Initialize(IDXGIOutput* output)
|
||||
Monitor::~Monitor()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Monitor::Initialize(IDXGIOutput* output)
|
||||
{
|
||||
output->GetDesc(&outputDesc_);
|
||||
monitorInfo_.cbSize = sizeof(MONITORINFOEX);
|
||||
@@ -29,53 +37,46 @@ HRESULT Monitor::Initialize(IDXGIOutput* output)
|
||||
{
|
||||
case S_OK:
|
||||
state_ = State::Available;
|
||||
Debug::Log("Monitor::Initialize() => OK.");
|
||||
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;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
Monitor::~Monitor()
|
||||
void Monitor::Render(UINT timeout)
|
||||
{
|
||||
if (deskDupl_ != nullptr)
|
||||
{
|
||||
deskDupl_->Release();
|
||||
}
|
||||
}
|
||||
if (!deskDupl_) return;
|
||||
|
||||
|
||||
HRESULT Monitor::Render(UINT timeout)
|
||||
{
|
||||
if (deskDupl_ == nullptr)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IDXGIResource* resource = nullptr;
|
||||
ComPtr<IDXGIResource> resource;
|
||||
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
||||
HRESULT hr;
|
||||
|
||||
const auto hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource);
|
||||
hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
switch (hr)
|
||||
@@ -83,37 +84,43 @@ HRESULT Monitor::Render(UINT timeout)
|
||||
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:
|
||||
break;
|
||||
}
|
||||
return hr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (unityTexture_)
|
||||
{
|
||||
ID3D11Texture2D* texture;
|
||||
resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
resource.As<ID3D11Texture2D>(&texture);
|
||||
|
||||
ID3D11DeviceContext* context;
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopyResource(unityTexture_, texture);
|
||||
context->Release();
|
||||
|
||||
resource->Release();
|
||||
context->CopyResource(unityTexture_, texture.Get());
|
||||
}
|
||||
|
||||
cursor_->UpdateBuffer(frameInfo);
|
||||
cursor_->UpdateTexture();
|
||||
|
||||
deskDupl_->ReleaseFrame();
|
||||
|
||||
return S_OK;
|
||||
hr = deskDupl_->ReleaseFrame();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Debug::Error("Monitor::Render() => ReleaseFrame() failed.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +148,7 @@ ID3D11Texture2D* Monitor::GetUnityTexture() const
|
||||
}
|
||||
|
||||
|
||||
IDXGIOutputDuplication* Monitor::GetDeskDupl()
|
||||
const ComPtr<IDXGIOutputDuplication>& Monitor::GetDeskDupl()
|
||||
{
|
||||
return deskDupl_;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <wrl/client.h>
|
||||
#include <memory>
|
||||
|
||||
class Cursor;
|
||||
@@ -23,8 +26,8 @@ public:
|
||||
|
||||
explicit Monitor(int id);
|
||||
~Monitor();
|
||||
HRESULT Initialize(IDXGIOutput* output);
|
||||
HRESULT Render(UINT timeout = 0);
|
||||
void Initialize(IDXGIOutput* output);
|
||||
void Render(UINT timeout = 0);
|
||||
void GetCursorTexture(ID3D11Texture2D* texture);
|
||||
|
||||
public:
|
||||
@@ -43,7 +46,7 @@ public:
|
||||
int GetRotation() const;
|
||||
int GetDpiX() const;
|
||||
int GetDpiY() const;
|
||||
IDXGIOutputDuplication* GetDeskDupl();
|
||||
const Microsoft::WRL::ComPtr<IDXGIOutputDuplication>& GetDeskDupl();
|
||||
const std::unique_ptr<Cursor>& GetCursor();
|
||||
|
||||
private:
|
||||
@@ -51,7 +54,7 @@ private:
|
||||
UINT dpiX_ = -1, dpiY_ = -1;
|
||||
State state_ = State::NotSet;
|
||||
std::unique_ptr<Cursor> cursor_;
|
||||
IDXGIOutputDuplication* deskDupl_ = nullptr;
|
||||
Microsoft::WRL::ComPtr<IDXGIOutputDuplication> deskDupl_;
|
||||
ID3D11Texture2D* unityTexture_ = nullptr;
|
||||
DXGI_OUTPUT_DESC outputDesc_;
|
||||
MONITORINFOEX monitorInfo_;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <wrl/client.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
@@ -12,6 +13,8 @@
|
||||
#include "Cursor.h"
|
||||
#include "MonitorManager.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
|
||||
MonitorManager::MonitorManager()
|
||||
{
|
||||
@@ -30,26 +33,23 @@ void MonitorManager::Initialize()
|
||||
Finalize();
|
||||
|
||||
// Get factory
|
||||
IDXGIFactory1* factory;
|
||||
CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));
|
||||
ComPtr<IDXGIFactory1> factory;
|
||||
CreateDXGIFactory1(IID_PPV_ARGS(&factory));
|
||||
|
||||
// Check all display adapters
|
||||
int id = 0;
|
||||
IDXGIAdapter1* adapter;
|
||||
ComPtr<IDXGIAdapter1> adapter;
|
||||
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
|
||||
{
|
||||
// Search the main monitor from all outputs
|
||||
IDXGIOutput* output;
|
||||
ComPtr<IDXGIOutput> output;
|
||||
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
|
||||
{
|
||||
auto monitor = std::make_shared<Monitor>(id++);
|
||||
monitor->Initialize(output);
|
||||
monitor->Initialize(output.Get());
|
||||
monitors_.push_back(monitor);
|
||||
output->Release();
|
||||
}
|
||||
adapter->Release();
|
||||
}
|
||||
factory->Release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <vector>
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
#include "IUnityInterface.h"
|
||||
#include "IUnityGraphics.h"
|
||||
#include "IUnityGraphicsD3D11.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "Debug.h"
|
||||
#include "Monitor.h"
|
||||
#include "Cursor.h"
|
||||
#include "MonitorManager.h"
|
||||
@@ -18,36 +18,9 @@
|
||||
#pragma comment(lib, "Shcore.lib")
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
IUnityInterfaces* g_unity = nullptr;
|
||||
std::unique_ptr<MonitorManager> g_manager;
|
||||
std::queue<Message> g_messages;
|
||||
}
|
||||
|
||||
|
||||
IUnityInterfaces* GetUnity()
|
||||
{
|
||||
return g_unity;
|
||||
}
|
||||
|
||||
|
||||
ID3D11Device* GetDevice()
|
||||
{
|
||||
return GetUnity()->Get<IUnityGraphicsD3D11>()->GetDevice();
|
||||
}
|
||||
|
||||
|
||||
const std::unique_ptr<MonitorManager>& GetMonitorManager()
|
||||
{
|
||||
return g_manager;
|
||||
}
|
||||
|
||||
|
||||
void SendMessageToUnity(Message message)
|
||||
{
|
||||
g_messages.push(message);
|
||||
}
|
||||
IUnityInterfaces* g_unity = nullptr;
|
||||
std::unique_ptr<MonitorManager> g_manager;
|
||||
std::queue<Message> g_messages;
|
||||
|
||||
|
||||
extern "C"
|
||||
@@ -57,12 +30,20 @@ extern "C"
|
||||
if (g_unity && !g_manager)
|
||||
{
|
||||
g_manager = std::make_unique<MonitorManager>();
|
||||
Debug::Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API FinalizeUDD()
|
||||
{
|
||||
g_manager.reset();
|
||||
|
||||
std::queue<Message> empty;
|
||||
g_messages.swap(empty);
|
||||
|
||||
Debug::SetLogFunc(nullptr);
|
||||
Debug::SetErrorFunc(nullptr);
|
||||
Debug::Finalize();
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
|
||||
@@ -73,8 +54,8 @@ extern "C"
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginUnload()
|
||||
{
|
||||
g_unity = nullptr;
|
||||
FinalizeUDD();
|
||||
g_unity = nullptr;
|
||||
}
|
||||
|
||||
void UNITY_INTERFACE_API OnRenderEvent(int id)
|
||||
@@ -103,7 +84,7 @@ extern "C"
|
||||
g_manager->Update();
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT Message PopMessage()
|
||||
UNITY_INTERFACE_EXPORT Message UNITY_INTERFACE_API PopMessage()
|
||||
{
|
||||
if (g_messages.empty()) return Message::None;
|
||||
|
||||
@@ -112,6 +93,21 @@ extern "C"
|
||||
return message;
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetDebugMode(Debug::Mode mode)
|
||||
{
|
||||
Debug::SetMode(mode);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetLogFunc(Debug::DebugLogFuncPtr func)
|
||||
{
|
||||
Debug::SetLogFunc(func);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetErrorFunc(Debug::DebugLogFuncPtr func)
|
||||
{
|
||||
Debug::SetErrorFunc(func);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT size_t UNITY_INTERFACE_API GetMonitorCount()
|
||||
{
|
||||
if (!g_manager) return 0;
|
||||
@@ -142,6 +138,15 @@ extern "C"
|
||||
g_manager->SetTimeout(timeout);
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetId(int id)
|
||||
{
|
||||
if (!g_manager) return;
|
||||
if (auto monitor = g_manager->GetMonitor(id))
|
||||
{
|
||||
monitor->GetId();
|
||||
}
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT MonitorState UNITY_INTERFACE_API GetState(int id)
|
||||
{
|
||||
if (!g_manager) return MonitorState::NotSet;
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins"</Command>
|
||||
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86_64"</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@@ -122,10 +122,12 @@
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins"</Command>
|
||||
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86_64"</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Common.cpp" />
|
||||
<ClCompile Include="Debug.cpp" />
|
||||
<ClCompile Include="MonitorManager.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="Monitor.cpp" />
|
||||
@@ -133,6 +135,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Common.h" />
|
||||
<ClInclude Include="Debug.h" />
|
||||
<ClInclude Include="MonitorManager.h" />
|
||||
<ClInclude Include="include\IUnityGraphics.h" />
|
||||
<ClInclude Include="include\IUnityGraphicsD3D11.h" />
|
||||
|
||||
@@ -19,11 +19,14 @@
|
||||
<ClInclude Include="Cursor.h" />
|
||||
<ClInclude Include="Common.h" />
|
||||
<ClInclude Include="MonitorManager.h" />
|
||||
<ClInclude Include="Debug.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Monitor.cpp" />
|
||||
<ClCompile Include="Cursor.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="MonitorManager.cpp" />
|
||||
<ClCompile Include="Common.cpp" />
|
||||
<ClCompile Include="Debug.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Binary file not shown.
Reference in New Issue
Block a user